Add def and do special forms

Introduces `def` for variable assignment and `do` for block expressions,
enabling multiple statements within a single expression.
This commit is contained in:
Michael Schimmel
2026-02-17 00:47:24 +01:00
parent 145e12b811
commit 21574520d5
2 changed files with 60 additions and 24 deletions
+30 -15
View File
@@ -115,15 +115,23 @@ pub enum UntypedKind {
then_br: Box<Node<UntypedKind>>,
else_br: Option<Box<Node<UntypedKind>>>,
},
// CLOSURE SUPPORT
// DEFINITION (new)
Def {
name: Arc<str>,
value: Box<Node<UntypedKind>>,
},
Lambda {
params: Vec<Arc<str>>,
body: Arc<Node<UntypedKind>>, // Arc for cheap cloning into closure
body: Arc<Node<UntypedKind>>,
},
Call {
callee: Box<Node<UntypedKind>>,
args: Vec<Node<UntypedKind>>,
},
// BLOCK (do ...) to evaluate multiple expressions
Block {
exprs: Vec<Node<UntypedKind>>,
},
Extension(Box<dyn CustomNode>),
}
@@ -148,19 +156,32 @@ impl Node<UntypedKind> {
} else {
Ok(Value::Void)
}
}
// --- CLOSURE IMPLEMENTATION ---
},
// --- DEF (Assignment) ---
UntypedKind::Def { name, value } => {
let val = value.eval(ctx)?;
let mut scope = ctx.scope.lock().unwrap();
scope.define(name, val.clone());
Ok(val) // Return value of definition
},
// --- BLOCK (do) ---
UntypedKind::Block { exprs } => {
let mut last_val = Value::Void;
for expr in exprs {
last_val = expr.eval(ctx)?;
}
Ok(last_val)
},
UntypedKind::Lambda { params, body } => {
let captured_scope = ctx.scope.clone();
let params = params.clone();
let body = body.clone();
Ok(Value::Function(Arc::new(move |args| {
// 1. New Scope with captured parent
let mut new_scope = Scope::new(Some(captured_scope.clone()));
// 2. Bind Args
for (i, param) in params.iter().enumerate() {
if i < args.len() {
new_scope.define(param, args[i].clone());
@@ -168,10 +189,6 @@ impl Node<UntypedKind> {
new_scope.define(param, Value::Void);
}
}
// 3. Eval Body
// Note: We swallow errors here because Value::Function signature is simple.
// In a full VM, we'd return Result<Value, Error>.
let mut sub_ctx = Context { scope: Arc::new(Mutex::new(new_scope)) };
body.eval(&mut sub_ctx).unwrap_or(Value::Void)
})))
@@ -179,17 +196,15 @@ impl Node<UntypedKind> {
UntypedKind::Call { callee, args } => {
let func_val = callee.eval(ctx)?;
let mut eval_args = Vec::with_capacity(args.len());
for arg in args {
eval_args.push(arg.eval(ctx)?);
}
match func_val {
Value::Function(f) => Ok(f(eval_args)),
_ => Err(format!("Attempt to call a non-function value: {}", func_val)),
}
}
},
UntypedKind::Extension(ext) => ext.eval(self, ctx),
}