Add lambda expression support
Introduces `UntypedKind::Lambda` to represent function closures. Adds `parse_fn` to the parser to handle lambda syntax. Updates `Node::eval` to correctly evaluate lambda expressions, creating new scopes for each invocation with captured variables. Improves handling of call expressions by passing the AST node's identity. Removes unnecessary comments and simplifies some error handling.
This commit is contained in:
+59
-34
@@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
use crate::ast::lexer::{Lexer, Token, TokenKind};
|
||||
use crate::ast::types::{Identity, NodeIdentity, Value, Keyword};
|
||||
use crate::ast::nodes::{Node, UntypedKind};
|
||||
use crate::ast::nodes::{Node, UntypedKind, Context};
|
||||
|
||||
pub struct Parser<'a> {
|
||||
lexer: Lexer<'a>,
|
||||
@@ -27,13 +27,17 @@ impl<'a> Parser<'a> {
|
||||
pub fn parse_expression(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
match self.peek() {
|
||||
TokenKind::LeftParen => self.parse_list(),
|
||||
TokenKind::LeftBracket => self.parse_vector(),
|
||||
// TokenKind::LeftBrace => self.parse_map(), // TODO
|
||||
TokenKind::LeftBracket => self.parse_vector_literal(),
|
||||
TokenKind::Quote => {
|
||||
let identity = Arc::new(NodeIdentity { location: self.current_token.location });
|
||||
self.parse_reader_macro(UntypedKind::Call {
|
||||
callee: Box::new(self.make_id_node("quote", identity)),
|
||||
args: vec![], // will be filled
|
||||
self.advance()?; // consume '
|
||||
let expr = self.parse_expression()?;
|
||||
Ok(Node {
|
||||
identity: identity.clone(),
|
||||
kind: UntypedKind::Call {
|
||||
callee: Box::new(self.make_id_node("quote", identity)),
|
||||
args: vec![expr],
|
||||
},
|
||||
})
|
||||
}
|
||||
_ => self.parse_atom(),
|
||||
@@ -65,21 +69,24 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn parse_list(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let start_loc = self.advance()?.location; // consume '('
|
||||
let identity = Arc::new(NodeIdentity { location: start_loc });
|
||||
|
||||
if *self.peek() == TokenKind::RightParen {
|
||||
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(head.identity.clone()),
|
||||
_ => self.parse_call(head),
|
||||
"if" => self.parse_if(identity),
|
||||
"fn" => self.parse_fn(identity),
|
||||
_ => self.parse_call(head, identity), // Pass head + identity
|
||||
}
|
||||
} else {
|
||||
self.parse_call(head)
|
||||
self.parse_call(head, identity)
|
||||
};
|
||||
|
||||
self.expect(TokenKind::RightParen)?;
|
||||
@@ -87,6 +94,7 @@ 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;
|
||||
@@ -101,10 +109,41 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_call(&mut self, callee: Node<UntypedKind>) -> Result<Node<UntypedKind>, String> {
|
||||
let mut args = Vec::new();
|
||||
let identity = callee.identity.clone();
|
||||
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()?;
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Lambda {
|
||||
params,
|
||||
body: Arc::new(body),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_param_vector(&mut self) -> Result<Vec<Arc<str>>, String> {
|
||||
if *self.peek() != TokenKind::LeftBracket {
|
||||
return Err(format!("Expected parameter vector [...] for fn, found {:?}", self.peek()));
|
||||
}
|
||||
self.advance()?; // consume '['
|
||||
|
||||
let mut params = Vec::new();
|
||||
while *self.peek() != TokenKind::RightBracket {
|
||||
let token = self.advance()?;
|
||||
match token.kind {
|
||||
TokenKind::Identifier(name) => params.push(name),
|
||||
_ => return Err(format!("Expected identifier in param vector, found {:?}", token.kind)),
|
||||
}
|
||||
}
|
||||
self.expect(TokenKind::RightBracket)?;
|
||||
Ok(params)
|
||||
}
|
||||
|
||||
fn parse_call(&mut self, callee: Node<UntypedKind>, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
let mut args = Vec::new();
|
||||
|
||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||
args.push(self.parse_expression()?);
|
||||
}
|
||||
@@ -115,17 +154,20 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_vector(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
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 {
|
||||
// Vector elements in Myc are usually just constants in a list
|
||||
let expr = self.parse_expression()?;
|
||||
// Simple direct eval for literals (Context::new creates fresh scope)
|
||||
match expr.eval(&mut crate::ast::nodes::Context::new()) {
|
||||
// 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!("Error evaluating vector element: {}", e)),
|
||||
Err(e) => return Err(format!("Vector literal error: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,23 +179,6 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_reader_macro(&mut self, _template: UntypedKind) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?; // consume '
|
||||
let expr = self.parse_expression()?;
|
||||
|
||||
// 'x -> (quote x)
|
||||
let identity = Arc::new(NodeIdentity { location: token.location });
|
||||
let quote_id = self.make_id_node("quote", identity.clone());
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Call {
|
||||
callee: Box::new(quote_id),
|
||||
args: vec![expr],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn expect(&mut self, kind: TokenKind) -> Result<(), String> {
|
||||
let token = self.advance()?;
|
||||
if token.kind == kind {
|
||||
|
||||
Reference in New Issue
Block a user