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