Introduce boxing for captured variables
The binder now uses an `UpvalueAnalyzer` to identify local variables that are captured by nested functions. These identified variables are marked with `is_boxed: true` during `DefLocal` node creation. The VM then uses this flag to wrap such variables in a `Value::Cell` (using `Rc<RefCell<_>>`) to ensure they can be mutated across function calls. feat: Introduce boxing for captured variables Add UpvalueAnalyzer to identify variables captured by nested lambdas. Modify Binder to use the analyzer and mark captured local variables for boxing. Update BoundKind::DefLocal to include an `is_boxed` flag. Update VM to box captured variables when they are defined. Add tests for upvalue capture detection.
This commit is contained in:
@@ -82,6 +82,28 @@ impl VM {
|
||||
Ok(val)
|
||||
},
|
||||
|
||||
BoundKind::DefLocal { slot, value, is_boxed } => {
|
||||
let val = self.eval(value)?;
|
||||
let final_val = if *is_boxed {
|
||||
Value::Cell(Rc::new(RefCell::new(val)))
|
||||
} else {
|
||||
val
|
||||
};
|
||||
|
||||
let frame = self.frames.last().ok_or("No call frame")?;
|
||||
let abs_index = frame.stack_base + (*slot as usize);
|
||||
|
||||
// If it's the exact top of stack, push it. Otherwise, set it.
|
||||
if abs_index == self.stack.len() {
|
||||
self.stack.push(final_val.clone());
|
||||
} else if abs_index < self.stack.len() {
|
||||
self.stack[abs_index] = final_val.clone();
|
||||
} else {
|
||||
return Err(format!("Stack gap at local {}", slot));
|
||||
}
|
||||
Ok(final_val)
|
||||
},
|
||||
|
||||
BoundKind::If { cond, then_br, else_br } => {
|
||||
let c = self.eval(cond)?;
|
||||
if c.is_truthy() {
|
||||
|
||||
Reference in New Issue
Block a user