diff --git a/crates/oxide_bytecode/src/opcode.rs b/crates/oxide_bytecode/src/opcode.rs index 64fa3368..e6e29643 100644 --- a/crates/oxide_bytecode/src/opcode.rs +++ b/crates/oxide_bytecode/src/opcode.rs @@ -91,6 +91,7 @@ pub enum OpCode { SET_HOME_OBJECT = 0x47, DEFINE_ACCESSOR = 0x48, CREATE_CLOSURE = 0x4A, + CREATE_REGEXP = 0x4B, // ── Object Property (0x50-0x5F) ── IC_GET_PROP = 0x50, @@ -240,6 +241,7 @@ impl TryFrom for OpCode { 0x47 => Ok(OpCode::SET_HOME_OBJECT), 0x48 => Ok(OpCode::DEFINE_ACCESSOR), 0x4A => Ok(OpCode::CREATE_CLOSURE), + 0x4B => Ok(OpCode::CREATE_REGEXP), 0x50 => Ok(OpCode::IC_GET_PROP), 0x51 => Ok(OpCode::IC_SET_PROP), 0x52 => Ok(OpCode::GET_PROP), @@ -360,6 +362,7 @@ impl fmt::Display for OpCode { OpCode::SET_HOME_OBJECT => "SET_HOME_OBJECT", OpCode::DEFINE_ACCESSOR => "DEFINE_ACCESSOR", OpCode::CREATE_CLOSURE => "CREATE_CLOSURE", + OpCode::CREATE_REGEXP => "CREATE_REGEXP", OpCode::IC_GET_PROP => "IC_GET_PROP", OpCode::IC_SET_PROP => "IC_SET_PROP", OpCode::GET_PROP => "GET_PROP", diff --git a/crates/oxide_compiler/src/counter/expr/literal.rs b/crates/oxide_compiler/src/counter/expr/literal.rs index e3234428..2ba0caf5 100644 --- a/crates/oxide_compiler/src/counter/expr/literal.rs +++ b/crates/oxide_compiler/src/counter/expr/literal.rs @@ -18,7 +18,11 @@ impl Compiler { } pub(in crate::counter) fn count_regexp_literal(&self, ctx: &mut CompileCtx) { - ctx.alloc_reg(); + ctx.alloc_reg(); // pattern reg (LOAD_CONST) + ctx.projected_pc += 1; + ctx.alloc_reg(); // flags reg (LOAD_CONST) + ctx.projected_pc += 1; + ctx.alloc_reg(); // result reg (CREATE_REGEXP) ctx.projected_pc += 1; } diff --git a/crates/oxide_compiler/src/emitter/expr/literal.rs b/crates/oxide_compiler/src/emitter/expr/literal.rs index 7d25b98d..4f2e0560 100644 --- a/crates/oxide_compiler/src/emitter/expr/literal.rs +++ b/crates/oxide_compiler/src/emitter/expr/literal.rs @@ -68,11 +68,16 @@ impl Compiler { let raw_str = raw.to_string(); if raw_str.len() >= 2 && raw_str.starts_with('/') { let last_slash = raw_str.rfind('/').unwrap_or(raw_str.len() - 1); - let pattern = &raw_str[1..last_slash]; - let flags = &raw_str[last_slash + 1..]; - let ci = ctx.add_constant(Constant::RegExp(pattern.to_string(), flags.to_string())); + let pattern = raw_str[1..last_slash].to_string(); + let flags = raw_str[last_slash + 1..].to_string(); + let pat_ci = ctx.add_constant(Constant::String(pattern)); + let pat_reg = ctx.alloc_reg(); + ctx.emit_load_const(pat_reg, pat_ci); + let flags_ci = ctx.add_constant(Constant::String(flags)); + let flags_reg = ctx.alloc_reg(); + ctx.emit_load_const(flags_reg, flags_ci); let r = ctx.alloc_reg(); - ctx.emit_load_const(r, ci); + ctx.emit(opcode::encode(OpCode::CREATE_REGEXP, r, pat_reg, flags_reg)); Ok(r) } else { Err(format!("unsupported regexp literal: {:?}", lit)) diff --git a/crates/oxide_vm/src/vm.rs b/crates/oxide_vm/src/vm.rs index fe1ec94f..462ba899 100644 --- a/crates/oxide_vm/src/vm.rs +++ b/crates/oxide_vm/src/vm.rs @@ -752,6 +752,37 @@ impl Vm { ); self.regs[rd] = result; } + OpCode::CREATE_REGEXP => { + let pat_val = self.regs[a]; + let flags_val = self.regs[b]; + let ctor_ptr = + self.session.builtin_world().regexp_constructor.as_ptr() as *mut JsObject; + let ctor = unsafe { &*ctor_ptr }; + let Some(native_fn) = ctor.native_fn() else { + self.raise_error_kind("TypeError", "RegExp constructor unavailable")?; + return Ok(JsValue::undefined()); + }; + let saved_0 = self.regs[0]; + let saved_1 = self.regs[1]; + let saved_2 = self.regs[2]; + self.regs[0] = JsValue::undefined(); + self.regs[1] = pat_val; + self.regs[2] = flags_val; + let func = unsafe { crate::vm::native_fn_ptr_to_fn(native_fn) }; + let result = match func(self, &[0, 1, 2]) { + crate::native::NativeResult::Ok(v) => v, + crate::native::NativeResult::Err(e) => { + return Err(self.error_message_text("TypeError", &self.error_text(e))); + } + crate::native::NativeResult::TailCall { .. } => { + return Err(self.error_message_text("TypeError", "unexpected tail call")); + } + }; + self.regs[0] = saved_0; + self.regs[1] = saved_1; + self.regs[2] = saved_2; + self.regs[rd] = result; + } OpCode::ADD => { self.dispatch_add(rd, a, b)?;