diff --git a/crates/oxide_emit/Cargo.toml b/crates/oxide_emit/Cargo.toml index 865f846d..503d41e6 100644 --- a/crates/oxide_emit/Cargo.toml +++ b/crates/oxide_emit/Cargo.toml @@ -10,3 +10,4 @@ description = "OxideJS - AST to IR emit pass" oxide_parser = { path = "../oxide_parser" } oxide_bytecode = { path = "../oxide_bytecode" } oxide_ir = { path = "../oxide_ir" } +regex.workspace = true diff --git a/crates/oxide_emit/src/expr/literal.rs b/crates/oxide_emit/src/expr/literal.rs index ba11ae48..87c7f66f 100644 --- a/crates/oxide_emit/src/expr/literal.rs +++ b/crates/oxide_emit/src/expr/literal.rs @@ -67,6 +67,17 @@ impl Emitter { let last_slash = raw_str.rfind('/').unwrap_or(raw_str.len() - 1); let pattern = raw_str[1..last_slash].to_string(); let flags = raw_str[last_slash + 1..].to_string(); + // 非法正则字面量须在编译期报 SyntaxError(负面测试期望编译失败)。 + if regex::RegexBuilder::new(&pattern) + .case_insensitive(flags.contains('i')) + .multi_line(flags.contains('m')) + .build() + .is_err() + { + return Err(format!( + "SyntaxError: Invalid regular expression: /{pattern}/{flags}" + )); + } let pat_ci = ctx.add_constant(Constant::String(pattern)); let pat_reg = ctx.alloc_reg(); ctx.inst(Inst::load_const(Operand::Reg(pat_reg), pat_ci)); diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index e023d0c6..1d5a3064 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -343,7 +343,10 @@ impl Vm { let result = match func(self, &[0, 1, 2]) { NativeResult::Ok(v) => v, NativeResult::Err(e) => { - return Err(self.error_message_text("TypeError", &self.error_text(e))); + // 保留原始错误对象与类型(非法正则字面量须抛 SyntaxError,非 TypeError)。 + self.exception_value = Some(e); + self.pending_error_kind = Some(self.thrown_error_kind(e)); + return self.unwind().map(|_| None); } NativeResult::TailCall { .. } => { return Err(self.error_message_text("TypeError", "unexpected tail call"));