From 3d7e8edd75700dc1b0587596d96a50390e3c0bce Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Mon, 12 Oct 2026 16:30:51 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20emit=20=E5=86=97=E4=BD=99=E6=A0=87?= =?UTF-8?q?=E5=BF=97=E5=8F=82=E6=95=B0=E6=94=B6=E6=95=9B=E4=B8=BA=E5=86=85?= =?UTF-8?q?=E9=83=A8=E6=8E=A8=E5=AF=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 42 +++++------ Cargo.toml | 2 +- crates/oxide_emit/src/class/emit.rs | 2 +- crates/oxide_emit/src/class/field.rs | 2 +- crates/oxide_emit/src/class/method.rs | 2 +- crates/oxide_emit/src/compile_ctx.rs | 14 ++-- crates/oxide_emit/src/expr/assignment.rs | 8 +- crates/oxide_emit/src/expr/identifier.rs | 16 ++-- crates/oxide_emit/src/function_body.rs | 6 +- crates/oxide_emit/src/module.rs | 74 ++++++++----------- crates/oxide_emit/src/prepass/declare.rs | 21 ++---- crates/oxide_emit/src/shared/binding.rs | 38 +++++----- crates/oxide_emit/src/shared/chain.rs | 4 +- crates/oxide_emit/src/shared/class_field.rs | 4 +- crates/oxide_emit/src/shared/class_key.rs | 23 ++---- .../src/stmt/declaration/class_decl.rs | 2 +- crates/oxide_emit/src/stmt/declaration/var.rs | 6 +- .../src/stmt/exception/try_catch.rs | 2 +- crates/oxide_emit/src/stmt/iteration/for_.rs | 7 +- .../oxide_emit/src/stmt/iteration/for_in.rs | 7 +- .../oxide_emit/src/stmt/iteration/for_of.rs | 2 +- crates/oxide_emit/src/symbol_table.rs | 54 +++++++------- 22 files changed, 151 insertions(+), 187 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac8994ca..5f8eea55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "oxide_builtins" -version = "0.17.1" +version = "0.17.2" dependencies = [ "chrono", "fast-float", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "oxide_bytecode" -version = "0.17.1" +version = "0.17.2" dependencies = [ "num-bigint", "oxide_log", @@ -1193,7 +1193,7 @@ dependencies = [ [[package]] name = "oxide_cfg" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_emit", @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "oxide_cli" -version = "0.17.1" +version = "0.17.2" dependencies = [ "ansi_term", "bumpalo", @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "oxide_code_cache" -version = "0.17.1" +version = "0.17.2" dependencies = [ "lru", "oxide_bytecode", @@ -1237,7 +1237,7 @@ dependencies = [ [[package]] name = "oxide_compiler" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1258,7 +1258,7 @@ dependencies = [ [[package]] name = "oxide_dce" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1272,7 +1272,7 @@ dependencies = [ [[package]] name = "oxide_emit" -version = "0.17.1" +version = "0.17.2" dependencies = [ "num-bigint", "oxc_allocator", @@ -1288,7 +1288,7 @@ dependencies = [ [[package]] name = "oxide_engine" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1300,7 +1300,7 @@ dependencies = [ [[package]] name = "oxide_fold" -version = "0.17.1" +version = "0.17.2" dependencies = [ "num-bigint", "oxide_bytecode", @@ -1312,7 +1312,7 @@ dependencies = [ [[package]] name = "oxide_ir" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_log", @@ -1321,7 +1321,7 @@ dependencies = [ [[package]] name = "oxide_kernel" -version = "0.17.1" +version = "0.17.2" dependencies = [ "bumpalo", "dashmap", @@ -1335,7 +1335,7 @@ dependencies = [ [[package]] name = "oxide_liveness" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1347,7 +1347,7 @@ dependencies = [ [[package]] name = "oxide_log" -version = "0.17.1" +version = "0.17.2" dependencies = [ "tracing", "tracing-appender", @@ -1356,11 +1356,11 @@ dependencies = [ [[package]] name = "oxide_net" -version = "0.17.1" +version = "0.17.2" [[package]] name = "oxide_parser" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxc_allocator", "oxc_ast", @@ -1375,7 +1375,7 @@ dependencies = [ [[package]] name = "oxide_regalloc" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_cfg", @@ -1391,7 +1391,7 @@ dependencies = [ [[package]] name = "oxide_runtime_api" -version = "0.17.1" +version = "0.17.2" dependencies = [ "num-bigint", "num-traits", @@ -1404,7 +1404,7 @@ dependencies = [ [[package]] name = "oxide_test262" -version = "0.17.1" +version = "0.17.2" dependencies = [ "oxide_bytecode", "oxide_compiler", @@ -1424,7 +1424,7 @@ dependencies = [ [[package]] name = "oxide_types" -version = "0.17.1" +version = "0.17.2" dependencies = [ "bumpalo", "dashmap", @@ -1437,7 +1437,7 @@ dependencies = [ [[package]] name = "oxide_vm" -version = "0.17.1" +version = "0.17.2" dependencies = [ "bumpalo", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 1c8940ad..81acefe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ members = [ ] [workspace.package] -version = "0.17.1" +version = "0.17.2" edition = "2021" license = "MIT" rust-version = "1.80" diff --git a/crates/oxide_emit/src/class/emit.rs b/crates/oxide_emit/src/class/emit.rs index e23176e5..ba0d8801 100644 --- a/crates/oxide_emit/src/class/emit.rs +++ b/crates/oxide_emit/src/class/emit.rs @@ -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 } diff --git a/crates/oxide_emit/src/class/field.rs b/crates/oxide_emit/src/class/field.rs index 9364329d..c58e4bc0 100644 --- a/crates/oxide_emit/src/class/field.rs +++ b/crates/oxide_emit/src/class/field.rs @@ -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( diff --git a/crates/oxide_emit/src/class/method.rs b/crates/oxide_emit/src/class/method.rs index 1ab20446..21d14b75 100644 --- a/crates/oxide_emit/src/class/method.rs +++ b/crates/oxide_emit/src/class/method.rs @@ -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 { "".to_string() diff --git a/crates/oxide_emit/src/compile_ctx.rs b/crates/oxide_emit/src/compile_ctx.rs index 9d07b146..52cd7425 100644 --- a/crates/oxide_emit/src/compile_ctx.rs +++ b/crates/oxide_emit/src/compile_ctx.rs @@ -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) { diff --git a/crates/oxide_emit/src/expr/assignment.rs b/crates/oxide_emit/src/expr/assignment.rs index 65ef5f58..c6a8d1a1 100644 --- a/crates/oxide_emit/src/expr/assignment.rs +++ b/crates/oxide_emit/src/expr/assignment.rs @@ -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!( diff --git a/crates/oxide_emit/src/expr/identifier.rs b/crates/oxide_emit/src/expr/identifier.rs index 141b9799..f7ac9385 100644 --- a/crates/oxide_emit/src/expr/identifier.rs +++ b/crates/oxide_emit/src/expr/identifier.rs @@ -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(()) } diff --git a/crates/oxide_emit/src/function_body.rs b/crates/oxide_emit/src/function_body.rs index 2ce275e8..1edb112e 100644 --- a/crates/oxide_emit/src/function_body.rs +++ b/crates/oxide_emit/src/function_body.rs @@ -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 { diff --git a/crates/oxide_emit/src/module.rs b/crates/oxide_emit/src/module.rs index 510c1ace..63858b6d 100644 --- a/crates/oxide_emit/src/module.rs +++ b/crates/oxide_emit/src/module.rs @@ -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, diff --git a/crates/oxide_emit/src/prepass/declare.rs b/crates/oxide_emit/src/prepass/declare.rs index 11e389ec..2c2e8d89 100644 --- a/crates/oxide_emit/src/prepass/declare.rs +++ b/crates/oxide_emit/src/prepass/declare.rs @@ -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 占位)。声明点与闭包捕获据 diff --git a/crates/oxide_emit/src/shared/binding.rs b/crates/oxide_emit/src/shared/binding.rs index 70fd47f8..f9e20470 100644 --- a/crates/oxide_emit/src/shared/binding.rs +++ b/crates/oxide_emit/src/shared/binding.rs @@ -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 { diff --git a/crates/oxide_emit/src/shared/chain.rs b/crates/oxide_emit/src/shared/chain.rs index 96c4f2ab..d5107ada 100644 --- a/crates/oxide_emit/src/shared/chain.rs +++ b/crates/oxide_emit/src/shared/chain.rs @@ -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, Option), 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); diff --git a/crates/oxide_emit/src/shared/class_field.rs b/crates/oxide_emit/src/shared/class_field.rs index 4ef48ee5..cea67405 100644 --- a/crates/oxide_emit/src/shared/class_field.rs +++ b/crates/oxide_emit/src/shared/class_field.rs @@ -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, 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))); diff --git a/crates/oxide_emit/src/shared/class_key.rs b/crates/oxide_emit/src/shared/class_key.rs index 55be0536..7042a65c 100644 --- a/crates/oxide_emit/src/shared/class_key.rs +++ b/crates/oxide_emit/src/shared/class_key.rs @@ -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 { - 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 { + 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 取键(方法/静态字段在类定义期使用)。 diff --git a/crates/oxide_emit/src/stmt/declaration/class_decl.rs b/crates/oxide_emit/src/stmt/declaration/class_decl.rs index 599766ab..dc9f9dad 100644 --- a/crates/oxide_emit/src/stmt/declaration/class_decl.rs +++ b/crates/oxide_emit/src/stmt/declaration/class_decl.rs @@ -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 } }; diff --git a/crates/oxide_emit/src/stmt/declaration/var.rs b/crates/oxide_emit/src/stmt/declaration/var.rs index b3f2edc0..fe0d5c8a 100644 --- a/crates/oxide_emit/src/stmt/declaration/var.rs +++ b/crates/oxide_emit/src/stmt/declaration/var.rs @@ -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) diff --git a/crates/oxide_emit/src/stmt/exception/try_catch.rs b/crates/oxide_emit/src/stmt/exception/try_catch.rs index 5421fcaf..3573ce9d 100644 --- a/crates/oxide_emit/src/stmt/exception/try_catch.rs +++ b/crates/oxide_emit/src/stmt/exception/try_catch.rs @@ -100,7 +100,7 @@ impl Emitter { // 每次 catch 执行都为参数新建词法环境:被捕获参数在入口发 // MAKE_CELL_FRESH(替换而非覆写上一入口的 cell),上一入口 // 闭包持有的旧 cell 指针仍可读到旧值。 - self.emit_binding_pattern(¶m.pattern, src_reg, VariableDeclarationKind::Let, false, true, ctx)?; + self.emit_binding_pattern(¶m.pattern, src_reg, VariableDeclarationKind::Let, true, ctx)?; } // catch 块函数预声明先于 lexical,块入口物化与 try/普通块同口径。 self.predeclare_block_function_declarations(&catch.body.body, ctx, false); diff --git a/crates/oxide_emit/src/stmt/iteration/for_.rs b/crates/oxide_emit/src/stmt/iteration/for_.rs index 994f8986..3105b781 100644 --- a/crates/oxide_emit/src/stmt/iteration/for_.rs +++ b/crates/oxide_emit/src/stmt/iteration/for_.rs @@ -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, diff --git a/crates/oxide_emit/src/stmt/iteration/for_in.rs b/crates/oxide_emit/src/stmt/iteration/for_in.rs index 2c55dbe4..60e6b1a8 100644 --- a/crates/oxide_emit/src/stmt/iteration/for_in.rs +++ b/crates/oxide_emit/src/stmt/iteration/for_in.rs @@ -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 头声明登记释放栈(资源值即本迭代键)。 diff --git a/crates/oxide_emit/src/stmt/iteration/for_of.rs b/crates/oxide_emit/src/stmt/iteration/for_of.rs index 7fff530b..6f2805a2 100644 --- a/crates/oxide_emit/src/stmt/iteration/for_of.rs +++ b/crates/oxide_emit/src/stmt/iteration/for_of.rs @@ -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); diff --git a/crates/oxide_emit/src/symbol_table.rs b/crates/oxide_emit/src/symbol_table.rs index 41f61109..fb8ee317 100644 --- a/crates/oxide_emit/src/symbol_table.rs +++ b/crates/oxide_emit/src/symbol_table.rs @@ -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));