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
-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