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.
This commit is contained in:
Giulio Agostini
2025-10-10 10:18:02 +02:00
parent c1ecd7d1f7
commit 07cedc27bf
10 changed files with 331 additions and 64 deletions
+2
View File
@@ -26,3 +26,5 @@ rust-project.json
# End of https://www.toptal.com/developers/gitignore/api/rust,rust-analyzer
.zed/
.idea/
+15 -10
View File
@@ -182,16 +182,17 @@ impl Interpreter {
fn interpret_stmt_inner(&mut self, stmt: Stmt) -> LoxResult<BaseValue> {
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),
},
+137 -43
View File
@@ -120,96 +120,142 @@ impl Debug for Expr {
pub enum Stmt {
Expression {
expression: Box<AstNode<Expr>>,
return_value: Box<BaseValue>,
},
Print {
expression: Box<AstNode<Expr>>,
},
Stmt {
expression: Box<AstNode<Expr>>,
return_value: Box<BaseValue>,
},
VarDeclaration {
name: String,
initializer: Option<Box<AstNode<Expr>>>,
return_value: Box<BaseValue>,
},
VarAssigment {
name: String,
value: Box<AstNode<Expr>>,
return_value: Box<BaseValue>,
},
Return {
expression: Box<AstNode<Expr>>,
return_value: Box<BaseValue>,
},
Block {
statements: Box<Vec<AstNode<Stmt>>>,
label: String,
return_value: Box<BaseValue>,
},
If {
condition: Box<AstNode<Expr>>,
then_branch: Box<AstNode<Stmt>>,
elif_branch: Vec<(Box<AstNode<Expr>>, Box<AstNode<Stmt>>)>,
else_branch: Option<Box<AstNode<Stmt>>>,
return_value: Box<BaseValue>,
},
While {
condition: Box<AstNode<Expr>>,
body: Box<AstNode<Stmt>>,
return_value: Box<BaseValue>,
},
For {
variable: Box<AstNode<Stmt>>,
condition: Box<AstNode<Expr>>,
increment: Box<AstNode<Stmt>>,
body: Box<AstNode<Stmt>>,
return_value: Box<BaseValue>,
},
}
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::<Vec<_>>()
.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::<Vec<_>>()
.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",
}
+10
View File
@@ -271,6 +271,10 @@ pub enum BaseValue {
Nil,
Function(LoxFunction),
NativeFunction(NativeFunction),
Return {
value: Box<BaseValue>,
labels: Vec<String>,
},
}
impl BaseValue {
@@ -292,6 +296,9 @@ impl Display for BaseValue {
BaseValue::Nil => write!(f, "nil"),
BaseValue::Function(..) => write!(f, "<fn lox function>"),
BaseValue::NativeFunction(..) => write!(f, "<native native function>"),
BaseValue::Return { labels, .. } => {
write!(f, "<return value [return:{}]>", 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<String>,
pub body: AstNode<Stmt>,
pub closure: Option<EnvironmentStack>,
pub guard: Option<Box<Expr>>,
@@ -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<Stmt>) -> Self {
LoxFunction {
parameters,
return_type: None,
body,
closure: None,
guard: None,
+14 -1
View File
@@ -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,
))
+36 -10
View File
@@ -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)?;
+1
View File
@@ -2,6 +2,7 @@ mod backend;
mod common;
mod frontend;
mod logging;
mod middleend;
use crate::{
backend::interpreter::{EvaluateInterpreter, Interpreter},
+115
View File
@@ -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<Stmt>),
AstExpr(&'a mut AstNode<Expr>),
}
// 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<Stmt> {
fn as_target(&mut self) -> OperationTarget {
OperationTarget::AstStmt(self)
}
}
impl AsOperationTarget for AstNode<Expr> {
fn as_target(&mut self) -> OperationTarget {
OperationTarget::AstExpr(self)
}
}
// Crawler generico con Command Pattern
struct Crawler<T: AsOperationTarget> {
node: T,
operations: Vec<Box<dyn Operation>>,
}
impl<T: AsOperationTarget> Crawler<T> {
fn new(node: T) -> Self {
Self {
node,
operations: vec![],
}
}
fn add_operation(&mut self, op: Box<dyn Operation>) {
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<dyn Operation>) -> Self {
self.operations.push(op);
self
}
fn get_node(&self) -> &T {
&self.node
}
fn get_node_mut(&mut self) -> &mut T {
&mut self.node
}
}
+1
View File
@@ -0,0 +1 @@
pub mod crawler;
View File