fix(compiler): 完善闭包捕获(cell 索引稳定、参数遮蔽、函数/类名捕获、b 槽立即数)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
|
|
||||||
use crate::emit_ctx::{LabelCtx, ScopeCtx};
|
use crate::emit_ctx::{LabelCtx, ScopeCtx};
|
||||||
use crate::ir::inst::Inst;
|
use crate::ir::inst::Inst;
|
||||||
@@ -145,9 +145,10 @@ pub(crate) struct CompileCtx {
|
|||||||
pub(crate) current_upvalue_captures: Vec<UpvalueCapture>,
|
pub(crate) current_upvalue_captures: Vec<UpvalueCapture>,
|
||||||
/// 本函数作用域声明的绑定名(参数 + 变量/函数声明,AST 收集,emit 前确定)。
|
/// 本函数作用域声明的绑定名(参数 + 变量/函数声明,AST 收集,emit 前确定)。
|
||||||
pub(crate) own_bindings: HashSet<String>,
|
pub(crate) own_bindings: HashSet<String>,
|
||||||
/// 本函数被嵌套函数捕获的绑定名(AST 分析,emit 前确定)。
|
/// 本函数被嵌套函数捕获的绑定名 → cell_idx(名字排序分配,稳定跨 run)。
|
||||||
/// 捕获判断(MAKE_CELL / CELL_GET / CELL_SET)统一查此集合,消除符号表时序依赖。
|
/// 捕获判断(MAKE_CELL / CELL_GET / CELL_SET)与子函数 upvalue cell_idx 统一查此映射,
|
||||||
pub(crate) captured_bindings: HashSet<String>,
|
/// 消除符号表时序依赖与 cell 索引错位。
|
||||||
|
pub(crate) captured_bindings: BTreeMap<String, u8>,
|
||||||
/// Set when alloc_reg() overflows into the reserved this/new.target range (≥254).
|
/// Set when alloc_reg() overflows into the reserved this/new.target range (≥254).
|
||||||
/// Checked after each emit phase to produce a compile error rather than silent corruption.
|
/// Checked after each emit phase to produce a compile error rather than silent corruption.
|
||||||
pub(crate) reg_overflow: bool,
|
pub(crate) reg_overflow: bool,
|
||||||
@@ -210,7 +211,6 @@ impl CompileCtx {
|
|||||||
builtin_reg_map: Vec::new(),
|
builtin_reg_map: Vec::new(),
|
||||||
private_name_map: Vec::new(),
|
private_name_map: Vec::new(),
|
||||||
next_private_name_id: 1,
|
next_private_name_id: 1,
|
||||||
cell_registry: Vec::new(),
|
|
||||||
},
|
},
|
||||||
nested: Vec::new(),
|
nested: Vec::new(),
|
||||||
enclosing_this_reg: 254, // conventional this register at top level
|
enclosing_this_reg: 254, // conventional this register at top level
|
||||||
@@ -221,7 +221,7 @@ impl CompileCtx {
|
|||||||
field_buffer: None,
|
field_buffer: None,
|
||||||
current_upvalue_captures: Vec::new(),
|
current_upvalue_captures: Vec::new(),
|
||||||
own_bindings: HashSet::new(),
|
own_bindings: HashSet::new(),
|
||||||
captured_bindings: HashSet::new(),
|
captured_bindings: BTreeMap::new(),
|
||||||
reg_overflow: false,
|
reg_overflow: false,
|
||||||
const_overflow: false,
|
const_overflow: false,
|
||||||
}
|
}
|
||||||
@@ -522,6 +522,17 @@ impl Compiler {
|
|||||||
|
|
||||||
// ── 闭包捕获分析(AST 级,时序无关)──
|
// ── 闭包捕获分析(AST 级,时序无关)──
|
||||||
|
|
||||||
|
/// 收集函数参数的绑定名(BindingIdentifier 形态)。
|
||||||
|
fn collect_fn_param_names(&self, params: &oxide_parser::FormalParameters) -> HashSet<String> {
|
||||||
|
let mut names = HashSet::new();
|
||||||
|
for p in ¶ms.items {
|
||||||
|
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &p.pattern {
|
||||||
|
names.insert(bi.name.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
names
|
||||||
|
}
|
||||||
|
|
||||||
/// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体)。
|
/// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体)。
|
||||||
fn collect_own_binding_names(&self, param_names: &[&str], stmts: &[Statement]) -> HashSet<String> {
|
fn collect_own_binding_names(&self, param_names: &[&str], stmts: &[Statement]) -> HashSet<String> {
|
||||||
let mut names = HashSet::new();
|
let mut names = HashSet::new();
|
||||||
@@ -621,6 +632,7 @@ impl Compiler {
|
|||||||
Statement::FunctionDeclaration(fd) => {
|
Statement::FunctionDeclaration(fd) => {
|
||||||
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||||
let mut inner = shadow.clone();
|
let mut inner = shadow.clone();
|
||||||
|
inner.extend(self.collect_fn_param_names(&fd.params));
|
||||||
inner.extend(self.collect_own_binding_names(&[], body));
|
inner.extend(self.collect_own_binding_names(&[], body));
|
||||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||||
}
|
}
|
||||||
@@ -728,11 +740,13 @@ impl Compiler {
|
|||||||
Expression::FunctionExpression(fe) => {
|
Expression::FunctionExpression(fe) => {
|
||||||
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||||
let mut inner = shadow.clone();
|
let mut inner = shadow.clone();
|
||||||
|
inner.extend(self.collect_fn_param_names(&fe.params));
|
||||||
inner.extend(self.collect_own_binding_names(&[], body));
|
inner.extend(self.collect_own_binding_names(&[], body));
|
||||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||||
}
|
}
|
||||||
Expression::ArrowFunctionExpression(ae) => {
|
Expression::ArrowFunctionExpression(ae) => {
|
||||||
let mut inner = shadow.clone();
|
let mut inner = shadow.clone();
|
||||||
|
inner.extend(self.collect_fn_param_names(&ae.params));
|
||||||
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
|
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
|
||||||
self.collect_capture_names_shadowed(&ae.body.statements, ref_set, &inner, out);
|
self.collect_capture_names_shadowed(&ae.body.statements, ref_set, &inner, out);
|
||||||
}
|
}
|
||||||
@@ -836,12 +850,19 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 分析本函数:哪些绑定被任意深度嵌套函数捕获 → captured_bindings。
|
/// 分析本函数:哪些绑定被任意深度嵌套函数捕获 → captured_bindings。
|
||||||
fn collect_captured_bindings(&self, stmts: &[Statement], own: &HashSet<String>) -> HashSet<String> {
|
fn collect_captured_bindings(&self, stmts: &[Statement], own: &HashSet<String>) -> BTreeMap<String, u8> {
|
||||||
let mut captured = HashSet::new();
|
let mut names = HashSet::new();
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
self.collect_captured_stmt(stmt, own, &mut captured);
|
self.collect_captured_stmt(stmt, own, &mut names);
|
||||||
}
|
}
|
||||||
captured
|
// 名字排序分配 cell_idx(稳定跨 run,父 MAKE_CELL 与子 upvalue 统一引用)
|
||||||
|
let mut sorted: Vec<String> = names.into_iter().collect();
|
||||||
|
sorted.sort();
|
||||||
|
sorted
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, n)| (n, i as u8))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。
|
/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。
|
||||||
@@ -939,10 +960,14 @@ impl Compiler {
|
|||||||
match expr {
|
match expr {
|
||||||
Expression::FunctionExpression(fe) => {
|
Expression::FunctionExpression(fe) => {
|
||||||
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||||
self.collect_capture_names(body, own, out);
|
let mut inner = self.collect_fn_param_names(&fe.params);
|
||||||
|
inner.extend(self.collect_own_binding_names(&[], body));
|
||||||
|
self.collect_capture_names_shadowed(body, own, &inner, out);
|
||||||
}
|
}
|
||||||
Expression::ArrowFunctionExpression(ae) => {
|
Expression::ArrowFunctionExpression(ae) => {
|
||||||
self.collect_capture_names(&ae.body.statements, own, out);
|
let mut inner = self.collect_fn_param_names(&ae.params);
|
||||||
|
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
|
||||||
|
self.collect_capture_names_shadowed(&ae.body.statements, own, &inner, out);
|
||||||
}
|
}
|
||||||
Expression::CallExpression(ce) => {
|
Expression::CallExpression(ce) => {
|
||||||
self.collect_captured_expr(&ce.callee, own, out);
|
self.collect_captured_expr(&ce.callee, own, out);
|
||||||
@@ -984,20 +1009,26 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 分析子函数 body:引用父级绑定的名字 → upvalue_captures(enclosing_reg 由父 emit 完成后填充)。
|
/// 分析子函数 body:引用父级绑定的名字 → upvalue_captures(enclosing_reg 由父 emit 完成后填充)。
|
||||||
|
/// 分析子函数 body:引用父级被捕获绑定的名字 → upvalue_captures。
|
||||||
|
/// cell_idx 直接取父 captured_bindings 映射(父 emit 前已确定,索引一致);
|
||||||
|
/// enclosing_reg 由父 emit 完成后填充(assemble_ir)。
|
||||||
fn collect_upvalue_names(
|
fn collect_upvalue_names(
|
||||||
&self, body_stmts: &[Statement], parent_own: &HashSet<String>, sub_own: &HashSet<String>,
|
&self, body_stmts: &[Statement], parent_captured: &BTreeMap<String, u8>, sub_own: &HashSet<String>,
|
||||||
) -> Vec<UpvalueCapture> {
|
) -> Vec<UpvalueCapture> {
|
||||||
|
let parent_names: HashSet<String> = parent_captured.keys().cloned().collect();
|
||||||
let mut names = HashSet::new();
|
let mut names = HashSet::new();
|
||||||
self.collect_capture_names_shadowed(body_stmts, parent_own, sub_own, &mut names);
|
self.collect_capture_names_shadowed(body_stmts, &parent_names, sub_own, &mut names);
|
||||||
let mut captures = Vec::with_capacity(names.len());
|
names
|
||||||
for (cell_idx, name) in names.iter().enumerate() {
|
.into_iter()
|
||||||
captures.push(UpvalueCapture {
|
.map(|name| {
|
||||||
name: name.clone(),
|
let cell_idx = parent_captured.get(&name).copied().unwrap_or(0);
|
||||||
enclosing_reg: 0, // assemble_ir 时从父符号表填充
|
UpvalueCapture {
|
||||||
cell_idx: cell_idx as u8,
|
name,
|
||||||
});
|
enclosing_reg: 0, // assemble_ir 时从父符号表填充
|
||||||
}
|
cell_idx,
|
||||||
captures
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1496,13 +1527,8 @@ impl Compiler {
|
|||||||
|
|
||||||
// Free variable analysis for upvalue capture (Ordinary + Arrow functions only)
|
// Free variable analysis for upvalue capture (Ordinary + Arrow functions only)
|
||||||
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
|
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
|
||||||
let captures = self.collect_upvalue_names(body_stmts, &parent_ctx.own_bindings, &ctx.own_bindings);
|
ctx.current_upvalue_captures =
|
||||||
ctx.current_upvalue_captures = captures;
|
self.collect_upvalue_names(body_stmts, &parent_ctx.captured_bindings, &ctx.own_bindings);
|
||||||
ctx.scopes.cell_registry = ctx
|
|
||||||
.current_upvalue_captures
|
|
||||||
.iter()
|
|
||||||
.map(|u| (u.name.clone(), u.cell_idx))
|
|
||||||
.collect();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.predeclare_function_declarations(body_stmts, &mut ctx);
|
self.predeclare_function_declarations(body_stmts, &mut ctx);
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ pub(crate) struct ScopeCtx {
|
|||||||
pub(crate) builtin_reg_map: Vec<(String, u8)>,
|
pub(crate) builtin_reg_map: Vec<(String, u8)>,
|
||||||
pub(crate) private_name_map: Vec<(String, u32)>,
|
pub(crate) private_name_map: Vec<(String, u32)>,
|
||||||
pub(crate) next_private_name_id: u32,
|
pub(crate) next_private_name_id: u32,
|
||||||
pub(crate) cell_registry: Vec<(String, u8)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reserved for destructuring-pattern state (Phase 15). Intentionally empty
|
/// Reserved for destructuring-pattern state (Phase 15). Intentionally empty
|
||||||
|
|||||||
@@ -146,14 +146,7 @@ impl Compiler {
|
|||||||
return Ok(val_reg);
|
return Ok(val_reg);
|
||||||
}
|
}
|
||||||
// Check if target is a captured cell
|
// Check if target is a captured cell
|
||||||
if ctx.captured_bindings.contains(name) {
|
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||||
let cell_idx = ctx
|
|
||||||
.scopes
|
|
||||||
.cell_registry
|
|
||||||
.iter()
|
|
||||||
.find(|(n, _)| n == name)
|
|
||||||
.map(|(_, idx)| *idx)
|
|
||||||
.unwrap_or(0);
|
|
||||||
ctx.inst(Inst::new(OpCode::CELL_SET, Operand::None, Operand::Reg(val_reg as u32), Operand::Imm(cell_idx as u16)));
|
ctx.inst(Inst::new(OpCode::CELL_SET, Operand::None, Operand::Reg(val_reg as u32), Operand::Imm(cell_idx as u16)));
|
||||||
return Ok(val_reg);
|
return Ok(val_reg);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,12 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.captured_bindings.contains(name) {
|
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||||
let cell_idx = ctx
|
|
||||||
.scopes
|
|
||||||
.cell_registry
|
|
||||||
.iter()
|
|
||||||
.find(|(n, _)| n == name)
|
|
||||||
.map(|(_, idx)| *idx)
|
|
||||||
.unwrap_or(0);
|
|
||||||
let r = ctx.alloc_reg();
|
let r = ctx.alloc_reg();
|
||||||
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
|
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
|
||||||
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(r as u32), Operand::Reg(binding.reg as u32), Operand::Reg(cell_idx as u32)));
|
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(r as u32), Operand::Reg(binding.reg as u32), Operand::Imm(cell_idx as u16)));
|
||||||
} else {
|
} else {
|
||||||
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(r as u32), Operand::None, Operand::Reg(cell_idx as u32)));
|
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(r as u32), Operand::None, Operand::Imm(cell_idx as u16)));
|
||||||
}
|
}
|
||||||
return Ok(r);
|
return Ok(r);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ impl Compiler {
|
|||||||
let name = id.name.as_str();
|
let name = id.name.as_str();
|
||||||
// Check if this is an upvalue or captured cell reference
|
// Check if this is an upvalue or captured cell reference
|
||||||
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
|
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
|
||||||
let is_captured = ctx.captured_bindings.contains(name);
|
let captured_cell = ctx.captured_bindings.get(name).copied();
|
||||||
if let Some(uv) = uv_idx {
|
if let Some(uv) = uv_idx {
|
||||||
// Upvalue: LOAD_UPVALUE + CONST(1) + ADD/SUB + STORE_UPVALUE
|
// Upvalue: LOAD_UPVALUE + CONST(1) + ADD/SUB + STORE_UPVALUE
|
||||||
let val_reg = ctx.alloc_reg();
|
let val_reg = ctx.alloc_reg();
|
||||||
@@ -238,15 +238,8 @@ impl Compiler {
|
|||||||
ctx.inst(Inst::new(op, Operand::Reg(val_reg as u32), Operand::Reg(val_reg as u32), Operand::Reg(one_reg as u32)));
|
ctx.inst(Inst::new(op, Operand::Reg(val_reg as u32), Operand::Reg(val_reg as u32), Operand::Reg(one_reg as u32)));
|
||||||
ctx.inst(Inst::new(OpCode::STORE_UPVALUE, Operand::None, Operand::Reg(val_reg as u32), Operand::Imm(uv as u16)));
|
ctx.inst(Inst::new(OpCode::STORE_UPVALUE, Operand::None, Operand::Reg(val_reg as u32), Operand::Imm(uv as u16)));
|
||||||
Ok(val_reg)
|
Ok(val_reg)
|
||||||
} else if is_captured {
|
} else if let Some(cell_idx) = captured_cell {
|
||||||
// Captured cell: CELL_GET + CONST(1) + ADD/SUB + CELL_SET
|
// Captured cell: CELL_GET + CONST(1) + ADD/SUB + CELL_SET
|
||||||
let cell_idx = ctx
|
|
||||||
.scopes
|
|
||||||
.cell_registry
|
|
||||||
.iter()
|
|
||||||
.find(|(n, _)| n == name)
|
|
||||||
.map(|(_, idx)| *idx)
|
|
||||||
.unwrap_or(0);
|
|
||||||
let val_reg = ctx.alloc_reg();
|
let val_reg = ctx.alloc_reg();
|
||||||
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
|
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
|
||||||
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(val_reg as u32), Operand::Reg(binding.reg as u32), Operand::Imm(cell_idx as u16)));
|
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(val_reg as u32), Operand::Reg(binding.reg as u32), Operand::Imm(cell_idx as u16)));
|
||||||
|
|||||||
@@ -88,14 +88,16 @@ pub fn lower(f: &IRFunction) -> Result<CompiledModule, String> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Operand → u8 槽位。Const/Imm/Label 不在通用槽位路径(拆字/offset 单独处理)。
|
/// Operand → u8 槽位。Const/Imm 在 a 槽走拆字(operand_pair_to_u8);
|
||||||
|
/// 出现在 b/rd 槽时按低字节直写(const_flag、cell_idx、uv_idx 等一字节立即数)。
|
||||||
fn operand_to_u8(o: &Operand) -> u8 {
|
fn operand_to_u8(o: &Operand) -> u8 {
|
||||||
match o {
|
match o {
|
||||||
Operand::Reg(r) => *r as u8,
|
Operand::Reg(r) => *r as u8,
|
||||||
Operand::This => 254,
|
Operand::This => 254,
|
||||||
Operand::NewTarget => 255,
|
Operand::NewTarget => 255,
|
||||||
Operand::None => 0,
|
Operand::Imm(v) => (v & 0xFF) as u8,
|
||||||
Operand::Const(_) | Operand::Imm(_) | Operand::Label(_) => 0,
|
Operand::Const(v) => (v & 0xFF) as u8,
|
||||||
|
Operand::Label(_) | Operand::None => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,7 @@ impl Compiler {
|
|||||||
ctx.declare(name, var_reg, kind, is_const)?;
|
ctx.declare(name, var_reg, kind, is_const)?;
|
||||||
var_reg
|
var_reg
|
||||||
};
|
};
|
||||||
if ctx.captured_bindings.contains(name) {
|
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||||
let cell_idx = ctx.scopes.cell_registry.len() as u8;
|
|
||||||
ctx.scopes.cell_registry.push((name.to_string(), cell_idx));
|
|
||||||
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(src_reg as u32), Operand::Imm(cell_idx as u16), Operand::None));
|
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(src_reg as u32), Operand::Imm(cell_idx as u16), Operand::None));
|
||||||
} else {
|
} else {
|
||||||
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg as u32), Operand::Reg(src_reg as u32), Operand::Imm(if is_const { 1 } else { 0 })));
|
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg as u32), Operand::Reg(src_reg as u32), Operand::Imm(if is_const { 1 } else { 0 })));
|
||||||
|
|||||||
@@ -20,7 +20,11 @@ impl Compiler {
|
|||||||
ctx.declare(&name, var_reg, VariableDeclarationKind::Let, false)?;
|
ctx.declare(&name, var_reg, VariableDeclarationKind::Let, false)?;
|
||||||
ctx.init_var(&name);
|
ctx.init_var(&name);
|
||||||
let ctor_reg = self.emit_class(class, ctx)?;
|
let ctor_reg = self.emit_class(class, ctx)?;
|
||||||
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg as u32), Operand::Reg(ctor_reg as u32), Operand::None));
|
if let Some(&cell_idx) = ctx.captured_bindings.get(&name) {
|
||||||
|
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(var_reg as u32), Operand::Imm(cell_idx as u16), Operand::None));
|
||||||
|
} else {
|
||||||
|
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg as u32), Operand::Reg(ctor_reg as u32), Operand::None));
|
||||||
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,11 @@ impl Compiler {
|
|||||||
let var_reg = ctx.lookup(&name)?;
|
let var_reg = ctx.lookup(&name)?;
|
||||||
ctx.reserve_reg(var_reg);
|
ctx.reserve_reg(var_reg);
|
||||||
ctx.inst(Inst::create_closure(Operand::Reg(var_reg as u32), ctx.nested.len() as u16));
|
ctx.inst(Inst::create_closure(Operand::Reg(var_reg as u32), ctx.nested.len() as u16));
|
||||||
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg as u32), Operand::Reg(var_reg as u32), Operand::None));
|
if let Some(&cell_idx) = ctx.captured_bindings.get(&name) {
|
||||||
|
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(var_reg as u32), Operand::Imm(cell_idx as u16), Operand::None));
|
||||||
|
} else {
|
||||||
|
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg as u32), Operand::Reg(var_reg as u32), Operand::None));
|
||||||
|
}
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,7 @@ impl Compiler {
|
|||||||
ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const)?;
|
ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const)?;
|
||||||
var_reg
|
var_reg
|
||||||
};
|
};
|
||||||
let is_captured = ctx.captured_bindings.contains(bi.name.as_str());
|
if let Some(&cell_idx) = ctx.captured_bindings.get(bi.name.as_str()) {
|
||||||
if is_captured {
|
|
||||||
let cell_idx = ctx.scopes.cell_registry.len() as u8;
|
|
||||||
ctx.scopes.cell_registry.push((bi.name.to_string(), cell_idx));
|
|
||||||
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(tmp as u32), Operand::Imm(cell_idx as u16), Operand::None));
|
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(tmp as u32), Operand::Imm(cell_idx as u16), Operand::None));
|
||||||
} else {
|
} else {
|
||||||
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg as u32), Operand::Reg(tmp as u32), Operand::None));
|
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg as u32), Operand::Reg(tmp as u32), Operand::None));
|
||||||
|
|||||||
@@ -120,3 +120,11 @@ fn multiple_arrows_in_same_scope() {
|
|||||||
// // const o = {x:10, f:function(){ return (() => this.x)(); }}; o.f()
|
// // const o = {x:10, f:function(){ return (() => this.x)(); }}; o.f()
|
||||||
// // Expected: 10
|
// // Expected: 10
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// -- Closure capture diagnostics --
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn closure_captures_outer_let() {
|
||||||
|
assert_eq!(eval("var f; { let x = 7; f = () => x; } f()"), "7");
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user