mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
feat: 捕获 cell 换键 for 头按绑定身份取索引
This commit is contained in:
@@ -68,6 +68,7 @@ impl Emitter {
|
||||
for name in &names {
|
||||
if ctx.captured_bindings.contains_key(name) || self.is_global_tier_name(ctx, name) {
|
||||
head_keep.insert(name.clone());
|
||||
ctx.for_head_keep.insert(name.clone());
|
||||
}
|
||||
}
|
||||
head_env = Some(self.begin_for_head_env(names.clone(), ctx)?);
|
||||
@@ -111,6 +112,15 @@ impl Emitter {
|
||||
}
|
||||
} else {
|
||||
ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const)?;
|
||||
// 头名回填:保留头名在 init 声明点建绑定后把覆盖 cell 索引
|
||||
// 写进绑定字段,解析点按绑定身份取索引;非保留头名走寄存器
|
||||
// 循环,不置位绑定字段(否则体区读经可见判定命中陈旧 cell,
|
||||
// update 段写寄存器不覆写 cell,循环条件恒真致死循环)。
|
||||
if head_keep.contains(bi.name.as_str()) {
|
||||
if let Some(&idx) = ctx.captured_bindings.get(bi.name.as_str()) {
|
||||
ctx.set_binding_cell_idx(bi.name.as_str(), idx);
|
||||
}
|
||||
}
|
||||
(var_reg, false)
|
||||
};
|
||||
if !already_bound {
|
||||
@@ -121,10 +131,12 @@ impl Emitter {
|
||||
Operand::None,
|
||||
));
|
||||
}
|
||||
// 词法头无初始化声明:覆盖 cell 须置为已初始化(undefined),
|
||||
// 否则后续 init 表达式内创建、捕获该头名的闭包读时误报 TDZ。
|
||||
if !matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(bi.name.as_str()) {
|
||||
// 词法头无初始化声明:保留头名的覆盖 cell 须置为已初始化
|
||||
// (undefined),否则后续 init 表达式内创建、捕获该头名的
|
||||
// 闭包读时误报 TDZ;非保留头名走寄存器循环,不建 cell。
|
||||
// 索引按绑定实例取(`visible_cell` 已含可见性判定)。
|
||||
if !matches!(decl.kind, VariableDeclarationKind::Var) && head_keep.contains(bi.name.as_str()) {
|
||||
if let Some((cell_idx, _)) = ctx.visible_cell(bi.name.as_str()) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::MAKE_CELL,
|
||||
Operand::Reg(tmp),
|
||||
@@ -149,6 +161,7 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
ctx.for_head_store_registers.clear();
|
||||
ctx.for_head_keep.clear();
|
||||
// 撤出非保留头名的覆盖:普通 for-let 回退寄存器循环,只有被闭包引用或与顶层
|
||||
// var/函数同名的头名保留独立 cell 贯穿循环。
|
||||
for name in head_names.iter().flatten() {
|
||||
@@ -157,11 +170,14 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
// 每迭代 fresh cell 的绑定:保留覆盖者(仍含 cell 下标);已撤出覆盖的头名
|
||||
// 走寄存器,不含在内。
|
||||
// 走寄存器,不含在内。门控用保留集而非可见性判定:头名字段对保留与非保留
|
||||
// 头名都置位,可见性对全部头名返 Some,按可见性门控会误纳非保留头名。
|
||||
let mut fresh_bindings: Vec<(String, u8)> = Vec::new();
|
||||
for name in &update_names {
|
||||
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
fresh_bindings.push((name.clone(), cell_idx));
|
||||
if head_keep.contains(name) {
|
||||
if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
fresh_bindings.push((name.clone(), cell_idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.labels.set_label_pos(start_label, ctx.insts.len());
|
||||
|
||||
@@ -67,7 +67,7 @@ impl Emitter {
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 逐头名:移除旧条目并记入恢复清单。
|
||||
/// 2. 按现有最大 cell 索引顺序分配 TDZ cell(与类 brand 合成 cell 同口径)。
|
||||
/// 2. 按共享计数器顺序分配 TDZ cell(与块级追加 / 合成 cell 同口径)。
|
||||
/// 3. 发射未初始化 MAKE_CELL 并覆盖映射。
|
||||
///
|
||||
/// # 副作用
|
||||
@@ -76,11 +76,9 @@ impl Emitter {
|
||||
/// 防头名泄漏进兄弟语句的捕获判定。
|
||||
pub(crate) fn begin_for_head_env(&self, names: Vec<String>, ctx: &mut CompileCtx) -> Result<ForHeadEnv, String> {
|
||||
let mut entries = Vec::with_capacity(names.len());
|
||||
let mut next = ctx.captured_bindings.values().copied().max().map_or(0, |m| m.saturating_add(1));
|
||||
for name in names {
|
||||
let saved = ctx.captured_bindings.remove(&name);
|
||||
let tdz_idx = next;
|
||||
next = next.saturating_add(1);
|
||||
let tdz_idx = ctx.alloc_cell_idx();
|
||||
ctx.captured_bindings.insert(name.clone(), tdz_idx);
|
||||
// 头名登记:声明点索引解析据此走映射回退,不就地追加新索引。
|
||||
ctx.for_head_env_names.insert(name.clone());
|
||||
@@ -96,7 +94,6 @@ impl Emitter {
|
||||
));
|
||||
entries.push((name, saved, tdz_idx, 0));
|
||||
}
|
||||
ctx.next_cell_idx = next;
|
||||
Ok(ForHeadEnv { entries })
|
||||
}
|
||||
|
||||
@@ -117,12 +114,10 @@ impl Emitter {
|
||||
if env.entries.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut next = ctx.captured_bindings.values().copied().max().map_or(0, |m| m.saturating_add(1));
|
||||
// 默认值窗口的 TDZ 占位:未初始化标志折入 MAKE_CELL 立即数高字节。
|
||||
let undef_reg = self.emit_undefined(ctx);
|
||||
for (name, _, _, body_idx) in &mut env.entries {
|
||||
let idx = next;
|
||||
next = next.saturating_add(1);
|
||||
let idx = ctx.alloc_cell_idx();
|
||||
*body_idx = idx;
|
||||
ctx.captured_bindings.insert(name.clone(), idx);
|
||||
ctx.inst(Inst::new(
|
||||
@@ -132,7 +127,6 @@ impl Emitter {
|
||||
Operand::None,
|
||||
));
|
||||
}
|
||||
ctx.next_cell_idx = next;
|
||||
}
|
||||
|
||||
/// 语句收尾恢复捕获映射:旧条目放回(无旧条目则移除),头名不进入后续
|
||||
@@ -148,6 +142,7 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
ctx.for_head_env_names.remove(&name);
|
||||
ctx.for_head_keep.remove(&name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +157,11 @@ impl Emitter {
|
||||
// 每迭代 fresh cell,体发射后恢复捕获映射。
|
||||
let mut head_env = self
|
||||
.collect_for_head_lexical_names(&fi.left)
|
||||
.map(|names| self.begin_for_head_env(names, ctx))
|
||||
.map(|names| {
|
||||
// for-in 全头名保留(无撤出覆盖),保留集填全头名供头名回填门控。
|
||||
ctx.for_head_keep.extend(names.iter().cloned());
|
||||
self.begin_for_head_env(names, ctx)
|
||||
})
|
||||
.transpose()?;
|
||||
let obj_reg = self.emit_expression(&fi.right, ctx)?;
|
||||
if let Some(env) = &mut head_env {
|
||||
@@ -201,6 +200,12 @@ impl Emitter {
|
||||
}
|
||||
} else {
|
||||
ctx.declare(name, var_reg, decl.kind, is_const)?;
|
||||
// 头名回填:体区绑定点建绑定后把覆盖 cell 索引写进绑定
|
||||
// 字段,解析点按绑定身份取索引(var 头绑定已回填,
|
||||
// 同值覆盖幂等)。
|
||||
if let Some(&idx) = ctx.captured_bindings.get(name) {
|
||||
ctx.set_binding_cell_idx(name, idx);
|
||||
}
|
||||
var_reg
|
||||
};
|
||||
if ctx.targets_readonly_builtin(name, target_reg) {
|
||||
@@ -209,7 +214,7 @@ impl Emitter {
|
||||
if ctx.is_strict {
|
||||
self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx)?;
|
||||
}
|
||||
} else if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
|
||||
} else 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,
|
||||
@@ -253,17 +258,13 @@ impl Emitter {
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Imm(uv_idx as u16),
|
||||
));
|
||||
} else 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(key_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
} else {
|
||||
self.emit_for_in_assignment_target_write(name, key_reg, ctx)?;
|
||||
}
|
||||
} else if let Some((cell_idx, _)) = ctx.visible_cell(name) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::CELL_SET,
|
||||
Operand::None,
|
||||
Operand::Reg(key_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
} else {
|
||||
self.emit_for_in_assignment_target_write(name, key_reg, ctx)?;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,11 @@ impl Emitter {
|
||||
// 每迭代 fresh cell,体发射后恢复捕获映射(同 for-in 覆盖)。
|
||||
let mut head_env = self
|
||||
.collect_for_head_lexical_names(&fo.left)
|
||||
.map(|names| self.begin_for_head_env(names, ctx))
|
||||
.map(|names| {
|
||||
// for-of 全头名保留(无撤出覆盖),保留集填全头名供头名回填门控。
|
||||
ctx.for_head_keep.extend(names.iter().cloned());
|
||||
self.begin_for_head_env(names, ctx)
|
||||
})
|
||||
.transpose()?;
|
||||
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
|
||||
if let Some(env) = &mut head_env {
|
||||
@@ -77,7 +81,11 @@ impl Emitter {
|
||||
// 词法头 TDZ 环境:同同步 for-of(右值区未初始化 cell → 体区 fresh cell)。
|
||||
let mut head_env = self
|
||||
.collect_for_head_lexical_names(&fo.left)
|
||||
.map(|names| self.begin_for_head_env(names, ctx))
|
||||
.map(|names| {
|
||||
// for-await-of 全头名保留(无撤出覆盖),保留集填全头名供头名回填门控。
|
||||
ctx.for_head_keep.extend(names.iter().cloned());
|
||||
self.begin_for_head_env(names, ctx)
|
||||
})
|
||||
.transpose()?;
|
||||
let iter_src_reg = self.emit_expression(&fo.right, ctx)?;
|
||||
if let Some(env) = &mut head_env {
|
||||
@@ -153,18 +161,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(val_reg),
|
||||
Operand::Imm(cell_idx as u16),
|
||||
));
|
||||
return Ok(());
|
||||
}
|
||||
// 目标若是被捕获 cell,走 CELL_SET;仅当名字当前可解析为真实词法
|
||||
// 绑定时才写 cell(`visible_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),
|
||||
));
|
||||
return Ok(());
|
||||
}
|
||||
let var_reg = ctx.lookup_or_global(name);
|
||||
if ctx.targets_readonly_builtin(name, var_reg) {
|
||||
|
||||
Reference in New Issue
Block a user