diff --git a/example.lox b/example.lox deleted file mode 100644 index e72e665..0000000 --- a/example.lox +++ /dev/null @@ -1,24 +0,0 @@ -// var Person :: struct { -// name: String, -// age: Int, -// address: String, -// } -// var func_name :: fn(param, param2) {param is Int} do -do - print "ciao"; - 1 + 2; - var cavallo = 1 + 2; - cavallo = cavallo + 1; - print cavallo; - cavallo -end -do - var cavallo = 0; - print "cavallo"; - while cavallo < 10 do - cavallo = cavallo + 1; - print cavallo; - end - 89 -end -99 diff --git a/examples/example.lox b/examples/example.lox new file mode 100644 index 0000000..828bb0c --- /dev/null +++ b/examples/example.lox @@ -0,0 +1,23 @@ +// var Person :: struct { +// name: String, +// age: Int, +// address: String, +// } +//func_name :: fn(param: Number, param2: String) {param is Int} do +func_name :: fn(param: Int, param2: String) do + print param; + cavallo := 5; + print cavallo; + while cavallo < 10 do + cavallo = cavallo + 1; + print cavallo; + end + + for i := 11; i <= 21; i = i + 1; do + print i; + end + + return False or True; +end + +func_name(1,2) diff --git a/examples/function_call.lox b/examples/function_call.lox new file mode 100644 index 0000000..663d520 --- /dev/null +++ b/examples/function_call.lox @@ -0,0 +1,20 @@ + +function :: fn() do + print "Function"; +end + + +function_factory :: fn() do + print "Function Factory"; + function +end + +function_fatcoty_factory :: fn() do + print "Function Factory Factory"; + function_factory +end + +//function(); +//function_factory()(); +function_fatcoty_factory()()(); +clock() diff --git a/test_error.lox b/examples/test_error.lox similarity index 100% rename from test_error.lox rename to examples/test_error.lox diff --git a/test_source_tracking.lox b/examples/test_source_tracking.lox similarity index 100% rename from test_source_tracking.lox rename to examples/test_source_tracking.lox diff --git a/src/backend/environment.rs b/src/backend/environment.rs index 0da0e53..91681f2 100644 --- a/src/backend/environment.rs +++ b/src/backend/environment.rs @@ -5,7 +5,7 @@ use crate::{ result::{runtime_error, LoxResult}, }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct EnvironmentStack { stack: Vec>, } @@ -39,7 +39,30 @@ impl EnvironmentStack { ) } - pub fn set(&mut self, name: String, value: LiteralValue) { - self.stack.last_mut().unwrap().insert(name, value); + pub fn declare(&mut self, name: String, value: LiteralValue) -> LoxResult { + self.stack.last_mut().unwrap().insert(name, value.clone()); + Ok(value) + } + + pub fn set(&mut self, name: String, value: LiteralValue) -> LoxResult { + let size = self.stack.len(); + + for i in (0..size).rev() { + if let Some(_) = self.stack[i].get(&name) { + let mut founded = false; + self.stack[i].entry(name.clone()).and_modify(|v| { + *v = value.clone(); + founded = true; + }); + + if founded { + return Ok(value); + } + } + } + runtime_error( + SourceSlice::default(), // todo change this to the actual source slice + format!("Undefined variable '{}'", name), + ) } } diff --git a/src/backend/interpreter.rs b/src/backend/interpreter.rs index c06497c..a361a6a 100644 --- a/src/backend/interpreter.rs +++ b/src/backend/interpreter.rs @@ -3,9 +3,10 @@ use crate::{ frontend::{ ast::{AstNode, AstNodeKind, Expr, Stmt}, source_registry::SourceSlice, - tokens::{LiteralValue, TokenType}, + tokens::{LiteralValue, NativeFunction, TokenType}, }, - result::{LoxError, LoxResult}, + logging::display_ast::PrettyPrintExt, + result::{runtime_error, LoxError, LoxResult}, }; use std::{ fmt::{Debug, Display}, @@ -174,15 +175,15 @@ pub struct Interpreter { } pub trait EvaluateInterpreter { - fn interpret(&mut self, stmt: T) -> LoxResult; + fn evaluate(&mut self, stmt: T) -> LoxResult; } impl<'a, R: AstNodeKind + Clone + Debug + Display> EvaluateInterpreter> for Interpreter where Interpreter: EvaluateInterpreter, { - fn interpret(&mut self, stmt: AstNode) -> LoxResult { - match self.interpret(stmt.node.clone()) { + fn evaluate(&mut self, stmt: AstNode) -> LoxResult { + match self.evaluate(stmt.node.clone()) { Ok(value) => Ok(value), Err(err) => Err(LoxError::RuntimeError { source_slice: stmt.source_slice, @@ -194,40 +195,109 @@ where // Direct Expr evaluation to avoid infinite recursion impl EvaluateInterpreter for Interpreter { - fn interpret(&mut self, expr: Expr) -> LoxResult { + fn evaluate(&mut self, expr: Expr) -> LoxResult { match expr { Expr::Literal { value } => Ok(value), - Expr::Variable { name } => self.enviorment.get(&name), + Expr::Identifier { name } => self.enviorment.get(&name), Expr::Binary { left, operator, right, } => { - let left_val = self.interpret(*left)?; - let right_val = self.interpret(*right)?; + let left_val = self.evaluate(*left)?; + let right_val = self.evaluate(*right)?; self.evaluate_binary(left_val, operator, right_val) } Expr::Unary { operator, operand } => { - let operand_val = self.interpret(*operand)?; + let operand_val = self.evaluate(*operand)?; self.evaluate_unary(operator, operand_val) } - Expr::Grouping { expression } => self.interpret(*expression), + Expr::Grouping { expression } => self.evaluate(*expression), + Expr::Call { callee, arguments } => self.evaluate_call(callee, arguments), } } } impl EvaluateInterpreter> for Interpreter { - fn interpret(&mut self, node: AstNode) -> LoxResult { + fn evaluate(&mut self, node: AstNode) -> LoxResult { let stmt = node.node; - let _source_slice = node.source_slice; - self.interpret_stmt_inner(stmt) + let result = self.interpret_stmt_inner(stmt); + match result { + Ok(value) => Ok(value), + Err(LoxError::RuntimeError { + message, + source_slice, + }) if source_slice == SourceSlice::default() => { + runtime_error(node.source_slice.clone(), message) + } + Err(err) => Err(err), + } } } impl Interpreter { pub fn new() -> Self { - Self { - enviorment: EnvironmentStack::new(), + let mut env = EnvironmentStack::new(); + let _ = env.declare( + "clock".to_string(), + LiteralValue::NativeFunction(NativeFunction::new(0, |_args| { + LiteralValue::Number( + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_millis() as f64, + ) + })), + ); + Self { enviorment: env } + } + fn evaluate_call( + &mut self, + callee: Box>, + arguments: Vec>, + ) -> LoxResult { + let source_slice = callee.source_slice.clone(); + + // Estrai il nome della variabile se il callee è un identificatore + let function_name = match &callee.node { + Expr::Identifier { name } => Some(name.clone()), + _ => None, + }; + + let function = if let Some(name) = function_name { + // Se abbiamo un nome di variabile, ottieni la funzione dall'ambiente + self.enviorment.get(&name)? + } else { + // Altrimenti valuta l'espressione callee (per casi più complessi) + self.evaluate(*callee)? + }; + + if !function.is_callable() { + return runtime_error(source_slice, "Can only call functions"); + } + + let evaluated_arguments = arguments + .iter() + .map(|arg| self.evaluate(arg.clone())) + .collect::, LoxError>>()?; + + match function { + LiteralValue::NativeFunction(func) => Ok((func.function)(&evaluated_arguments)), + LiteralValue::Function(func) => { + func.parameters + .iter() + .enumerate() + .map(|(index, par)| { + let value = evaluated_arguments.get(index).unwrap(); + self.enviorment.declare(par.0.clone(), value.clone()) + }) + .collect::>>()?; + self.evaluate(func.body) + } + _ => runtime_error( + source_slice.clone(), + "This is callable, but apparently is not implemented", + ), } } @@ -248,6 +318,8 @@ impl Interpreter { TokenType::LessEqual => Ok(LiteralValue::Boolean(left <= right)), TokenType::EqualEqual => Ok(LiteralValue::Boolean(left == right)), TokenType::BangEqual => Ok(LiteralValue::Boolean(left != right)), + TokenType::And => Ok(LiteralValue::Boolean(left.is_truthy() && right.is_truthy())), + TokenType::Or => Ok(LiteralValue::Boolean(left.is_truthy() || right.is_truthy())), _ => Err(error(format!( "Unsupported binary operator: {:?}", operator @@ -269,75 +341,108 @@ impl Interpreter { fn interpret_stmt_inner(&mut self, stmt: Stmt) -> LoxResult { match stmt { - Stmt::Expression { expression } => self.interpret(*expression), + Stmt::Expression { expression } => self.evaluate(*expression), Stmt::Print { expression } => { - let value = self.interpret(*expression)?; + let value = self.evaluate(*expression)?; println!("print interpreter: \t{}", value); Ok(LiteralValue::Nil) } Stmt::Block { statements } => self.evaluate_block(*statements), - Stmt::Stmt { expression } => self.interpret(*expression.clone()), - Stmt::Return { expression } => self.interpret(*expression), - Stmt::Var { name, initializer } => { - let value = if let Some(expr) = initializer { - self.interpret(*expr)? - } else { - LiteralValue::Nil + Stmt::Stmt { expression } => self.evaluate(*expression.clone()), + Stmt::Return { expression } => self.evaluate(*expression), + Stmt::VarDeclaration { name, initializer } => { + let value = match initializer { + Some(expr_node) => match &expr_node.node { + Expr::Literal { value } => { + if value.is_callable() { + value.clone() + } else { + value.clone() + } + } + _ => self.evaluate(*expr_node)?, + }, + None => LiteralValue::Nil, }; - self.enviorment.set(name.clone(), value); - return Ok(LiteralValue::Nil); + self.enviorment.declare(name.clone(), value) } - Stmt::Assign { name, value } => { - let result = self.interpret(*value)?; - self.enviorment.set(name.clone(), result); - Ok(LiteralValue::Nil) + + Stmt::VarAssigment { name, value } => { + let result = self.evaluate(*value)?; + self.enviorment.set(name.clone(), result) } Stmt::If { condition, then_branch, elif_branch, else_branch, - } => { - let condition = self.interpret(*condition)?; - match condition { - LiteralValue::Boolean(true) => self.interpret(*then_branch), - LiteralValue::Boolean(false) => { - for (elif_condition, elif_then_branch) in elif_branch { - let condition = self.interpret(*elif_condition)?; - match condition { - LiteralValue::Boolean(true) => { - return self.interpret(*elif_then_branch); - } - LiteralValue::Boolean(false) => continue, - _ => { - return Err(LoxError::TypeMismatch { - source_slice: SourceSlice::default(), // todo change this to the actual source slice - expected: "boolean".to_string(), - found: condition.to_string(), - }); - } - }; - } - if let Some(else_block) = else_branch { - self.interpret(*else_block) - } else { - Ok(LiteralValue::Nil) - } - } - _ => Err(LoxError::TypeMismatch { - source_slice: SourceSlice::default(), // todo change this to the actual source slice - expected: "boolean".to_string(), - found: condition.to_string(), - }), - } - } + } => self.evaluate_if(condition, then_branch, elif_branch, else_branch), Stmt::While { condition, body } => { - while self.interpret(*condition.clone())?.is_truthy() { - self.interpret(*body.clone())?; + while self.evaluate(*condition.clone())?.is_truthy() { + self.evaluate(*body.clone())?; } Ok(LiteralValue::Nil) } - Stmt::For { .. } => todo!(), + Stmt::For { + variable, + condition, + increment, + body, + } => { + self.enviorment.push_new_scope(); + let source_slice = variable.source_slice.clone(); + let val = self.evaluate(*variable)?; + if !matches!(val, LiteralValue::Number(..)) { + return runtime_error(source_slice, "Expected number literal"); + } + let mut ret = LiteralValue::Nil; + while self.evaluate(*condition.clone())?.is_truthy() { + ret = self.evaluate(*body.clone())?; + self.evaluate(*increment.clone())?; + } + + Ok(ret) + } + } + } + fn evaluate_if( + &mut self, + condition: Box>, + then_branch: Box>, + elif_branch: Vec<(Box>, Box>)>, + else_branch: Option>>, + ) -> LoxResult { + let condition = self.evaluate(*condition)?; + match condition { + LiteralValue::Boolean(true) => self.evaluate(*then_branch), + LiteralValue::Boolean(false) => { + for (elif_condition, elif_then_branch) in elif_branch { + let condition = self.evaluate(*elif_condition)?; + match condition { + LiteralValue::Boolean(true) => { + return self.evaluate(*elif_then_branch); + } + LiteralValue::Boolean(false) => continue, + _ => { + return Err(LoxError::TypeMismatch { + source_slice: SourceSlice::default(), // todo change this to the actual source slice + expected: "boolean".to_string(), + found: condition.to_string(), + }); + } + }; + } + if let Some(else_block) = else_branch { + self.evaluate(*else_block) + } else { + Ok(LiteralValue::Nil) + } + } + _ => Err(LoxError::TypeMismatch { + source_slice: SourceSlice::default(), // todo change this to the actual source slice + expected: "boolean".to_string(), + found: condition.to_string(), + }), } } @@ -357,13 +462,13 @@ impl Interpreter { // Ora elements è sempre disponibile for statement in elements.iter() { - self.interpret((*statement).clone())?; + self.evaluate((*statement).clone())?; } // Gestisci l'espressione finale se presente match final_expr { Some(expr) => { - let res = self.interpret(*expr.clone()); + let res = self.evaluate(*expr.clone()); self.enviorment.pop_scope(); res } diff --git a/src/frontend/ast.rs b/src/frontend/ast.rs index fe8e7ad..9131315 100644 --- a/src/frontend/ast.rs +++ b/src/frontend/ast.rs @@ -15,7 +15,9 @@ use std::fmt::{Debug, Display}; * * expression_statement -> expression ";" * print_statement -> "print" expression ";" - * var_statement -> "var" IDENTIFIER ("=" expression)? ";" + * var_statement -> ("var")? IDENTIFIER (":" IDENTIFIER)? (("=" expression)? ";")| function_declaration + * function_declaration -> "::" "(" parameters? ")" ("->" IDENTIFIER)? block_statement + * parameters -> ( IDENTIFIER (":" IDENTIFIER)? ("," IDENTIFIER (":" IDENTIFIER)? )* ) * assignment_statement -> IDENTIFIER "=" expression ";" * block_statement -> "do" statement* "end" * if_statement -> "if" expression "then" statement ("elif" expression "then" statement)* ("else" statement)? "end" @@ -29,10 +31,12 @@ use std::fmt::{Debug, Display}; * comparison -> term ((">" | ">=" | "<" | "<=") term)* * term -> factor (("+" | "-") factor)* * factor -> unary (("*" | "/") unary)* - * unary -> ("!" | "-") unary | primary + * unary -> ("!" | "-") unary | call + * call -> primary ("(" arguments ")")* + * arguments -> expression ("," expression)* * primary -> NUMBER | STRING | "true" | "false" | "nil" | "(" expression ")" | IDENTIFIER */ -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Expr { Literal { value: LiteralValue, @@ -49,9 +53,13 @@ pub enum Expr { Grouping { expression: Box>, }, - Variable { + Identifier { name: String, }, + Call { + callee: Box>, + arguments: Vec>, + }, } // Implementazione Display per Expr (per debugging) @@ -66,7 +74,17 @@ impl std::fmt::Display for Expr { } => write!(f, "Binary ({} {} {})", left.node, operator, right.node), Expr::Unary { operator, operand } => write!(f, "Unary ({} {})", operator, operand.node), Expr::Grouping { expression } => write!(f, "Grouping (group {})", expression.node), - Expr::Variable { name } => write!(f, "Variable (variable {})", name), + Expr::Identifier { name } => write!(f, "Identifier (variable {})", name), + Expr::Call { callee, arguments } => write!( + f, + "Call ({}({}))", + callee.node, + arguments + .iter() + .map(|arg| arg.node.to_string()) + .collect::>() + .join(", ") + ), } } } @@ -82,12 +100,22 @@ impl Debug for Expr { } => write!(f, "({:?} {:?} {:?})", operator, left.node, right.node), Expr::Unary { operator, operand } => write!(f, "({:?} {:?})", operator, operand.node), Expr::Grouping { expression } => write!(f, "(group {:?})", expression.node), - Expr::Variable { name } => write!(f, "(variable {:?})", name), + Expr::Identifier { name } => write!(f, "(variable {:?})", name), + Expr::Call { callee, arguments } => write!( + f, + "Call ({}({}))", + callee.node, + arguments + .iter() + .map(|arg| arg.node.to_string()) + .collect::>() + .join(", ") + ), } } } -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Stmt { Expression { expression: Box>, @@ -98,11 +126,11 @@ pub enum Stmt { Stmt { expression: Box>, }, - Var { + VarDeclaration { name: String, initializer: Option>>, }, - Assign { + VarAssigment { name: String, value: Box>, }, @@ -123,8 +151,9 @@ pub enum Stmt { body: Box>, }, For { - variable: Box>, - iterable: Box>, + variable: Box>, + condition: Box>, + increment: Box>, body: Box>, }, } @@ -153,11 +182,11 @@ impl Display for Stmt { } Stmt::Print { expression } => write!(f, "Print({});", expression.node), Stmt::Stmt { expression } => write!(f, "Stmt({});", expression.node), - Stmt::Var { name, initializer } => match initializer { + Stmt::VarDeclaration { name, initializer } => match initializer { Some(init) => write!(f, "Var({} = {});", name, init.node), None => write!(f, "Var({});", name), }, - Stmt::Assign { name, value } => write!(f, "Assign({} = {});", name, value.node), + Stmt::VarAssigment { name, value } => write!(f, "Assign({} = {});", name, value.node), Stmt::Return { expression } => write!(f, "Return({});", expression.node), Stmt::Block { statements } => write!( f, @@ -173,12 +202,13 @@ impl Display for Stmt { } Stmt::For { variable, - iterable, + condition, + increment, body, } => write!( f, - "For({} in {}) {{\n{}\n}}", - variable.node, iterable.node, body.node + "For({} = {} in {}) {{\n{}\n}}", + variable.node, condition.node, increment.node, body.node ), } } @@ -209,11 +239,13 @@ impl Debug for Stmt { } Stmt::Print { expression } => write!(f, "Print({:?});", expression.node), Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression.node), - Stmt::Var { name, initializer } => match initializer { + Stmt::VarDeclaration { name, initializer } => match initializer { Some(init) => write!(f, "Var({:?} = {:?});", name, init.node), None => write!(f, "Var({:?});", name), }, - Stmt::Assign { name, value } => write!(f, "Assign({:?} = {:?});", name, value.node), + Stmt::VarAssigment { name, value } => { + write!(f, "Assign({:?} = {:?});", name, value.node) + } Stmt::Return { expression } => write!(f, "Return({:?});", expression.node), Stmt::Block { statements } => write!( f, @@ -229,12 +261,13 @@ impl Debug for Stmt { } Stmt::For { variable, - iterable, + condition, + increment, body, } => write!( f, - "For({:?} in {:?}) {{\n{:?}\n}}", - variable.node, iterable.node, body.node + "For({:?} = {:?} in {:?}) {{\n{:?}\n}}", + variable.node, condition.node, increment.node, body.node ), } } @@ -253,12 +286,10 @@ impl AstNodeKind for Expr { operator: _, right: _, } => "binary expression", - Expr::Unary { - operator: _, - operand: _, - } => "unary expression", - Expr::Grouping { expression: _ } => "grouping expression", - Expr::Variable { name: _ } => "variable expression", + Expr::Unary { .. } => "unary expression", + Expr::Grouping { .. } => "grouping expression", + Expr::Identifier { .. } => "variable expression", + Expr::Call { .. } => "call expression", } } } @@ -267,8 +298,8 @@ impl AstNodeKind for Stmt { fn kind(&self) -> &'static str { match self { Stmt::Expression { .. } => "expression", - Stmt::Var { .. } => "variable declaration", - Stmt::Assign { .. } => "assignment", + Stmt::VarDeclaration { .. } => "variable declaration", + Stmt::VarAssigment { .. } => "assignment", Stmt::Return { .. } => "return statement", Stmt::Block { .. } => "block statement", Stmt::If { .. } => "if statement", @@ -280,7 +311,7 @@ impl AstNodeKind for Stmt { } } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Default)] pub struct AstNode { pub node: T, pub source_slice: SourceSlice, diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index 0933b5c..588c15a 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -38,6 +38,7 @@ fn get_keyword_token(word: &str) -> Option { "True" => Some(TokenType::True), "False" => Some(TokenType::False), "Nil" => Some(TokenType::Nil), + "fn" => Some(TokenType::Fn), _ => None, } } @@ -146,6 +147,7 @@ impl Lexer { ('-', _) => Ok(Some(self.make_token(TokenType::Minus))), ('+', _) => Ok(Some(self.make_token(TokenType::Plus))), (';', _) => Ok(Some(self.make_token(TokenType::Semicolon))), + (':', _) => Ok(Some(self.make_token(TokenType::Colon))), ('*', _) => Ok(Some(self.make_token(TokenType::Star))), ('%', _) => Ok(Some(self.make_token(TokenType::Percent))), ('!', '=') => { @@ -262,7 +264,7 @@ impl Lexer { } fn identifier(&mut self) -> LoxResult> { - while self.peek().is_alphanumeric() { + while self.peek().is_alphanumeric() || self.peek() == '_' { self.advance(); } let text = self.input[self.start_char..self.current_char].to_string(); diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index 4a3012b..b1283b3 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -1,11 +1,11 @@ use crate::{ frontend::{ ast::{AstNode, Expr, Stmt}, - source_registry::SourceSlice, - tokens::{LiteralValue, Token, TokenType}, + source_registry::{SourcePosition, SourceSlice}, + tokens::{LiteralValue, LoxFunction, Token, TokenType}, }, logging::display_ast::{pretty_print_with_config, PrettyConfig}, - result::{parse_error, LoxError, LoxResult}, + result::{parse_error, runtime_error, LoxResult}, }; pub struct Parser { @@ -58,10 +58,14 @@ impl Parser { fn statement(&mut self) -> LoxResult> { match (&self.peek().token_type, &self.peek_next().token_type) { - (TokenType::Var, _) => self.var_statement(), (TokenType::Print, _) => self.print_statement(), (TokenType::Return, _) => self.return_statement(), (TokenType::StartBlock, _) => self.block_statement(), + (TokenType::Var, TokenType::Identifier) => { + self.advance(); + self.var_statement() + } + (TokenType::Identifier, TokenType::Colon) => self.var_statement(), (TokenType::Identifier, TokenType::Equal) => self.assignment_statement(), (TokenType::If, _) => self.if_statement(), (TokenType::While, _) => self.while_statement(), @@ -72,46 +76,78 @@ impl Parser { 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()?; + self.advance(); // consume 'for' + + let variable = self.var_statement()?; + let condition = self.expression()?; + self.consume(TokenType::Semicolon, "Expected ';' after for condition")?; + let increment = self.assignment_statement()?; + + self.consume(TokenType::StartBlock, "Expected 'do' after for range")?; + let body = self.statement()?; - let end_slice = body.source_slice.clone(); + self.consume(TokenType::EndBlock, "Expected 'end' after for body")?; + + 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), - iterable: Box::new(iterable), + condition: Box::new(condition), + increment: Box::new(increment), body: Box::new(body), }, 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()?; + // 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(); @@ -178,11 +214,103 @@ impl Parser { fn var_statement(&mut self) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); - self.advance(); let name = self.consume(TokenType::Identifier, "Expect variable name.")?; let name_lexeme = name.lexeme.clone(); - self.consume(TokenType::Equal, "Expect '=' after variable name.")?; - let value = self.expression()?; + + let mut _type_annotation = LiteralValue::Nil; + self.consume(TokenType::Colon, "Expect column")?; + + 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.advance(); + 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::RightBrace { + self.advance(); + guard = Some(Box::new(self.expression()?.node.clone())); + self.consume(TokenType::RightBrace, "Expected '}' after guard expression")?; + } + + let body = self.statement()?; + let node = AstNode { + node: Expr::Literal { + value: LiteralValue::Function(LoxFunction { + parameters, + body, + closure: None, + guard, + }), + }, + source_slice: combine_position.clone(), + }; + Ok(AstNode::new( + Stmt::VarDeclaration { + name: name_lexeme, + initializer: Some(Box::new(node)), + }, + 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 { + node: Expr::Literal { + value: LiteralValue::Nil, + }, + source_slice: 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.", @@ -194,14 +322,13 @@ impl Parser { end_slice.end_position, ); Ok(AstNode::new( - Stmt::Var { + Stmt::VarDeclaration { name: name_lexeme, initializer: Some(Box::new(value)), }, combined_slice, )) } - fn assignment_statement(&mut self) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); let name = self.consume(TokenType::Identifier, "Expect variable name.")?; @@ -219,7 +346,7 @@ impl Parser { end_slice.end_position, ); Ok(AstNode::new( - Stmt::Assign { + Stmt::VarAssigment { name: name_lexeme, value: Box::new(value), }, @@ -481,7 +608,56 @@ impl Parser { )); } - self.primary() + 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> { @@ -523,9 +699,7 @@ impl Parser { if let Some(literal) = literal { Ok(AstNode::new(Expr::Literal { value: literal }, source_slice)) } else { - Err(self - .error(self.previous(), "Expected number literal") - .into()) + parse_error(self.peek().source_slice.clone(), "Expected number literal") } } TokenType::String => { @@ -535,9 +709,7 @@ impl Parser { if let Some(literal) = literal { Ok(AstNode::new(Expr::Literal { value: literal }, source_slice)) } else { - Err(self - .error(self.previous(), "Expected string literal") - .into()) + parse_error(self.peek().source_slice.clone(), "Expected string literal") } } TokenType::LeftParen => { @@ -556,9 +728,9 @@ impl Parser { let name = self.peek().lexeme.clone(); let source_slice = self.peek().source_slice.clone(); self.advance(); - Ok(AstNode::new(Expr::Variable { name }, source_slice)) + Ok(AstNode::new(Expr::Identifier { name }, source_slice)) } - _ => Err(self.error(self.peek(), "Expect expression.").into()), + _ => parse_error(self.peek().source_slice.clone(), "Expect expression."), } } @@ -606,14 +778,7 @@ impl Parser { self.advance(); Ok(self.previous()) } else { - Err(self.error(self.peek(), message).into()) - } - } - - fn error(&self, token: &Token, message: &str) -> LoxError { - LoxError::ParseError { - source_slice: token.source_slice.clone(), - message: message.to_string(), + return parse_error(self.peek().source_slice.clone(), message); } } @@ -628,7 +793,6 @@ impl Parser { match self.peek().token_type { TokenType::Class | TokenType::Fun - | TokenType::Var | TokenType::For | TokenType::If | TokenType::While diff --git a/src/frontend/tokens.rs b/src/frontend/tokens.rs index 9535000..a3345c3 100644 --- a/src/frontend/tokens.rs +++ b/src/frontend/tokens.rs @@ -1,6 +1,13 @@ use std::fmt; -use crate::frontend::source_registry::SourceSlice; +use crate::{ + backend::environment::EnvironmentStack, + frontend::{ + ast::{AstNode, Expr, Stmt}, + source_registry::SourceSlice, + }, + result::{runtime_error, LoxResult}, +}; #[derive(Debug, Clone, PartialEq)] pub enum LiteralValue { @@ -9,6 +16,37 @@ pub enum LiteralValue { Number(f64), Boolean(bool), Nil, + Function(LoxFunction), + NativeFunction(NativeFunction), +} + +#[derive(Debug, Clone, PartialEq)] +pub struct LoxFunction { + pub parameters: Vec<(String, String)>, + pub body: AstNode, + pub closure: Option, + pub guard: Option>, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct NativeFunction { + pub arity: usize, + pub function: fn(&[LiteralValue]) -> LiteralValue, +} + +impl NativeFunction { + pub fn new(arity: usize, function: fn(&[LiteralValue]) -> LiteralValue) -> Self { + NativeFunction { arity, function } + } +} + +impl LiteralValue { + pub fn is_callable(&self) -> bool { + match self { + LiteralValue::Function(..) | LiteralValue::NativeFunction(..) => true, + _ => false, + } + } } impl fmt::Display for LiteralValue { @@ -19,6 +57,8 @@ impl fmt::Display for LiteralValue { LiteralValue::Number(n) => write!(f, "{}", n), LiteralValue::Boolean(b) => write!(f, "{}", b), LiteralValue::Nil => write!(f, "nil"), + LiteralValue::Function(..) => write!(f, ""), + LiteralValue::NativeFunction(..) => write!(f, ""), } } } @@ -37,6 +77,7 @@ pub enum TokenType { Minus, Plus, Semicolon, + Colon, Slash, Star, Percent, @@ -57,6 +98,7 @@ pub enum TokenType { Number, // Keywords + Fn, And, Class, StartBlock, @@ -134,6 +176,8 @@ impl fmt::Display for TokenType { TokenType::Val => write!(f, "val"), TokenType::Percent => write!(f, "%"), TokenType::In => write!(f, "in"), + TokenType::Colon => write!(f, ":"), + TokenType::Fn => write!(f, "fn"), } } } diff --git a/src/logging/display_ast.rs b/src/logging/display_ast.rs index 4b9ae82..c21f473 100644 --- a/src/logging/display_ast.rs +++ b/src/logging/display_ast.rs @@ -165,7 +165,6 @@ impl PrettyPrint for Expr { write!(f, "{}Literal {{ value: {:?} }}", indent, value) } } - Expr::Binary { left, operator, @@ -195,7 +194,6 @@ impl PrettyPrint for Expr { write!(f, "{}}}", indent) } } - Expr::Unary { operator, operand } => { if ctx.config.compact { let operand_str = @@ -215,7 +213,6 @@ impl PrettyPrint for Expr { write!(f, "{}}}", indent) } } - Expr::Grouping { expression } => { if ctx.config.compact { let expr_str = @@ -229,12 +226,27 @@ impl PrettyPrint for Expr { write!(f, "{}}}", indent) } } - - Expr::Variable { name } => { + Expr::Identifier { name } => { if ctx.config.compact { write!(f, "{}", name) } else { - write!(f, "{}Variable {{ name: {:?} }}", indent, name) + write!(f, "{}Identifier {{ name: {:?} }}", indent, name) + } + } + Expr::Call { callee, arguments } => { + if ctx.config.compact { + write!(f, "{}", callee) + } else { + write!(f, "{}Call {{ callee: ", indent)?; + callee.pretty_print(&ctx.child_context(true), f)?; + write!(f, ", arguments: [")?; + for (i, arg) in arguments.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + arg.pretty_print(&ctx.child_context(true), f)?; + } + write!(f, "] }}") } } } @@ -276,7 +288,7 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::Var { name, initializer } => { + Stmt::VarDeclaration { name, initializer } => { if ctx.config.compact { match initializer { Some(init) => { @@ -302,7 +314,7 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::Assign { name, value } => { + Stmt::VarAssigment { name, value } => { if ctx.config.compact { let value_str = pretty_print_with_config(value.as_ref(), &PrettyConfig::compact()); @@ -412,13 +424,16 @@ impl PrettyPrint for Stmt { } Stmt::For { variable, - iterable, + condition, + increment, body, } => { write!(f, "{}for (", ctx.child_context(true).indent())?; variable.pretty_print(&ctx.child_context(true), f)?; - write!(f, " in ")?; - iterable.pretty_print(&ctx.child_context(true), f)?; + write!(f, "; ")?; + condition.pretty_print(&ctx.child_context(true), f)?; + write!(f, "; ")?; + increment.pretty_print(&ctx.child_context(true), f)?; writeln!(f, ") {{")?; body.pretty_print(&ctx.child_context(true), f)?; writeln!(f, "{}}}", ctx.child_context(true).indent()) diff --git a/src/logging/display_token.rs b/src/logging/display_token.rs index a4db9aa..df15511 100644 --- a/src/logging/display_token.rs +++ b/src/logging/display_token.rs @@ -196,6 +196,8 @@ impl Token { TokenType::Val => "VAL", TokenType::Eof => "EOF", TokenType::In => "IN", + TokenType::Colon => ":", + TokenType::Fn => "FN", } } @@ -232,6 +234,7 @@ impl Token { | TokenType::Super | TokenType::This | TokenType::Var + | TokenType::Fn | TokenType::Val => ("\x1b[34m", self.token_type_symbol()), TokenType::Identifier | TokenType::String | TokenType::Number => { ("\x1b[32m", self.token_type_symbol()) @@ -243,6 +246,7 @@ impl Token { | TokenType::LeftBracket | TokenType::RightBracket | TokenType::Comma + | TokenType::Colon | TokenType::Dot | TokenType::Semicolon => ("\x1b[37m", self.token_type_symbol()), TokenType::StartBlock | TokenType::EndBlock => ("\x1b[35m", self.token_type_symbol()), diff --git a/src/main.rs b/src/main.rs index ce2694f..957bc57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,43 +1,82 @@ mod backend; mod frontend; mod logging; -mod prompt; mod result; use crate::{ - backend::{ - environment::EnvironmentStack, - interpreter::{EvaluateInterpreter, Interpreter}, - }, + backend::interpreter::{EvaluateInterpreter, Interpreter}, frontend::{ lexer::Lexer, parser::Parser, - source_registry::{SourceId, SourceRegistry, SourceSlice}, + source_registry::{SourceId, SourceRegistry}, }, - prompt::prompt_lines, result::{LoxError, LoxResult}, }; use std::env; use std::fs; +#[derive(Debug, Clone, Copy, PartialEq)] +enum ExecutionStage { + Tokens, + Ast, + Full, +} + fn main() -> LoxResult<()> { let args: Vec = env::args().collect(); let mut lox = LoxInterpreter::new(); - let _ = if args.len() > 2 { - eprintln!("Usage: {} [script]", args[0]); - std::process::exit(64); - } else if args.len() == 2 { - // Esegui file - lox.run_file(&args[1]) - } else { - // Modalità interattiva - lox.run_prompt() + let (stage, file_path) = parse_args(&args); + + let _ = match file_path { + Some(path) => lox.run_file(&path, stage), + None => lox.run_prompt(stage), }; Ok(()) } +fn parse_args(args: &[String]) -> (ExecutionStage, Option) { + if args.len() == 1 { + // Solo il nome del programma: modalità interattiva completa + (ExecutionStage::Full, None) + } else if args.len() == 2 { + // Un argomento: potrebbe essere file o flag + let arg = &args[1]; + if arg == "--tokens" || arg == "--ast" || arg == "--full" { + // Flag senza file: modalità interattiva + let stage = match arg.as_str() { + "--tokens" => ExecutionStage::Tokens, + "--ast" => ExecutionStage::Ast, + "--full" => ExecutionStage::Full, + _ => ExecutionStage::Full, + }; + (stage, None) + } else { + // File senza flag: esecuzione completa del file + (ExecutionStage::Full, Some(arg.clone())) + } + } else if args.len() == 3 { + // Due argomenti: flag + file + let flag = &args[1]; + let file = &args[2]; + let stage = match flag.as_str() { + "--tokens" => ExecutionStage::Tokens, + "--ast" => ExecutionStage::Ast, + "--full" => ExecutionStage::Full, + _ => { + eprintln!("Unknown flag: {}. Use --tokens, --ast, or --full", flag); + eprintln!("Usage: {} [--tokens|--ast|--full] [script]", args[0]); + std::process::exit(64); + } + }; + (stage, Some(file.clone())) + } else { + eprintln!("Usage: {} [--tokens|--ast|--full] [script]", args[0]); + std::process::exit(64); + } +} + struct LoxInterpreter { source_registry: SourceRegistry, } @@ -50,60 +89,133 @@ impl LoxInterpreter { } // ✅ Pipeline funzionale per file - fn run_file(&mut self, path: &str) -> LoxResult<()> { + fn run_file(&mut self, path: &str, stage: ExecutionStage) -> LoxResult<()> { fs::read_to_string(path) .map_err(|e| LoxError::IoError { message: e.to_string(), }) .and_then(|source| self.source_registry.add_source_string(source)) - .and_then(|source_id| self.process_source(source_id)) - .map(|result| println!("file {}", result)) + .and_then(|source_id| self.process_source(source_id, stage)) + .map(|result| match stage { + ExecutionStage::Tokens => println!("=== TOKENS ===\n{}", result), + ExecutionStage::Ast => println!("=== AST ===\n{}", result), + ExecutionStage::Full => println!("=== EXECUTION RESULT ===\n{}", result), + }) } // ✅ Pipeline funzionale per prompt - fn run_prompt(&mut self) -> LoxResult<()> { - println!("Lox REPL - Type 'exit' to quit"); + fn run_prompt(&mut self, stage: ExecutionStage) -> LoxResult<()> { + use std::io::{self, Write}; - prompt_lines(|source| self.source_registry.add_source_string(source)) - .for_each(|line| println!("hi: {}", line)); + println!("Lox REPL (Stage: {:?}) - Type 'exit' to quit", stage); + + loop { + print!("> "); + io::stdout().flush().ok(); + + let mut input = String::new(); + match io::stdin().read_line(&mut input) { + Ok(_) => { + let line = input.trim(); + if line == "exit" || line.is_empty() { + break; + } + + match self.source_registry.add_source_string(line.to_string()) { + Ok(source_id) => { + match self.process_source(source_id, stage) { + Ok(result) => match stage { + ExecutionStage::Tokens => println!("Tokens: {}", result), + ExecutionStage::Ast => println!("AST: {}", result), + ExecutionStage::Full => println!("Result: {}", result), + }, + Err(_) => {} // Errore già stampato in process_source + } + } + Err(e) => eprintln!("Error: {}", e), + } + } + Err(e) => { + eprintln!("Error reading input: {}", e); + break; + } + } + } Ok(()) } - fn process_source(&self, source_id: SourceId) -> LoxResult { - let mut lexer = Lexer::new( - self.source_registry.get_by_id(source_id).content.clone(), - source_id, - ); - let res = lexer - .scans_tokens() - .and_then(|tokens| Parser::new(tokens).parse()) - .and_then(|asts| { - // println!("asts: {:?}", asts); - Ok(asts) - }) - .and_then(|stmts| { - let mut interpreter = Interpreter::new(); - let mut result = None; - for (index, stmt) in stmts.iter().enumerate() { - println!("executing stmt {}: {:?}", index, stmt); - result = Some(interpreter.interpret(stmt.clone())?); - } - match result { - Some(res) => Ok(res), - _ => Err(LoxError::RuntimeError { - source_slice: SourceSlice::default(), - message: "what?????".to_string(), - }), - } - }) - .and_then(|result| Ok(format!("{}", result))) - .or_else(|err| { + fn process_source(&self, source_id: SourceId, stage: ExecutionStage) -> LoxResult { + let source_content = self.source_registry.get_by_id(source_id).content.clone(); + let mut lexer = Lexer::new(source_content, source_id); + + // Stage 1: Tokenization + let tokens = lexer.scans_tokens().or_else(|err| { + err.print_with_context(&self.source_registry); + Err(err) + })?; + + if stage == ExecutionStage::Tokens { + return Ok(format_tokens(&tokens)); + } + + // Stage 2: Parsing + let ast = Parser::new(tokens).parse().or_else(|err| { + err.print_with_context(&self.source_registry); + Err(err) + })?; + + if stage == ExecutionStage::Ast { + return Ok(format_ast(&ast)); + } + + // Stage 3: Interpretation + let mut interpreter = Interpreter::new(); + let mut result = None; + + for (index, stmt) in ast.iter().enumerate() { + println!("Executing statement {}: {:?}", index, stmt); + result = Some(interpreter.evaluate(stmt.clone()).or_else(|err| { err.print_with_context(&self.source_registry); Err(err) - }); - // println!("result {}", res); + })?); + } - res + match result { + Some(res) => Ok(format!("{}", res)), + None => Ok("No statements executed".to_string()), + } } } + +fn format_tokens(tokens: &[crate::frontend::tokens::Token]) -> String { + tokens + .iter() + .enumerate() + .map(|(i, token)| format!("{:3}: {:?}", i, token)) + .collect::>() + .join("\n") +} + +fn format_ast(ast: &[crate::frontend::ast::AstNode]) -> String { + use crate::logging::display_ast::{pretty_print_with_config, PrettyConfig}; + + let config = PrettyConfig { + indent: " ".to_string(), + max_depth: None, + show_positions: false, + ..Default::default() + }; + + ast.iter() + .enumerate() + .map(|(i, stmt)| { + format!( + "Statement {}:\n{}", + i, + pretty_print_with_config(&stmt.node, &config) + ) + }) + .collect::>() + .join("\n\n") +} diff --git a/src/prompt.rs b/src/prompt.rs deleted file mode 100644 index 88218b1..0000000 --- a/src/prompt.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::io::{self, Write}; - -use crate::{frontend::source_registry::SourceId, result::LoxResult}; - -pub fn prompt_lines(mut process_source: T) -> impl Iterator -where - T: FnMut(String) -> LoxResult, -{ - std::iter::from_fn(move || { - print!("> "); - io::stdout().flush().ok()?; - - let mut input = String::new(); - io::stdin().read_line(&mut input).ok()?; - - let line = input.trim(); - if line == "exit" || line.is_empty() { - None - } else { - match process_source(line.to_string()) { - Ok(source_id) => Some(source_id), - Err(err) => { - eprintln!("Error: {}", err); - None - } - } - } - }) -} diff --git a/src/result.rs b/src/result.rs index aa708ae..9f0ec6f 100644 --- a/src/result.rs +++ b/src/result.rs @@ -402,6 +402,7 @@ impl std::error::Error for LoxError {} pub type LoxResult = Result; /// Helper function to create a lexical error +#[allow(dead_code)] pub fn lexical_error(source_slice: SourceSlice, message: impl Into) -> LoxResult { Err(LoxError::LexicalError { source_slice, @@ -410,6 +411,7 @@ pub fn lexical_error(source_slice: SourceSlice, message: impl Into) - } /// Helper function to create a parse error +#[allow(dead_code)] pub fn parse_error(source_slice: SourceSlice, message: impl Into) -> LoxResult { Err(LoxError::ParseError { source_slice, @@ -418,7 +420,6 @@ pub fn parse_error(source_slice: SourceSlice, message: impl Into) -> } /// Helper function to create a runtime error -#[allow(dead_code)] pub fn runtime_error(source_slice: SourceSlice, message: impl Into) -> LoxResult { Err(LoxError::RuntimeError { source_slice,