diff --git a/src/bytecode.rs b/src/bytecode.rs index 11bd434..7371145 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -32,8 +32,6 @@ pub enum OpCode { /// [ .. 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) ] Call { arity: usize }, - /// return a value - Ret, /// make a function Func { idx: ThunkIdx }, /// push param `sym` into TOS diff --git a/src/ty/common.rs b/src/ty/common.rs index 127b5ab..7d17366 100644 --- a/src/ty/common.rs +++ b/src/ty/common.rs @@ -8,7 +8,7 @@ pub struct Catchable { msg: Option, } -#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)] pub struct Symbol(EcoString); impl> From 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 + } +} diff --git a/src/ty/internal/attrset.rs b/src/ty/internal/attrset.rs index 0551888..b3e603b 100644 --- a/src/ty/internal/attrset.rs +++ b/src/ty/internal/attrset.rs @@ -43,9 +43,13 @@ impl AttrSet { self } - pub fn to_data(self) -> HashTrieMapSync { + pub fn into_inner(self) -> HashTrieMapSync { self.data } + + pub fn as_inner(&self) -> &HashTrieMapSync { + &self.data + } } impl ToPublic for AttrSet { diff --git a/src/ty/internal/func.rs b/src/ty/internal/func.rs index 69c16c0..44d0424 100644 --- a/src/ty/internal/func.rs +++ b/src/ty/internal/func.rs @@ -1,8 +1,9 @@ use ecow::EcoString; +use itertools::Itertools; use rpds::HashTrieMap; use crate::bytecode::{OpCodes, ThunkIdx}; -use crate::ty::internal::Value; +use crate::ty::internal::{Thunk, Value}; use crate::vm::{LockedEnv, VM}; @@ -39,7 +40,38 @@ impl Func { match self.param.unwrap() { 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() diff --git a/src/vm/test.rs b/src/vm/test.rs index 4691c7d..aedc548 100644 --- a/src/vm/test.rs +++ b/src/vm/test.rs @@ -173,4 +173,7 @@ fn test_func() { test_expr("(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) { 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)); } diff --git a/src/vm/vm.rs b/src/vm/vm.rs index 290b2b4..d4c25f6 100644 --- a/src/vm/vm.rs +++ b/src/vm/vm.rs @@ -111,9 +111,6 @@ impl VM { OpCode::SetAlias { sym } => { stack.tos_mut()?.as_mut().unwrap_func().set_alias(sym); } - OpCode::Ret => { - todo!() - } OpCode::UnOp { op } => { use UnOp::*; let value = stack.pop()?; @@ -200,7 +197,7 @@ impl VM { )?; } OpCode::EnterEnv => { - env.enter(stack.pop()?.unwrap_attr_set().to_data()); + env.enter(stack.pop()?.unwrap_attr_set().into_inner()); } OpCode::LeaveEnv => { env.leave();