Files
OxideJS-New/crates/oxide_emit/src/emit_ctx.rs
T
pjh123 744899aae9 fix: for-of/for-in 提前退出时按规范顺序完成 IteratorClose
return/break/continue 逃出 for-of 时此前完全不执行 IteratorClose:
BREAK/CONTINUE/RETURN 指令现在经 ext 字携带词法逃出的迭代器层数
(for-of + for-in 各 16 位),运行时在全部 finally 穿越之后、真正
跳转/返回之前按 LIFO 关闭——与规范 §13.7.5.4(循环体完成值已含
内部 try-finally 处理,IteratorClose 在后)顺序一致。

- emit 词法:LabelCtx 增加 for-of/for-in 深度计数,loop/switch/label
  打开时快照,break/continue/return 按当前深度减目标深度计算逃出层数
  (switch 内 break 以 switch 打开点为基准,目标循环自身不计入)
- 指令编码:brk/cont/ret 三参构造,lower 跳转路径补发 ext 字
- 运行时:dispatch_break/continue/return 读取逃出计数,无 finally 时
  直接关闭后跳转/返回,有 finally 时随 Completion 悬挂由 TRY_FINALLY_END
  在穿越完成后消费;生成器 .return()/.throw() 注入经 complete_generator_return
  全关快照栈迭代器;return() 抛错经 unwind 替代完成值并关闭剩余迭代器
- 顺带:for-in 逃出残留(无 return() 语义,仅弹栈);for-await-of 的
  异步迭代器不做同步关闭(return() promise 须 await,走异步机制)
- 新增 15 项回归测试:return/labeled break/continue/switch/while/finally
  顺序/抛错优先/生成器注入/for-in/for-await-of 嵌套
2026-08-16 09:31:39 +08:00

100 lines
4.2 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! `CompileCtx` 的成组子上下文。
//!
//! 把编译器中心 `CompileCtx` 拆开,语法域 worker 只借用所需切片:
//! `LabelCtx` 负责跳转目标解析,`ScopeCtx` 负责标识符绑定。
//! `PatternCtx` 为解构工作预留。执行流字段(insts/registers/pc 等)仍
//! 平铺在 `CompileCtx` 上。
use crate::symbol_table::SymbolTable;
use crate::LabelScope;
use oxide_ir::operand::LabelId;
use oxide_parser::MethodDefinitionKind;
/// 循环语句类别:决定逃出计数是否计入 for-of / for-in 迭代器关闭。
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum LoopKind {
/// while / do-while / C 风格 for:无迭代器关闭语义。
Plain,
ForOf,
ForAwaitOf,
ForIn,
}
impl LoopKind {
/// 是否计入 for-of 逃出关闭计数。for-await-of 的逃出(labeled break /
/// continue / return)需要异步 await 迭代器 return() 的 promise,走
/// 异步挂起机制另行实现——此处只计同步 for-of,避免运行时同步调用异步
/// 迭代器的 return()。
pub(crate) fn is_for_of(self) -> bool {
matches!(self, LoopKind::ForOf)
}
pub(crate) fn is_for_in(self) -> bool {
matches!(self, LoopKind::ForIn)
}
}
/// 循环打开时的词法快照:break/continue/return 逃出时据此计算需关闭的迭代器层数。
#[derive(Debug, Clone, Copy)]
pub(crate) struct LoopEntry {
pub(crate) break_label: LabelId,
pub(crate) continue_label: LabelId,
/// 循环打开时嵌套的 finally 域数(finally 逃出计数用)。
pub(crate) finally_depth_at_open: usize,
/// 循环打开时已打开的 for-of/for-await-of 循环数。
pub(crate) for_of_depth_at_open: usize,
/// 循环打开时已打开的 for-in 循环数。
pub(crate) for_in_depth_at_open: usize,
pub(crate) kind: LoopKind,
}
/// 跳转目标 / 标签语句解析状态。
pub(crate) struct LabelCtx {
/// label id → 指令下标。id 连续递增,Vec 索引即 id;写入前须扩容。
pub(crate) label_pos: Vec<Option<usize>>,
/// 每个条目记录循环打开时的词法快照(finally/for-of/for-in 深度)。
pub(crate) loop_stack: Vec<LoopEntry>,
/// 每个条目记录 switch 打开时的词法快照(finally/for-of/for-in 深度):
/// switch 内 break 的逃出计数以打开点为准,switch 之前已打开的迭代器
/// 不属于本次逃出。
pub(crate) switch_stack: Vec<(LabelId, usize, usize, usize)>,
/// 活动标签语句作用域(解析 `break label` / `continue label`)。
pub(crate) label_scopes: Vec<LabelScope>,
/// 等待绑定到下一个循环 continue 目标的标签名。
pub(crate) pending_loop_labels: Vec<String>,
/// 当前打开(正在 emit)的 try/finally 域数。
pub(crate) finally_depth: usize,
/// 当前打开的 for-of/for-await-of 循环数(逃出计数基数)。
pub(crate) for_of_depth: usize,
/// 当前打开的 for-in 循环数(逃出计数基数)。
pub(crate) for_in_depth: usize,
pub(crate) label_counter: u32,
}
impl LabelCtx {
/// 按 id 扩容后写入 label 定义位置。
pub(crate) fn set_label_pos(&mut self, id: LabelId, pos: usize) {
if id as usize >= self.label_pos.len() {
self.label_pos.resize(id as usize + 1, None);
}
self.label_pos[id as usize] = Some(pos);
}
}
/// 标识符绑定状态:符号表、builtin 寄存器、私有名。
pub(crate) struct ScopeCtx {
pub(crate) symbols: SymbolTable,
pub(crate) builtin_reg_map: Vec<(String, u32)>,
pub(crate) private_name_map: Vec<(String, u32)>,
/// 私有元素类型(name, kind,static 标志)。kind=None 表示字段;
/// instance 字段的私有访问走 PrivateFieldFind 原型链查找,不加 brand 检查。
pub(crate) private_element_kinds: Vec<(String, Option<MethodDefinitionKind>, bool)>,
/// 当前类的私有 brand 私有名 id:私有方法/访问器访问时对实例做 brand 检查。
pub(crate) private_brand_id: Option<u32>,
pub(crate) next_private_name_id: u32,
}
/// 预留的解构 pattern 状态。当前为空;为后续解构工作预留归属地,避免改动 `ScopeCtx`。
#[allow(dead_code)]
pub(crate) struct PatternCtx;