Add static variable resolution with scope tracking

- Add distance-based get_at on EnvironmentStack
- Add distance-based assign_at on EnvironmentStack
- Introduce ErrorSink to accumulate diagnostics across passes
- Implement Resolver with a ScopeStack and per-node distance map
- Extend interpreter to store locals distances for runtime lookup
- Add tests for resolution behavior and error accumulation
  Add static variable resolution with scope tracking
This commit is contained in:
Giulio Agostini
2026-06-30 15:05:34 +02:00
parent d40fe2a550
commit 9f15a00b98
8 changed files with 666 additions and 116 deletions
+21 -1
View File
@@ -15,6 +15,7 @@ use crate::{
parser::Parser,
source_registry::{SourceId, SourceRegistry},
},
middleend::variable_resolution::Resolver,
};
use std::env;
use std::fs;
@@ -185,7 +186,11 @@ impl LoxInterpreter {
// Funzione per eseguire l'AST
fn execute_ast(&self, ast: Vec<AstNode<Stmt>>, debug: bool) -> LoxResult<String> {
// Static resolution pass: compute variable scope distances and report
// any resolution errors before executing.
let locals = self.resolve(&ast)?;
let mut interpreter = Interpreter::new();
interpreter.set_locals(locals);
let mut result = None;
for (index, stmt) in ast.iter().enumerate() {
@@ -204,6 +209,19 @@ impl LoxInterpreter {
}
}
// Static variable resolution; prints and returns the first error, if any.
fn resolve(
&self,
ast: &[AstNode<Stmt>],
) -> LoxResult<std::collections::HashMap<crate::common::ast::NodeId, usize>> {
Resolver::resolve_program(ast).map_err(|errors| {
for err in &errors {
err.print_with_context(&self.source_registry);
}
errors.into_iter().next().unwrap()
})
}
fn process_source(
&self,
source_id: SourceId,
@@ -245,8 +263,10 @@ impl LoxInterpreter {
return Ok(format_ast(&ast));
}
// Stage 3: Interpretation
// Stage 3: Resolution + Interpretation
let locals = self.resolve(&ast)?;
let mut interpreter = Interpreter::new();
interpreter.set_locals(locals);
let mut result = None;
for (index, stmt) in ast.iter().enumerate() {