fix: capture object keys and scope loop bindings
This commit is contained in:
@@ -589,8 +589,16 @@ impl Emitter {
|
||||
}
|
||||
Expression::ObjectExpression(o) => {
|
||||
for prop in &o.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
self.collect_capture_names_expr(&p.value, ref_set, shadow, out);
|
||||
match prop {
|
||||
oxide_parser::ObjectPropertyKind::ObjectProperty(p) => {
|
||||
if p.computed {
|
||||
self.collect_capture_names_expr(p.key.to_expression(), ref_set, shadow, out);
|
||||
}
|
||||
self.collect_capture_names_expr(&p.value, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => {
|
||||
self.collect_capture_names_expr(&spread.argument, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -884,8 +892,16 @@ impl Emitter {
|
||||
}
|
||||
Expression::ObjectExpression(o) => {
|
||||
for prop in &o.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
self.collect_captured_expr(&p.value, own, out);
|
||||
match prop {
|
||||
oxide_parser::ObjectPropertyKind::ObjectProperty(p) => {
|
||||
if p.computed {
|
||||
self.collect_captured_expr(p.key.to_expression(), own, out);
|
||||
}
|
||||
self.collect_captured_expr(&p.value, own, out);
|
||||
}
|
||||
oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => {
|
||||
self.collect_captured_expr(&spread.argument, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,11 +187,16 @@ impl Emitter {
|
||||
}
|
||||
Expression::ObjectExpression(obj) => {
|
||||
for prop in &obj.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
if p.computed {
|
||||
self.pre_scan_builtin_expr(p.key.to_expression(), ctx);
|
||||
match prop {
|
||||
oxide_parser::ObjectPropertyKind::ObjectProperty(p) => {
|
||||
if p.computed {
|
||||
self.pre_scan_builtin_expr(p.key.to_expression(), ctx);
|
||||
}
|
||||
self.pre_scan_builtin_expr(&p.value, ctx);
|
||||
}
|
||||
oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => {
|
||||
self.pre_scan_builtin_expr(&spread.argument, ctx);
|
||||
}
|
||||
self.pre_scan_builtin_expr(&p.value, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ impl Emitter {
|
||||
let Statement::ForStatement(fr) = stmt else {
|
||||
return Ok(None);
|
||||
};
|
||||
ctx.push_scope();
|
||||
let start_label = ctx.next_label_id();
|
||||
let update_label = ctx.next_label_id();
|
||||
let end_label = ctx.next_label_id();
|
||||
@@ -135,6 +136,7 @@ impl Emitter {
|
||||
ctx.labels.set_label_pos(end_label, ctx.insts.len());
|
||||
ctx.pop_label_scopes(n_labeled);
|
||||
ctx.pop_loop();
|
||||
ctx.pop_scope();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ impl Emitter {
|
||||
let Statement::ForInStatement(fi) = stmt else {
|
||||
return Ok(None);
|
||||
};
|
||||
ctx.push_scope();
|
||||
let start_label = ctx.next_label_id();
|
||||
let end_label = ctx.next_label_id();
|
||||
let obj_reg = self.emit_expression(&fi.right, ctx)?;
|
||||
@@ -40,7 +41,12 @@ impl Emitter {
|
||||
ctx.declare(name, var_reg, decl.kind, is_const)?;
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL };
|
||||
ctx.inst(Inst::new(op, Operand::Reg(key_reg), Operand::Imm(cell_idx as u16), Operand::None));
|
||||
ctx.inst(Inst::new(
|
||||
op,
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
Operand::None,
|
||||
));
|
||||
} else {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::STORE_VAR,
|
||||
@@ -68,6 +74,7 @@ impl Emitter {
|
||||
ctx.inst(Inst::new(OpCode::FOR_IN_CLEANUP, Operand::None, Operand::None, Operand::None));
|
||||
ctx.pop_label_scopes(n_labeled);
|
||||
ctx.pop_loop();
|
||||
ctx.pop_scope();
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ impl Emitter {
|
||||
}
|
||||
|
||||
fn emit_sync_for_of_statement(&self, fo: &ForOfStatement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
|
||||
ctx.push_scope();
|
||||
let start_label = ctx.next_label_id();
|
||||
let end_label = ctx.next_label_id();
|
||||
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
|
||||
@@ -42,6 +43,7 @@ impl Emitter {
|
||||
ctx.inst(Inst::new(OpCode::FOR_OF_CLOSE, Operand::None, Operand::None, Operand::None));
|
||||
ctx.pop_label_scopes(n_labeled);
|
||||
ctx.pop_loop();
|
||||
ctx.pop_scope();
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@@ -51,10 +53,16 @@ impl Emitter {
|
||||
/// 挂起(恢复值经 reg 0 交付)→ LOAD_VAR 拷贝为结果对象 → DONE 检查 done →
|
||||
/// FOR_OF_NEXT 读 value → 绑定左侧 → 循环体 → CLOSE 异步收尾。
|
||||
fn emit_for_await_of_statement(&self, fo: &ForOfStatement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
|
||||
ctx.push_scope();
|
||||
let start_label = ctx.next_label_id();
|
||||
let end_label = ctx.next_label_id();
|
||||
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
|
||||
ctx.inst(Inst::new(OpCode::FOR_AWAIT_OF_INIT, Operand::None, Operand::Reg(iter_src_reg), Operand::None));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::FOR_AWAIT_OF_INIT,
|
||||
Operand::None,
|
||||
Operand::Reg(iter_src_reg),
|
||||
Operand::None,
|
||||
));
|
||||
ctx.labels.set_label_pos(start_label, ctx.insts.len());
|
||||
ctx.push_loop(end_label, start_label);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||
@@ -80,6 +88,7 @@ impl Emitter {
|
||||
ctx.inst(Inst::new(OpCode::FOR_AWAIT_OF_CLOSE, Operand::None, Operand::None, Operand::None));
|
||||
ctx.pop_label_scopes(n_labeled);
|
||||
ctx.pop_loop();
|
||||
ctx.pop_scope();
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user