fix: try/finally 支持 break/continue/return 穿越 finally(completion 机制)

This commit is contained in:
爱特每羊队
2026-08-08 12:38:25 +08:00
parent 6c7b10d6c5
commit a814dd0700
18 changed files with 529 additions and 39 deletions
@@ -1,4 +1,8 @@
//! break/continue 语句 emit:解析标签与最近循环的跳转目标。
//!
//! 计算 break/continue 逃出的 finally 域数(目标打开时的 finally 深度与当前深度之差):
//! 逃出 ≥1 个 finally → 发 BREAK/CONTINUE(运行时穿越 finally 后再跳转);
//! 不逃出(目标在 try 域内,如 switch/循环内部的 break)→ 发普通 JMP。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
@@ -7,38 +11,51 @@ impl Emitter {
pub(crate) fn emit_break_statement(
&self, stmt: &oxide_parser::BreakStatement, ctx: &mut CompileCtx,
) -> Result<Option<u32>, String> {
let break_label = if let Some(label) = &stmt.label {
let (break_label, fd_at_open) = if let Some(label) = &stmt.label {
let name = label.name.as_str();
let scope = ctx
.find_label(name)
.ok_or_else(|| format!("SyntaxError: Undefined label '{name}'"))?;
scope.break_label
} else if let Some(sw_label) = ctx.current_switch() {
*sw_label
(scope.break_label, scope.finally_depth_at_open)
} else if let Some((sw_label, fd)) = ctx.current_switch() {
(*sw_label, *fd)
} else {
let (bl, _) = ctx.current_loop().ok_or("break outside switch or loop".to_string())?;
*bl
let (bl, _, fd) = ctx.current_loop().ok_or("break outside switch or loop".to_string())?;
(*bl, *fd)
};
ctx.inst(Inst::jmp(break_label));
let crossed = ctx.labels.finally_depth.saturating_sub(fd_at_open) as u16;
if crossed > 0 {
ctx.inst(Inst::brk(break_label, crossed));
} else {
ctx.inst(Inst::jmp(break_label));
}
Ok(None)
}
pub(crate) fn emit_continue_statement(
&self, stmt: &oxide_parser::ContinueStatement, ctx: &mut CompileCtx,
) -> Result<Option<u32>, String> {
let continue_label = if let Some(label) = &stmt.label {
let (continue_label, fd_at_open) = if let Some(label) = &stmt.label {
let name = label.name.as_str();
let scope = ctx
.find_label(name)
.ok_or_else(|| format!("SyntaxError: Undefined label '{name}'"))?;
scope.continue_label.ok_or_else(|| {
format!("SyntaxError: Illegal continue statement: '{name}' does not denote an iteration statement")
})?
(
scope.continue_label.ok_or_else(|| {
format!("SyntaxError: Illegal continue statement: '{name}' does not denote an iteration statement")
})?,
scope.finally_depth_at_open,
)
} else {
let (_, cl) = ctx.current_loop().ok_or("continue outside loop".to_string())?;
*cl
let (_, cl, fd) = ctx.current_loop().ok_or("continue outside loop".to_string())?;
(*cl, *fd)
};
ctx.inst(Inst::jmp(continue_label));
let crossed = ctx.labels.finally_depth.saturating_sub(fd_at_open) as u16;
if crossed > 0 {
ctx.inst(Inst::cont(continue_label, crossed));
} else {
ctx.inst(Inst::jmp(continue_label));
}
Ok(None)
}
}