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>>,
|
then_br: Box<Node<UntypedKind>>,
|
||||||
else_br: Option<Box<Node<UntypedKind>>>,
|
else_br: Option<Box<Node<UntypedKind>>>,
|
||||||
},
|
},
|
||||||
// CLOSURE SUPPORT
|
// DEFINITION (new)
|
||||||
|
Def {
|
||||||
|
name: Arc<str>,
|
||||||
|
value: Box<Node<UntypedKind>>,
|
||||||
|
},
|
||||||
Lambda {
|
Lambda {
|
||||||
params: Vec<Arc<str>>,
|
params: Vec<Arc<str>>,
|
||||||
body: Arc<Node<UntypedKind>>, // Arc for cheap cloning into closure
|
body: Arc<Node<UntypedKind>>,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
callee: Box<Node<UntypedKind>>,
|
callee: Box<Node<UntypedKind>>,
|
||||||
args: Vec<Node<UntypedKind>>,
|
args: Vec<Node<UntypedKind>>,
|
||||||
},
|
},
|
||||||
|
// BLOCK (do ...) to evaluate multiple expressions
|
||||||
|
Block {
|
||||||
|
exprs: Vec<Node<UntypedKind>>,
|
||||||
|
},
|
||||||
Extension(Box<dyn CustomNode>),
|
Extension(Box<dyn CustomNode>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,19 +156,32 @@ impl Node<UntypedKind> {
|
|||||||
} else {
|
} else {
|
||||||
Ok(Value::Void)
|
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 } => {
|
UntypedKind::Lambda { params, body } => {
|
||||||
let captured_scope = ctx.scope.clone();
|
let captured_scope = ctx.scope.clone();
|
||||||
let params = params.clone();
|
let params = params.clone();
|
||||||
let body = body.clone();
|
let body = body.clone();
|
||||||
|
|
||||||
Ok(Value::Function(Arc::new(move |args| {
|
Ok(Value::Function(Arc::new(move |args| {
|
||||||
// 1. New Scope with captured parent
|
|
||||||
let mut new_scope = Scope::new(Some(captured_scope.clone()));
|
let mut new_scope = Scope::new(Some(captured_scope.clone()));
|
||||||
|
|
||||||
// 2. Bind Args
|
|
||||||
for (i, param) in params.iter().enumerate() {
|
for (i, param) in params.iter().enumerate() {
|
||||||
if i < args.len() {
|
if i < args.len() {
|
||||||
new_scope.define(param, args[i].clone());
|
new_scope.define(param, args[i].clone());
|
||||||
@@ -168,10 +189,6 @@ impl Node<UntypedKind> {
|
|||||||
new_scope.define(param, Value::Void);
|
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)) };
|
let mut sub_ctx = Context { scope: Arc::new(Mutex::new(new_scope)) };
|
||||||
body.eval(&mut sub_ctx).unwrap_or(Value::Void)
|
body.eval(&mut sub_ctx).unwrap_or(Value::Void)
|
||||||
})))
|
})))
|
||||||
@@ -179,17 +196,15 @@ impl Node<UntypedKind> {
|
|||||||
|
|
||||||
UntypedKind::Call { callee, args } => {
|
UntypedKind::Call { callee, args } => {
|
||||||
let func_val = callee.eval(ctx)?;
|
let func_val = callee.eval(ctx)?;
|
||||||
|
|
||||||
let mut eval_args = Vec::with_capacity(args.len());
|
let mut eval_args = Vec::with_capacity(args.len());
|
||||||
for arg in args {
|
for arg in args {
|
||||||
eval_args.push(arg.eval(ctx)?);
|
eval_args.push(arg.eval(ctx)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
match func_val {
|
match func_val {
|
||||||
Value::Function(f) => Ok(f(eval_args)),
|
Value::Function(f) => Ok(f(eval_args)),
|
||||||
_ => Err(format!("Attempt to call a non-function value: {}", func_val)),
|
_ => Err(format!("Attempt to call a non-function value: {}", func_val)),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
UntypedKind::Extension(ext) => ext.eval(self, ctx),
|
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));
|
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 head = self.parse_expression()?;
|
||||||
|
|
||||||
let result = if let UntypedKind::Identifier(name) = &head.kind {
|
let result = if let UntypedKind::Identifier(name) = &head.kind {
|
||||||
match name.as_ref() {
|
match name.as_ref() {
|
||||||
"if" => self.parse_if(identity),
|
"if" => self.parse_if(identity),
|
||||||
"fn" => self.parse_fn(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 {
|
} else {
|
||||||
self.parse_call(head, identity)
|
self.parse_call(head, identity)
|
||||||
@@ -94,7 +94,6 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_if(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
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 cond = Box::new(self.parse_expression()?);
|
||||||
let then_br = Box::new(self.parse_expression()?);
|
let then_br = Box::new(self.parse_expression()?);
|
||||||
let mut else_br = None;
|
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 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 params = self.parse_param_vector()?;
|
||||||
let body = self.parse_expression()?;
|
let body = self.parse_expression()?;
|
||||||
|
|
||||||
@@ -157,14 +182,10 @@ impl<'a> Parser<'a> {
|
|||||||
fn parse_vector_literal(&mut self) -> Result<Node<UntypedKind>, String> {
|
fn parse_vector_literal(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||||
let token = self.advance()?; // consume '['
|
let token = self.advance()?; // consume '['
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
// Temporary evaluation context for literals
|
|
||||||
let mut temp_ctx = Context::new();
|
let mut temp_ctx = Context::new();
|
||||||
|
|
||||||
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
||||||
let expr = self.parse_expression()?;
|
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) {
|
match expr.eval(&mut temp_ctx) {
|
||||||
Ok(val) => elements.push(val),
|
Ok(val) => elements.push(val),
|
||||||
Err(e) => return Err(format!("Vector literal error: {}", e)),
|
Err(e) => return Err(format!("Vector literal error: {}", e)),
|
||||||
|
|||||||
Reference in New Issue
Block a user