feat: functions with formal parameters

This commit is contained in:
2025-05-04 15:21:44 +08:00
parent bc50464db9
commit eea4a4ce9f
6 changed files with 53 additions and 10 deletions

View File

@@ -32,8 +32,6 @@ pub enum OpCode {
/// [ .. func args @ .. ] consume (`arity` + 2) elements, call `func` with args` of length `arity` /// [ .. func args @ .. ] consume (`arity` + 2) elements, call `func` with args` of length `arity`
/// Example: __add 1 2 => [ LookUp("__add") Const(1) Const(2) Call(2) ] /// Example: __add 1 2 => [ LookUp("__add") Const(1) Const(2) Call(2) ]
Call { arity: usize }, Call { arity: usize },
/// return a value
Ret,
/// make a function /// make a function
Func { idx: ThunkIdx }, Func { idx: ThunkIdx },
/// push param `sym` into TOS /// push param `sym` into TOS

View File

@@ -8,7 +8,7 @@ pub struct Catchable {
msg: Option<String>, msg: Option<String>,
} }
#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)] #[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)]
pub struct Symbol(EcoString); pub struct Symbol(EcoString);
impl<T: Into<EcoString>> From<T> for Symbol { impl<T: Into<EcoString>> From<T> for Symbol {
@@ -24,3 +24,12 @@ impl Deref for Symbol {
} }
} }
impl Symbol {
pub fn into_inner(self) -> EcoString {
self.0
}
pub fn as_inner(&self) -> &EcoString {
&self.0
}
}

View File

@@ -43,9 +43,13 @@ impl AttrSet {
self self
} }
pub fn to_data(self) -> HashTrieMapSync<Symbol, Value> { pub fn into_inner(self) -> HashTrieMapSync<Symbol, Value> {
self.data self.data
} }
pub fn as_inner(&self) -> &HashTrieMapSync<Symbol, Value> {
&self.data
}
} }
impl ToPublic for AttrSet { impl ToPublic for AttrSet {

View File

@@ -1,8 +1,9 @@
use ecow::EcoString; use ecow::EcoString;
use itertools::Itertools;
use rpds::HashTrieMap; use rpds::HashTrieMap;
use crate::bytecode::{OpCodes, ThunkIdx}; use crate::bytecode::{OpCodes, ThunkIdx};
use crate::ty::internal::Value; use crate::ty::internal::{Thunk, Value};
use crate::vm::{LockedEnv, VM}; use crate::vm::{LockedEnv, VM};
@@ -39,7 +40,38 @@ impl Func {
match self.param.unwrap() { match self.param.unwrap() {
Ident(ident) => env.enter(HashTrieMap::new_sync().insert(ident.into(), arg)), Ident(ident) => env.enter(HashTrieMap::new_sync().insert(ident.into(), arg)),
Formals { .. } => todo!() Formals {
formals,
ellipsis,
alias,
} => {
let arg = arg.unwrap_attr_set();
let mut new = HashTrieMap::new_sync();
if !ellipsis
&& arg
.as_inner()
.iter()
.map(|(k, _)| k.as_inner())
.sorted()
.ne(formals.iter().map(|(k, _)| k).sorted())
{
todo!()
}
for (formal, default) in formals {
// let arg = if let Some(default) = default {
// arg.select(format)
// }
let arg = arg
.select(formal.clone().into())
.or_else(|| default.map(|idx| Value::Thunk(Thunk(idx))))
.unwrap();
new.insert_mut(formal.into(), arg);
}
if let Some(alias) = alias {
new.insert_mut(alias.into(), Value::AttrSet(arg));
}
env.enter(new);
}
} }
vm.eval(self.opcodes, &mut env).unwrap() vm.eval(self.opcodes, &mut env).unwrap()

View File

@@ -173,4 +173,7 @@ fn test_func() {
test_expr("(x: x) 1", int!(1)); test_expr("(x: x) 1", int!(1));
test_expr("(x: x) (x: x) 1", int!(1)); test_expr("(x: x) (x: x) 1", int!(1));
test_expr("(x: y: x + y) 1 1", int!(2)); test_expr("(x: y: x + y) 1 1", int!(2));
test_expr("({ x, y }: x + y) { x = 1; y = 2; }", int!(3));
test_expr("({ x, y, ... }: x + y) { x = 1; y = 2; z = 3; }", int!(3));
test_expr("(inputs@{ x, y, ... }: x + inputs.y) { x = 1; y = 2; z = 3; }", int!(3));
} }

View File

@@ -111,9 +111,6 @@ impl VM {
OpCode::SetAlias { sym } => { OpCode::SetAlias { sym } => {
stack.tos_mut()?.as_mut().unwrap_func().set_alias(sym); stack.tos_mut()?.as_mut().unwrap_func().set_alias(sym);
} }
OpCode::Ret => {
todo!()
}
OpCode::UnOp { op } => { OpCode::UnOp { op } => {
use UnOp::*; use UnOp::*;
let value = stack.pop()?; let value = stack.pop()?;
@@ -200,7 +197,7 @@ impl VM {
)?; )?;
} }
OpCode::EnterEnv => { OpCode::EnterEnv => {
env.enter(stack.pop()?.unwrap_attr_set().to_data()); env.enter(stack.pop()?.unwrap_attr_set().into_inner());
} }
OpCode::LeaveEnv => { OpCode::LeaveEnv => {
env.leave(); env.leave();