feat: 搭建闭包捕获基础设施

This commit is contained in:
2026-06-30 19:58:58 +08:00
parent 930b14b3f0
commit c58aae4862
17 changed files with 660 additions and 12 deletions
@@ -142,6 +142,20 @@ impl Compiler {
} else {
let val_reg = self.emit_expression(&assign.right, ctx)?;
let name = id_ref.name.as_str();
// Check if target is an upvalue reference
if let Some(uv_idx) = ctx.current_upvalue_captures.iter().position(|u| u.name == name) {
ctx.emit(opcode::encode(OpCode::STORE_UPVALUE, 0, val_reg, uv_idx as u8));
return Ok(val_reg);
}
// Check if target is a captured cell
if ctx.scopes.symbols.lookup_is_captured(name) {
let cell_idx = ctx.scopes.cell_registry.iter()
.find(|(n, _)| n == name)
.map(|(_, idx)| *idx)
.unwrap_or(0);
ctx.emit(opcode::encode(OpCode::CELL_SET, 0, val_reg, cell_idx));
return Ok(val_reg);
}
let var_reg = ctx.lookup_or_global(name);
let is_const = ctx.lookup_const_flag(name);
let const_flag = if is_const { 1 } else { 0 };
@@ -56,7 +56,34 @@ impl Compiler {
pub(in crate::emitter) fn emit_identifier_expression(
&self, ident: &oxide_parser::IdentifierReference, ctx: &mut CompileCtx,
) -> Result<u8, String> {
let var_reg = ctx.lookup_or_builtin(ident.name.as_str())?;
let name = ident.name.as_str();
// Check if this is an upvalue reference (nested closure)
for (uv_idx, up) in ctx.current_upvalue_captures.iter().enumerate() {
if up.name == name {
let r = ctx.alloc_reg();
let idx = uv_idx as u8;
ctx.emit(opcode::encode(OpCode::LOAD_UPVALUE, r, idx, 0));
return Ok(r);
}
}
// Check if the owner's binding is captured (cell access)
if ctx.scopes.symbols.lookup_is_captured(name) {
let cell_idx = ctx.scopes.cell_registry.iter()
.find(|(n, _)| n == name)
.map(|(_, idx)| *idx)
.unwrap_or(0);
let r = ctx.alloc_reg();
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
ctx.emit(opcode::encode(OpCode::CELL_GET, r, binding.reg, cell_idx));
} else {
ctx.emit(opcode::encode(OpCode::CELL_GET, r, 0, cell_idx));
}
return Ok(r);
}
let var_reg = ctx.lookup_or_builtin(name)?;
let r = ctx.alloc_reg();
ctx.emit(opcode::encode(OpCode::LOAD_VAR, r, var_reg, 0));
Ok(r)