Introduce NodeId for AST and synthetic slices

This commit is contained in:
Giulio Agostini
2026-06-30 14:05:46 +02:00
parent ef8abda048
commit d40fe2a550
11 changed files with 504 additions and 170 deletions
+16 -20
View File
@@ -3,7 +3,7 @@ use std::collections::HashMap;
use crate::{
backend::environment::EnvironmentStack,
common::{
ast::{AstNode, Expr, Stmt},
ast::{AstNode, Expr, NodeId, Stmt},
lox_result::{LoxError, LoxResult},
},
frontend::source_registry::SourceSlice,
@@ -12,7 +12,7 @@ use crate::{
struct Resolver {
scopes: EnvironmentStack<bool>,
locals: HashMap<SourceSlice, usize>,
locals: HashMap<NodeId, usize>,
}
impl Resolver {
@@ -27,6 +27,7 @@ impl Resolver {
if self.scopes.is_empty() {
return;
}
let scope = self.scopes.peek();
let _ = self.scopes.set(name.clone(), false);
}
@@ -37,13 +38,16 @@ impl Resolver {
let _ = self.scopes.set(name.clone(), true);
}
fn resolve_local(&mut self, name: &String) {
fn resolve_local(&mut self, id: NodeId, name: &String) {
let depth = self.scopes.depth();
for i in (0..depth).rev() {
if self.scopes.scope_contains(i, name) {
self.locals.insert(, i);
// Distance = how many scopes up from the innermost the binding lives.
self.locals.insert(id, depth - 1 - i);
return;
}
}
// Not found in any tracked scope: assume global, record nothing.
}
}
@@ -57,20 +61,8 @@ impl Visitor for Resolver {
self.define(name);
Ok(())
}
Stmt::VarAssigment { name, .. } => {
match self.scopes.get(name) {
Ok(true) => (),
Ok(false) => {
return Err(LoxError::RuntimeError {
source_slice: SourceSlice::default(),
message: "Cant read local variable in it own lintilizer".to_string(),
})
}
Err(err) => return Err(err),
}
// `walk_stmt` resolves the assigned value.
walk_stmt(self, stmt)
}
// NOTE: assignment is now an `Expr::Assign`, not a statement.
// Add an `Expr::Assign` arm to `visit_expr` to resolve assignments.
Stmt::Block { .. } => {
self.scopes.push_new_scope();
walk_stmt(self, stmt)?;
@@ -87,11 +79,15 @@ impl Visitor for Resolver {
Expr::Identifier { name, .. } => {
if !self.scopes.is_empty() && self.scopes.get(name).is_ok() {
return Err(LoxError::ParseError {
source_slice: SourceSlice::default(),
source_slice: SourceSlice::synthetic(),
message: "Cant read local varialbe in it own initializer".to_string(),
});
}
Ok(())
walk_expr(self, expr)
}
Expr::Assign { name, .. } => {
self.resolve_local(expr.id, name);
walk_expr(self, expr)
}
_ => walk_expr(self, expr),
}
+1 -1
View File
@@ -73,7 +73,6 @@ pub fn walk_stmt<V: Visitor>(visitor: &mut V, stmt: &AstNode<Stmt>) -> LoxResult
}
Ok(())
}
Stmt::VarAssigment { value, .. } => visitor.visit_expr(value),
Stmt::Return { expression, .. } => visitor.visit_expr(expression),
Stmt::Block { statements, .. } => {
for statement in statements.iter() {
@@ -137,6 +136,7 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &AstNode<Expr>) -> LoxResult
visitor.visit_expr(right)
}
Expr::Unary { operand, .. } => visitor.visit_expr(operand),
Expr::Assign { value, .. } => visitor.visit_expr(value),
Expr::Grouping { expression } => visitor.visit_expr(expression),
Expr::Call {
callee, arguments, ..