From 07cedc27bfc83951063f94bceb39b4a35faec69a Mon Sep 17 00:00:00 2001 From: Giulio Agostini Date: Fri, 10 Oct 2025 10:18:02 +0200 Subject: [PATCH] Add .idea to gitignore and prep return value types Add middleend module for AST return value tracking The changes introduce support for tracking return values and labels across AST nodes. The key changes include: - Adding ReturnValue type to BaseValue - Adding return_type field to LoxFunction - Adding label field to Block statements - Creating middleend crawler module for AST traversal Add return value types to AST This accurately captures both changes: adding `.idea/` to gitignore and adding return value types to the AST structure. The changes include adding return value fields to statement nodes and adjusting the interpreter logic accordingly. --- .gitignore | 2 + src/backend/interpreter.rs | 25 +++--- src/common/ast.rs | 180 ++++++++++++++++++++++++++++--------- src/common/base_value.rs | 10 +++ src/frontend/parser.rs | 15 +++- src/logging/display_ast.rs | 46 +++++++--- src/main.rs | 1 + src/middleend/crawler.rs | 115 ++++++++++++++++++++++++ src/middleend/mod.rs | 1 + tests/test_example.rs | 0 10 files changed, 331 insertions(+), 64 deletions(-) create mode 100644 src/middleend/crawler.rs create mode 100644 src/middleend/mod.rs create mode 100644 tests/test_example.rs diff --git a/.gitignore b/.gitignore index 4495404..91a8d77 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ rust-project.json # End of https://www.toptal.com/developers/gitignore/api/rust,rust-analyzer .zed/ + +.idea/ diff --git a/src/backend/interpreter.rs b/src/backend/interpreter.rs index 235467f..3e811db 100644 --- a/src/backend/interpreter.rs +++ b/src/backend/interpreter.rs @@ -182,16 +182,17 @@ impl Interpreter { fn interpret_stmt_inner(&mut self, stmt: Stmt) -> LoxResult { match stmt { - Stmt::Expression { expression } => self.evaluate(*expression), - Stmt::Print { expression } => { + Stmt::Expression { expression, .. } => self.evaluate(*expression), + Stmt::Print { expression, .. } => { let value = self.evaluate(*expression)?; println!("{}", value); Ok(BaseValue::Nil) } - Stmt::Block { statements } => self.evaluate_block(*statements), - Stmt::Stmt { expression } => self.evaluate(*expression.clone()), - Stmt::Return { expression } => self.evaluate(*expression), - Stmt::VarDeclaration { name, initializer } => { + Stmt::Block { statements, .. } => self.evaluate_block(*statements), + Stmt::Return { expression, .. } => self.evaluate(*expression), + Stmt::VarDeclaration { + name, initializer, .. + } => { let value = match initializer { Some(expr_node) => match &expr_node.node { Expr::Literal { value } => { @@ -208,7 +209,7 @@ impl Interpreter { self.enviorment.declare(name.clone(), value) } - Stmt::VarAssigment { name, value } => { + Stmt::VarAssigment { name, value, .. } => { let result = self.evaluate(*value)?; self.enviorment.set(name.clone(), result) } @@ -217,8 +218,11 @@ impl Interpreter { then_branch, elif_branch, else_branch, + .. } => self.evaluate_if(condition, then_branch, elif_branch, else_branch), - Stmt::While { condition, body } => { + Stmt::While { + condition, body, .. + } => { while self.evaluate(*condition.clone())?.is_truthy() { self.evaluate(*body.clone())?; } @@ -229,6 +233,7 @@ impl Interpreter { condition, increment, body, + .. } => { self.enviorment.push_new_scope(); let source_slice = variable.source_slice.clone(); @@ -291,8 +296,8 @@ impl Interpreter { 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)), + Stmt::Expression { expression, .. } => (body, Some(expression)), + Stmt::Return { expression, .. } => (body, Some(expression)), _ => (statements.as_slice(), None), }, diff --git a/src/common/ast.rs b/src/common/ast.rs index 0127b79..adc10b5 100644 --- a/src/common/ast.rs +++ b/src/common/ast.rs @@ -120,96 +120,142 @@ impl Debug for Expr { pub enum Stmt { Expression { expression: Box>, + return_value: Box, }, Print { expression: Box>, - }, - Stmt { - expression: Box>, + return_value: Box, }, VarDeclaration { name: String, initializer: Option>>, + return_value: Box, }, VarAssigment { name: String, value: Box>, + return_value: Box, }, Return { expression: Box>, + return_value: Box, }, Block { statements: Box>>, + label: String, + return_value: Box, }, If { condition: Box>, then_branch: Box>, elif_branch: Vec<(Box>, Box>)>, else_branch: Option>>, + return_value: Box, }, While { condition: Box>, body: Box>, + return_value: Box, }, For { variable: Box>, condition: Box>, increment: Box>, body: Box>, + return_value: Box, }, } impl Display for Stmt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Stmt::Expression { expression } => write!(f, "Expression ({})", expression.node), + Stmt::Expression { + expression, + return_value, + } => write!(f, "Expression ({}) -> {:?}", expression.node, return_value), Stmt::If { condition, then_branch, elif_branch, else_branch, + return_value, } => { let mut result = format!("IF ({}) {{\n{}\n}}", condition.node, then_branch.node); for (condition, branch) in elif_branch { result.push_str(&format!( - " ELIF ({}) {{\n{}\n}}", - condition.node, branch.node + " ELIF ({}) {{\n{}\n}} -> {:?}", + condition.node, branch.node, return_value )); } if let Some(else_branch) = else_branch { - result.push_str(&format!(" ELSE {{\n{}\n}}", else_branch.node)); + result.push_str(&format!( + " ELSE {{\n{}\n}} -> {:?}", + else_branch.node, return_value + )); } write!(f, "IfStmt {}", result) } - Stmt::Print { expression } => write!(f, "Print({});", expression.node), - Stmt::Stmt { expression } => write!(f, "Stmt({});", expression.node), - Stmt::VarDeclaration { name, initializer } => match initializer { - Some(init) => write!(f, "Var({} = {});", name, init.node), - None => write!(f, "Var({});", name), + Stmt::Print { + expression, + return_value, + } => write!(f, "Print({}) -> {:?};", expression.node, return_value), + Stmt::VarDeclaration { + name, + initializer, + return_value, + } => match initializer { + Some(init) => write!(f, "Var({} = {}) -> {:?};", name, init.node, return_value), + None => write!(f, "Var({}) -> {:?};", name, return_value), }, - Stmt::VarAssigment { name, value } => write!(f, "Assign({} = {});", name, value.node), - Stmt::Return { expression } => write!(f, "Return({});", expression.node), - Stmt::Block { statements } => write!( + Stmt::VarAssigment { + name, + value, + return_value, + } => write!( f, - "Block([\n{}\n])", + "Assign({} = {}) -> {:?};", + name, value.node, return_value + ), + Stmt::Return { + expression, + return_value, + } => write!(f, "Return({}) -> {:?};", expression.node, return_value), + Stmt::Block { + statements, + label, + return_value, + } => write!( + f, + "Block [{}] ([\n{}\n]) -> {:?}", + label, statements .iter() .map(|stmt| format!("\t \t{}", stmt.node)) .collect::>() - .join("\n") + .join("\n"), + return_value ), - Stmt::While { condition, body } => { - write!(f, "While({}) {{\n{}\n}}", condition.node, body.node) + Stmt::While { + condition, + body, + return_value, + } => { + write!( + f, + "While({}) {{\n{}\n}} -> {:?}", + condition.node, body.node, return_value + ) } Stmt::For { variable, condition, increment, body, + return_value, } => write!( f, - "For({} = {} in {}) {{\n{}\n}}", - variable.node, condition.node, increment.node, body.node + "For({} = {} in {}) {{\n{}\n}} -> {:?}", + variable.node, condition.node, increment.node, body.node, return_value ), } } @@ -218,57 +264,106 @@ impl Display for Stmt { impl Debug for Stmt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Stmt::Expression { expression } => write!(f, " Expression ({:?})", expression.node), + Stmt::Expression { + expression, + return_value, + } => write!( + f, + " Expression ({:?}) -> {:?}", + expression.node, return_value + ), Stmt::If { condition, then_branch, elif_branch, else_branch, + return_value, } => { - let mut result = - format!("IF ({:?}) {{\n{:?}\n}}", condition.node, then_branch.node); + let mut result = format!( + "IF ({:?}) {{\n{:?}\n}} -> {:?} ", + condition.node, then_branch.node, return_value + ); for (condition, branch) in elif_branch { result.push_str(&format!( - " ELIF ({:?}) {{\n{:?}\n}}", - condition.node, branch.node + " ELIF ({:?}) {{\n{:?}\n}} -> {:?} ", + condition.node, branch.node, return_value )); } if let Some(else_branch) = else_branch { - result.push_str(&format!(" ELSE {{\n{:?}\n}}", else_branch.node)); + result.push_str(&format!( + " ELSE {{\n{:?}\n}} -> {:?}", + else_branch.node, return_value + )); } write!(f, "IfStmt {:?}", result) } - Stmt::Print { expression } => write!(f, "Print({:?});", expression.node), - Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression.node), - Stmt::VarDeclaration { name, initializer } => match initializer { - Some(init) => write!(f, "Var({:?} = {:?});", name, init.node), - None => write!(f, "Var({:?});", name), + Stmt::Print { + expression, + return_value, + } => write!(f, "Print({:?}) -> {:?};", expression.node, return_value), + Stmt::VarDeclaration { + name, + initializer, + return_value, + } => match initializer { + Some(init) => write!( + f, + "Var({:?} = {:?}) -> {:?};", + name, init.node, return_value + ), + None => write!(f, "Var({:?}) -> {:?};", name, return_value), }, - Stmt::VarAssigment { name, value } => { - write!(f, "Assign({:?} = {:?});", name, value.node) + Stmt::VarAssigment { + name, + value, + return_value, + } => { + write!( + f, + "Assign({:?} = {:?}) -> {:?};", + name, value.node, return_value + ) } - Stmt::Return { expression } => write!(f, "Return({:?});", expression.node), - Stmt::Block { statements } => write!( + Stmt::Return { + expression, + return_value, + } => write!(f, "Return({:?}) -> {:?};", expression.node, return_value), + Stmt::Block { + label, + statements, + return_value, + } => write!( f, - "Block([\n{:?}\n])", + "Block [{}] ([\n{:?}\n]) -> {:?}", + label, statements .iter() .map(|stmt| format!("{:?}", stmt.node)) .collect::>() - .join("\t\t\n") + .join("\t\t\n"), + return_value ), - Stmt::While { condition, body } => { - write!(f, "While({:?}) {{\n{:?}\n}}", condition.node, body.node) + Stmt::While { + condition, + body, + return_value, + } => { + write!( + f, + "While({:?}) {{\n{:?}\n}} -> {:?}", + condition.node, body.node, return_value + ) } Stmt::For { variable, condition, increment, body, + return_value, } => write!( f, - "For({:?} = {:?} in {:?}) {{\n{:?}\n}}", - variable.node, condition.node, increment.node, body.node + "For({:?} = {:?} in {:?}) {{\n{:?}\n}} -> {:?}", + variable.node, condition.node, increment.node, body.node, return_value ), } } @@ -305,7 +400,6 @@ impl AstNodeKind for Stmt { Stmt::Block { .. } => "block statement", Stmt::If { .. } => "if statement", Stmt::Print { .. } => "print statement", - Stmt::Stmt { .. } => "statement", Stmt::While { .. } => "while statement", Stmt::For { .. } => "for statement", } diff --git a/src/common/base_value.rs b/src/common/base_value.rs index 9ae8024..98191f9 100644 --- a/src/common/base_value.rs +++ b/src/common/base_value.rs @@ -271,6 +271,10 @@ pub enum BaseValue { Nil, Function(LoxFunction), NativeFunction(NativeFunction), + Return { + value: Box, + labels: Vec, + }, } impl BaseValue { @@ -292,6 +296,9 @@ impl Display for BaseValue { BaseValue::Nil => write!(f, "nil"), BaseValue::Function(..) => write!(f, ""), BaseValue::NativeFunction(..) => write!(f, ""), + BaseValue::Return { labels, .. } => { + write!(f, "", labels.join(":")) + } } } } @@ -299,6 +306,7 @@ impl Display for BaseValue { #[derive(Debug, Clone, PartialEq)] pub struct LoxFunction { pub parameters: Vec<(String, String)>, + pub return_type: Option, pub body: AstNode, pub closure: Option, pub guard: Option>, @@ -313,6 +321,7 @@ impl LoxFunction { ) -> Self { LoxFunction { parameters, + return_type: None, body, closure, guard, @@ -322,6 +331,7 @@ impl LoxFunction { pub fn anonymous_function(parameters: Vec<(String, String)>, body: AstNode) -> Self { LoxFunction { parameters, + return_type: None, body, closure: None, guard: None, diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index bb705f8..5dee948 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -87,6 +87,7 @@ impl Parser { condition: Box::new(condition), increment: Box::new(increment), body: Box::new(body), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) @@ -149,6 +150,7 @@ impl Parser { Stmt::While { condition: Box::new(condition), body: Box::new(body), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) @@ -193,6 +195,7 @@ impl Parser { then_branch: Box::new(then_branch), elif_branch: elif_branches, else_branch: else_branch, + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) @@ -261,6 +264,7 @@ impl Parser { node: Expr::Literal { value: BaseValue::Function(LoxFunction { parameters, + return_type: None, body, closure: None, guard, @@ -272,6 +276,7 @@ impl Parser { Stmt::VarDeclaration { name: name_lexeme, initializer: Some(Box::new(node)), + return_value: Box::new(BaseValue::Nil), }, combine_position.clone(), )) @@ -313,6 +318,7 @@ impl Parser { Stmt::VarDeclaration { name: name_lexeme, initializer: Some(Box::new(value)), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) @@ -337,6 +343,7 @@ impl Parser { Stmt::VarAssigment { name: name_lexeme, value: Box::new(value), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) @@ -357,6 +364,7 @@ impl Parser { Ok(AstNode::new( Stmt::Print { expression: Box::new(expr), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) @@ -384,6 +392,8 @@ impl Parser { Ok(AstNode::new( Stmt::Block { statements: Box::new(statements), + label: String::default(), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) @@ -401,8 +411,9 @@ impl Parser { end_slice.end_position, ); return Ok(AstNode::new( - Stmt::Stmt { + Stmt::Expression { expression: Box::new(expr), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )); @@ -412,6 +423,7 @@ impl Parser { Ok(AstNode::new( Stmt::Expression { expression: Box::new(expr), + return_value: Box::new(BaseValue::Nil), }, expr_slice, )) @@ -431,6 +443,7 @@ impl Parser { Ok(AstNode::new( Stmt::Return { expression: Box::new(expr), + return_value: Box::new(BaseValue::Nil), }, combined_slice, )) diff --git a/src/logging/display_ast.rs b/src/logging/display_ast.rs index da837e1..8f93d95 100644 --- a/src/logging/display_ast.rs +++ b/src/logging/display_ast.rs @@ -263,7 +263,10 @@ impl PrettyPrint for Stmt { let indent = ctx.indent(); match self { - Stmt::Expression { expression } => { + Stmt::Expression { + expression, + return_value, + } => { if ctx.config.compact { let expr_str = pretty_print_with_config(expression.as_ref(), &PrettyConfig::compact()); @@ -276,7 +279,10 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::Print { expression } => { + Stmt::Print { + expression, + return_value, + } => { if ctx.config.compact { let expr_str = pretty_print_with_config(expression.as_ref(), &PrettyConfig::compact()); @@ -289,7 +295,11 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::VarDeclaration { name, initializer } => { + Stmt::VarDeclaration { + name, + initializer, + return_value, + } => { if ctx.config.compact { match initializer { Some(init) => { @@ -315,7 +325,11 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::VarAssigment { name, value } => { + Stmt::VarAssigment { + name, + value, + return_value, + } => { if ctx.config.compact { let value_str = pretty_print_with_config(value.as_ref(), &PrettyConfig::compact()); @@ -329,7 +343,10 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::Return { expression } => { + Stmt::Return { + expression, + return_value, + } => { if ctx.config.compact { let expr_str = pretty_print_with_config(expression.as_ref(), &PrettyConfig::compact()); @@ -342,11 +359,15 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::Block { statements } => { + Stmt::Block { + statements, + label, + return_value, + } => { if ctx.config.compact { - write!(f, "{{ ... ({} statements) }}", statements.len()) + write!(f, "{{ ... [{}] ({} statements) }}", label, statements.len()) } else { - writeln!(f, "{}Block {{", indent)?; + writeln!(f, "{}Block [{}] {{", label, indent)?; writeln!(f, "{}statements: [", ctx.child_context(false).indent())?; for (i, stmt) in statements.iter().enumerate() { let is_last = i == statements.len() - 1; @@ -366,6 +387,7 @@ impl PrettyPrint for Stmt { then_branch, elif_branch, else_branch, + return_value, } => { if ctx.config.compact { let cond_str = @@ -415,8 +437,11 @@ impl PrettyPrint for Stmt { write!(f, "{}}}", indent) } } - Stmt::Stmt { expression } => expression.pretty_print(ctx, f), - Stmt::While { condition, body } => { + Stmt::While { + condition, + body, + return_value, + } => { write!(f, "{}while (", ctx.child_context(true).indent())?; condition.pretty_print(&ctx.child_context(true), f)?; writeln!(f, ") {{")?; @@ -428,6 +453,7 @@ impl PrettyPrint for Stmt { condition, increment, body, + return_value, } => { write!(f, "{}for (", ctx.child_context(true).indent())?; variable.pretty_print(&ctx.child_context(true), f)?; diff --git a/src/main.rs b/src/main.rs index 98e2653..d10766d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod backend; mod common; mod frontend; mod logging; +mod middleend; use crate::{ backend::interpreter::{EvaluateInterpreter, Interpreter}, diff --git a/src/middleend/crawler.rs b/src/middleend/crawler.rs new file mode 100644 index 0000000..8feaa2f --- /dev/null +++ b/src/middleend/crawler.rs @@ -0,0 +1,115 @@ +use crate::common::{ + ast::{AstNode, Expr, Stmt}, + lox_result::LoxResult, +}; + +// Enum per tutti i possibili target di operazioni +enum OperationTarget<'a> { + Stmt(&'a mut Stmt), + Expr(&'a mut Expr), + AstStmt(&'a mut AstNode), + AstExpr(&'a mut AstNode), +} + +// Trait per le operazioni +trait Operation: Send + Sync { + fn execute(&self, target: OperationTarget) -> LoxResult<()>; +} + +// Operazione concreta per set_label +struct SetLabelOperation { + new_label: String, +} + +impl SetLabelOperation { + fn new(label: String) -> Self { + Self { new_label: label } + } +} + +impl Operation for SetLabelOperation { + fn execute(&self, target: OperationTarget) -> LoxResult<()> { + match target { + OperationTarget::Stmt(stmt) => { + if let Stmt::Block { label, .. } = stmt { + *label = self.new_label.clone(); + } + } + OperationTarget::AstStmt(node) => { + if let Stmt::Block { label, .. } = &mut node.node { + *label = self.new_label.clone(); + } + } + _ => {} // Expr non hanno label + } + Ok(()) + } +} + +// Trait per convertire tipi in OperationTarget +trait AsOperationTarget { + fn as_target(&mut self) -> OperationTarget; +} + +impl AsOperationTarget for Stmt { + fn as_target(&mut self) -> OperationTarget { + OperationTarget::Stmt(self) + } +} + +impl AsOperationTarget for Expr { + fn as_target(&mut self) -> OperationTarget { + OperationTarget::Expr(self) + } +} + +impl AsOperationTarget for AstNode { + fn as_target(&mut self) -> OperationTarget { + OperationTarget::AstStmt(self) + } +} + +impl AsOperationTarget for AstNode { + fn as_target(&mut self) -> OperationTarget { + OperationTarget::AstExpr(self) + } +} + +// Crawler generico con Command Pattern +struct Crawler { + node: T, + operations: Vec>, +} + +impl Crawler { + fn new(node: T) -> Self { + Self { + node, + operations: vec![], + } + } + + fn add_operation(&mut self, op: Box) { + self.operations.push(op); + } + + fn execute_operations(&mut self) -> LoxResult<()> { + for op in &self.operations { + op.execute(self.node.as_target())?; + } + Ok(()) + } + + fn with_operation(mut self, op: Box) -> Self { + self.operations.push(op); + self + } + + fn get_node(&self) -> &T { + &self.node + } + + fn get_node_mut(&mut self) -> &mut T { + &mut self.node + } +} diff --git a/src/middleend/mod.rs b/src/middleend/mod.rs new file mode 100644 index 0000000..145a637 --- /dev/null +++ b/src/middleend/mod.rs @@ -0,0 +1 @@ +pub mod crawler; diff --git a/tests/test_example.rs b/tests/test_example.rs new file mode 100644 index 0000000..e69de29