refactor: emit 冗余标志参数收敛为内部推导

This commit is contained in:
2026-10-12 16:30:51 +00:00
parent 2d5cba7e98
commit 3d7e8edd75
22 changed files with 151 additions and 187 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ impl Emitter {
None => {
let reg = ctx.alloc_reg();
ctx.push_scope_with_kind(ScopeKind::BlockScope);
ctx.declare(name, reg, VariableDeclarationKind::Const, true)?;
ctx.declare(name, reg, VariableDeclarationKind::Const)?;
pushed_scope = true;
reg
}
+1 -1
View File
@@ -35,7 +35,7 @@ impl Emitter {
let key_reg = if prop.computed {
self.emit_class_array_key_reg(key_slot.unwrap_or(0), ctx)?
} else {
self.emit_class_key_reg(&prop.key, false, ctx)?
self.emit_class_key_reg(&prop.key, ctx)?
};
let value_reg = self.emit_field_value(prop.value.as_ref(), ctx)?;
ctx.inst(Inst::define_prop(
+1 -1
View File
@@ -39,7 +39,7 @@ impl Emitter {
let key_reg = if method.computed {
self.emit_class_array_key_reg(key_slot.unwrap_or(0), ctx)?
} else {
self.emit_class_key_reg(&method.key, false, ctx)?
self.emit_class_key_reg(&method.key, ctx)?
};
let method_name = if method.computed {
"<computed>".to_string()
+6 -8
View File
@@ -397,22 +397,20 @@ impl CompileCtx {
self.scopes.symbols.pop_scope();
}
pub(crate) fn declare(
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind, is_const: bool,
) -> Result<(), String> {
self.scopes.symbols.declare(name, reg, kind, is_const)
pub(crate) fn declare(&mut self, name: &str, reg: u32, kind: VariableDeclarationKind) -> Result<(), String> {
self.scopes.symbols.declare(name, reg, kind)
}
pub(crate) fn declare_initialized(
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind, is_const: bool,
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind,
) -> Result<(), String> {
self.scopes.symbols.declare_initialized(name, reg, kind, is_const)
self.scopes.symbols.declare_initialized(name, reg, kind)
}
pub(crate) fn declare_predeclared(
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind, is_const: bool,
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind,
) -> Result<(), String> {
self.scopes.symbols.declare_predeclared(name, reg, kind, is_const)
self.scopes.symbols.declare_predeclared(name, reg, kind)
}
pub(crate) fn push_scope_with_kind(&mut self, kind: ScopeKind) {
+2 -6
View File
@@ -725,14 +725,10 @@ impl Emitter {
}
}
if with_dynamic {
let is_const = ctx.lookup_const_flag(name);
let const_flag: u16 = if is_const { 1 } else { 0 };
self.emit_with_dynamic_write(name, val_reg, const_flag, ctx)?;
self.emit_with_dynamic_write(name, val_reg, ctx)?;
return Ok(val_reg);
}
let is_const = ctx.lookup_const_flag(name);
let const_flag: u16 = if is_const { 1 } else { 0 };
self.emit_identifier_store(name, val_reg, const_flag, ctx)?;
self.emit_identifier_store(name, val_reg, ctx)?;
Ok(val_reg)
}
} else if matches!(
+7 -9
View File
@@ -174,17 +174,17 @@ impl Emitter {
/// 静态标识符写入:upvalue / 被捕获 cell / 普通槽(含 const guard)。
///
/// # 边界与前提
/// - `const_flag` 为 1 时编译期直接抛 TypeError(值无关),覆盖普通/upvalue/cell 全写路径;
/// 不发射写指令(THROW 后不可达)。
/// - const 绑定(符号表与 upvalue 快照派生)编译期直接抛 TypeError(值无关),
/// 覆盖普通/upvalue/cell 全写路径;不发射写指令(THROW 后不可达)。
/// - cell 写穿共享单元,无运行时 guard;const 拦截由本入口编译期完成。
/// - 不可写全局内置(undefined/NaN/Infinity)的全局绑定写在此拦截:sloppy 跳过
/// 寄存器写(槽保留入口预载原值),strict 抛 TypeError;局部遮蔽绑定不受影响。
///
/// # 副作用
/// - live 模块顶层对导出源绑定的写入追加 `__moduleSet`,同步命名空间条目。
pub(crate) fn emit_identifier_store(
&self, name: &str, val_reg: u32, const_flag: u16, ctx: &mut CompileCtx,
) -> Result<(), String> {
pub(crate) fn emit_identifier_store(&self, name: &str, val_reg: u32, ctx: &mut CompileCtx) -> Result<(), String> {
// const 标志从符号表与 upvalue 快照派生:赋值路径对 const 再赋值统一编译期拦截。
let const_flag: u16 = if ctx.lookup_const_flag(name) { 1 } else { 0 };
// 循环 update 段的 let/const 循环变量是 per-iteration 可变绑定(CreateMutableBinding),
// 写寄存器而非 cell,且豁免 const 检查(register_update_names 覆盖全部循环头声明名)。
let in_loop_update = ctx.register_update_names.iter().any(|n| n == name);
@@ -294,9 +294,7 @@ impl Emitter {
/// - 对象属性存在性判定与动态读取一致(`in` 含原型链)。
/// - 回退目标未在静态作用域声明时落隐式全局(sloppy 物化全局属性,
/// strict 抛 ReferenceError),与静态写路径同形。
pub(crate) fn emit_with_dynamic_write(
&self, name: &str, val_reg: u32, const_flag: u16, ctx: &mut CompileCtx,
) -> Result<(), String> {
pub(crate) fn emit_with_dynamic_write(&self, name: &str, val_reg: u32, ctx: &mut CompileCtx) -> Result<(), String> {
let obj_reg = ctx.innermost_with_obj().expect("with stack non-empty");
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
let key_reg = ctx.alloc_reg();
@@ -320,7 +318,7 @@ impl Emitter {
ctx.labels.set_label_pos(fallback_label, ctx.insts.len());
// 回退写静态作用域:已声明绑定走常规写路径;未声明名是隐式全局
// (sloppy 物化全局属性、strict 抛 ReferenceError),与静态写路径同形。
self.emit_identifier_store(name, val_reg, const_flag, ctx)?;
self.emit_identifier_store(name, val_reg, ctx)?;
ctx.labels.set_label_pos(end_label, ctx.insts.len());
Ok(())
}
+3 -3
View File
@@ -582,7 +582,7 @@ impl Emitter {
for spec in param_specs {
let name = spec.register_name();
let reg = ctx.alloc_reg();
ctx.declare_initialized(name, reg, VariableDeclarationKind::Var, false)?;
ctx.declare_initialized(name, reg, VariableDeclarationKind::Var)?;
}
// 闭包捕获分析(AST 级,emit 前确定):须在参数默认值 emit 之前,
@@ -624,7 +624,7 @@ impl Emitter {
&& self.arguments_obj_needed(body_stmts, &ctx.param_names, !param_defaults.is_empty())
{
let reg = ctx.alloc_reg();
ctx.declare_initialized("arguments", reg, VariableDeclarationKind::Var, false)?;
ctx.declare_initialized("arguments", reg, VariableDeclarationKind::Var)?;
ctx.own_bindings.insert("arguments".to_string());
arguments_reg = Some(reg);
}
@@ -868,7 +868,7 @@ impl Emitter {
} else {
src_reg
};
self.emit_binding_pattern(pattern, src_reg, VariableDeclarationKind::Var, false, false, ctx)?;
self.emit_binding_pattern(pattern, src_reg, VariableDeclarationKind::Var, false, ctx)?;
}
ParamSpec::Identifier { name, initializer } => {
if let Some(init) = initializer {
+32 -42
View File
@@ -695,7 +695,6 @@ impl Emitter {
s.local.name.as_str(),
val_reg,
VariableDeclarationKind::Const,
true,
false,
ctx,
)?;
@@ -727,7 +726,7 @@ impl Emitter {
&& ctx.scopes.symbols.lookup_any(&source).is_none()
{
let reg = ctx.alloc_reg();
ctx.declare_predeclared(&source, reg, VariableDeclarationKind::Let, false)?;
ctx.declare_predeclared(&source, reg, VariableDeclarationKind::Let)?;
// 表达式形态 TDZ 保持;函数声明形态由提升臂在求值
// 前初始化,此处不做初始化。
}
@@ -750,7 +749,6 @@ impl Emitter {
s.local.name.as_str(),
val_reg,
VariableDeclarationKind::Const,
true,
false,
ctx,
)?;
@@ -787,7 +785,6 @@ impl Emitter {
s.local.name.as_str(),
bind_reg,
VariableDeclarationKind::Const,
true,
false,
ctx,
)?;
@@ -1099,11 +1096,15 @@ impl Emitter {
let undef_idx = ctx.add_constant(Constant::Undefined);
let undef_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(undef_reg), undef_idx));
self.emit_bind_target(local, undef_reg, VariableDeclarationKind::Const, true, false, ctx)?;
self.emit_bind_target(local, undef_reg, VariableDeclarationKind::Const, false, ctx)?;
ctx.lookup(local)
}
fn emit_module_set(&self, ctx: &mut CompileCtx, ns_reg: u32, name: &str, value_reg: u32) -> Result<(), String> {
fn emit_module_set(&self, ctx: &mut CompileCtx, name: &str, value_reg: u32) -> Result<(), String> {
// 非模块上下文无命名空间对象,静默返回(防御守卫)。
let Some(ns_reg) = ctx.module_ns_reg else {
return Ok(());
};
let name_reg = self.load_string_const(name, ctx);
self.emit_module_call(ctx, "__moduleSet", &[ns_reg, name_reg, value_reg])?;
Ok(())
@@ -1118,9 +1119,11 @@ impl Emitter {
/// # 副作用
/// - 依赖运行期 `module_frame_cell(cell_idx)` 取当前字节码帧 cell,改命名空间
/// 条目状态为共享 cell。
fn emit_module_set_cell(
&self, ctx: &mut CompileCtx, ns_reg: u32, export_name: &str, cell_idx: u8,
) -> Result<(), String> {
fn emit_module_set_cell(&self, ctx: &mut CompileCtx, export_name: &str, cell_idx: u8) -> Result<(), String> {
// 非模块上下文无命名空间对象,静默返回(防御守卫)。
let Some(ns_reg) = ctx.module_ns_reg else {
return Ok(());
};
let name_reg = self.load_string_const(export_name, ctx);
let idx = ctx.add_constant(Constant::Int(cell_idx as i32));
let cell_reg = ctx.alloc_reg();
@@ -1143,23 +1146,27 @@ impl Emitter {
/// # 副作用
/// - 命中时发 `__moduleSetCell`(条目状态改 Cell);否则发 `__moduleSet`。
fn emit_export_registration(
&self, ctx: &mut CompileCtx, ns_reg: u32, exported_name: &str, source_name: &str, value_reg: u32,
&self, ctx: &mut CompileCtx, exported_name: &str, source_name: &str, value_reg: u32,
) -> Result<(), String> {
if ctx.module_live_ns_active
&& !ctx.module_live_imports.contains_key(source_name)
&& ctx.visible_binding_reg(source_name).is_some()
{
if let Some(&cell_idx) = ctx.captured_bindings.get(source_name) {
return self.emit_module_set_cell(ctx, ns_reg, exported_name, cell_idx);
return self.emit_module_set_cell(ctx, exported_name, cell_idx);
}
}
self.emit_module_set(ctx, ns_reg, exported_name, value_reg)
self.emit_module_set(ctx, exported_name, value_reg)
}
/// 发 `__moduleSetReexport`:注册带 `(dep_path, imported)` 来源身份的再导出。
fn emit_module_set_reexport(
&self, ctx: &mut CompileCtx, ns_reg: u32, export_name: &str, value_reg: u32, dep_path: &str, imported: &str,
&self, ctx: &mut CompileCtx, export_name: &str, value_reg: u32, dep_path: &str, imported: &str,
) -> Result<(), String> {
// 非模块上下文无命名空间对象,静默返回(防御守卫)。
let Some(ns_reg) = ctx.module_ns_reg else {
return Ok(());
};
let name_reg = self.load_string_const(export_name, ctx);
let path_reg = self.load_string_const(dep_path, ctx);
let imported_reg = self.load_string_const(imported, ctx);
@@ -1181,9 +1188,9 @@ impl Emitter {
pub(crate) fn emit_module_write_through(
&self, name: &str, value_reg: u32, ctx: &mut CompileCtx,
) -> Result<(), String> {
let Some(ns_reg) = ctx.module_ns_reg else {
if ctx.module_ns_reg.is_none() {
return Ok(());
};
}
let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) else {
return Ok(());
};
@@ -1191,7 +1198,7 @@ impl Emitter {
return Ok(());
};
for export_name in export_names {
self.emit_module_set(ctx, ns_reg, &export_name, value_reg)?;
self.emit_module_set(ctx, &export_name, value_reg)?;
}
Ok(())
}
@@ -1272,7 +1279,7 @@ impl Emitter {
if let BindingPattern::BindingIdentifier(bi) = &d.id {
let name = bi.name.as_str();
let val_reg = self.load_var_reg(name, ctx)?;
self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?;
self.emit_export_registration(ctx, name, name, val_reg)?;
self.emit_self_alias_write(ctx, name, val_reg);
}
}
@@ -1282,7 +1289,7 @@ impl Emitter {
if let Some(id) = &fd.id {
let name = id.name.as_str();
let val_reg = self.load_var_reg(name, ctx)?;
self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?;
self.emit_export_registration(ctx, name, name, val_reg)?;
self.emit_self_alias_write(ctx, name, val_reg);
}
}
@@ -1291,7 +1298,7 @@ impl Emitter {
if let Some(id) = &cl.id {
let name = id.name.as_str();
let val_reg = self.load_var_reg(name, ctx)?;
self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?;
self.emit_export_registration(ctx, name, name, val_reg)?;
self.emit_self_alias_write(ctx, name, val_reg);
}
}
@@ -1316,14 +1323,7 @@ impl Emitter {
.ok_or_else(|| format!("export from unknown module: {source}"))?;
let name_reg = self.load_string_const(&local_name, ctx);
let val_reg = self.emit_module_call(ctx, "__moduleLinkGet", &[dep_ns_reg, name_reg])?;
self.emit_module_set_reexport(
ctx,
ns_reg,
&exported_name,
val_reg,
&dep_path,
&local_name,
)?;
self.emit_module_set_reexport(ctx, &exported_name, val_reg, &dep_path, &local_name)?;
// 自导入名可能来自 star 转发(占位路径):导出语句执行时
// 就地刷新本地槽,覆盖同模块 body 内导出后读取的形态。
self.emit_self_alias_write(ctx, &exported_name, val_reg);
@@ -1333,14 +1333,14 @@ impl Emitter {
// (依赖模块路径, 导入名);命名空间导入的导入名为共享哨兵。
if let Some((dep_path, imported)) = ctx.module_import_origins.get(&local_name).cloned() {
let val_reg = self.load_var_reg(&local_name, ctx)?;
self.emit_module_set_reexport(ctx, ns_reg, &exported_name, val_reg, &dep_path, &imported)?;
self.emit_module_set_reexport(ctx, &exported_name, val_reg, &dep_path, &imported)?;
// 自导入名重分类为间接导出时同样就地刷新占位槽。
self.emit_self_alias_write(ctx, &exported_name, val_reg);
continue;
}
// 本地导出:来源恒为 Local。
let val_reg = self.load_var_reg(&local_name, ctx)?;
self.emit_export_registration(ctx, ns_reg, &exported_name, &local_name, val_reg)?;
self.emit_export_registration(ctx, &exported_name, &local_name, val_reg)?;
}
}
}
@@ -1359,7 +1359,7 @@ impl Emitter {
.map(|_| SYNTHETIC_DEFAULT_BINDING.to_string())
});
if let Some(name) = &binding {
self.emit_bind_target(name, reg, VariableDeclarationKind::Var, false, false, ctx)?;
self.emit_bind_target(name, reg, VariableDeclarationKind::Var, false, ctx)?;
}
if fd.id.is_none() {
set_implicit_name_of_last_nested(ctx, DEFAULT_EXPORT_NAME);
@@ -1375,14 +1375,7 @@ impl Emitter {
cl.id.is_none().then_some(DEFAULT_EXPORT_NAME),
)?;
if let Some(id) = &cl.id {
self.emit_bind_target(
id.name.as_str(),
reg,
VariableDeclarationKind::Const,
true,
false,
ctx,
)?;
self.emit_bind_target(id.name.as_str(), reg, VariableDeclarationKind::Const, false, ctx)?;
(reg, id.name.to_string())
} else {
if ctx.scopes.symbols.lookup_any(SYNTHETIC_DEFAULT_BINDING).is_some() {
@@ -1393,7 +1386,6 @@ impl Emitter {
reg,
VariableDeclarationKind::Let,
false,
false,
ctx,
)?;
}
@@ -1430,14 +1422,13 @@ impl Emitter {
reg,
VariableDeclarationKind::Let,
false,
false,
ctx,
)?;
}
(reg, SYNTHETIC_DEFAULT_BINDING.to_string())
}
};
self.emit_export_registration(ctx, ns_reg, DEFAULT_EXPORT_NAME, &source_name, val_reg)?;
self.emit_export_registration(ctx, DEFAULT_EXPORT_NAME, &source_name, val_reg)?;
self.emit_self_alias_write(ctx, DEFAULT_EXPORT_NAME, val_reg);
}
Statement::ExportAllDeclaration(exp) => {
@@ -1456,7 +1447,6 @@ impl Emitter {
let exported_name = module_export_name_str(exported);
self.emit_module_set_reexport(
ctx,
ns_reg,
&exported_name,
dep_ns_reg,
&dep_path,
+8 -13
View File
@@ -30,7 +30,7 @@ impl Emitter {
None => "*default*".to_string(),
};
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(name.as_str(), reg, VariableDeclarationKind::Var, false);
let _ = ctx.declare_initialized(name.as_str(), reg, VariableDeclarationKind::Var);
}
}
@@ -52,7 +52,7 @@ impl Emitter {
continue;
};
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Var, false);
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Var);
}
}
@@ -66,7 +66,7 @@ impl Emitter {
let _ = ctx.lookup_or_builtin(name);
} else {
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(name, reg, VariableDeclarationKind::Var, false);
let _ = ctx.declare_initialized(name, reg, VariableDeclarationKind::Var);
}
}
@@ -233,7 +233,7 @@ impl Emitter {
continue;
}
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Let, false);
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Let);
}
Statement::BlockStatement(bs) => {
ctx.push_scope();
@@ -336,7 +336,7 @@ impl Emitter {
Statement::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
let reg = ctx.alloc_reg();
let _ = ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Let, false);
let _ = ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Let);
}
}
Statement::ExportNamedDeclaration(exp) => {
@@ -354,12 +354,8 @@ impl Emitter {
Declaration::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
let reg = ctx.alloc_reg();
let _ = ctx.declare_predeclared(
id.name.as_str(),
reg,
VariableDeclarationKind::Let,
false,
);
let _ =
ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Let);
}
}
_ => {}
@@ -372,7 +368,7 @@ impl Emitter {
if let ExportDefaultDeclarationKind::ClassDeclaration(cd) = &exp.declaration {
if let Some(id) = &cd.id {
let reg = ctx.alloc_reg();
let _ = ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Let, false);
let _ = ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Let);
}
}
}
@@ -397,7 +393,6 @@ impl Emitter {
} else {
VariableDeclarationKind::Let
},
is_const,
);
// 块级遮蔽绑定:名字在捕获集且最内层为块作用域时,追加新 cell
// 索引并发未初始化 MAKE_CELL(TDZ 占位)。声明点与闭包捕获据
+17 -21
View File
@@ -55,8 +55,7 @@ impl Emitter {
/// - 声明撞全局不可写内置(undefined/NaN/Infinity):sloppy 静默跳过写(槽保留
/// 入口预载原值),strict 抛 TypeError;局部遮蔽绑定不受影响。
pub(crate) fn emit_bind_target(
&self, name: &str, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, fresh_cell: bool,
ctx: &mut CompileCtx,
&self, name: &str, src_reg: u32, kind: VariableDeclarationKind, fresh_cell: bool, ctx: &mut CompileCtx,
) -> Result<(), String> {
let target_reg = if matches!(kind, VariableDeclarationKind::Var) {
// `var` 名已预声明(hoisting),复用预登记槽位而非新分配,使 n_registers 与 let/const 一致。
@@ -64,7 +63,7 @@ impl Emitter {
reg
} else {
let var_reg = ctx.alloc_reg();
ctx.declare(name, var_reg, kind, is_const)?;
ctx.declare(name, var_reg, kind)?;
var_reg
}
} else {
@@ -74,7 +73,7 @@ impl Emitter {
reg
} else {
let var_reg = ctx.alloc_reg();
ctx.declare(name, var_reg, kind, is_const)?;
ctx.declare(name, var_reg, kind)?;
var_reg
}
};
@@ -117,7 +116,7 @@ impl Emitter {
} else if !ctx.with_stack.is_empty() && !ctx.is_with_internal_binding(name) {
// with 内 var 初始化:对象有该属性则写对象,否则写提升槽(动态解析);
// 未声明名经回退臂落隐式全局,与静态写路径同形。
self.emit_with_dynamic_write(name, src_reg, 0, ctx)?;
self.emit_with_dynamic_write(name, src_reg, ctx)?;
} else {
// const 声明路径 STORE_VAR 恒 b=0,不查运行时 guard。
// guard 读 regs[rd] 判断槽是否已初始化,依赖槽初始为 undefined;
@@ -229,15 +228,15 @@ impl Emitter {
}
pub(crate) fn emit_binding_pattern(
&self, pattern: &BindingPattern, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, fresh_cell: bool,
&self, pattern: &BindingPattern, src_reg: u32, kind: VariableDeclarationKind, fresh_cell: bool,
ctx: &mut CompileCtx,
) -> Result<(), String> {
match pattern {
BindingPattern::BindingIdentifier(bi) => {
self.emit_bind_target(bi.name.as_str(), src_reg, kind, is_const, fresh_cell, ctx)
self.emit_bind_target(bi.name.as_str(), src_reg, kind, fresh_cell, ctx)
}
BindingPattern::ArrayPattern(ap) => self.emit_array_binding(ap, src_reg, kind, is_const, fresh_cell, ctx),
BindingPattern::ObjectPattern(op) => self.emit_object_binding(op, src_reg, kind, is_const, fresh_cell, ctx),
BindingPattern::ArrayPattern(ap) => self.emit_array_binding(ap, src_reg, kind, fresh_cell, ctx),
BindingPattern::ObjectPattern(op) => self.emit_object_binding(op, src_reg, kind, fresh_cell, ctx),
BindingPattern::AssignmentPattern(ap) => {
// `[x = fn]`:默认值函数按绑定名推断 name。
let name = match &ap.left {
@@ -245,14 +244,13 @@ impl Emitter {
_ => None,
};
let val_reg = self.emit_default_if_undefined(src_reg, &ap.right, name, ctx)?;
self.emit_binding_pattern(&ap.left, val_reg, kind, is_const, fresh_cell, ctx)
self.emit_binding_pattern(&ap.left, val_reg, kind, fresh_cell, ctx)
}
}
}
fn emit_array_binding(
&self, ap: &ArrayPattern, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, fresh_cell: bool,
ctx: &mut CompileCtx,
&self, ap: &ArrayPattern, src_reg: u32, kind: VariableDeclarationKind, fresh_cell: bool, ctx: &mut CompileCtx,
) -> Result<(), String> {
ctx.inst(Inst::new(OpCode::FOR_OF_INIT, Operand::None, Operand::Reg(src_reg), Operand::None));
for elem in &ap.elements {
@@ -261,12 +259,12 @@ impl Emitter {
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_OF_NEXT, Operand::Reg(val_reg), Operand::None, Operand::None));
if let Some(pattern) = elem {
self.emit_binding_pattern(pattern, val_reg, kind, is_const, fresh_cell, ctx)?;
self.emit_binding_pattern(pattern, val_reg, kind, fresh_cell, ctx)?;
}
}
if let Some(rest) = &ap.rest {
let rest_reg = self.emit_collect_rest_array(ctx)?;
self.emit_binding_pattern(&rest.argument, rest_reg, kind, is_const, fresh_cell, ctx)?;
self.emit_binding_pattern(&rest.argument, rest_reg, kind, fresh_cell, ctx)?;
}
ctx.inst(Inst::new(OpCode::FOR_OF_CLOSE, Operand::None, Operand::None, Operand::None));
Ok(())
@@ -300,8 +298,7 @@ impl Emitter {
}
fn emit_object_binding(
&self, op: &ObjectPattern, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, fresh_cell: bool,
ctx: &mut CompileCtx,
&self, op: &ObjectPattern, src_reg: u32, kind: VariableDeclarationKind, fresh_cell: bool, ctx: &mut CompileCtx,
) -> Result<(), String> {
// 对象解构先 ToObject(rhs):null/undefined 抛 TypeError(含空 pattern),
// 原始值包装为对应对象,保证属性读取与 rest 都以对象为源。
@@ -317,8 +314,7 @@ impl Emitter {
excl_arr_reg = Some(self.emit_new_excluded_array(ctx));
}
for prop in &op.properties {
let (prop_reg, static_key, key_reg) =
self.emit_object_property_read_key(obj_reg, &prop.key, prop.computed, ctx)?;
let (prop_reg, static_key, key_reg) = self.emit_object_property_read_key(obj_reg, &prop.key, ctx)?;
if let Some(key) = static_key {
excluded.push(key.clone());
if let Some(arr) = excl_arr_reg {
@@ -329,7 +325,7 @@ impl Emitter {
self.emit_push_excluded_key(arr, Some(key_reg), "", excl_push, ctx);
excl_push += 1;
}
self.emit_binding_pattern(&prop.value, prop_reg, kind, is_const, fresh_cell, ctx)?;
self.emit_binding_pattern(&prop.value, prop_reg, kind, fresh_cell, ctx)?;
}
if let Some(rest) = &op.rest {
let rest_reg = ctx.alloc_reg();
@@ -340,7 +336,7 @@ impl Emitter {
excluded_idx as u32,
excl_arr_reg.map(Operand::Reg),
));
self.emit_binding_pattern(&rest.argument, rest_reg, kind, is_const, fresh_cell, ctx)?;
self.emit_binding_pattern(&rest.argument, rest_reg, kind, fresh_cell, ctx)?;
}
Ok(())
}
@@ -574,7 +570,7 @@ impl Emitter {
}
AssignmentTargetProperty::AssignmentTargetPropertyProperty(prop) => {
let (prop_reg, static_key, key_reg) =
self.emit_object_property_read_key(obj_reg, &prop.name, prop.computed, ctx)?;
self.emit_object_property_read_key(obj_reg, &prop.name, ctx)?;
if let Some(key) = static_key {
excluded.push(key.clone());
if let Some(arr) = excl_arr_reg {
+3 -1
View File
@@ -305,8 +305,10 @@ impl Emitter {
/// 读取对象属性并产出键信息:非计算键走字符串常量 IC 路径,计算键在字面量可折叠时走 IC,否则动态求值。
/// 返回 `(结果寄存器, 常量键名, 键寄存器)`,后两者互补为 None(计算键路径无论 IC 折叠还是动态求值均以寄存器返回键)。
pub(crate) fn emit_object_property_read_key(
&self, src_reg: u32, key: &PropertyKey, computed: bool, ctx: &mut CompileCtx,
&self, src_reg: u32, key: &PropertyKey, ctx: &mut CompileCtx,
) -> Result<(u32, Option<String>, Option<u32>), String> {
// 计算键即表达式形态键(oxc 计算键恒为 Expression 继承变体),静态/私有名键非计算。
let computed = key.is_expression();
if !computed {
let key_name = crate::shared::string_pool::pool_key_property(key)?;
let prop_reg = self.emit_object_property_read(src_reg, &key_name, ctx);
+3 -1
View File
@@ -10,6 +10,8 @@ use oxide_parser::{Expression, MethodDefinitionKind, PropertyKey};
impl Emitter {
/// 实例字段初始化:define 语义(不触发原型 setter)。
/// 非计算键用字符串常量;计算键从 `@@field_keys` upvalue 数组按 `key_slot` 取(类定义期求值一次)。
/// 类元素字符串字面量键(`"a" = 1`)非计算(oxc `computed` 标志为假),
/// 故 `computed` 取 AST 标志而非按键形态推导。
pub(crate) fn emit_public_field_init(
&self, target: Operand, key: &PropertyKey, computed: bool, value: Option<&Expression>, key_slot: Option<u8>,
ctx: &mut CompileCtx,
@@ -17,7 +19,7 @@ impl Emitter {
let key_reg = if computed {
self.emit_instance_field_key(key_slot, ctx)?
} else {
self.emit_class_key_reg(key, false, ctx)?
self.emit_class_key_reg(key, ctx)?
};
let value_reg = self.emit_field_value(value, ctx)?;
ctx.inst(Inst::define_prop(target, Operand::Reg(value_reg), Operand::Reg(key_reg)));
+8 -15
View File
@@ -57,21 +57,14 @@ impl Emitter {
Ok((brand_reg, brand_id))
}
pub(crate) fn emit_class_key_reg(
&self, key: &PropertyKey, computed: bool, ctx: &mut CompileCtx,
) -> Result<u32, String> {
if !computed {
let name = crate::shared::string_pool::pool_key_property(key)?;
let idx = ctx.add_constant(Constant::String(name));
let reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(reg), idx));
return Ok(reg);
}
if matches!(key, PropertyKey::PrivateIdentifier(_)) {
return Err("private class elements not yet supported".into());
}
self.emit_expression(key.to_expression(), ctx)
/// 非计算类属性键的寄存器:全部调用点均为非计算键(计算键经
/// `emit_class_array_key_reg` 从类定义期数组取),直接取池键字符串常量。
pub(crate) fn emit_class_key_reg(&self, key: &PropertyKey, ctx: &mut CompileCtx) -> Result<u32, String> {
let name = crate::shared::string_pool::pool_key_property(key)?;
let idx = ctx.add_constant(Constant::String(name));
let reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(reg), idx));
Ok(reg)
}
/// 从类定义期 computed key 数组按 slot 取键(方法/静态字段在类定义期使用)。
@@ -26,7 +26,7 @@ impl Emitter {
Some(reg) => reg,
None => {
let reg = ctx.alloc_reg();
ctx.declare(&name, reg, VariableDeclarationKind::Let, false)?;
ctx.declare(&name, reg, VariableDeclarationKind::Let)?;
reg
}
};
@@ -35,7 +35,7 @@ impl Emitter {
}
if let Some(init) = &d.init {
let val_reg = self.emit_expression(init, ctx)?;
self.emit_binding_pattern(&d.id, val_reg, decl.kind, is_const, reexec, ctx)?;
self.emit_binding_pattern(&d.id, val_reg, decl.kind, reexec, ctx)?;
if let BindingPattern::BindingIdentifier(bi) = &d.id {
if crate::is_anonymous_function_definition(init) {
if let Some(sub_mod) = ctx.nested.last_mut() {
@@ -59,7 +59,7 @@ impl Emitter {
// 无初始化 var 是纯声明而非赋值:绑定已预先存在(提升引用或先前写入)
// 时保留槽值,仅首次声明把 undefined 物化进槽。
let (target_reg, already_bound) = if matches!(decl.kind, VariableDeclarationKind::Var) {
match ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const) {
match ctx.declare(bi.name.as_str(), var_reg, decl.kind) {
Ok(()) => (var_reg, false),
Err(_) => (ctx.lookup(bi.name.as_str()).unwrap_or(var_reg), true),
}
@@ -70,7 +70,7 @@ impl Emitter {
reg
} else {
let r = ctx.alloc_reg();
ctx.declare(bi.name.as_str(), r, decl.kind, is_const)?;
ctx.declare(bi.name.as_str(), r, decl.kind)?;
r
};
(target, false)
@@ -100,7 +100,7 @@ impl Emitter {
// 每次 catch 执行都为参数新建词法环境:被捕获参数在入口发
// MAKE_CELL_FRESH(替换而非覆写上一入口的 cell),上一入口
// 闭包持有的旧 cell 指针仍可读到旧值。
self.emit_binding_pattern(&param.pattern, src_reg, VariableDeclarationKind::Let, false, true, ctx)?;
self.emit_binding_pattern(&param.pattern, src_reg, VariableDeclarationKind::Let, true, ctx)?;
}
// catch 块函数预声明先于 lexical,块入口物化与 try/普通块同口径。
self.predeclare_block_function_declarations(&catch.body.body, ctx, false);
+3 -4
View File
@@ -98,12 +98,11 @@ impl Emitter {
}
}
for d in &decl.declarations {
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
if let Some(init_expr) = &d.init {
let val_reg = self.emit_expression(init_expr, ctx)?;
// 捕获头名的寄存器补写在 `emit_bind_target` 经
// `for_head_store_registers` 完成(解构叶用各自的叶值,不用整头 RHS)。
self.emit_binding_pattern(&d.id, val_reg, decl.kind, is_const, false, ctx)?;
self.emit_binding_pattern(&d.id, val_reg, decl.kind, false, ctx)?;
// using/await using 头声明登记释放栈(资源值即 init 表达式结果)。
self.emit_dispose_register(val_reg, decl.kind, ctx);
} else if let BindingPattern::BindingIdentifier(bi) = &d.id {
@@ -114,12 +113,12 @@ impl Emitter {
// 无初始化 var 是纯声明而非赋值:绑定已预先存在(提升引用或
// 先前写入)时保留槽值,仅首次声明把 undefined 物化进槽。
let (target_reg, already_bound) = if matches!(decl.kind, VariableDeclarationKind::Var) {
match ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const) {
match ctx.declare(bi.name.as_str(), var_reg, decl.kind) {
Ok(()) => (var_reg, false),
Err(_) => (ctx.lookup(bi.name.as_str()).unwrap_or(var_reg), true),
}
} else {
ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const)?;
ctx.declare(bi.name.as_str(), var_reg, decl.kind)?;
// 头名回填:保留头名在 init 声明点建绑定后把覆盖 cell 索引
// 写进绑定字段,解析点按绑定身份取索引;非保留头名走寄存器
// 循环,不置位绑定字段(否则体区读经可见判定命中陈旧 cell,
@@ -199,7 +199,6 @@ impl Emitter {
ForStatementLeft::VariableDeclaration(decl) => {
// let/const 声明对被捕获绑定用 fresh cell(每迭代新 cell);var 单绑定。
let fresh_cell = !matches!(decl.kind, VariableDeclarationKind::Var);
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
for d in &decl.declarations {
match &d.id {
oxide_parser::BindingPattern::BindingIdentifier(bi) => {
@@ -209,12 +208,12 @@ impl Emitter {
// GlobalDeclarationInstantiation(脚本顶层声明实例化)序言预登记的内置名、
// 同 scope 先前声明)时复用既有槽位,不重复声明;let/const 同 scope 重复声明仍报错。
let target_reg = if matches!(decl.kind, VariableDeclarationKind::Var) {
match ctx.declare(name, var_reg, decl.kind, is_const) {
match ctx.declare(name, var_reg, decl.kind) {
Ok(()) => var_reg,
Err(_) => ctx.lookup(name).unwrap_or(var_reg),
}
} else {
ctx.declare(name, var_reg, decl.kind, is_const)?;
ctx.declare(name, var_reg, decl.kind)?;
// 头名回填:体区绑定点建绑定后把覆盖 cell 索引写进绑定
// 字段,解析点按绑定身份取索引(var 头绑定已回填,
// 同值覆盖幂等)。
@@ -256,7 +255,7 @@ impl Emitter {
// 解构头:数组 pattern 对迭代键字符串解构、对象 pattern 先
// ToObject 再按属性读;叶名绑定复用通用路径(含 let/const
// 声明、fresh cell 与顶层 var 全局属性反射)。
_ => self.emit_binding_pattern(&d.id, key_reg, decl.kind, is_const, fresh_cell, ctx)?,
_ => self.emit_binding_pattern(&d.id, key_reg, decl.kind, fresh_cell, ctx)?,
}
}
// using/await using 头声明登记释放栈(资源值即本迭代键)。
@@ -165,7 +165,7 @@ impl Emitter {
ForStatementLeft::VariableDeclaration(decl) => {
let fresh_cell = !matches!(decl.kind, VariableDeclarationKind::Var);
for d in &decl.declarations {
self.emit_binding_pattern(&d.id, val_reg, decl.kind, false, fresh_cell, ctx)?;
self.emit_binding_pattern(&d.id, val_reg, decl.kind, fresh_cell, ctx)?;
}
// using/await using 头声明登记释放栈(资源值即本迭代值)。
self.emit_dispose_register(val_reg, decl.kind, ctx);
+25 -29
View File
@@ -101,9 +101,7 @@ impl SymbolTable {
/// 声明绑定:`var` 提升到函数作用域,`let`/`const` 落在当前块。
/// 初始为未初始化态(TDZ);重复声明报错。
pub fn declare(
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind, is_const: bool,
) -> Result<(), String> {
pub fn declare(&mut self, name: &str, reg: u32, kind: VariableDeclarationKind) -> Result<(), String> {
let target_idx = if matches!(kind, VariableDeclarationKind::Var) {
self.find_var_target_scope()
} else {
@@ -119,7 +117,7 @@ impl SymbolTable {
Binding {
reg,
initialized: false,
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
is_const: matches!(kind, VariableDeclarationKind::Const),
lexical: !matches!(kind, VariableDeclarationKind::Var),
predeclared: false,
cell_idx: None,
@@ -233,9 +231,7 @@ impl SymbolTable {
}
/// 声明并直接标记为已初始化;绑定已存在时仅补初始化标志(供预声明路径)。
pub fn declare_initialized(
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind, is_const: bool,
) -> Result<(), String> {
pub fn declare_initialized(&mut self, name: &str, reg: u32, kind: VariableDeclarationKind) -> Result<(), String> {
let target_idx = if matches!(kind, VariableDeclarationKind::Var) {
self.find_var_target_scope()
} else {
@@ -252,7 +248,7 @@ impl SymbolTable {
Binding {
reg,
initialized: true,
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
is_const: matches!(kind, VariableDeclarationKind::Const),
lexical: !matches!(kind, VariableDeclarationKind::Var),
predeclared: false,
cell_idx: None,
@@ -278,7 +274,7 @@ impl SymbolTable {
/// 声明未初始化绑定并标记为预声明(TDZ 占位),供声明点复用槽位。
/// 与 `declare` 同作用域规则,仅 `predeclared` 标志不同。
pub(crate) fn declare_predeclared(
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind, is_const: bool,
&mut self, name: &str, reg: u32, kind: VariableDeclarationKind,
) -> Result<(), String> {
let target_idx = if matches!(kind, VariableDeclarationKind::Var) {
self.find_var_target_scope()
@@ -294,7 +290,7 @@ impl SymbolTable {
Binding {
reg,
initialized: false,
is_const: matches!(kind, VariableDeclarationKind::Const) || is_const,
is_const: matches!(kind, VariableDeclarationKind::Const),
lexical: !matches!(kind, VariableDeclarationKind::Var),
predeclared: true,
cell_idx: None,
@@ -411,7 +407,7 @@ mod tests {
#[test]
fn declare_and_lookup() {
let mut st = SymbolTable::new();
st.declare("x", 0, l(), false).unwrap();
st.declare("x", 0, l()).unwrap();
st.init_var("x");
assert_eq!(st.lookup("x").unwrap(), 0);
}
@@ -419,24 +415,24 @@ mod tests {
#[test]
fn tdz_error() {
let mut st = SymbolTable::new();
st.declare("x", 0, l(), false).unwrap();
st.declare("x", 0, l()).unwrap();
assert!(st.lookup("x").unwrap_err().contains("before initialization"));
}
#[test]
fn duplicate_declaration_error() {
let mut st = SymbolTable::new();
st.declare("x", 0, l(), false).unwrap();
assert!(st.declare("x", 1, l(), false).is_err());
st.declare("x", 0, l()).unwrap();
assert!(st.declare("x", 1, l()).is_err());
}
#[test]
fn nested_scopes_shadow() {
let mut st = SymbolTable::new();
st.declare("x", 0, l(), false).unwrap();
st.declare("x", 0, l()).unwrap();
st.init_var("x");
st.push_scope();
st.declare("x", 1, l(), false).unwrap();
st.declare("x", 1, l()).unwrap();
st.init_var("x");
assert_eq!(st.lookup("x").unwrap(), 1);
st.pop_scope();
@@ -454,7 +450,7 @@ mod tests {
#[test]
fn lookup_or_global_existing() {
let mut st = SymbolTable::new();
st.declare("x", 3, l(), false).unwrap();
st.declare("x", 3, l()).unwrap();
st.init_var("x");
let reg = st.lookup_or_global("x", 99);
assert_eq!(reg, 3);
@@ -464,12 +460,12 @@ mod tests {
fn var_hoists_to_function_scope() {
let mut st = SymbolTable::new();
// 全局作用域是函数作用域
st.declare("x", 0, l(), false).unwrap();
st.declare("x", 0, l()).unwrap();
st.init_var("x");
// 压入块作用域
st.push_scope();
// 块内的 var 声明应落到函数作用域
st.declare("y", 1, v(), false).unwrap();
st.declare("y", 1, v()).unwrap();
st.init_var("y");
st.pop_scope();
// y 可见(声明在函数作用域而非块作用域)
@@ -479,10 +475,10 @@ mod tests {
#[test]
fn let_block_scoped() {
let mut st = SymbolTable::new();
st.declare("x", 0, l(), false).unwrap();
st.declare("x", 0, l()).unwrap();
st.init_var("x");
st.push_scope();
st.declare("x", 1, l(), false).unwrap();
st.declare("x", 1, l()).unwrap();
st.init_var("x");
assert_eq!(st.lookup("x").unwrap(), 1);
st.pop_scope();
@@ -492,7 +488,7 @@ mod tests {
#[test]
fn const_has_is_const_flag() {
let mut st = SymbolTable::new();
st.declare("x", 0, c(), false).unwrap();
st.declare("x", 0, c()).unwrap();
st.init_var("x");
let reg = st.lookup("x").unwrap();
assert_eq!(reg, 0);
@@ -502,18 +498,18 @@ mod tests {
fn var_in_two_blocks_same_function_scope_is_duplicate() {
let mut st = SymbolTable::new();
st.push_scope();
st.declare("y", 1, v(), false).unwrap();
st.declare("y", 1, v()).unwrap();
st.pop_scope();
st.push_scope();
// 同一函数作用域,故应为重复声明
assert!(st.declare("y", 2, v(), false).is_err());
assert!(st.declare("y", 2, v()).is_err());
st.pop_scope();
}
#[test]
fn alias_shares_source_slot_and_const() {
let mut st = SymbolTable::new();
st.declare("x", 3, l(), false).unwrap();
st.declare("x", 3, l()).unwrap();
st.add_alias("y", "x").unwrap();
// 别名复用源寄存器,且是不可变的间接绑定。
assert_eq!(st.lookup_any("y"), Some(3));
@@ -525,7 +521,7 @@ mod tests {
#[test]
fn alias_tdz_follows_source_init() {
let mut st = SymbolTable::new();
st.declare("x", 3, l(), false).unwrap();
st.declare("x", 3, l()).unwrap();
st.add_alias("y", "x").unwrap();
st.init_var("x");
// 源声明点初始化同步解除别名 TDZ。
@@ -535,7 +531,7 @@ mod tests {
#[test]
fn alias_chain_resolves_to_base() {
let mut st = SymbolTable::new();
st.declare("x", 3, l(), false).unwrap();
st.declare("x", 3, l()).unwrap();
st.add_alias("y", "x").unwrap();
st.add_alias("z", "y").unwrap();
assert_eq!(st.resolve_alias_base("z"), "x");
@@ -551,9 +547,9 @@ mod tests {
#[test]
fn set_binding_cell_idx_innermost_first() {
let mut st = SymbolTable::new();
st.declare("x", 0, l(), false).unwrap();
st.declare("x", 0, l()).unwrap();
st.push_scope();
st.declare("x", 1, l(), false).unwrap();
st.declare("x", 1, l()).unwrap();
st.set_binding_cell_idx("x", 3);
let (inner, _) = st.lookup_any_binding("x").unwrap();
assert_eq!(inner.cell_idx, Some(3));