mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
fix: break/continue 携当前语句列表累积值且循环出口值按迭代回写
This commit is contained in:
@@ -1,18 +1,39 @@
|
||||
//! break/continue 语句 emit:解析标签与最近循环的跳转目标。
|
||||
//! break/continue 语句 emit:解析标签与最近循环的跳转目标,发射前按完成值帧
|
||||
//! 栈解析携值并写入出口目标寄存器。
|
||||
//!
|
||||
//! 计算 break/continue 逃出的 finally 域数(目标打开时的 finally 深度与当前深度之差)
|
||||
//! 与逃出的迭代器层数(for-of/for-in 深度之差,目标循环自身的关闭由 CLOSE /
|
||||
//! FOR_IN_CLEANUP 处理,不计入):逃出 ≥1 个 finally 域或 ≥1 层迭代器 → 发
|
||||
//! BREAK/CONTINUE(运行时穿越 finally、关闭逃出迭代器后再跳转);否则发普通 JMP。
|
||||
|
||||
use crate::emit_ctx::CompletionCarry;
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
|
||||
impl Emitter {
|
||||
/// break/continue 的携值写入:自完成值帧栈顶解析携值,非空携值在跳转前
|
||||
/// 写入出口目标寄存器——`Value(r)` 拷寄存器、`Undefined` 物化 undefined、
|
||||
/// `Empty` 不写(目标寄存器保持既有累积值,规范
|
||||
/// `UpdateEmpty(break, iterationResult)` 等义)。
|
||||
fn emit_completion_carry(&self, ctx: &mut CompileCtx, target_v_reg: u32) {
|
||||
match ctx.resolve_completion_carry(target_v_reg) {
|
||||
CompletionCarry::Value(r) => {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(target_v_reg), Operand::Reg(r), Operand::None));
|
||||
}
|
||||
CompletionCarry::Undefined => {
|
||||
let u = self.emit_undefined(ctx);
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(target_v_reg), Operand::Reg(u), Operand::None));
|
||||
}
|
||||
CompletionCarry::Empty => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn emit_break_statement(
|
||||
&self, stmt: &oxide_parser::BreakStatement, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
let (break_label, fd_at_open, fod_at_open, fid_at_open) = if let Some(label) = &stmt.label {
|
||||
let (break_label, fd_at_open, fod_at_open, fid_at_open, target_v_reg) = if let Some(label) = &stmt.label {
|
||||
let name = label.name.as_str();
|
||||
let scope = ctx
|
||||
.find_label(name)
|
||||
@@ -22,12 +43,19 @@ impl Emitter {
|
||||
scope.finally_depth_at_open,
|
||||
scope.for_of_depth_at_open,
|
||||
scope.for_in_depth_at_open,
|
||||
scope.completion_reg,
|
||||
)
|
||||
} else if let Some((sw_label, fd, fod, fid)) = ctx.current_switch() {
|
||||
} else if let Some(sw) = ctx.current_switch() {
|
||||
// switch 内 break:目标为 switch 出口。逃出计数以 switch 打开时的
|
||||
// 深度快照为基准——switch 之前已打开的循环不属于本次逃出,仅当
|
||||
// case 内新打开了迭代循环(并逃出)时才需关闭。
|
||||
(*sw_label, *fd, *fod, *fid)
|
||||
(
|
||||
sw.break_label,
|
||||
sw.finally_depth_at_open,
|
||||
sw.for_of_depth_at_open,
|
||||
sw.for_in_depth_at_open,
|
||||
Some(sw.result_reg),
|
||||
)
|
||||
} else {
|
||||
let entry = ctx.current_loop().ok_or("break outside switch or loop".to_string())?;
|
||||
(
|
||||
@@ -35,8 +63,12 @@ impl Emitter {
|
||||
entry.finally_depth_at_open,
|
||||
entry.for_of_depth_at_open,
|
||||
entry.for_in_depth_at_open,
|
||||
Some(entry.v_reg),
|
||||
)
|
||||
};
|
||||
if let Some(target_v_reg) = target_v_reg {
|
||||
self.emit_completion_carry(ctx, target_v_reg);
|
||||
}
|
||||
let crossed = ctx.labels.finally_depth.saturating_sub(fd_at_open) as u16;
|
||||
let (for_of_count, for_in_count) = escape_iter_counts(ctx, fod_at_open, fid_at_open);
|
||||
if crossed > 0 || for_of_count > 0 || for_in_count > 0 {
|
||||
@@ -50,7 +82,7 @@ impl Emitter {
|
||||
pub(crate) fn emit_continue_statement(
|
||||
&self, stmt: &oxide_parser::ContinueStatement, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
let (continue_label, fd_at_open, fod_at_open, fid_at_open) = if let Some(label) = &stmt.label {
|
||||
let (continue_label, fd_at_open, fod_at_open, fid_at_open, target_v_reg) = if let Some(label) = &stmt.label {
|
||||
let name = label.name.as_str();
|
||||
let scope = ctx
|
||||
.find_label(name)
|
||||
@@ -62,6 +94,7 @@ impl Emitter {
|
||||
scope.finally_depth_at_open,
|
||||
scope.for_of_depth_at_open,
|
||||
scope.for_in_depth_at_open,
|
||||
scope.completion_reg,
|
||||
)
|
||||
} else {
|
||||
let entry = ctx.current_loop().ok_or("continue outside loop".to_string())?;
|
||||
@@ -70,8 +103,12 @@ impl Emitter {
|
||||
entry.finally_depth_at_open,
|
||||
entry.for_of_depth_at_open,
|
||||
entry.for_in_depth_at_open,
|
||||
Some(entry.v_reg),
|
||||
)
|
||||
};
|
||||
if let Some(target_v_reg) = target_v_reg {
|
||||
self.emit_completion_carry(ctx, target_v_reg);
|
||||
}
|
||||
let crossed = ctx.labels.finally_depth.saturating_sub(fd_at_open) as u16;
|
||||
let (for_of_count, for_in_count) = escape_iter_counts(ctx, fod_at_open, fid_at_open);
|
||||
if crossed > 0 || for_of_count > 0 || for_in_count > 0 {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
//! 标签语句 emit:`emit_labeled_statement` 登记 break/continue 标签作用域。
|
||||
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_parser::Statement;
|
||||
|
||||
impl Emitter {
|
||||
@@ -15,6 +19,42 @@ impl Emitter {
|
||||
)
|
||||
}
|
||||
|
||||
/// 标签体是否含指向本标签的 `break <name>`:递归走语句树,不下钻嵌套
|
||||
/// 函数体(嵌套函数是独立编译单元,其 break 无法指向外层标签)。
|
||||
fn body_contains_break_to_label(stmt: &Statement, name: &str) -> bool {
|
||||
match stmt {
|
||||
Statement::BreakStatement(b) => b.label.as_ref().is_some_and(|l| l.name.as_str() == name),
|
||||
Statement::BlockStatement(b) => b.body.iter().any(|s| Self::body_contains_break_to_label(s, name)),
|
||||
Statement::IfStatement(i) => {
|
||||
Self::body_contains_break_to_label(&i.consequent, name)
|
||||
|| i.alternate
|
||||
.as_ref()
|
||||
.is_some_and(|a| Self::body_contains_break_to_label(a, name))
|
||||
}
|
||||
Statement::WhileStatement(w) => Self::body_contains_break_to_label(&w.body, name),
|
||||
Statement::DoWhileStatement(d) => Self::body_contains_break_to_label(&d.body, name),
|
||||
Statement::ForStatement(f) => Self::body_contains_break_to_label(&f.body, name),
|
||||
Statement::ForInStatement(f) => Self::body_contains_break_to_label(&f.body, name),
|
||||
Statement::ForOfStatement(f) => Self::body_contains_break_to_label(&f.body, name),
|
||||
Statement::LabeledStatement(l) => Self::body_contains_break_to_label(&l.body, name),
|
||||
Statement::SwitchStatement(s) => s
|
||||
.cases
|
||||
.iter()
|
||||
.any(|c| c.consequent.iter().any(|st| Self::body_contains_break_to_label(st, name))),
|
||||
Statement::TryStatement(t) => {
|
||||
t.block.body.iter().any(|s| Self::body_contains_break_to_label(s, name))
|
||||
|| t.handler
|
||||
.as_ref()
|
||||
.is_some_and(|h| h.body.body.iter().any(|s| Self::body_contains_break_to_label(s, name)))
|
||||
|| t.finalizer
|
||||
.as_ref()
|
||||
.is_some_and(|f| f.body.iter().any(|s| Self::body_contains_break_to_label(s, name)))
|
||||
}
|
||||
Statement::WithStatement(w) => Self::body_contains_break_to_label(&w.body, name),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn emit_labeled_statement(
|
||||
&self, stmt: &oxide_parser::LabeledStatement, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
@@ -24,9 +64,27 @@ impl Emitter {
|
||||
let body_result = if Self::is_iteration_statement(&stmt.body) {
|
||||
ctx.queue_loop_label(name)?;
|
||||
self.emit_statement(&stmt.body, ctx)?
|
||||
} else if Self::body_contains_break_to_label(&stmt.body, name) {
|
||||
// 体含指向本标签的 break:出口结果寄存器在此分配并初始 undefined,
|
||||
// 体正常完成回写、break 携值就地写入(break 后死语句的寄存器不得
|
||||
// 成为完成值)。
|
||||
let v_reg = ctx.alloc_reg();
|
||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||
ctx.inst(Inst::load_const(Operand::Reg(v_reg), undef_idx));
|
||||
let id = ctx.next_label_id();
|
||||
ctx.push_label_scope(name, id, None, Some(v_reg))?;
|
||||
ctx.push_completion_target(v_reg);
|
||||
let r = self.emit_statement(&stmt.body, ctx)?;
|
||||
if let Some(r) = r {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(v_reg), Operand::Reg(r), Operand::None));
|
||||
}
|
||||
ctx.pop_completion_target();
|
||||
ctx.labels.set_label_pos(id, ctx.insts.len());
|
||||
ctx.pop_label_scope();
|
||||
Some(v_reg)
|
||||
} else {
|
||||
let id = ctx.next_label_id();
|
||||
ctx.push_label_scope(name, id, None)?;
|
||||
ctx.push_label_scope(name, id, None, None)?;
|
||||
let r = self.emit_statement(&stmt.body, ctx)?;
|
||||
ctx.labels.set_label_pos(id, ctx.insts.len());
|
||||
ctx.pop_label_scope();
|
||||
|
||||
@@ -23,12 +23,17 @@ impl Emitter {
|
||||
for s in &block.body {
|
||||
self.emit_block_fn_entry_init_stmt(s, ctx)?;
|
||||
}
|
||||
// 块语句列表独立累积:压列表帧,每条非空语句记最后非空值寄存器,
|
||||
// break/continue 携值解析据此取块内累积值。
|
||||
ctx.push_completion_list();
|
||||
let mut r = None;
|
||||
for s in &block.body {
|
||||
if let Some(rr) = self.emit_statement(s, ctx)? {
|
||||
r = Some(rr);
|
||||
ctx.set_completion_last(rr);
|
||||
}
|
||||
}
|
||||
ctx.pop_completion_list();
|
||||
ctx.block_fn_entry_mats.pop();
|
||||
ctx.pop_scope();
|
||||
Ok(r)
|
||||
|
||||
@@ -19,7 +19,11 @@ impl Emitter {
|
||||
|
||||
ctx.inst(Inst::jmp_if_false(test_reg, else_label));
|
||||
|
||||
// if 支臂是 `UpdateEmpty(_, undefined)` 站点:压边界帧,支臂内空体
|
||||
// break/continue 穿越时携值物化 undefined。
|
||||
ctx.push_completion_boundary();
|
||||
let cons_reg = self.emit_statement(&ifs.consequent, ctx)?;
|
||||
ctx.pop_completion_boundary();
|
||||
let result_reg = ctx.alloc_reg();
|
||||
if let Some(r) = cons_reg {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(r), Operand::None));
|
||||
@@ -34,7 +38,9 @@ impl Emitter {
|
||||
|
||||
ctx.labels.set_label_pos(else_label, ctx.insts.len());
|
||||
if let Some(alt) = &ifs.alternate {
|
||||
ctx.push_completion_boundary();
|
||||
let alt_reg = self.emit_statement(alt, ctx)?;
|
||||
ctx.pop_completion_boundary();
|
||||
if let Some(r) = alt_reg {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(r), Operand::None));
|
||||
} else {
|
||||
|
||||
@@ -43,11 +43,16 @@ impl Emitter {
|
||||
for s in &ts.block.body {
|
||||
self.emit_block_fn_entry_init_stmt(s, ctx)?;
|
||||
}
|
||||
// try 体语句列表自压列表帧(不经块语句 emit):非空语句记累积,
|
||||
// 体内 break/continue 携值解析据此取 try 体累积值。
|
||||
ctx.push_completion_list();
|
||||
for s in &ts.block.body {
|
||||
if let Some(r) = self.emit_statement(s, ctx)? {
|
||||
last_try_result = Some(r);
|
||||
ctx.set_completion_last(r);
|
||||
}
|
||||
}
|
||||
ctx.pop_completion_list();
|
||||
ctx.block_fn_entry_mats.pop();
|
||||
ctx.pop_scope();
|
||||
ctx.inst(Inst::new(
|
||||
@@ -85,12 +90,16 @@ impl Emitter {
|
||||
for s in &catch.body.body {
|
||||
self.emit_block_fn_entry_init_stmt(s, ctx)?;
|
||||
}
|
||||
// catch 体语句列表自压列表帧(不经块语句 emit)。
|
||||
ctx.push_completion_list();
|
||||
let mut last_catch_result: Option<u32> = None;
|
||||
for s in &catch.body.body {
|
||||
if let Some(r) = self.emit_statement(s, ctx)? {
|
||||
last_catch_result = Some(r);
|
||||
ctx.set_completion_last(r);
|
||||
}
|
||||
}
|
||||
ctx.pop_completion_list();
|
||||
ctx.block_fn_entry_mats.pop();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_VAR,
|
||||
@@ -119,9 +128,15 @@ impl Emitter {
|
||||
for s in &ts.finalizer.as_ref().unwrap().body {
|
||||
self.emit_block_fn_entry_init_stmt(s, ctx)?;
|
||||
}
|
||||
// finally 体语句列表自压列表帧:体值本身被丢弃,但体内 break/continue
|
||||
// 的携值解析须取 finally 体自身累积值(非空体穿透)。
|
||||
ctx.push_completion_list();
|
||||
for s in &ts.finalizer.as_ref().unwrap().body {
|
||||
self.emit_statement(s, ctx)?;
|
||||
if let Some(r) = self.emit_statement(s, ctx)? {
|
||||
ctx.set_completion_last(r);
|
||||
}
|
||||
}
|
||||
ctx.pop_completion_list();
|
||||
ctx.block_fn_entry_mats.pop();
|
||||
ctx.pop_scope();
|
||||
ctx.inst(Inst::new(OpCode::TRY_FINALLY_END, Operand::None, Operand::None, Operand::None));
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
//! do-while 语句 emit:`emit_do_while_statement` 先执行体后测条件。
|
||||
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_parser::Statement;
|
||||
|
||||
impl Emitter {
|
||||
@@ -14,24 +16,26 @@ impl Emitter {
|
||||
let start_label = ctx.next_label_id();
|
||||
let cont_label = ctx.next_label_id();
|
||||
let end_label = ctx.next_label_id();
|
||||
ctx.labels.set_label_pos(start_label, ctx.insts.len());
|
||||
// continue 目标是条件位置:体先执行,continue 须绕过体直接去求值条件,
|
||||
// 不能指回体首(否则条件永不被求值)。
|
||||
ctx.push_loop(end_label, cont_label, crate::emit_ctx::LoopKind::Plain);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, cont_label);
|
||||
// 不能指回体首(否则条件永不被求值)。开环先于循环头标签落位:出口
|
||||
// 结果寄存器的 undefined 初始化落在回边外(入口执行一次)。
|
||||
let v_reg = ctx.push_loop(end_label, cont_label, crate::emit_ctx::LoopKind::Plain);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, cont_label, v_reg);
|
||||
ctx.labels.set_label_pos(start_label, ctx.insts.len());
|
||||
let body_result = self.emit_statement(&dw.body, ctx)?;
|
||||
// 体正常完成回写(回写点在 `cont_label` 落位前:体内 continue 绕过本点
|
||||
// 直达条件位置,不覆写本迭代累积值)。
|
||||
if let Some(r) = body_result {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(v_reg), Operand::Reg(r), Operand::None));
|
||||
}
|
||||
ctx.labels.set_label_pos(cont_label, ctx.insts.len());
|
||||
let test_reg = self.emit_expression(&dw.test, ctx)?;
|
||||
ctx.inst(Inst::jmp_if_true(test_reg, start_label));
|
||||
ctx.labels.set_label_pos(end_label, ctx.insts.len());
|
||||
ctx.pop_label_scopes(n_labeled);
|
||||
ctx.pop_loop();
|
||||
// 循环完成值 = 循环体最后一次非空完成值(体收敛寄存器每迭代覆写);空体
|
||||
// 物化 undefined 作为带值完成返回,不沿用循环前的值。
|
||||
let result = match body_result {
|
||||
Some(r) => r,
|
||||
None => self.emit_undefined(ctx),
|
||||
};
|
||||
Ok(Some(result))
|
||||
// 循环完成值 = 出口结果寄存器:入口 undefined、体正常完成每迭代覆写、
|
||||
// break/continue 携值写入(空携值不写,保持既有累积值)。
|
||||
Ok(Some(v_reg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ impl Emitter {
|
||||
let start_label = ctx.next_label_id();
|
||||
let update_label = ctx.next_label_id();
|
||||
let end_label = ctx.next_label_id();
|
||||
ctx.push_loop(end_label, update_label, crate::emit_ctx::LoopKind::Plain);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, update_label);
|
||||
let v_reg = ctx.push_loop(end_label, update_label, crate::emit_ctx::LoopKind::Plain);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, update_label, v_reg);
|
||||
// 循环头 let/const 声明名:update 段是 per-iteration 可变绑定(规范
|
||||
// §14.7.4.4 CreatePerIterationEnvironment 用 CreateMutableBinding)——
|
||||
// 规范允许 update 段写 let/const 循环变量,每迭代新建一个可变绑定;
|
||||
@@ -182,6 +182,12 @@ impl Emitter {
|
||||
ctx.inst(Inst::jmp_if_false(test_reg, end_label));
|
||||
}
|
||||
let body_result = self.emit_statement(&fr.body, ctx)?;
|
||||
// 体正常完成回写(回写点在 `update_label` 落位前:体内 continue 目标是
|
||||
// update 段,绕过本点不覆写本迭代累积值;update 段写循环变量寄存器,
|
||||
// 独立于本寄存器)。
|
||||
if let Some(r) = body_result {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(v_reg), Operand::Reg(r), Operand::None));
|
||||
}
|
||||
ctx.labels.set_label_pos(update_label, ctx.insts.len());
|
||||
if let Some(update) = &fr.update {
|
||||
// update 段写循环变量寄存器、不写 cell:被捕获的 let/const 循环变量每迭代
|
||||
@@ -203,12 +209,8 @@ impl Emitter {
|
||||
ctx.pop_label_scopes(n_labeled);
|
||||
ctx.pop_loop();
|
||||
ctx.pop_scope();
|
||||
// 循环完成值 = 循环体最后一次非空完成值;空体物化 undefined 作为带值完成
|
||||
// 返回,不沿用循环前的值。
|
||||
let result = match body_result {
|
||||
Some(r) => r,
|
||||
None => self.emit_undefined(ctx),
|
||||
};
|
||||
Ok(Some(result))
|
||||
// 循环完成值 = 出口结果寄存器:入口 undefined、体正常完成每迭代覆写、
|
||||
// break/continue 携值写入(空携值不写,保持既有累积值)。
|
||||
Ok(Some(v_reg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +164,8 @@ impl Emitter {
|
||||
}
|
||||
ctx.inst(Inst::new(OpCode::FOR_IN_INIT, Operand::None, Operand::Reg(obj_reg), Operand::None));
|
||||
ctx.labels.set_label_pos(start_label, ctx.insts.len());
|
||||
ctx.push_loop(end_label, start_label, crate::emit_ctx::LoopKind::ForIn);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||
let _v_reg = ctx.push_loop(end_label, start_label, crate::emit_ctx::LoopKind::ForIn);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label, _v_reg);
|
||||
let done_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::FOR_IN_DONE, Operand::Reg(done_reg), Operand::None, Operand::None));
|
||||
// done=true 表示迭代结束:done=false 时跳过 end jmp 继续迭代
|
||||
|
||||
@@ -38,8 +38,8 @@ impl Emitter {
|
||||
}
|
||||
ctx.inst(Inst::new(OpCode::FOR_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, crate::emit_ctx::LoopKind::ForOf);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||
let _v_reg = ctx.push_loop(end_label, start_label, crate::emit_ctx::LoopKind::ForOf);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label, _v_reg);
|
||||
let has_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::FOR_OF_DONE, Operand::Reg(has_reg), Operand::None, Operand::None));
|
||||
ctx.inst(Inst::jmp_if_false(has_reg, end_label));
|
||||
@@ -90,8 +90,8 @@ impl Emitter {
|
||||
Operand::None,
|
||||
));
|
||||
ctx.labels.set_label_pos(start_label, ctx.insts.len());
|
||||
ctx.push_loop(end_label, start_label, crate::emit_ctx::LoopKind::ForAwaitOf);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||
let _v_reg = ctx.push_loop(end_label, start_label, crate::emit_ctx::LoopKind::ForAwaitOf);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label, _v_reg);
|
||||
let next_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::FOR_AWAIT_OF_NEXT, Operand::Reg(next_reg), Operand::None, Operand::None));
|
||||
ctx.inst(Inst::await_expr(Operand::Reg(next_reg)));
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
//! while 语句 emit:`emit_while_statement` 先测条件后执行体。
|
||||
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_parser::Statement;
|
||||
|
||||
impl Emitter {
|
||||
@@ -11,23 +13,25 @@ impl Emitter {
|
||||
};
|
||||
let start_label = ctx.next_label_id();
|
||||
let end_label = ctx.next_label_id();
|
||||
// 开环先于循环头标签落位:出口结果寄存器的 undefined 初始化须落在回边
|
||||
// 外(入口执行一次),否则每迭代重置、末迭代出口读 undefined。
|
||||
let v_reg = ctx.push_loop(end_label, start_label, crate::emit_ctx::LoopKind::Plain);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label, v_reg);
|
||||
ctx.labels.set_label_pos(start_label, ctx.insts.len());
|
||||
ctx.push_loop(end_label, start_label, crate::emit_ctx::LoopKind::Plain);
|
||||
let n_labeled = ctx.take_pending_loop_labels(end_label, start_label);
|
||||
let test_reg = self.emit_expression(&wh.test, ctx)?;
|
||||
ctx.inst(Inst::jmp_if_false(test_reg, end_label));
|
||||
let body_result = self.emit_statement(&wh.body, ctx)?;
|
||||
// 体正常完成回写(回写点在 `jmp start` 前:体内 continue 绕过本点直达
|
||||
// 循环头,不覆写本迭代累积值)。
|
||||
if let Some(r) = body_result {
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(v_reg), Operand::Reg(r), Operand::None));
|
||||
}
|
||||
ctx.inst(Inst::jmp(start_label));
|
||||
ctx.labels.set_label_pos(end_label, ctx.insts.len());
|
||||
ctx.pop_label_scopes(n_labeled);
|
||||
ctx.pop_loop();
|
||||
// 循环完成值 = 循环体最后一次非空完成值:体收敛寄存器每迭代覆写、退出时
|
||||
// 持最近值;空体无寄存器可沿用,物化 undefined 作为带值完成返回,不沿用
|
||||
// 循环前的值。
|
||||
let result = match body_result {
|
||||
Some(r) => r,
|
||||
None => self.emit_undefined(ctx),
|
||||
};
|
||||
Ok(Some(result))
|
||||
// 循环完成值 = 出口结果寄存器:入口 undefined、体正常完成每迭代覆写、
|
||||
// break/continue 携值写入(空携值不写,保持既有累积值)。
|
||||
Ok(Some(v_reg))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,15 @@ impl Emitter {
|
||||
return Ok(None);
|
||||
};
|
||||
let end_label = ctx.next_label_id();
|
||||
ctx.push_switch(end_label);
|
||||
// CaseBlock 出口结果寄存器:入口初始 undefined(覆盖无命中/空块路径),
|
||||
// 每条子句的非空语句完成值逐语句覆写(与规范逐子句 `UpdateEmpty`
|
||||
// 累积终态等价:空子句不覆写前值);abrupt 出口不覆写,保留前子句
|
||||
// 累积值。
|
||||
let result_reg = ctx.alloc_reg();
|
||||
let undef = self.emit_undefined(ctx);
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(undef), Operand::None));
|
||||
ctx.push_switch(end_label, result_reg);
|
||||
ctx.push_completion_target(result_reg);
|
||||
// 判别式在 switch 外层词法环境求值,CaseBlock 环境尚未建立。
|
||||
let disc_reg = self.emit_expression(&sw.discriminant, ctx)?;
|
||||
let cases = &sw.cases;
|
||||
@@ -60,28 +68,26 @@ impl Emitter {
|
||||
Some(label) => ctx.inst(Inst::jmp(label)),
|
||||
None => ctx.inst(Inst::jmp(end_label)),
|
||||
}
|
||||
let mut last: Option<u32> = None;
|
||||
for (case_idx, case) in cases.iter().enumerate() {
|
||||
let case_label = case_labels[case_idx];
|
||||
ctx.labels.set_label_pos(case_label, ctx.insts.len());
|
||||
// 子句体不经 `emit_block_statement`,其语句列表须自压列表帧:
|
||||
// 非空语句记累积并逐语句覆写出口寄存器(运行期 resultValue)。
|
||||
ctx.push_completion_list();
|
||||
for s in &case.consequent {
|
||||
if let Some(r) = self.emit_statement(s, ctx)? {
|
||||
last = Some(r);
|
||||
ctx.set_completion_last(r);
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(r), Operand::None));
|
||||
}
|
||||
}
|
||||
ctx.pop_completion_list();
|
||||
}
|
||||
ctx.block_fn_entry_mats.pop();
|
||||
ctx.labels.set_label_pos(end_label, ctx.insts.len());
|
||||
ctx.pop_scope();
|
||||
ctx.pop_completion_target();
|
||||
ctx.pop_switch();
|
||||
// switch 完成值 = 已执行 case 链最后一次非空完成值(源序最后非空语句的
|
||||
// 收敛寄存器:命中后穿落到 break/尾即为其值,无命中则该寄存器不被写入而
|
||||
// 持 undefined);无命中物化 undefined 作为带值完成返回。
|
||||
let result = match last {
|
||||
Some(r) => r,
|
||||
None => self.emit_undefined(ctx),
|
||||
};
|
||||
Ok(Some(result))
|
||||
Ok(Some(result_reg))
|
||||
}
|
||||
|
||||
pub(crate) fn emit_switch_domain(&self, stmt: &Statement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
|
||||
|
||||
@@ -20,7 +20,11 @@ impl Emitter {
|
||||
let obj_reg = self.emit_expression(&with.object, ctx)?;
|
||||
ctx.inst(Inst::new(OpCode::TO_OBJECT, Operand::Reg(obj_reg), Operand::None, Operand::None));
|
||||
ctx.push_with(obj_reg);
|
||||
// with 体是 `UpdateEmpty(_, undefined)` 站点:压边界帧,体内空体
|
||||
// break/continue 穿越时携值物化 undefined。
|
||||
ctx.push_completion_boundary();
|
||||
let body_result = self.emit_statement(&with.body, ctx)?;
|
||||
ctx.pop_completion_boundary();
|
||||
ctx.pop_with();
|
||||
// with 完成值 = 体完成值;体为空(空完成)时按规范物化 undefined 作为带值
|
||||
// 完成返回,不沿用 with 前的值。
|
||||
|
||||
Reference in New Issue
Block a user