diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/fail_error.lox b/examples/fail_error.lox index 101823b..4bd04c0 100644 --- a/examples/fail_error.lox +++ b/examples/fail_error.lox @@ -1,4 +1,5 @@ // Test script to verify error positioning +"no"(); var a := 5; var b := "hello"; print 0; diff --git a/examples/test_closure.lox b/examples/test_closure.lox new file mode 100644 index 0000000..2e288c0 --- /dev/null +++ b/examples/test_closure.lox @@ -0,0 +1,12 @@ + +closure :: fn() do + value := "Closure"; + internal :: fn() do + print value; + return value; + end + return internal; +end + +internal := closure(); +internal(); diff --git a/examples/test_example.lox b/examples/test_example.lox index b9a3c8b..a1e87e2 100644 --- a/examples/test_example.lox +++ b/examples/test_example.lox @@ -6,23 +6,26 @@ //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; + print param2; + while param < param2 do + param = param + 1; + print param; + print param2; + //break; end - if True then do + if False then do print "this shoul be stop"; - return False; + return "Hahahaha"; end print "this shoud be un other stop"; - return 42; + //return 42; for i := 11; i <= 21; i = i + 1; do print i; + print "hello"; + break; end return False or True; end -func_name(1,2) +func_name(1,20) diff --git a/examples/test_function_call.lox b/examples/test_function_call.lox index 663d520..aa045ee 100644 --- a/examples/test_function_call.lox +++ b/examples/test_function_call.lox @@ -11,10 +11,20 @@ end function_fatcoty_factory :: fn() do print "Function Factory Factory"; - function_factory + return function_factory; end //function(); //function_factory()(); -function_fatcoty_factory()()(); +//function_fatcoty_factory()()(); clock() + +closure :: fn() do + value = "Closure"; + internal :: fn() do + print value; + end + return internal; +end + +closure() diff --git a/src/backend/interpreter.rs b/src/backend/interpreter.rs index 3e811db..360d8ec 100644 --- a/src/backend/interpreter.rs +++ b/src/backend/interpreter.rs @@ -33,7 +33,15 @@ where impl EvaluateInterpreter for Interpreter { fn evaluate(&mut self, expr: Expr) -> LoxResult { match expr { - Expr::Literal { value } => Ok(value), + Expr::Literal { value } => match value { + BaseValue::Function(mut func) => { + func.closure = Some(self.enviorment.clone()); + println!("Closure created"); + println!("current enviorment: {:?}", self.enviorment); + Ok(BaseValue::Function(func)) + } + _ => Ok(value), + }, Expr::Identifier { name } => self.enviorment.get(&name), Expr::Binary { left, @@ -120,15 +128,34 @@ impl Interpreter { match function { BaseValue::NativeFunction(func) => Ok((func.function)(&evaluated_arguments)), BaseValue::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) + // Save the current environment + let saved_env = self.enviorment.clone(); + + // If the function captured a closure, use it as the base environment + if let Some(closure_env) = func.closure { + self.enviorment = closure_env; + } + + // Push a new scope for the function's parameters + self.enviorment.push_new_scope(); + + // Declare parameters in the new scope + for (index, par) in func.parameters.iter().enumerate() { + let value = evaluated_arguments.get(index).unwrap(); + self.enviorment.declare(par.0.clone(), value.clone())?; + } + + // Execute the function body + let result = match self.evaluate(func.body) { + Ok(value) => Ok(value), + Err(LoxError::Return { value, .. }) => Ok(value), + Err(err) => Err(err), + }; + + // Restore the original environment (cleanup is automatic) + self.enviorment = saved_env; + + result } _ => runtime_error( source_slice.clone(), @@ -194,21 +221,11 @@ impl Interpreter { 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)?, - }, + Some(expr_node) => self.evaluate(*expr_node)?, None => BaseValue::Nil, }; self.enviorment.declare(name.clone(), value) } - Stmt::VarAssigment { name, value, .. } => { let result = self.evaluate(*value)?; self.enviorment.set(name.clone(), result) @@ -223,10 +240,18 @@ impl Interpreter { Stmt::While { condition, body, .. } => { + let mut ret = BaseValue::Nil; while self.evaluate(*condition.clone())?.is_truthy() { - self.evaluate(*body.clone())?; + match self.evaluate(*body.clone()) { + Ok(val) => ret = val, + Err(LoxError::Return { value, .. }) => { + ret = value; + break; + } + Err(err) => return Err(err), + }; } - Ok(BaseValue::Nil) + Ok(ret) } Stmt::For { variable, @@ -235,7 +260,6 @@ impl Interpreter { body, .. } => { - self.enviorment.push_new_scope(); let source_slice = variable.source_slice.clone(); let val = self.evaluate(*variable)?; if !matches!(val, BaseValue::Number(..)) { @@ -243,7 +267,14 @@ impl Interpreter { } let mut ret = BaseValue::Nil; while self.evaluate(*condition.clone())?.is_truthy() { - ret = self.evaluate(*body.clone())?; + match self.evaluate(*body.clone()) { + Ok(val) => ret = val, + Err(LoxError::Return { value, .. }) => { + ret = value; + break; + } + Err(err) => return Err(err), + }; self.evaluate(*increment.clone())?; } @@ -294,34 +325,26 @@ impl Interpreter { fn evaluate_block(&mut self, statements: Vec>) -> LoxResult { self.enviorment.push_new_scope(); - let (elements, final_expr) = match statements.split_last() { - Some((stmt, body)) => match &stmt.node { - Stmt::Expression { expression, .. } => (body, Some(expression)), - Stmt::Return { expression, .. } => (body, Some(expression)), - _ => (statements.as_slice(), None), - }, - - None => { - (&[][..], None) // Blocco vuoto - } - }; // Ora elements è sempre disponibile - for statement in elements.iter() { - self.evaluate((*statement).clone())?; - } + let mut result = Ok(BaseValue::Nil); + for statement in statements.iter() { + let node = statement.node.clone(); + match node { + Stmt::Return { expression, .. } => { + let value = self.evaluate(*expression)?; - // Gestisci l'espressione finale se presente - match final_expr { - Some(expr) => { - let res = self.evaluate(*expr.clone()); - self.enviorment.pop_scope(); - res - } - None => { - self.enviorment.pop_scope(); - Ok(BaseValue::Nil) - } + result = Err(LoxError::Return { + source_slice: statement.source_slice.clone(), + value: value, + return_label: "Hi".to_string(), + }); + break; + } + _ => result = self.evaluate((*statement).clone()), + }; } + self.enviorment.pop_scope(); + result } } diff --git a/src/common/ast.rs b/src/common/ast.rs index adc10b5..a796a28 100644 --- a/src/common/ast.rs +++ b/src/common/ast.rs @@ -138,6 +138,7 @@ pub enum Stmt { }, Return { expression: Box>, + label: String, return_value: Box, }, Block { @@ -219,7 +220,12 @@ impl Display for Stmt { Stmt::Return { expression, return_value, - } => write!(f, "Return({}) -> {:?};", expression.node, return_value), + label, + } => write!( + f, + "Return({}, {}) -> {:?};", + expression.node, label, return_value + ), Stmt::Block { statements, label, @@ -327,7 +333,12 @@ impl Debug for Stmt { Stmt::Return { expression, return_value, - } => write!(f, "Return({:?}) -> {:?};", expression.node, return_value), + label, + } => write!( + f, + "Return({:?}, {}) -> {:?};", + expression.node, label, return_value + ), Stmt::Block { label, statements, diff --git a/src/common/lox_result.rs b/src/common/lox_result.rs index 8ed8f7d..dce78e0 100644 --- a/src/common/lox_result.rs +++ b/src/common/lox_result.rs @@ -26,6 +26,11 @@ pub enum LoxError { expected: String, found: String, }, + Return { + source_slice: SourceSlice, + value: BaseValue, + return_label: String, + }, } /// Configuration for error display formatting @@ -84,6 +89,13 @@ impl LoxError { } => { format!("expected {}, found {}", expected, found) } + LoxError::Return { + value, + return_label, + .. + } => { + format!("return value: {} and label: {}", value, return_label) + } } } @@ -94,6 +106,11 @@ impl LoxError { LoxError::ParseError { source_slice, .. } => Some(source_slice.clone()), LoxError::IoError { .. } => None, LoxError::TypeMismatch { source_slice, .. } => Some(source_slice.clone()), + LoxError::Return { + value, + return_label, + .. + } => None, } } @@ -104,6 +121,7 @@ impl LoxError { LoxError::ParseError { .. } => "parse error", LoxError::IoError { .. } => "io error", LoxError::TypeMismatch { .. } => "type error", + LoxError::Return { .. } => "return error", } } @@ -396,6 +414,20 @@ impl fmt::Display for LoxError { found ) } + LoxError::Return { + value, + return_label, + source_slice, + } => { + write!( + f, + "Return error at {}:{}: value `{}`, label `{}`", + source_slice.start_position.line + 1, + source_slice.start_position.column + 1, + value, + return_label + ) + } } } } diff --git a/src/frontend/lexer.rs b/src/frontend/lexer.rs index b34d5ec..6751c21 100644 --- a/src/frontend/lexer.rs +++ b/src/frontend/lexer.rs @@ -29,6 +29,7 @@ fn get_keyword_token(word: &str) -> Option { "in" => Some(TokenType::In), "print" => Some(TokenType::Print), "return" => Some(TokenType::Return), + "break" => Some(TokenType::Break), "super" => Some(TokenType::Super), "this" => Some(TokenType::This), "true" => Some(TokenType::True), diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index 5dee948..29e8dad 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -2,7 +2,7 @@ use crate::{ common::{ ast::{AstNode, Expr, Stmt}, base_value::{BaseValue, LoxFunction}, - lox_result::{parse_error, runtime_error, LoxResult}, + lox_result::{parse_error, runtime_error, LoxError, LoxResult}, }, frontend::{ source_registry::SourceSlice, @@ -24,7 +24,7 @@ impl Parser { let mut statements = Vec::new(); let mut errors = Vec::new(); while !self.is_at_end() { - match self.statement() { + match self.statement(None) { Ok(stmt) => { statements.push(stmt.clone()); } @@ -42,11 +42,12 @@ impl Parser { Ok(statements) } - fn statement(&mut self) -> LoxResult> { + 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(), - (TokenType::StartBlock, _) => self.block_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() @@ -68,11 +69,7 @@ impl Parser { 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()?; - self.consume(TokenType::EndBlock, "Expected 'end' after for body")?; + let body = self.statement(Some("loop".to_string()))?; let end_slice = self.previous().source_slice.clone(); let combined_slice = SourceSlice::from_positions( @@ -118,7 +115,7 @@ impl Parser { // self.advance(); // self.consume(TokenType::In, "Expect 'in' after for variable.")?; // let iterable = self.expression()?; - // let body = self.statement()?; + // let body = self.statement(None)?; // let end_slice = body.source_slice.clone(); // let combined_slice = SourceSlice::from_positions( // start_slice.source_id, @@ -139,7 +136,7 @@ impl Parser { let start_slice = self.peek().source_slice.clone(); self.advance(); let condition = self.expression()?; - let body = self.statement()?; + 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, @@ -161,7 +158,7 @@ impl Parser { self.advance(); // consume 'if' let condition = self.expression()?; self.consume(TokenType::Then, "Expect 'then' after if condition.")?; - let then_branch = self.statement()?; + let then_branch = self.statement(None)?; let mut elif_branches = Vec::new(); let mut last_slice = then_branch.source_slice.clone(); @@ -169,14 +166,14 @@ impl Parser { self.advance(); // consume 'elif' let elif_condition = self.expression()?; self.consume(TokenType::Then, "Expect 'then' after elif condition.")?; - let elif_branch = self.statement()?; + 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()?; + let else_stmt = self.statement(None)?; last_slice = else_stmt.source_slice.clone(); Some(Box::new(else_stmt)) } else { @@ -259,7 +256,7 @@ impl Parser { self.consume(TokenType::RightBrace, "Expected '}' after guard expression")?; } - let body = self.statement()?; + let body = self.statement(None)?; let node = AstNode { node: Expr::Literal { value: BaseValue::Function(LoxFunction { @@ -370,12 +367,13 @@ impl Parser { )) } - fn block_statement(&mut self) -> LoxResult> { + 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()?; + let stmt = self.statement(label.clone())?; let should_break = matches!(stmt.node, Stmt::Expression { .. }); statements.push(stmt); if should_break { @@ -389,10 +387,15 @@ impl Parser { 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: String::default(), + label: label_str, return_value: Box::new(BaseValue::Nil), }, combined_slice, @@ -429,10 +432,31 @@ impl Parser { )) } - fn return_statement(&mut self) -> LoxResult> { + fn return_statement(&mut self, label: Option) -> LoxResult> { let start_slice = self.peek().source_slice.clone(); self.advance(); - let expr = self.expression()?; + let expr = match self.expression() { + Ok(expr) => expr, + Err(LoxError::ParseError { + message, + source_slice, + }) => { + if message == "Expect expression." { + AstNode { + node: Expr::Literal { + value: BaseValue::Nil, + }, + source_slice: 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( @@ -440,10 +464,16 @@ impl Parser { 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, )) diff --git a/src/frontend/tokens.rs b/src/frontend/tokens.rs index cdad154..d822670 100644 --- a/src/frontend/tokens.rs +++ b/src/frontend/tokens.rs @@ -57,6 +57,7 @@ pub enum TokenType { Is, Print, Return, + Break, Super, This, Var, @@ -92,6 +93,7 @@ impl fmt::Display for TokenType { TokenType::Or => write!(f, "or"), TokenType::Print => write!(f, "print"), TokenType::Return => write!(f, "return"), + TokenType::Break => write!(f, "break"), TokenType::Super => write!(f, "super"), TokenType::This => write!(f, "this"), TokenType::Var => write!(f, "var"), diff --git a/src/logging/display_token.rs b/src/logging/display_token.rs index f3b645f..5ce6980 100644 --- a/src/logging/display_token.rs +++ b/src/logging/display_token.rs @@ -190,6 +190,7 @@ impl Token { TokenType::Or => "OR", TokenType::Print => "PRINT", TokenType::Return => "RETURN", + TokenType::Break => "BREAK", TokenType::Super => "SUPER", TokenType::This => "THIS", TokenType::Var => "VAR", @@ -232,6 +233,7 @@ impl Token { | TokenType::Or | TokenType::Print | TokenType::Return + | TokenType::Break | TokenType::Super | TokenType::This | TokenType::Var diff --git a/src/main.rs b/src/main.rs index d10766d..f79d8f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,109 +30,35 @@ fn main() -> LoxResult<()> { let args: Vec = env::args().collect(); let (stage, file_path, debug) = parse_args(&args); + println!("running {file_path:?}"); let mut lox = LoxInterpreter::new(debug); - let _ = match file_path { + let res = match file_path { Some(path) => lox.run_file(&path, stage), None => lox.run_prompt(stage), }; - Ok(()) + res } fn parse_args(args: &[String]) -> (ExecutionStage, Option, bool) { - if args.len() == 1 { - // Solo il nome del programma: modalità interattiva completa - (ExecutionStage::Full, None, false) - } else if args.len() == 2 { - // Un argomento: potrebbe essere file o flag - let arg = &args[1]; - if arg == "--tokens" || arg == "--ast" || arg == "--full" || arg == "--debug" { - // Flag senza file: modalità interattiva - let stage = match arg.as_str() { - "--tokens" => ExecutionStage::Tokens, - "--ast" => ExecutionStage::Ast, - "--full" => ExecutionStage::Full, - "--debug" => ExecutionStage::Full, - _ => ExecutionStage::Full, - }; - let debug = arg == "--debug"; - (stage, None, debug) - } else { - // File senza flag: esecuzione completa del file - (ExecutionStage::Full, Some(arg.clone()), false) + println!("{args:?}"); + + let mut stage = ExecutionStage::Full; + let mut file_path = None; + let mut debug = false; + + for arg in args.iter().skip(1) { + match arg.as_str() { + "-t" | "--tokens" => stage = ExecutionStage::Tokens, + "-a" | "--ast" => stage = ExecutionStage::Ast, + "-f" | "--full" => stage = ExecutionStage::Full, + "-d" | "--debug" => debug = true, + _ => file_path = Some(arg.clone()), } - } else if args.len() == 3 { - // Due argomenti: potrebbero essere flag + file o due flag - let mut debug = false; - let mut stage = ExecutionStage::Full; - let mut file_path = None; - - for arg in &args[1..3] { - if arg == "--debug" { - debug = true; - } else if arg == "--tokens" || arg == "--ast" || arg == "--full" { - stage = match arg.as_str() { - "--tokens" => ExecutionStage::Tokens, - "--ast" => ExecutionStage::Ast, - "--full" => ExecutionStage::Full, - _ => ExecutionStage::Full, - }; - } else if !arg.starts_with("--") { - file_path = Some(arg.clone()); - } else { - eprintln!( - "Unknown flag: {}. Use --tokens, --ast, --full, or --debug", - arg - ); - eprintln!( - "Usage: {} [--tokens|--ast|--full] [--debug] [script]", - args[0] - ); - std::process::exit(64); - } - } - - (stage, file_path, debug) - } else if args.len() == 4 { - // Tre argomenti: flag + flag + file - let mut debug = false; - let mut stage = ExecutionStage::Full; - let mut file_path = None; - - for arg in &args[1..4] { - if arg == "--debug" { - debug = true; - } else if arg == "--tokens" || arg == "--ast" || arg == "--full" { - stage = match arg.as_str() { - "--tokens" => ExecutionStage::Tokens, - "--ast" => ExecutionStage::Ast, - "--full" => ExecutionStage::Full, - _ => ExecutionStage::Full, - }; - } else if !arg.starts_with("--") { - file_path = Some(arg.clone()); - } else { - eprintln!( - "Unknown flag: {}. Use --tokens, --ast, --full, or --debug", - arg - ); - eprintln!( - "Usage: {} [--tokens|--ast|--full] [--debug] [script]", - args[0] - ); - std::process::exit(64); - } - } - - (stage, file_path, debug) - } else { - eprintln!( - "Usage: {} [--tokens|--ast|--full] [--debug] [script]", - args[0] - ); - std::process::exit(64); } + + (stage, file_path, debug) } struct LoxInterpreter {