From 5efc64dc71a540c60e49ae902b681c4ee3545969 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Tue, 15 Sep 2026 21:19:29 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=94=99=E8=AF=AF=E5=AE=88?= =?UTF-8?q?=E5=8D=AB=E5=9B=9B=E5=87=BD=E6=95=B0=E8=BF=81=E5=87=BA=20emit.r?= =?UTF-8?q?s=20=E7=8B=AC=E7=AB=8B=E6=88=90=20errors=20=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_emit/src/emit.rs | 57 --------------------------- crates/oxide_emit/src/errors.rs | 69 +++++++++++++++++++++++++++++++++ crates/oxide_emit/src/lib.rs | 1 + 3 files changed, 70 insertions(+), 57 deletions(-) create mode 100644 crates/oxide_emit/src/errors.rs diff --git a/crates/oxide_emit/src/emit.rs b/crates/oxide_emit/src/emit.rs index dd0b1daa..6495acef 100644 --- a/crates/oxide_emit/src/emit.rs +++ b/crates/oxide_emit/src/emit.rs @@ -199,63 +199,6 @@ impl Emitter { self } - /// 生成运行时抛 `kind` 类型错误的指令序列,返回一个未定义 dummy 寄存器 - /// 保证 THROW 后不可达控制流的寄存器良定义。 - /// - /// # 步骤 - /// 1. 取全局错误构造器并 LOAD。 - /// 2. 加载错误消息常量,`new {kind}(msg)` 构造错误对象。 - /// 3. THROW 抛出;尾接 dummy 值保持后续读引用有确定寄存器。 - /// - /// # 边界与前提 - /// - `kind` 必须是已注册的全局构造器名(如 "ReferenceError"/"TypeError")。 - pub(crate) fn emit_throw_error(&self, kind: &str, msg: &str, ctx: &mut CompileCtx) -> Result { - let ctor_reg = ctx.lookup_or_builtin(kind)?; - let ctor = ctx.alloc_reg(); - ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(ctor), Operand::Reg(ctor_reg), Operand::None)); - let msg_reg = ctx.alloc_reg(); - let msg_idx = ctx.add_constant(Constant::String(msg.to_string())); - ctx.inst(Inst::load_const(Operand::Reg(msg_reg), msg_idx)); - let exc_reg = ctx.alloc_reg(); - ctx.inst(Inst::new_expression(Operand::Reg(exc_reg), Operand::Reg(ctor), Operand::Reg(msg_reg), 1)); - ctx.inst(Inst::new(OpCode::THROW, Operand::Reg(exc_reg), Operand::None, Operand::None)); - let dummy = ctx.alloc_reg(); - let undef_idx = ctx.add_constant(Constant::Undefined); - ctx.inst(Inst::load_const(Operand::Reg(dummy), undef_idx)); - Ok(dummy) - } - - /// 生成运行时抛 ReferenceError 的指令序列(TDZ 访问专用,语义见 [`emit_throw_error`])。 - pub(crate) fn emit_tdz_throw(&self, msg: &str, ctx: &mut CompileCtx) -> Result { - self.emit_throw_error("ReferenceError", msg, ctx) - } - - /// 赋值目标 TDZ 检查:未初始化绑定在赋值引用解析时抛 ReferenceError。 - /// 须在 RHS 求值之前调用(规范:赋值 LHS 的 ResolveBinding 先于 RHS 副作用)。 - /// - /// # 副作用 - /// - TDZ 命中时发射 THROW 指令序列,其后指令不可达但保持寄存器良定义。 - pub(crate) fn emit_identifier_tdz_guard(&self, name: &str, ctx: &mut CompileCtx) -> Result<(), String> { - if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) { - if !binding.initialized { - let _ = self.emit_tdz_throw(&format!("Cannot access '{name}' before initialization"), ctx)?; - } - } - Ok(()) - } - - /// const 写检查:已初始化的 const 绑定再赋值编译期抛 TypeError(与槽值无关)。 - /// 简单赋值在 RHS 求值之后、复合/更新在读旧值之前调用;解构赋值在写目标时调用。 - /// - /// # 副作用 - /// - const 命中时发射 THROW 指令序列,其后写指令不可达但保持寄存器良定义。 - pub(crate) fn emit_const_write_guard(&self, name: &str, ctx: &mut CompileCtx) -> Result<(), String> { - if ctx.lookup_const_flag(name) { - let _ = self.emit_throw_error("TypeError", "Assignment to constant variable", ctx)?; - } - Ok(()) - } - /// 遍历解构 pattern 收集内嵌默认值表达式(AssignmentPattern.right)与 /// 计算键表达式(`{[k]: a}` 的键,运行时求值)——二者都会在参数绑定期被 /// 内部闭包引用,须一并纳入捕获分析。 diff --git a/crates/oxide_emit/src/errors.rs b/crates/oxide_emit/src/errors.rs new file mode 100644 index 00000000..4c08e736 --- /dev/null +++ b/crates/oxide_emit/src/errors.rs @@ -0,0 +1,69 @@ +//! 错误构造/传播四守卫:运行时抛错指令序列与 TDZ / const 写检查。 +//! +//! 均为 `Emitter` 方法,与各语法域 emit 族共用 `CompileCtx` 编译上下文。 + +use crate::compile_ctx::CompileCtx; +use crate::Emitter; +use oxide_bytecode::module::Constant; +use oxide_bytecode::opcode::OpCode; +use oxide_ir::inst::Inst; +use oxide_ir::operand::Operand; + +impl Emitter { + /// 生成运行时抛 `kind` 类型错误的指令序列,返回一个未定义 dummy 寄存器 + /// 保证 THROW 后不可达控制流的寄存器良定义。 + /// + /// # 步骤 + /// 1. 取全局错误构造器并 LOAD。 + /// 2. 加载错误消息常量,`new {kind}(msg)` 构造错误对象。 + /// 3. THROW 抛出;尾接 dummy 值保持后续读引用有确定寄存器。 + /// + /// # 边界与前提 + /// - `kind` 必须是已注册的全局构造器名(如 "ReferenceError"/"TypeError")。 + pub(crate) fn emit_throw_error(&self, kind: &str, msg: &str, ctx: &mut CompileCtx) -> Result { + let ctor_reg = ctx.lookup_or_builtin(kind)?; + let ctor = ctx.alloc_reg(); + ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(ctor), Operand::Reg(ctor_reg), Operand::None)); + let msg_reg = ctx.alloc_reg(); + let msg_idx = ctx.add_constant(Constant::String(msg.to_string())); + ctx.inst(Inst::load_const(Operand::Reg(msg_reg), msg_idx)); + let exc_reg = ctx.alloc_reg(); + ctx.inst(Inst::new_expression(Operand::Reg(exc_reg), Operand::Reg(ctor), Operand::Reg(msg_reg), 1)); + ctx.inst(Inst::new(OpCode::THROW, Operand::Reg(exc_reg), Operand::None, Operand::None)); + let dummy = ctx.alloc_reg(); + let undef_idx = ctx.add_constant(Constant::Undefined); + ctx.inst(Inst::load_const(Operand::Reg(dummy), undef_idx)); + Ok(dummy) + } + + /// 生成运行时抛 ReferenceError 的指令序列(TDZ 访问专用,语义见 [`emit_throw_error`])。 + pub(crate) fn emit_tdz_throw(&self, msg: &str, ctx: &mut CompileCtx) -> Result { + self.emit_throw_error("ReferenceError", msg, ctx) + } + + /// 赋值目标 TDZ 检查:未初始化绑定在赋值引用解析时抛 ReferenceError。 + /// 须在 RHS 求值之前调用(规范:赋值 LHS 的 ResolveBinding 先于 RHS 副作用)。 + /// + /// # 副作用 + /// - TDZ 命中时发射 THROW 指令序列,其后指令不可达但保持寄存器良定义。 + pub(crate) fn emit_identifier_tdz_guard(&self, name: &str, ctx: &mut CompileCtx) -> Result<(), String> { + if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) { + if !binding.initialized { + let _ = self.emit_tdz_throw(&format!("Cannot access '{name}' before initialization"), ctx)?; + } + } + Ok(()) + } + + /// const 写检查:已初始化的 const 绑定再赋值编译期抛 TypeError(与槽值无关)。 + /// 简单赋值在 RHS 求值之后、复合/更新在读旧值之前调用;解构赋值在写目标时调用。 + /// + /// # 副作用 + /// - const 命中时发射 THROW 指令序列,其后写指令不可达但保持寄存器良定义。 + pub(crate) fn emit_const_write_guard(&self, name: &str, ctx: &mut CompileCtx) -> Result<(), String> { + if ctx.lookup_const_flag(name) { + let _ = self.emit_throw_error("TypeError", "Assignment to constant variable", ctx)?; + } + Ok(()) + } +} diff --git a/crates/oxide_emit/src/lib.rs b/crates/oxide_emit/src/lib.rs index 8d4723e4..26e3bd09 100644 --- a/crates/oxide_emit/src/lib.rs +++ b/crates/oxide_emit/src/lib.rs @@ -11,6 +11,7 @@ mod compile_ctx; pub mod emit; pub mod emit_ctx; mod emit_log; +mod errors; pub mod expr; pub mod module; pub mod prepass;