use crate::{ common::{ ast::{AstNode, Expr, Stmt}, base_value::{BaseValue, LoxFunction}, lox_result::{parse_error, runtime_error, LoxError, LoxResult}, }, frontend::{ source_registry::SourceSlice, tokens::{Token, TokenType}, }, }; pub struct Parser { tokens: Vec, current: usize, } impl Parser { pub fn new(tokens: Vec) -> Self { Self { tokens, current: 0 } } pub fn parse(&mut self) -> LoxResult>> { let mut statements = Vec::new(); let mut errors = Vec::new(); while !self.is_at_end() { match self.statement(None) { Ok(stmt) => { statements.push(stmt.clone()); } Err(err) => { errors.push(err); self.synchronize(); } } } if !errors.is_empty() { return Err(errors.into_iter().next().unwrap()); } Ok(statements) } fn statement(&mut self, label: Option) -> LoxResult> { match (&self.peek().token_type, &self.peek_next().token_type) { (TokenType::Print, _) => self.print_statement(), (TokenType::Return, _) => self.return_statement(label), (TokenType::Break, _) => self.return_statement(Some("loop".to_string())), (TokenType::StartBlock, _) => self.block_statement(label), (TokenType::Var, TokenType::Identifier) => { self.advance(); self.var_statement() } (TokenType::Identifier, TokenType::Colon) => self.var_statement(), (TokenType::If, _) => self.if_statement(), (TokenType::While, _) => self.while_statement(), (TokenType::For, _) => self.for_statement(), _ => self.expression_statement(), } } fn for_statement(&mut self) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); self.advance(); // consume 'for' let variable = self.var_statement()?; let condition = self.expression()?; self.consume(TokenType::Semicolon, "Expected ';' after for condition")?; let increment = self.expression_statement()?; let body = self.statement(Some("loop".to_string()))?; let end_slice = self.previous().source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); Ok(AstNode::new( Stmt::For { variable: Box::new(variable), condition: Box::new(condition), increment: Box::new(increment), body: Box::new(body), return_value: Box::new(BaseValue::Nil), }, combined_slice, )) } // fn for_statement(&mut self) -> LoxResult> { // let start_slice = self.peek().source_slice.clone(); // self.advance(); // let variable = if let Token { // token_type: TokenType::Identifier, // literal: Some(variable_name), // source_slice, // .. // } = self.peek() // { // AstNode { // node: Expr::Literal { // value: variable_name.clone(), // }, // source_slice: source_slice.clone(), // } // } else { // return parse_error( // self.peek().source_slice.clone(), // "Expect variable name after 'for' keyword.", // ); // }; // self.advance(); // self.consume(TokenType::In, "Expect 'in' after for variable.")?; // let iterable = self.expression()?; // let body = self.statement(None)?; // let end_slice = body.source_slice.clone(); // let combined_slice = SourceSlice::from_positions( // start_slice.source_id, // start_slice.start_position, // end_slice.end_position, // ); // Ok(AstNode::new( // Stmt::For { // variable: Box::new(variable), // iterable: Box::new(iterable), // body: Box::new(body), // }, // combined_slice, // )) // } fn while_statement(&mut self) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); self.advance(); let condition = self.expression()?; let body = self.statement(Some("loop".to_string()))?; let end_slice = body.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); Ok(AstNode::new( Stmt::While { condition: Box::new(condition), body: Box::new(body), return_value: Box::new(BaseValue::Nil), }, combined_slice, )) } fn if_statement(&mut self) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); self.advance(); // consume 'if' let condition = self.expression()?; self.consume(TokenType::Then, "Expect 'then' after if condition.")?; let then_branch = self.statement(None)?; let mut elif_branches = Vec::new(); let mut last_slice = then_branch.source_slice.clone(); while self.peek().token_type == TokenType::Elif { self.advance(); // consume 'elif' let elif_condition = self.expression()?; self.consume(TokenType::Then, "Expect 'then' after elif condition.")?; let elif_branch = self.statement(None)?; last_slice = elif_branch.source_slice.clone(); elif_branches.push((Box::new(elif_condition), Box::new(elif_branch))); } let else_branch = if self.peek().token_type == TokenType::Else { self.advance(); // consume 'else' let else_stmt = self.statement(None)?; last_slice = else_stmt.source_slice.clone(); Some(Box::new(else_stmt)) } else { None }; let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, last_slice.end_position, ); Ok(AstNode::new( Stmt::If { condition: Box::new(condition), then_branch: Box::new(then_branch), elif_branch: elif_branches, else_branch: else_branch, return_value: Box::new(BaseValue::Nil), }, combined_slice, )) } fn var_statement(&mut self) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); let name = self.consume(TokenType::Identifier, "Expect variable name.")?; let name_lexeme = name.lexeme.clone(); let mut _type_annotation = BaseValue::Nil; self.consume(TokenType::Colon, "Expect column")?; if self.peek().token_type == TokenType::Identifier { // TODO manage type annotation self.consume(TokenType::Identifier, "Expect type name.")?; } match self.peek().token_type { TokenType::Equal | TokenType::Identifier => { self.variable_declaration(start_slice, name_lexeme) } TokenType::Colon => self.function_declaration(start_slice, name_lexeme), _ => runtime_error(start_slice, "this is not supposed to be here"), } } fn function_declaration( &mut self, start_slice: SourceSlice, name_lexeme: String, ) -> LoxResult> { self.advance(); self.consume(TokenType::Fn, "Expect 'fn' after '::'")?; self.consume(TokenType::LeftParen, "Expect '(' after 'fn' ")?; let mut parameters: Vec<(String, String)> = vec![]; while self.peek().token_type != TokenType::RightParen { let expr = self .consume(TokenType::Identifier, "Expect identifier after '('")? .clone(); if self.peek().token_type == TokenType::Colon { self.advance(); let type_ = self.consume(TokenType::Identifier, "Expected identifier after ':' ")?; parameters.push((expr.lexeme, type_.lexeme.clone())); } else { parameters.push((expr.lexeme, "Any".to_string())); } if self.peek().token_type == TokenType::Comma { self.advance(); } } self.consume(TokenType::RightParen, "Expected ')' after parameters")?; let end_position = self.peek().source_slice.clone(); let combine_position = SourceSlice { source_id: start_slice.source_id, start_position: start_slice.start_position.clone(), end_position: end_position.end_position, }; let mut guard: Option>> = None; if self.peek().token_type == TokenType::LeftBrace { self.consume(TokenType::LeftBrace, "Expected '{' after guard expression")?; guard = Some(Box::new(self.expression()?)); self.consume(TokenType::RightBrace, "Expected '}' after guard expression")?; } let body = self.statement(None)?; let node = AstNode::new( Expr::Literal { value: BaseValue::Function(LoxFunction { parameters, return_type: None, body, closure: None, guard, }), }, combine_position.clone(), ); Ok(AstNode::new( Stmt::VarDeclaration { name: name_lexeme, initializer: Some(Box::new(node)), return_value: Box::new(BaseValue::Nil), }, combine_position.clone(), )) } fn variable_declaration( &mut self, start_slice: SourceSlice, name_lexeme: String, ) -> LoxResult> { if self.peek().token_type == TokenType::Identifier { self.advance(); if self.peek().token_type == TokenType::Identifier { self.advance(); } // todo: make type annotation } let mut value = AstNode::new( Expr::Literal { value: BaseValue::Nil, }, start_slice.clone(), ); if self.peek().token_type == TokenType::Equal { self.advance(); value = self.expression()?; } let semicolon = self.consume( TokenType::Semicolon, "Expect ';' after variable declaration.", )?; let end_slice = semicolon.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); Ok(AstNode::new( Stmt::VarDeclaration { name: name_lexeme, initializer: Some(Box::new(value)), return_value: Box::new(BaseValue::Nil), }, combined_slice, )) } fn print_statement(&mut self) -> LoxResult> { // consume the print keyword let start_slice = self.peek().source_slice.clone(); self.advance(); let expr = self.expression()?; let semicolon = self.consume(TokenType::Semicolon, "Expect ';' after value.")?; let end_slice = semicolon.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); Ok(AstNode::new( Stmt::Print { expression: Box::new(expr), return_value: Box::new(BaseValue::Nil), }, combined_slice, )) } fn block_statement(&mut self, label: Option) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); self.advance(); let mut statements = Vec::new(); while self.peek().token_type != TokenType::EndBlock && !self.is_at_end() { let stmt = self.statement(label.clone())?; statements.push(stmt); } let end_token = self.consume(TokenType::EndBlock, "Expect 'end' after block.")?; let end_slice = end_token.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); let label_str = if let Some(label) = label { label } else { String::default() }; Ok(AstNode::new( Stmt::Block { statements: Box::new(statements), label: label_str, return_value: Box::new(BaseValue::Nil), }, combined_slice, )) } fn expression_statement(&mut self) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); let expr = self.expression()?; if self.peek().token_type == TokenType::Semicolon { let semicolon = self.advance(); let end_slice = semicolon.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); return Ok(AstNode::new( Stmt::Expression { expression: Box::new(expr), return_value: Box::new(BaseValue::Nil), }, combined_slice, )); } // Use the expression's source slice for expression statements without semicolon let expr_slice = expr.source_slice.clone(); Ok(AstNode::new( Stmt::Expression { expression: Box::new(expr), return_value: Box::new(BaseValue::Nil), }, expr_slice, )) } fn return_statement(&mut self, label: Option) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); self.advance(); let expr = match self.expression() { Ok(expr) => expr, Err(LoxError::ParseError { message, source_slice, }) => { if message == "Expect expression." { AstNode::new( Expr::Literal { value: BaseValue::Nil, }, start_slice.clone(), ) } else { return Err(LoxError::ParseError { message, source_slice, }); } } Err(err) => return Err(err), }; let semicolon = self.consume(TokenType::Semicolon, "Expect ';' after return value.")?; let end_slice = semicolon.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); let label_str = if let Some(label) = label { label } else { String::default() }; Ok(AstNode::new( Stmt::Return { expression: Box::new(expr), return_value: Box::new(BaseValue::Nil), label: label_str, }, combined_slice, )) } fn expression(&mut self) -> LoxResult> { self.assignment() } fn assignment(&mut self) -> LoxResult> { let expr = self.or_and()?; if self.peek().token_type == TokenType::Equal { self.advance(); // consume '=' // Right-associative: `a = b = c` parses as `a = (b = c)`. let value = self.assignment()?; let combined_slice = SourceSlice::from_positions( expr.source_slice.source_id, expr.source_slice.start_position.clone(), value.source_slice.end_position.clone(), ); let target_slice = expr.source_slice.clone(); match expr.node { Expr::Identifier { name } => Ok(AstNode::new( Expr::Assign { name, value: Box::new(value), }, combined_slice, )), _ => parse_error(target_slice, "Invalid assignment target."), } } else { Ok(expr) } } fn or_and(&mut self) -> LoxResult> { let mut expr = self.logical_is()?; while [TokenType::Or, TokenType::And].contains(&self.peek().token_type) { let start_slice = expr.source_slice.clone(); let operator = self.peek().token_type.clone(); self.advance(); let right = self.logical_is()?; let end_slice = right.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); expr = AstNode::new( Expr::Binary { left: Box::new(expr), operator, right: Box::new(right), }, combined_slice, ); } Ok(expr) } fn logical_is(&mut self) -> LoxResult> { let mut expr = self.equality()?; while self.peek().token_type == TokenType::Is { let start_slice = expr.source_slice.clone(); let operator = self.peek().token_type.clone(); self.advance(); let right = self.equality()?; let end_slice = right.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); expr = AstNode::new( Expr::Binary { left: Box::new(expr), operator, right: Box::new(right), }, combined_slice, ); } Ok(expr) } fn equality(&mut self) -> LoxResult> { let mut expr = self.comparison()?; while [TokenType::BangEqual, TokenType::EqualEqual].contains(&self.peek().token_type) { let start_slice = expr.source_slice.clone(); let operator = self.peek().token_type.clone(); self.advance(); let right = self.comparison()?; let end_slice = right.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); expr = AstNode::new( Expr::Binary { left: Box::new(expr), operator, right: Box::new(right), }, combined_slice, ); } Ok(expr) } fn comparison(&mut self) -> LoxResult> { let mut expr = self.term()?; while [ TokenType::Greater, TokenType::GreaterEqual, TokenType::Less, TokenType::LessEqual, ] .contains(&self.peek().token_type) { let start_slice = expr.source_slice.clone(); let operator = self.peek().token_type.clone(); self.advance(); let right = self.term()?; let end_slice = right.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); expr = AstNode::new( Expr::Binary { left: Box::new(expr), operator, right: Box::new(right), }, combined_slice, ); } Ok(expr) } fn term(&mut self) -> LoxResult> { let mut expr = self.factor()?; while [TokenType::Plus, TokenType::Minus].contains(&self.peek().token_type) { let start_slice = expr.source_slice.clone(); let operator = self.peek().token_type.clone(); self.advance(); let right = self.factor()?; let end_slice = right.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); expr = AstNode::new( Expr::Binary { left: Box::new(expr), operator, right: Box::new(right), }, combined_slice, ); } Ok(expr) } fn factor(&mut self) -> LoxResult> { let mut expr = self.unary()?; while [TokenType::Slash, TokenType::Star].contains(&self.peek().token_type) { let start_slice = expr.source_slice.clone(); let operator = self.peek().token_type.clone(); self.advance(); let right = self.unary()?; let end_slice = right.source_slice.clone(); let combined_slice = SourceSlice::from_positions( start_slice.source_id, start_slice.start_position, end_slice.end_position, ); expr = AstNode::new( Expr::Binary { left: Box::new(expr), operator, right: Box::new(right), }, combined_slice, ); } Ok(expr) } fn unary(&mut self) -> LoxResult> { if [TokenType::Bang, TokenType::Minus].contains(&self.peek().token_type) { let operator = self.peek().token_type.clone(); let source_slice = self.peek().source_slice.clone(); self.advance(); let right = self.unary()?; return Ok(AstNode::new( Expr::Unary { operator, operand: Box::new(right), }, source_slice, )); } self.call() } fn call(&mut self) -> LoxResult> { let mut expr = self.primary()?; loop { if self.peek().token_type == TokenType::LeftParen { expr = self.finish_call(expr)?; } else { break; } } Ok(expr) } fn finish_call(&mut self, callee: AstNode) -> LoxResult> { let start_slice = callee.source_slice.start_position.clone(); self.advance(); // Consume '(' let mut arguments = Vec::new(); if self.peek().token_type != TokenType::RightParen { loop { arguments.push(self.expression()?); if self.peek().token_type == TokenType::Comma { self.advance(); } else { break; } } } self.consume(TokenType::RightParen, "Expect ')' after arguments.")?; // Estendi il source_slice per includere le parentesi di chiusura let end_slice = self.previous().source_slice.end_position.clone(); let full_slice = SourceSlice { source_id: callee.source_slice.source_id.clone(), start_position: start_slice.clone(), end_position: end_slice.clone(), }; Ok(AstNode::new( Expr::Call { callee: Box::new(callee), arguments, }, full_slice, )) } fn primary(&mut self) -> LoxResult> { match self.peek().token_type { TokenType::False => { let source_slice = self.peek().source_slice.clone(); self.advance(); Ok(AstNode::new( Expr::Literal { value: BaseValue::Boolean(false), }, source_slice, )) } TokenType::True => { let source_slice = self.peek().source_slice.clone(); self.advance(); Ok(AstNode::new( Expr::Literal { value: BaseValue::Boolean(true), }, source_slice, )) } TokenType::Nil => { let source_slice = self.peek().source_slice.clone(); self.advance(); Ok(AstNode::new( Expr::Literal { value: BaseValue::Nil, }, source_slice, )) } TokenType::Number => { let source_slice = self.peek().source_slice.clone(); let literal = self.peek().literal.clone(); self.advance(); if let Some(literal) = literal { Ok(AstNode::new(Expr::Literal { value: literal }, source_slice)) } else { parse_error(self.peek().source_slice.clone(), "Expected number literal") } } TokenType::String => { let source_slice = self.peek().source_slice.clone(); let literal = self.peek().literal.clone(); self.advance(); if let Some(literal) = literal { Ok(AstNode::new(Expr::Literal { value: literal }, source_slice)) } else { parse_error(self.peek().source_slice.clone(), "Expected string literal") } } TokenType::LeftParen => { let source_slice = self.peek().source_slice.clone(); self.advance(); let expr = self.expression()?; self.consume(TokenType::RightParen, "Expect ')' after expression.")?; Ok(AstNode::new( Expr::Grouping { expression: Box::new(expr), }, source_slice, )) } TokenType::Identifier => { let name = self.peek().lexeme.clone(); let source_slice = self.peek().source_slice.clone(); self.advance(); Ok(AstNode::new(Expr::Identifier { name }, source_slice)) } _ => parse_error(self.peek().source_slice.clone(), "Expect expression."), } } fn is_at_end(&self) -> bool { if self.current >= self.tokens.len() { true } else { self.tokens[self.current].token_type == TokenType::Eof } } fn advance(&mut self) -> &Token { if !self.is_at_end() { self.current += 1; } self.previous() } fn peek(&self) -> &Token { if self.is_at_end() { &self.tokens.last().unwrap() } else { &self.tokens[self.current] } } fn peek_next(&self) -> &Token { if self.is_at_end() { &self.peek() } else { &self.tokens[self.current + 1] } } fn previous(&self) -> &Token { if self.current == 0 { &self.tokens[0] } else { &self.tokens[self.current - 1] } } fn consume(&mut self, token_type: TokenType, message: &str) -> LoxResult<&Token> { if self.peek().token_type == token_type { self.advance(); Ok(self.previous()) } else { return parse_error(self.peek().source_slice.clone(), message); } } fn synchronize(&mut self) { self.advance(); while !self.is_at_end() { if self.previous().token_type == TokenType::Semicolon { return; } match self.peek().token_type { TokenType::Class | TokenType::Fun | TokenType::For | TokenType::If | TokenType::While | TokenType::Print | TokenType::Return => return, _ => {} } self.advance(); } } } #[cfg(test)] mod tests { use super::*; use crate::common::base_value::Number; use crate::frontend::lexer::Lexer; /// Lex and parse `src`, returning the parser's result. fn parse_source(src: &str) -> LoxResult>> { let tokens = Lexer::new(src.to_string(), 0) .scans_tokens() .expect("source should lex without errors"); Parser::new(tokens).parse() } /// Parse `src`, panicking if parsing fails. fn parse_ok(src: &str) -> Vec> { parse_source(src).expect("expected source to parse") } /// Extract the inner expression of an expression statement. fn expression_of(stmt: &AstNode) -> &AstNode { match &stmt.node { Stmt::Expression { expression, .. } => expression, other => panic!("expected expression statement, got {:?}", other), } } #[test] fn parses_number_literal_expression() { let stmts = parse_ok("42;"); assert_eq!(stmts.len(), 1); match &expression_of(&stmts[0]).node { Expr::Literal { value } => { assert_eq!(*value, BaseValue::Number(Number::I32(42))); } other => panic!("expected literal, got {:?}", other), } } #[test] fn respects_multiplication_precedence_over_addition() { // 1 + 2 * 3 should parse as 1 + (2 * 3) let stmts = parse_ok("1 + 2 * 3;"); match &expression_of(&stmts[0]).node { Expr::Binary { operator, right, .. } => { assert_eq!(*operator, TokenType::Plus); match &right.node { Expr::Binary { operator, .. } => { assert_eq!(*operator, TokenType::Star) } other => panic!("expected nested binary, got {:?}", other), } } other => panic!("expected binary expression, got {:?}", other), } } #[test] fn parses_unary_negation() { let stmts = parse_ok("-5;"); match &expression_of(&stmts[0]).node { Expr::Unary { operator, .. } => assert_eq!(*operator, TokenType::Minus), other => panic!("expected unary expression, got {:?}", other), } } #[test] fn parses_grouping_to_change_precedence() { // (1 + 2) * 3 should have a grouping on the left of the multiply. let stmts = parse_ok("(1 + 2) * 3;"); match &expression_of(&stmts[0]).node { Expr::Binary { operator, left, .. } => { assert_eq!(*operator, TokenType::Star); assert!(matches!(left.node, Expr::Grouping { .. })); } other => panic!("expected binary expression, got {:?}", other), } } #[test] fn parses_comparison_expression() { let stmts = parse_ok("1 < 2;"); match &expression_of(&stmts[0]).node { Expr::Binary { operator, .. } => assert_eq!(*operator, TokenType::Less), other => panic!("expected binary expression, got {:?}", other), } } #[test] fn parses_print_statement() { let stmts = parse_ok("print 1;"); assert!(matches!(stmts[0].node, Stmt::Print { .. })); } #[test] fn parses_var_declaration_with_initializer() { let stmts = parse_ok("var x: Int = 5;"); match &stmts[0].node { Stmt::VarDeclaration { name, initializer, .. } => { assert_eq!(name, "x"); assert!(initializer.is_some()); } other => panic!("expected var declaration, got {:?}", other), } } #[test] fn parses_assignment_statement() { let stmts = parse_ok("x = 5;"); match &stmts[0].node { Stmt::Expression { expression, .. } => match &expression.node { Expr::Assign { name, .. } => assert_eq!(name, "x"), other => panic!("expected assign expression, got {:?}", other), }, other => panic!("expected expression statement, got {:?}", other), } } #[test] fn parses_block_statement() { let stmts = parse_ok("do print 1; print 2; end"); match &stmts[0].node { Stmt::Block { statements, .. } => assert_eq!(statements.len(), 2), other => panic!("expected block statement, got {:?}", other), } } #[test] fn parses_if_statement() { let stmts = parse_ok("if true then print 1;"); assert!(matches!(stmts[0].node, Stmt::If { .. })); } #[test] fn parses_while_statement() { let stmts = parse_ok("while true do print 1; end"); assert!(matches!(stmts[0].node, Stmt::While { .. })); } #[test] fn errors_on_missing_semicolon_after_print() { assert!(parse_source("print 1").is_err()); } #[test] fn errors_on_unclosed_grouping() { assert!(parse_source("(1 + 2;").is_err()); } }