Add source location tracking to AST nodes

The commit expands the source location tracking through the AST by:

1. Switching from raw Expr/Stmt nodes to AstNode wrappers containing
source slices 2. Updating interpreter and parser to preserve location
info through node traversal 3. Enhancing error reporting with richer
source context information
This commit is contained in:
Giulio Agostini
2025-10-04 19:02:33 +02:00
parent 113a683beb
commit 41253e932a
11 changed files with 886 additions and 352 deletions
+80 -59
View File
@@ -38,16 +38,16 @@ pub enum Expr {
value: LiteralValue,
},
Binary {
left: Box<Expr>,
left: Box<AstNode<Expr>>,
operator: TokenType,
right: Box<Expr>,
right: Box<AstNode<Expr>>,
},
Unary {
operator: TokenType,
operand: Box<Expr>,
operand: Box<AstNode<Expr>>,
},
Grouping {
expression: Box<Expr>,
expression: Box<AstNode<Expr>>,
},
Variable {
name: String,
@@ -67,13 +67,13 @@ impl ExprPrint for Expr {
operator,
right,
} => {
format!("Binary ({} {} {})", left, operator, right)
format!("Binary ({} {} {})", left.node, operator, right.node)
}
Expr::Unary { operator, operand } => {
format!("Unary ({} {})", operator, operand)
format!("Unary ({} {})", operator, operand.node)
}
Expr::Grouping { expression } => {
format!("Grouping (group {})", expression)
format!("Grouping (group {})", expression.node)
}
Expr::Variable { name } => {
format!("Variable (variable {})", name)
@@ -91,9 +91,9 @@ impl std::fmt::Display for Expr {
left,
operator,
right,
} => write!(f, "Binary ({} {} {})", left, operator, right),
Expr::Unary { operator, operand } => write!(f, "Unary ({} {})", operator, operand),
Expr::Grouping { expression } => write!(f, "Grouping (group {})", expression),
} => 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),
}
}
@@ -107,9 +107,9 @@ impl Debug for Expr {
left,
operator,
right,
} => write!(f, "({:?} {:?} {:?})", operator, left, right),
Expr::Unary { operator, operand } => write!(f, "({:?} {:?})", operator, operand),
Expr::Grouping { expression } => write!(f, "(group {:?})", expression),
} => 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),
}
}
@@ -118,86 +118,96 @@ impl Debug for Expr {
#[derive(Clone)]
pub enum Stmt {
Expression {
expression: Box<Expr>,
expression: Box<AstNode<Expr>>,
},
Print {
expression: Box<Expr>,
expression: Box<AstNode<Expr>>,
},
Stmt {
expression: Box<Expr>,
expression: Box<AstNode<Expr>>,
},
Var {
name: String,
initializer: Option<Box<Expr>>,
initializer: Option<Box<AstNode<Expr>>>,
},
Assign {
name: String,
value: Box<Expr>,
value: Box<AstNode<Expr>>,
},
Return {
expression: Box<Expr>,
expression: Box<AstNode<Expr>>,
},
Block {
statements: Box<Vec<Stmt>>,
statements: Box<Vec<AstNode<Stmt>>>,
},
If {
condition: Box<Expr>,
then_branch: Box<Stmt>,
elif_branch: Vec<(Box<Expr>, Box<Stmt>)>,
else_branch: Option<Box<Stmt>>,
condition: Box<AstNode<Expr>>,
then_branch: Box<AstNode<Stmt>>,
elif_branch: Vec<(Box<AstNode<Expr>>, Box<AstNode<Stmt>>)>,
else_branch: Option<Box<AstNode<Stmt>>>,
},
While {
condition: Box<Expr>,
body: Box<Stmt>,
condition: Box<AstNode<Expr>>,
body: Box<AstNode<Stmt>>,
},
For {
variable: Box<Expr>,
iterable: Box<Expr>,
body: Box<Stmt>,
variable: Box<AstNode<Expr>>,
iterable: Box<AstNode<Expr>>,
body: Box<AstNode<Stmt>>,
},
}
impl Display for Stmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Stmt::Expression { expression } => write!(f, "Expression ({})", expression),
Stmt::Expression { expression } => write!(f, "Expression ({})", expression.node),
Stmt::If {
condition,
then_branch,
elif_branch,
else_branch,
} => {
let mut result = format!("IF ({}) {{\n{}\n}}", condition, then_branch);
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, branch));
result.push_str(&format!(
" ELIF ({}) {{\n{}\n}}",
condition.node, branch.node
));
}
if let Some(else_branch) = else_branch {
result.push_str(&format!(" ELSE {{\n{}\n}}", else_branch));
result.push_str(&format!(" ELSE {{\n{}\n}}", else_branch.node));
}
write!(f, "IfStmt {}", result)
}
Stmt::Print { expression } => write!(f, "Print({});", expression),
Stmt::Stmt { expression } => write!(f, "Stmt({});", expression),
Stmt::Var { name, initializer } => {
write!(f, "Var({} = {:?});", name, initializer)
}
Stmt::Assign { name, value } => write!(f, "Assign({} = {});", name, value),
Stmt::Return { expression } => write!(f, "Return({});", expression),
Stmt::Print { expression } => write!(f, "Print({});", expression.node),
Stmt::Stmt { expression } => write!(f, "Stmt({});", expression.node),
Stmt::Var { 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::Return { expression } => write!(f, "Return({});", expression.node),
Stmt::Block { statements } => write!(
f,
"Block([\n{}\n])",
statements
.iter()
.map(|stmt| format!("\t \t{}", stmt))
.map(|stmt| format!("\t \t{}", stmt.node))
.collect::<Vec<_>>()
.join("\n")
),
Stmt::While { condition, body } => todo!(),
Stmt::While { condition, body } => {
write!(f, "While({}) {{\n{}\n}}", condition.node, body.node)
}
Stmt::For {
variable,
iterable,
body,
} => todo!(),
} => write!(
f,
"For({} in {}) {{\n{}\n}}",
variable.node, iterable.node, body.node
),
}
}
}
@@ -205,44 +215,55 @@ 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),
Stmt::Expression { expression } => write!(f, " Expression ({:?})", expression.node),
Stmt::If {
condition,
then_branch,
elif_branch,
else_branch,
} => {
let mut result = format!("IF ({:?}) {{\n{:?}\n}}", condition, then_branch);
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, branch));
result.push_str(&format!(
" ELIF ({:?}) {{\n{:?}\n}}",
condition.node, branch.node
));
}
if let Some(else_branch) = else_branch {
result.push_str(&format!(" ELSE {{\n{:?}\n}}", else_branch));
result.push_str(&format!(" ELSE {{\n{:?}\n}}", else_branch.node));
}
write!(f, "IfStmt {:?}", result)
}
Stmt::Print { expression } => write!(f, "Print({:?});", expression),
Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression),
Stmt::Var { name, initializer } => {
write!(f, "Var({:?} = {:?});", name, initializer)
}
Stmt::Assign { name, value } => write!(f, "Assign({:?} = {:?});", name, value),
Stmt::Return { expression } => write!(f, "Return({:?});", expression),
Stmt::Print { expression } => write!(f, "Print({:?});", expression.node),
Stmt::Stmt { expression } => write!(f, "Stmt({:?});", expression.node),
Stmt::Var { 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::Return { expression } => write!(f, "Return({:?});", expression.node),
Stmt::Block { statements } => write!(
f,
"Block([\n{:?}\n])",
statements
.iter()
.map(|stmt| format!("{:?}", stmt))
.map(|stmt| format!("{:?}", stmt.node))
.collect::<Vec<_>>()
.join("\t\t\n")
),
Stmt::While { condition, body } => todo!(),
Stmt::While { condition, body } => {
write!(f, "While({:?}) {{\n{:?}\n}}", condition.node, body.node)
}
Stmt::For {
variable,
iterable,
body,
} => todo!(),
} => write!(
f,
"For({:?} in {:?}) {{\n{:?}\n}}",
variable.node, iterable.node, body.node
),
}
}
}
@@ -289,12 +310,12 @@ impl AstNodeKind for Stmt {
} => "if statement",
Stmt::Print { expression: _ } => "print statement",
Stmt::Stmt { expression: _ } => "statement",
Stmt::While { condition, body } => todo!(),
Stmt::While { condition, body } => "while statement",
Stmt::For {
variable,
iterable,
body,
} => todo!(),
} => "for statement",
}
}
}