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 -9
View File
@@ -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)),