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),
|
||||
}
|
||||
|
||||
+30
-9
@@ -75,15 +75,15 @@ impl<'a> Parser<'a> {
|
||||
return Err(format!("Empty list () is not a valid expression at {:?}", start_loc));
|
||||
}
|
||||
|
||||
// Peek at head to check for special forms
|
||||
// We parse the first expression to check if it's an identifier "if", "fn", etc.
|
||||
let head = self.parse_expression()?;
|
||||
|
||||
let result = if let UntypedKind::Identifier(name) = &head.kind {
|
||||
match name.as_ref() {
|
||||
"if" => self.parse_if(identity),
|
||||
"fn" => self.parse_fn(identity),
|
||||
_ => self.parse_call(head, identity), // Pass head + identity
|
||||
"def" => self.parse_def(identity),
|
||||
"do" => self.parse_do(identity),
|
||||
_ => self.parse_call(head, identity),
|
||||
}
|
||||
} else {
|
||||
self.parse_call(head, identity)
|
||||
@@ -94,7 +94,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn parse_if(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
// 'if' was already consumed as head
|
||||
let cond = Box::new(self.parse_expression()?);
|
||||
let then_br = Box::new(self.parse_expression()?);
|
||||
let mut else_br = None;
|
||||
@@ -109,8 +108,34 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_def(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
// (def name value)
|
||||
let name_node = self.parse_expression()?;
|
||||
let name = match name_node.kind {
|
||||
UntypedKind::Identifier(s) => s,
|
||||
_ => return Err("Expected identifier for def name".to_string()),
|
||||
};
|
||||
|
||||
let value = Box::new(self.parse_expression()?);
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Def { name, value },
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_do(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
let mut exprs = Vec::new();
|
||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||
exprs.push(self.parse_expression()?);
|
||||
}
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Block { exprs },
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_fn(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
// 'fn' was consumed. Next must be [params] vector.
|
||||
let params = self.parse_param_vector()?;
|
||||
let body = self.parse_expression()?;
|
||||
|
||||
@@ -157,14 +182,10 @@ impl<'a> Parser<'a> {
|
||||
fn parse_vector_literal(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?; // consume '['
|
||||
let mut elements = Vec::new();
|
||||
|
||||
// Temporary evaluation context for literals
|
||||
let mut temp_ctx = Context::new();
|
||||
|
||||
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
||||
let expr = self.parse_expression()?;
|
||||
// Simple direct eval for literals inside vectors (e.g. [1 2 3])
|
||||
// In a full compiler, we would return a VectorNode here instead of evaluating immediately.
|
||||
match expr.eval(&mut temp_ctx) {
|
||||
Ok(val) => elements.push(val),
|
||||
Err(e) => return Err(format!("Vector literal error: {}", e)),
|
||||
|
||||
Reference in New Issue
Block a user