mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 捕获 cell 换键地基——绑定增 cell_idx 并解析点按绑定身份取索引
This commit is contained in:
Generated
+18
-18
@@ -1095,7 +1095,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1120,7 +1120,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1128,7 +1128,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1139,7 +1139,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1159,7 +1159,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1168,7 +1168,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1187,7 +1187,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1201,7 +1201,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1216,7 +1216,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1225,7 +1225,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1240,7 +1240,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1252,7 +1252,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1261,7 +1261,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1276,7 +1276,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1292,7 +1292,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1304,7 +1304,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"hashbrown 0.14.5",
|
||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -94,6 +94,10 @@ pub struct CompileCtx {
|
||||
/// 捕获判断(MAKE_CELL / CELL_GET / CELL_SET)与子函数 upvalue cell_idx 统一查此映射,
|
||||
/// 消除符号表时序依赖与 cell 索引错位。
|
||||
pub(crate) captured_bindings: BTreeMap<String, u8>,
|
||||
/// 下一可用 cell 索引(计数器):捕获分析后初始化为名字集大小(函数级索引
|
||||
/// 0..n-1 占满),块级遮蔽绑定预声明追加与合成 cell 经 `alloc_cell_idx`
|
||||
/// 递增取号,保证与函数级名字排序索引及历次追加互不碰撞。
|
||||
pub(crate) next_cell_idx: u8,
|
||||
/// 正在发射的 C 风格 for 头 let/const 声明名(含解构叶)。头名不像块级
|
||||
/// let/const 那样在块入口预声明,init 表达式内创建的嵌套函数引用同头尚未
|
||||
/// declare 的前向名时,父捕获可见性过滤据此放行;init 发射完毕后移除,
|
||||
@@ -248,6 +252,7 @@ impl CompileCtx {
|
||||
block_fn_suppressed: HashSet::new(),
|
||||
block_fn_entry_mats: Vec::new(),
|
||||
captured_bindings: BTreeMap::new(),
|
||||
next_cell_idx: 0,
|
||||
pending_for_head_names: HashSet::new(),
|
||||
global_tier_names: HashSet::new(),
|
||||
upvalue_const_flags: HashSet::new(),
|
||||
@@ -417,6 +422,52 @@ impl CompileCtx {
|
||||
(!self.is_implicit_global_reg(binding.reg)).then_some(binding.reg)
|
||||
}
|
||||
|
||||
/// 解析点 cell 索引与绑定寄存器:名字当前可见(真实词法绑定、非隐式全局
|
||||
/// 登记)时返回 (cell_idx, binding_reg)。索引优先取绑定自身字段(函数级
|
||||
/// 回填与块级追加的真源),绑定未分配索引时回退捕获映射(for 头覆盖 /
|
||||
/// catch 参数等容器面,后续子任务逐面收编)。块级遮蔽绑定在块退出后不可
|
||||
/// 解析,返回 None(落全局解析),不得按名误读已失效 cell。
|
||||
pub(crate) fn visible_cell(&self, name: &str) -> Option<(u8, u32)> {
|
||||
let (binding, _) = self.scopes.symbols.lookup_any_binding(name)?;
|
||||
if self.is_implicit_global_reg(binding.reg) {
|
||||
return None;
|
||||
}
|
||||
let idx = binding.cell_idx.or_else(|| self.captured_bindings.get(name).copied())?;
|
||||
Some((idx, binding.reg))
|
||||
}
|
||||
|
||||
/// 设置捕获集并同步 cell 索引计数器:映射值为 0..n-1 的名字排序索引,
|
||||
/// 计数器自 n 起保证后续追加(块级预声明 / 合成 cell)不与既有索引碰撞。
|
||||
pub(crate) fn set_captured_bindings(&mut self, map: BTreeMap<String, u8>) {
|
||||
self.next_cell_idx = map.len() as u8;
|
||||
self.captured_bindings = map;
|
||||
}
|
||||
|
||||
/// 分配一个新 cell 索引:取当前计数器值并递增。块级遮蔽绑定预声明追加与
|
||||
/// 合成 cell 共用,分配序由发射序决定,跨 run 稳定。
|
||||
#[allow(dead_code)] // 块级遮蔽绑定预声明追加(后续子任务)消费,本件仅立计数器
|
||||
pub(crate) fn alloc_cell_idx(&mut self) -> u8 {
|
||||
let idx = self.next_cell_idx;
|
||||
self.next_cell_idx = self.next_cell_idx.saturating_add(1);
|
||||
idx
|
||||
}
|
||||
|
||||
/// 给最内层同名可见绑定写入 cell 索引(委托符号表)。
|
||||
pub(crate) fn set_binding_cell_idx(&mut self, name: &str, idx: u8) {
|
||||
self.scopes.symbols.set_binding_cell_idx(name, idx);
|
||||
}
|
||||
|
||||
/// 函数级绑定 cell 索引回填:捕获集(名字排序分配)的索引写入对应绑定
|
||||
/// 实例,使解析点按绑定身份取索引。预声明完成后调用,函数级绑定(参数 /
|
||||
/// var / 直接子级词法 / 块级函数外层 var / arguments)此时已齐。
|
||||
pub(crate) fn backfill_captured_cell_idxs(&mut self) {
|
||||
let entries: Vec<(String, u8)> =
|
||||
self.captured_bindings.iter().map(|(name, &idx)| (name.clone(), idx)).collect();
|
||||
for (name, idx) in entries {
|
||||
self.set_binding_cell_idx(&name, idx);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lookup_const_flag(&self, name: &str) -> bool {
|
||||
// upvalue 捕获的 const:子 ctx 符号表不含父函数作用域绑定,查快照标志。
|
||||
self.scopes.symbols.lookup_is_const(name) || self.upvalue_const_flags.contains(name)
|
||||
@@ -810,9 +861,16 @@ impl CompileCtx {
|
||||
param_layout,
|
||||
builtin_reg_map: std::mem::take(&mut self.scopes.builtin_reg_map),
|
||||
upvalue_captures,
|
||||
// 容量按名字集大小取:别名捕获合并会让多个名字共享同一 cell,
|
||||
// 下标可重复但不超过名字数,故 len 恒覆盖实际使用的最大下标。
|
||||
cells_needed: self.captured_bindings.len() as u8,
|
||||
// 容量覆盖全部已分配 cell 索引:函数级名字排序索引(映射值 0..n-1)
|
||||
// 与追加索引(计数器,块级预声明 / 合成 cell)取较大者加一;别名
|
||||
// 捕获合并让多个名字共享同一 cell,下标可重复。
|
||||
cells_needed: self
|
||||
.captured_bindings
|
||||
.values()
|
||||
.copied()
|
||||
.max()
|
||||
.map_or(0, |m| m.saturating_add(1))
|
||||
.max(self.next_cell_idx),
|
||||
n_registers: self.max_regs,
|
||||
is_arrow: false,
|
||||
is_class_constructor: false,
|
||||
|
||||
@@ -49,7 +49,6 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
|
||||
let captured_cell = ctx.captured_bindings.get(name).copied();
|
||||
let const_flag = if ctx.lookup_const_flag(name) { 1 } else { 0 };
|
||||
if let Some(uv) = uv_idx {
|
||||
let val_reg = ctx.alloc_reg();
|
||||
@@ -68,16 +67,12 @@ impl Emitter {
|
||||
));
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
Ok(val_reg)
|
||||
} else if let Some(cell_idx) = captured_cell {
|
||||
} else if let Some((cell_idx, binding_reg)) = ctx.visible_cell(name) {
|
||||
let val_reg = ctx.alloc_reg();
|
||||
let a_operand = match ctx.scopes.symbols.lookup_any_binding(name) {
|
||||
Some((binding, _)) => Operand::Reg(binding.reg),
|
||||
None => Operand::None,
|
||||
};
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(val_reg),
|
||||
a_operand,
|
||||
Operand::Reg(binding_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(rhs), Operand::None));
|
||||
@@ -376,7 +371,6 @@ impl Emitter {
|
||||
self.emit_identifier_tdz_guard(name, ctx)?;
|
||||
// 目标判定:upvalue / 被捕获 cell / 普通槽,读与写须穿透共享单元。
|
||||
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
|
||||
let captured_cell = ctx.captured_bindings.get(name).copied();
|
||||
let result_reg = ctx.alloc_reg();
|
||||
if let Some(uv) = uv_idx {
|
||||
ctx.inst(Inst::new(
|
||||
@@ -385,15 +379,11 @@ impl Emitter {
|
||||
Operand::Imm(uv as u16),
|
||||
Operand::None,
|
||||
));
|
||||
} else if let Some(cell_idx) = captured_cell {
|
||||
let a_operand = match ctx.scopes.symbols.lookup_any_binding(name) {
|
||||
Some((binding, _)) => Operand::Reg(binding.reg),
|
||||
None => Operand::None,
|
||||
};
|
||||
} else if let Some((cell_idx, binding_reg)) = ctx.visible_cell(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(result_reg),
|
||||
a_operand,
|
||||
Operand::Reg(binding_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
} else {
|
||||
@@ -429,7 +419,7 @@ impl Emitter {
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(uv as u16),
|
||||
));
|
||||
} else if let Some(cell_idx) = captured_cell {
|
||||
} else if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
|
||||
@@ -34,18 +34,17 @@ impl Emitter {
|
||||
// 捕获集是函数级名字并集:块级 let/const 的 cell 在块退出后仍存留,但名字
|
||||
// 已不在作用域链内。仅当名字当前可解析为真实词法绑定时才走 cell(隐式全局
|
||||
// 登记不算),否则落下方全局解析(未声明读经 LOAD_GLOBAL 抛 ReferenceError),
|
||||
// 不得按名误读已失效的 cell。
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
if let Some(binding_reg) = ctx.visible_binding_reg(name) {
|
||||
let r = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(r),
|
||||
Operand::Reg(binding_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
return Ok(r);
|
||||
}
|
||||
// 不得按名误读已失效的 cell。索引按绑定实例取(`visible_cell` 已含可见性
|
||||
// 判定),同名多绑定各读各的 cell。
|
||||
if let Some((cell_idx, binding_reg)) = ctx.visible_cell(name) {
|
||||
let r = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(r),
|
||||
Operand::Reg(binding_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
let var_reg = match ctx.lookup_or_builtin(name) {
|
||||
@@ -117,29 +116,16 @@ impl Emitter {
|
||||
Operand::Imm(uv_idx as u16),
|
||||
Operand::None,
|
||||
));
|
||||
} else if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
} else if let Some((cell_idx, binding_reg)) = ctx.visible_cell(name) {
|
||||
// 回退分支的捕获 cell 同样只在名字当前可解析为真实词法绑定时才有效;
|
||||
// 否则与静态解析一致:顶层 tier 名读全局对象属性,其余读 undefined
|
||||
// (with 回退不抛未解析引用)。
|
||||
if let Some(binding_reg) = ctx.visible_binding_reg(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(result_reg),
|
||||
Operand::Reg(binding_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
} else if self.is_global_tier_name(ctx, name) {
|
||||
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_GLOBAL,
|
||||
Operand::Reg(result_reg),
|
||||
Operand::Const(key_idx),
|
||||
Operand::None,
|
||||
));
|
||||
} else {
|
||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||
ctx.inst(Inst::load_const(Operand::Reg(result_reg), undef_idx));
|
||||
}
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(result_reg),
|
||||
Operand::Reg(binding_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
} else if self.is_global_tier_name(ctx, name) {
|
||||
// 顶层已声明 var:with 对象无该属性时回退读全局对象属性(顶层 var 的唯一
|
||||
// 存储,引擎侧不保留镜像副本)。
|
||||
@@ -229,17 +215,16 @@ impl Emitter {
|
||||
// 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法绑定时才写
|
||||
// cell——捕获集按名保留的块级绑定在块退出后不可解析(隐式全局登记不算),
|
||||
// 须落下方全局写(sloppy 物化隐式全局属性,strict 抛 ReferenceError)。
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
if ctx.visible_binding_reg(name).is_some() {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
// 索引按绑定实例取(`visible_cell` 已含可见性判定),同名多绑定各写各的 cell。
|
||||
if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, val_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
let var_reg = ctx.lookup_or_global(name);
|
||||
if ctx.targets_readonly_builtin(name, var_reg) {
|
||||
|
||||
@@ -629,7 +629,6 @@ impl Emitter {
|
||||
self.emit_const_write_guard(name, ctx)?;
|
||||
}
|
||||
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
|
||||
let captured_cell = ctx.captured_bindings.get(name).copied();
|
||||
// 循环 update 段:被捕获绑定走寄存器 INC/DEC——C 风格 for 的 let/const
|
||||
// 循环变量每迭代新分配一个 cell,update 写寄存器供其拷入,不污染本迭代
|
||||
// 闭包捕获的 cell(机制见 `compile_ctx.rs` 的 `register_update_names` 字段文档)。
|
||||
@@ -731,25 +730,16 @@ impl Emitter {
|
||||
));
|
||||
self.emit_module_write_through(name, new_reg, ctx)?;
|
||||
Ok(if update.prefix { new_reg } else { old_reg })
|
||||
} else if let Some(cell_idx) = captured_cell {
|
||||
} else if let Some((cell_idx, binding_reg)) = ctx.visible_cell(name) {
|
||||
// 被捕获 cell:CELL_GET 旧值 + 常量 1 + ADD/SUB + CELL_SET。
|
||||
// 后缀形式须保留旧值(结果寄存器),前缀返回新值。
|
||||
let old_reg = ctx.alloc_reg();
|
||||
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(old_reg),
|
||||
Operand::Reg(binding.reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
} else {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(old_reg),
|
||||
Operand::None,
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
}
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_GET,
|
||||
Operand::Reg(old_reg),
|
||||
Operand::Reg(binding_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
let one_idx = ctx.add_constant(Constant::Int(1));
|
||||
let one_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(one_reg), one_idx));
|
||||
|
||||
@@ -365,6 +365,9 @@ impl Emitter {
|
||||
is_const: binding.is_const,
|
||||
lexical: binding.lexical,
|
||||
predeclared: false,
|
||||
// 父层 cell 索引在子帧无效:子帧经 upvalue 路径访问父捕获
|
||||
// 绑定,不复制索引(复制会让解析点误发子帧 cell 表读)。
|
||||
cell_idx: None,
|
||||
},
|
||||
);
|
||||
inherited_reg_start = inherited_reg_start.max(binding.reg.saturating_add(1));
|
||||
@@ -390,6 +393,7 @@ impl Emitter {
|
||||
// 类 this 自绑定非用户词法声明,不置位。
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
},
|
||||
);
|
||||
inherited_reg_start = inherited_reg_start.max(reg.saturating_add(1));
|
||||
@@ -444,6 +448,10 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
// 函数级绑定 cell 索引回填:预声明完成后函数级绑定已齐,捕获集的名字
|
||||
// 排序索引写入各绑定实例,解析点据此按绑定身份取索引。
|
||||
ctx.backfill_captured_cell_idxs();
|
||||
|
||||
// `var` 与块级函数外层 var 绑定入口实例化(非捕获名):预声明只登记槽位、
|
||||
// 不发射定义指令,声明点对已绑定名又跳过 undefined 写,缺失入口写会让首次
|
||||
// 写入前的读取取到调用方遗留的寄存器值。捕获名已由参数 prologue 的
|
||||
@@ -635,7 +643,7 @@ impl Emitter {
|
||||
// 字段初始化表达式(值表达式)与参数默认值一并纳入捕获分析。
|
||||
let mut capture_exprs: Vec<&oxide_parser::Expression> = param_defaults.clone();
|
||||
capture_exprs.extend_from_slice(extra_capture_exprs);
|
||||
ctx.captured_bindings = collect_captured_bindings(body_stmts, &capture_exprs, &ctx.own_bindings);
|
||||
ctx.set_captured_bindings(collect_captured_bindings(body_stmts, &capture_exprs, &ctx.own_bindings));
|
||||
// 自由变量分析:收集 upvalue 捕获(类方法也是普通函数,可捕获外层变量)。
|
||||
if matches!(
|
||||
body_context,
|
||||
|
||||
@@ -449,7 +449,9 @@ impl Emitter {
|
||||
|
||||
// 闭包捕获分析(import 绑定名纳入 own_bindings,供嵌套函数 cell 捕获)。
|
||||
ctx.own_bindings = collect_own_binding_names(&[], body);
|
||||
ctx.captured_bindings = collect_captured_bindings(body, &[], &ctx.own_bindings);
|
||||
ctx.set_captured_bindings(collect_captured_bindings(body, &[], &ctx.own_bindings));
|
||||
// 模块顶层函数级绑定 cell 索引回填:预声明已完成,绑定已齐。
|
||||
ctx.backfill_captured_cell_idxs();
|
||||
|
||||
// —— 模块命名空间对象 ——
|
||||
let ns_reg = self.emit_module_call(ctx, "__moduleObject", &[])?;
|
||||
|
||||
@@ -349,8 +349,10 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
ctx.global_tier_names = tier_names;
|
||||
ctx.captured_bindings = collect_captured_bindings(&program.body, &[], &ctx.own_bindings);
|
||||
ctx.set_captured_bindings(collect_captured_bindings(&program.body, &[], &ctx.own_bindings));
|
||||
ctx.captured_bindings.retain(|n, _| !ctx.global_tier_names.contains(n));
|
||||
// 顶层函数级绑定 cell 索引回填:预声明已完成,绑定已齐。
|
||||
ctx.backfill_captured_cell_idxs();
|
||||
|
||||
// 顶层 var 入口实例化:被捕获的 var 名统一 MAKE_CELL(undefined),使 var
|
||||
// 声明语句执行前创建的闭包读取到 undefined(脚本 GlobalDeclarationInstantiation
|
||||
|
||||
@@ -86,7 +86,9 @@ impl Emitter {
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
// 索引按绑定实例取(`visible_cell` 已含可见性判定):函数级绑定走回填
|
||||
// 索引,绑定未分配索引时回退捕获映射(for 头覆盖等容器面)。
|
||||
if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
let op = if fresh_cell { OpCode::MAKE_CELL_FRESH } else { OpCode::MAKE_CELL };
|
||||
ctx.inst(Inst::new(op, Operand::Reg(src_reg), Operand::Imm(cell_idx as u16), Operand::None));
|
||||
// C 风格 for 头绑定:cell 之外补写绑定寄存器——循环体/test/update 读寄存器,
|
||||
@@ -158,18 +160,17 @@ impl Emitter {
|
||||
return Ok(());
|
||||
}
|
||||
// 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法绑定时才写
|
||||
// cell,否则落下方全局解析(未声明名不建隐式全局登记)。
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
if ctx.visible_binding_reg(name).is_some() {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
// cell,否则落下方全局解析(未声明名不建隐式全局登记)。索引按绑定实例
|
||||
// 取(`visible_cell` 已含可见性判定),同名多绑定各写各的 cell。
|
||||
if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
let var_reg = ctx.lookup_or_global(name);
|
||||
if ctx.targets_readonly_builtin(name, var_reg) {
|
||||
@@ -391,18 +392,17 @@ impl Emitter {
|
||||
return Ok(());
|
||||
}
|
||||
// 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法绑定时才写
|
||||
// cell,否则落下方全局解析(未声明名不建隐式全局登记)。
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
if ctx.visible_binding_reg(name).is_some() {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
// cell,否则落下方全局解析(未声明名不建隐式全局登记)。索引按绑定实例
|
||||
// 取(`visible_cell` 已含可见性判定),同名多绑定各写各的 cell。
|
||||
if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(src_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, src_reg, ctx)?;
|
||||
return Ok(());
|
||||
}
|
||||
let var_reg = ctx.lookup_or_global(name);
|
||||
if ctx.targets_readonly_builtin(name, var_reg) {
|
||||
@@ -511,18 +511,17 @@ impl Emitter {
|
||||
continue;
|
||||
}
|
||||
// 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法绑定时才写
|
||||
// cell,否则落下方全局解析(未声明名不建隐式全局登记)。
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
if ctx.visible_binding_reg(name).is_some() {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(prop_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, prop_reg, ctx)?;
|
||||
continue;
|
||||
}
|
||||
// cell,否则落下方全局解析(未声明名不建隐式全局登记)。索引按绑定实例
|
||||
// 取(`visible_cell` 已含可见性判定),同名多绑定各写各的 cell。
|
||||
if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(prop_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
self.emit_module_write_through(name, prop_reg, ctx)?;
|
||||
continue;
|
||||
}
|
||||
let var_reg = ctx.lookup_or_global(name);
|
||||
if ctx.targets_readonly_builtin(name, var_reg) {
|
||||
|
||||
@@ -30,6 +30,10 @@ pub(crate) struct Binding {
|
||||
/// 由块/函数级预声明(TDZ 占位)创建,声明点据此复用槽位。
|
||||
/// 非预声明的同名绑定(如同 scope 的参数/var)不计,避免误复用。
|
||||
pub(crate) predeclared: bool,
|
||||
/// 该绑定实例的闭包捕获 cell 索引:`None` 表示未被捕获(无 cell)。
|
||||
/// 函数级绑定由捕获分析的名字排序分配回填;块级遮蔽绑定在预声明点
|
||||
/// 追加新索引。解析点按绑定实例取索引,同名多绑定各持各的 cell。
|
||||
pub(crate) cell_idx: Option<u8>,
|
||||
}
|
||||
|
||||
/// 作用域符号表:名字 → 寄存器号/初始化状态/const 标志。
|
||||
@@ -115,6 +119,7 @@ impl SymbolTable {
|
||||
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
|
||||
lexical: !matches!(kind, VariableDeclarationKind::Var),
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
@@ -151,6 +156,17 @@ impl SymbolTable {
|
||||
None
|
||||
}
|
||||
|
||||
/// 给最内层同名可见绑定写入 cell 索引(函数级回填与块级追加共用)。
|
||||
/// 名字未在任何作用域声明时静默跳过。
|
||||
pub(crate) fn set_binding_cell_idx(&mut self, name: &str, idx: u8) {
|
||||
for scope in self.scopes.iter_mut().rev() {
|
||||
if let Some(b) = scope.bindings.get_mut(name) {
|
||||
b.cell_idx = Some(idx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 消费当前(最内层)作用域中由预声明创建的绑定槽:存在且 `predeclared`
|
||||
/// 时返回其寄存器并清除标志(声明点复用后不再视作预声明);否则返回 None。
|
||||
/// 同 scope 的非预声明绑定(参数/var/未推 scope 的 try 内声明)不计,避免误复用。
|
||||
@@ -179,6 +195,7 @@ impl SymbolTable {
|
||||
is_const: false,
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
},
|
||||
);
|
||||
reg_for_new
|
||||
@@ -220,6 +237,7 @@ impl SymbolTable {
|
||||
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
|
||||
lexical: !matches!(kind, VariableDeclarationKind::Var),
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
@@ -233,6 +251,7 @@ impl SymbolTable {
|
||||
is_const: false,
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -258,6 +277,7 @@ impl SymbolTable {
|
||||
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
|
||||
lexical: !matches!(kind, VariableDeclarationKind::Var),
|
||||
predeclared: true,
|
||||
cell_idx: None,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
@@ -318,6 +338,7 @@ impl SymbolTable {
|
||||
// 导入绑定是模块作用域词法(const)绑定,同 let/const 置位。
|
||||
lexical: true,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
},
|
||||
);
|
||||
self.aliases.insert(local.to_string(), base);
|
||||
@@ -504,4 +525,26 @@ mod tests {
|
||||
let mut st = SymbolTable::new();
|
||||
assert!(st.add_alias("y", "missing").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_binding_cell_idx_innermost_first() {
|
||||
let mut st = SymbolTable::new();
|
||||
st.declare("x", 0, l(), false).unwrap();
|
||||
st.push_scope();
|
||||
st.declare("x", 1, l(), false).unwrap();
|
||||
st.set_binding_cell_idx("x", 3);
|
||||
let (inner, _) = st.lookup_any_binding("x").unwrap();
|
||||
assert_eq!(inner.cell_idx, Some(3));
|
||||
st.pop_scope();
|
||||
// 外层绑定不受内层写入影响:同名多绑定各持各的 cell 索引。
|
||||
let (outer, _) = st.lookup_any_binding("x").unwrap();
|
||||
assert_eq!(outer.cell_idx, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_binding_cell_idx_missing_name_noop() {
|
||||
let mut st = SymbolTable::new();
|
||||
st.set_binding_cell_idx("missing", 0);
|
||||
assert!(st.lookup_any_binding("missing").is_none());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user