feat: functions with formal parameters
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct Catchable {
|
||||
msg: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Constructor)]
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)]
|
||||
pub struct Symbol(EcoString);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,13 @@ impl AttrSet {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn to_data(self) -> HashTrieMapSync<Symbol, Value> {
|
||||
pub fn into_inner(self) -> HashTrieMapSync<Symbol, Value> {
|
||||
self.data
|
||||
}
|
||||
|
||||
pub fn as_inner(&self) -> &HashTrieMapSync<Symbol, Value> {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl ToPublic for AttrSet {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user