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:
+30
-15
@@ -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),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user