Skip to content

Commit 4f0c3eb

Browse files
committed
fix: compiler symbol resolve bug
1 parent 51014cc commit 4f0c3eb

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

compiler/symbol_table.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,39 @@ impl SymbolTable {
4747
return symbol;
4848
}
4949

50-
pub fn resolve(&self, name: String) -> Option<Rc<Symbol>> {
51-
let symbol = self.symbols.get(&name);
52-
if symbol.is_none() && self.outer.is_some() {
53-
return self.outer.as_ref().unwrap().resolve(name);
50+
// Resolve a name in the current scope, capturing free variables from outers when needed.
51+
pub fn resolve(&mut self, name: String) -> Option<Rc<Symbol>> {
52+
if let Some(sym) = self.symbols.get(&name) {
53+
return Some(sym.clone());
5454
}
55-
return symbol.cloned();
55+
56+
// If not found locally, try outer scopes.
57+
if let Some(outer) = &self.outer {
58+
// We can't mutate outer here, so use a read-only helper to locate the original symbol.
59+
if let Some(original) = outer.resolve_readonly(&name) {
60+
return match original.scope {
61+
// Globals and builtins are accessed directly.
62+
SymbolScope::Global | SymbolScope::Builtin => Some(original),
63+
// Locals (from outer scope) or already-free symbols should be captured as a new free symbol here.
64+
SymbolScope::LOCAL | SymbolScope::Free | SymbolScope::Function => {
65+
Some(self.define_free(original))
66+
}
67+
};
68+
}
69+
}
70+
71+
None
72+
}
73+
74+
// Read-only resolver used internally to search outer scopes without mutating them.
75+
fn resolve_readonly(&self, name: &str) -> Option<Rc<Symbol>> {
76+
if let Some(sym) = self.symbols.get(name) {
77+
return Some(sym.clone());
78+
}
79+
if let Some(outer) = &self.outer {
80+
return outer.resolve_readonly(name);
81+
}
82+
None
5683
}
5784

5885
pub fn define_builtin(&mut self, index: usize, name: String) -> Rc<Symbol> {

compiler/vm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ impl VM {
411411
let mut free = Vec::with_capacity(num_free);
412412
for i in 0..num_free {
413413
let f = self.stack[self.sp - num_free + i].clone();
414-
free[i] = f;
414+
free.push(f);
415415
}
416416
self.sp = self.sp - num_free;
417417
let closure = ClosureObj (Closure {

0 commit comments

Comments
 (0)