feat: 支持 RegExpr 与 Symbol 部分方法

This commit is contained in:
爱特每羊队
2026-06-08 10:36:39 +08:00
parent ffdb53dac7
commit 06acc7e34a
19 changed files with 1057 additions and 45 deletions
@@ -0,0 +1,56 @@
use std::sync::Arc;
use oxide_kernel::bind_method;
use oxide_kernel::kernel::OxideKernel;
use oxide_types::object::JsObject;
use crate::bind_constructor_hash;
pub fn bind_regexp(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let ctor_ptr = kernel.builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let ctor = unsafe { &mut *ctor_ptr };
let proto_ptr = kernel.builtin_world().regexp_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &mut *proto_ptr };
let sf = kernel.string_forge().as_ref();
let sh = kernel.shape_forge().as_ref();
ctor.set_native_fn(Some(crate::builtins::regexp::regexp_constructor as *const ()));
ctor.set_native_arg_count(2);
bind_method!(
kernel.builtin_world(),
proto,
sf,
sh,
"exec",
crate::builtins::regexp::regexp_exec,
1
);
bind_method!(
kernel.builtin_world(),
proto,
sf,
sh,
"test",
crate::builtins::regexp::regexp_test,
1
);
bind_method!(
kernel.builtin_world(),
proto,
sf,
sh,
"toString",
crate::builtins::regexp::regexp_to_string,
0
);
bind_constructor_hash!(
kernel,
global,
"RegExp",
ctor_ptr,
crate::builtins::regexp::regexp_constructor,
2
);
}
@@ -0,0 +1,70 @@
use std::sync::Arc;
use oxide_kernel::bind_method;
use oxide_kernel::kernel::OxideKernel;
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use crate::bind_constructor_hash;
pub fn bind_symbol(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let ctor_ptr = kernel.builtin_world().symbol_constructor.as_ptr() as *mut JsObject;
let ctor = unsafe { &mut *ctor_ptr };
let proto_ptr = kernel.builtin_world().symbol_proto.as_ptr() as *mut JsObject;
let proto = unsafe { &mut *proto_ptr };
let sf = kernel.string_forge().as_ref();
let sh = kernel.shape_forge().as_ref();
bind_method!(
kernel.builtin_world(),
proto,
sf,
sh,
"toString",
crate::builtins::symbol::symbol_to_string,
0
);
let sym_match_val = JsValue::from_js_object(
kernel.builtin_world().sym_match.as_ptr() as *mut JsObject,
);
bind_well_known_symbol(kernel, ctor, sf, sh, "match", sym_match_val);
let sym_replace_val = JsValue::from_js_object(
kernel.builtin_world().sym_replace.as_ptr() as *mut JsObject,
);
bind_well_known_symbol(kernel, ctor, sf, sh, "replace", sym_replace_val);
let sym_search_val = JsValue::from_js_object(
kernel.builtin_world().sym_search.as_ptr() as *mut JsObject,
);
bind_well_known_symbol(kernel, ctor, sf, sh, "search", sym_search_val);
let sym_split_val = JsValue::from_js_object(
kernel.builtin_world().sym_split.as_ptr() as *mut JsObject,
);
bind_well_known_symbol(kernel, ctor, sf, sh, "split", sym_split_val);
bind_constructor_hash!(
kernel,
global,
"Symbol",
ctor_ptr,
crate::builtins::symbol::symbol_constructor,
1
);
}
fn bind_well_known_symbol(
kernel: &Arc<OxideKernel>,
ctor: &mut JsObject,
_sf: &oxide_kernel::string_forge::StringForge,
_sh: &oxide_kernel::shape_forge::ShapeForge,
name: &str,
val: JsValue,
) {
let si = kernel.string_forge().intern(name).0;
let shape_id = kernel.shape_forge().make_shape(ctor.shape_id(), si);
ctor.set_shape_id(shape_id);
ctor.ensure_hash_props().push(Box::new(val));
}
+4
View File
@@ -8,8 +8,10 @@ pub mod bind_map;
pub mod bind_math;
pub mod bind_number;
pub mod bind_object;
pub mod bind_regexp;
pub mod bind_set;
pub mod bind_string;
pub mod bind_symbol;
use std::sync::Arc;
@@ -60,4 +62,6 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_map::bind_map(kernel, global);
bind_boolean::bind_boolean(kernel, global);
bind_function::bind_function(kernel);
bind_regexp::bind_regexp(kernel, global);
bind_symbol::bind_symbol(kernel, global);
}
+2
View File
@@ -9,5 +9,7 @@ pub mod map;
pub mod math;
pub mod number;
pub mod object;
pub mod regexp;
pub mod set;
pub mod string;
pub mod symbol;
+261
View File
@@ -0,0 +1,261 @@
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use crate::coercion;
use crate::native::NativeResult;
use crate::vm::Vm;
fn get_regexp_ptr(vm: &Vm, args: &[u8]) -> Result<*mut JsObject, JsValue> {
let this_val = vm.reg(args[0]);
if !this_val.is_object() {
return Err(JsValue::string(
vm.kernel()
.string_forge()
.intern("TypeError: RegExp.prototype method called on non-object")
.0,
0,
));
}
let ptr = this_val.as_js_object_ptr();
if ptr.is_null() {
return Err(JsValue::string(
vm.kernel()
.string_forge()
.intern("TypeError: null object")
.0,
0,
));
}
Ok(ptr)
}
fn parse_flags(flags: &str) -> (bool, bool, bool) {
let mut global = false;
let mut ignore_case = false;
let mut multi_line = false;
for c in flags.chars() {
match c {
'g' => global = true,
'i' => ignore_case = true,
'm' => multi_line = true,
_ => {}
}
}
(global, ignore_case, multi_line)
}
fn set_prop(obj: &mut JsObject, name: &str, val: JsValue, vm: &Vm) {
let si = vm.kernel().string_forge().intern(name).0;
let shape_id = vm.kernel().shape_forge().make_shape(obj.shape_id(), si);
obj.set_shape_id(shape_id);
obj.ensure_hash_props().push(Box::new(val));
}
fn get_prop(obj: &JsObject, idx: usize) -> JsValue {
obj.hash_props_vec()
.and_then(|v| v.get(idx))
.map(|b| **b)
.unwrap_or(JsValue::undefined())
}
fn set_prop_at(obj: *mut JsObject, idx: usize, val: JsValue) {
unsafe {
let re = &mut *obj;
if let Some(vec) = re.hash_props_vec() {
let ptr = vec.as_ptr() as *mut Box<JsValue>;
let v = &mut *ptr.add(idx);
**v = val;
}
}
}
pub fn regexp_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let (pattern, flags) = if args.len() < 2 {
(String::new(), String::new())
} else if args.len() < 3 {
let pat = coercion::to_string(vm.kernel().string_forge().as_ref(), vm.reg(args[1]));
(pat, String::new())
} else {
let pat = coercion::to_string(vm.kernel().string_forge().as_ref(), vm.reg(args[1]));
let fl = coercion::to_string(vm.kernel().string_forge().as_ref(), vm.reg(args[2]));
(pat, fl)
};
let (global, ignore_case, multi_line) = parse_flags(&flags);
let mut obj = JsObject::new_empty(
EMPTY_SHAPE_ID,
JsValue::from_js_object(
vm.kernel().builtin_world().regexp_proto.as_ptr() as *mut JsObject,
),
);
let compiled = regex::RegexBuilder::new(&pattern)
.case_insensitive(ignore_case)
.multi_line(multi_line)
.build();
match compiled {
Ok(re) => {
let re_ptr = Box::into_raw(Box::new(re));
obj.set_native_fn(Some(re_ptr as *const ()));
}
Err(e) => {
let msg = format!("SyntaxError: Invalid regular expression: {}", e);
return Err(JsValue::string(
vm.kernel().string_forge().intern(&msg).0,
0,
));
}
}
set_prop(&mut obj, "lastIndex", JsValue::int(0), vm);
set_prop(&mut obj, "source", vm.intern(&pattern), vm);
set_prop(&mut obj, "flags", vm.intern(&flags), vm);
set_prop(&mut obj, "global", JsValue::bool(global), vm);
set_prop(&mut obj, "ignoreCase", JsValue::bool(ignore_case), vm);
set_prop(&mut obj, "multiline", JsValue::bool(multi_line), vm);
set_prop(&mut obj, "dotAll", JsValue::bool(false), vm);
set_prop(&mut obj, "sticky", JsValue::bool(false), vm);
set_prop(&mut obj, "unicode", JsValue::bool(false), vm);
let obj_ptr = vm.epoch().alloc(obj);
Ok(JsValue::from_js_object(obj_ptr))
}
pub fn regexp_test(vm: &mut Vm, args: &[u8]) -> NativeResult {
let re_ptr = get_regexp_ptr(vm, args)?;
let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() {
None => {
return Err(JsValue::string(
vm.kernel()
.string_forge()
.intern("TypeError: invalid RegExp")
.0,
0,
));
}
Some(p) => p,
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let haystack = coercion::to_string(
vm.kernel().string_forge().as_ref(),
vm.reg(if args.len() > 1 { args[1] } else { args[0] }),
);
let last_index =
coercion::to_number(get_prop(re, 0), vm.kernel().string_forge().as_ref()) as usize;
let is_global = get_prop(re, 3).as_bool();
if is_global {
let result = regex.find_at(&haystack, last_index).is_some();
Ok(JsValue::bool(result))
} else {
Ok(JsValue::bool(regex.is_match(&haystack)))
}
}
pub fn regexp_exec(vm: &mut Vm, args: &[u8]) -> NativeResult {
let re_ptr = get_regexp_ptr(vm, args)?;
let fn_ptr = {
let re = unsafe { &*re_ptr };
match re.native_fn() {
None => {
return Err(JsValue::string(
vm.kernel()
.string_forge()
.intern("TypeError: invalid RegExp")
.0,
0,
));
}
Some(p) => p,
}
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let haystack = coercion::to_string(
vm.kernel().string_forge().as_ref(),
vm.reg(if args.len() > 1 { args[1] } else { args[0] }),
);
let (last_index, is_global) = {
let re = unsafe { &*re_ptr };
let li =
coercion::to_number(get_prop(re, 0), vm.kernel().string_forge().as_ref()) as usize;
let g = get_prop(re, 3).as_bool();
(li, g)
};
let match_result = if is_global {
if last_index > haystack.len() {
return Ok(JsValue::null());
}
regex.find_at(&haystack, last_index)
} else {
regex.find(&haystack)
};
if let Some(m) = match_result {
let mut match_obj = JsObject::new_empty(
EMPTY_SHAPE_ID,
JsValue::from_js_object(
vm.kernel().builtin_world().array_proto.as_ptr() as *mut JsObject,
),
);
let full_match = &haystack[m.start()..m.end()];
let full_si = vm.kernel().string_forge().intern(full_match).0;
match_obj
.ensure_hash_props()
.push(Box::new(JsValue::string(full_si, 0)));
let captures = regex.captures(&haystack[m.start()..m.end()]);
if let Some(caps) = &captures {
for i in 1..caps.len() {
let cap_str = caps.get(i).map(|cm| cm.as_str()).unwrap_or("");
let si = vm.kernel().string_forge().intern(cap_str).0;
match_obj
.ensure_hash_props()
.push(Box::new(JsValue::string(si, 0)));
}
}
set_prop(&mut match_obj, "index", JsValue::int(m.start() as i32), vm);
let haystack_val = vm.intern(&haystack);
set_prop(&mut match_obj, "input", haystack_val, vm);
set_prop(&mut match_obj, "groups", JsValue::undefined(), vm);
if is_global {
set_prop_at(re_ptr, 0, JsValue::int(m.end() as i32));
}
let obj_ptr = vm.epoch().alloc(match_obj);
Ok(JsValue::from_js_object(obj_ptr))
} else {
if is_global {
set_prop_at(re_ptr, 0, JsValue::int(0));
}
Ok(JsValue::null())
}
}
pub fn regexp_to_string(vm: &mut Vm, args: &[u8]) -> NativeResult {
let re_ptr = get_regexp_ptr(vm, args)?;
let re = unsafe { &*re_ptr };
let source = {
let val = get_prop(re, 1);
vm.lookup_str(val).unwrap_or_default()
};
let flags = {
let val = get_prop(re, 2);
vm.lookup_str(val).unwrap_or_default()
};
let result = format!("/{}/{}", source, flags);
let si = vm.kernel().string_forge().intern(&result).0;
Ok(JsValue::string(si, 0))
}
+91 -42
View File
@@ -6,7 +6,6 @@ use crate::coercion;
use crate::native::NativeResult;
use crate::vm::Vm;
use memchr::memchr;
use regex::Regex;
fn this_string(vm: &Vm, args: &[u8]) -> String {
coercion::to_string(vm.kernel().string_forge().as_ref(), vm.reg(args[0]))
@@ -35,6 +34,27 @@ fn as_string(vm: &Vm, val: JsValue) -> String {
coercion::to_string(vm.kernel().string_forge().as_ref(), val)
}
fn is_regexp_obj(val: JsValue, vm: &Vm) -> bool {
if !val.is_object() {
return false;
}
let ptr = val.as_js_object_ptr();
if ptr.is_null() {
return false;
}
let obj = unsafe { &*ptr };
let proto = obj.proto();
if !proto.is_object() {
return false;
}
let proto_ptr = proto.as_js_object_ptr();
if proto_ptr.is_null() {
return false;
}
let rp = vm.kernel().builtin_world().regexp_proto.as_ptr() as *mut JsObject;
std::ptr::eq(proto_ptr, rp)
}
pub fn string_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
let s = this_string(vm, args);
if args.len() < 2 {
@@ -291,27 +311,35 @@ pub fn string_split(vm: &mut Vm, args: &[u8]) -> NativeResult {
let parts = vec![s.clone()];
return Ok(make_string_array(vm, &parts));
}
let sep = as_string(vm, vm.reg(args[1]));
let sep_val = vm.reg(args[1]);
let limit = if args.len() > 2 {
coercion::to_number(vm.reg(args[2]), vm.kernel().string_forge().as_ref()) as usize
} else {
usize::MAX
};
let parts: Vec<String>;
if sep.starts_with('/') && sep.len() > 2 && sep.ends_with('/') {
let pattern = &sep[1..sep.len() - 1];
if let Ok(re) = Regex::new(pattern) {
let raw: Vec<&str> = re.split(&s).collect();
parts = raw.iter().map(|p| p.to_string()).take(limit).collect();
} else {
parts = vec![s.clone()];
}
} else if sep.is_empty() {
parts = s.chars().map(|c| c.to_string()).take(limit).collect();
} else {
parts = s.split(&sep).map(|p| p.to_string()).take(limit).collect();
if is_regexp_obj(sep_val, vm) {
let re_ptr = sep_val.as_js_object_ptr();
let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() {
Some(p) => p,
None => {
let parts = vec![s.clone()];
return Ok(make_string_array(vm, &parts));
}
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let raw: Vec<&str> = regex.split(&s).collect();
let parts: Vec<String> = raw.iter().map(|p| p.to_string()).take(limit).collect();
return Ok(make_string_array(vm, &parts));
}
let sep = as_string(vm, sep_val);
let parts: Vec<String> = if sep.is_empty() {
s.chars().map(|c| c.to_string()).take(limit).collect()
} else {
s.split(&sep).map(|p| p.to_string()).take(limit).collect()
};
Ok(make_string_array(vm, &parts))
}
@@ -320,23 +348,27 @@ pub fn string_replace(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return Ok(vm.intern(&s));
}
let pattern = as_string(vm, vm.reg(args[1]));
let pattern_val = vm.reg(args[1]);
let replacement = if args.len() > 2 {
as_string(vm, vm.reg(args[2]))
} else {
String::new()
};
let result = if pattern.starts_with('/') && pattern.len() > 2 && pattern.ends_with('/') {
let pat = &pattern[1..pattern.len() - 1];
if let Ok(re) = Regex::new(pat) {
re.replace_all(&s, replacement.as_str()).to_string()
} else {
s.clone()
}
} else {
s.replacen(&pattern, &replacement, 1)
};
if is_regexp_obj(pattern_val, vm) {
let re_ptr = pattern_val.as_js_object_ptr();
let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() {
Some(p) => p,
None => return Ok(vm.intern(&s)),
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let result = regex.replace_all(&s, replacement.as_str()).to_string();
return Ok(vm.intern(&result));
}
let pattern = as_string(vm, pattern_val);
let result = s.replacen(&pattern, &replacement, 1);
Ok(vm.intern(&result))
}
@@ -345,14 +377,22 @@ pub fn string_match_fn(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return Ok(JsValue::undefined());
}
let pattern = as_string(vm, vm.reg(args[1]));
if pattern.starts_with('/') && pattern.len() > 2 && pattern.ends_with('/') {
let pat = &pattern[1..pattern.len() - 1];
if let Ok(re) = Regex::new(pat) {
let matches: Vec<String> = re.find_iter(&s).map(|m| m.as_str().to_string()).collect();
return Ok(make_string_array(vm, &matches));
}
} else if let Some(pos) = s.find(&pattern) {
let pattern_val = vm.reg(args[1]);
if is_regexp_obj(pattern_val, vm) {
let re_ptr = pattern_val.as_js_object_ptr();
let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() {
Some(p) => p,
None => return Ok(JsValue::undefined()),
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
let matches: Vec<String> = regex.find_iter(&s).map(|m| m.as_str().to_string()).collect();
return Ok(make_string_array(vm, &matches));
}
let pattern = as_string(vm, pattern_val);
if let Some(pos) = s.find(&pattern) {
return Ok(make_string_array(
vm,
&[s[pos..pos + pattern.len()].to_string()],
@@ -366,15 +406,24 @@ pub fn string_search(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return Ok(JsValue::int(-1));
}
let pattern = as_string(vm, vm.reg(args[1]));
if pattern.starts_with('/') && pattern.len() > 2 && pattern.ends_with('/') {
let pat = &pattern[1..pattern.len() - 1];
if let Ok(re) = Regex::new(pat) {
if let Some(m) = re.find(&s) {
return Ok(JsValue::int(m.start() as i32));
}
let pattern_val = vm.reg(args[1]);
if is_regexp_obj(pattern_val, vm) {
let re_ptr = pattern_val.as_js_object_ptr();
let re = unsafe { &*re_ptr };
let fn_ptr = match re.native_fn() {
Some(p) => p,
None => return Ok(JsValue::int(-1)),
};
let regex = unsafe { &*(fn_ptr as *const regex::Regex) };
if let Some(m) = regex.find(&s) {
return Ok(JsValue::int(m.start() as i32));
}
} else if let Some(pos) = s.find(&pattern) {
return Ok(JsValue::int(-1));
}
let pattern = as_string(vm, pattern_val);
if let Some(pos) = s.find(&pattern) {
return Ok(JsValue::int(pos as i32));
}
Ok(JsValue::int(-1))
+66
View File
@@ -0,0 +1,66 @@
use oxide_types::object::JsObject;
use oxide_types::value::JsValue;
use crate::coercion;
use crate::native::NativeResult;
use crate::vm::Vm;
pub fn symbol_constructor(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
if this_val.is_object() {
let ptr = this_val.as_js_object_ptr();
if !ptr.is_null() {
let obj = unsafe { &*ptr };
let proto = obj.proto();
if proto.is_object() {
let proto_ptr = proto.as_js_object_ptr();
if !proto_ptr.is_null() {
let sp = vm.kernel().builtin_world().symbol_proto.as_ptr() as *mut JsObject;
if std::ptr::eq(proto_ptr, sp) {
return Err(JsValue::string(
vm.kernel()
.string_forge()
.intern("TypeError: Symbol is not a constructor")
.0,
0,
));
}
}
}
}
}
let description = if args.len() > 1 {
coercion::to_string(vm.kernel().string_forge().as_ref(), vm.reg(args[1]))
} else {
String::new()
};
vm.symbol_counter = vm.symbol_counter.wrapping_add(1);
let idx = vm.symbol_descriptions.len() as u32;
vm.symbol_descriptions.push(description);
Ok(JsValue::symbol(idx))
}
pub fn symbol_to_string(vm: &mut Vm, args: &[u8]) -> NativeResult {
let this_val = vm.reg(args[0]);
if !this_val.is_symbol() {
return Err(JsValue::string(
vm.kernel()
.string_forge()
.intern("TypeError: Symbol.prototype.toString requires a Symbol")
.0,
0,
));
}
let idx = this_val.as_symbol_index();
let desc = vm
.symbol_descriptions
.get(idx as usize)
.cloned()
.unwrap_or_default();
let result = format!("Symbol({})", desc);
let si = vm.kernel().string_forge().intern(&result).0;
Ok(JsValue::string(si, 0))
}
+9
View File
@@ -101,6 +101,9 @@ pub fn to_boolean(val: JsValue, string_forge: &StringForge) -> bool {
if val.is_object() {
return true;
}
if val.is_symbol() {
return true;
}
false
}
@@ -172,6 +175,9 @@ pub fn strict_eq(lhs: JsValue, rhs: JsValue) -> bool {
if lhs.is_object() && rhs.is_object() {
return lhs.as_ptr() == rhs.as_ptr();
}
if lhs.is_symbol() && rhs.is_symbol() {
return lhs.as_symbol_index() == rhs.as_symbol_index();
}
false
}
@@ -260,6 +266,9 @@ pub fn same_value(lhs: JsValue, rhs: JsValue) -> bool {
if lhs.is_object() && rhs.is_object() {
return lhs.as_ptr() == rhs.as_ptr();
}
if lhs.is_symbol() && rhs.is_symbol() {
return lhs.as_symbol_index() == rhs.as_symbol_index();
}
false
}
+2
View File
@@ -25,6 +25,8 @@ impl Vm {
"number"
} else if val.is_string() {
"string"
} else if val.is_symbol() {
"symbol"
} else if val.is_object() {
let obj = unsafe { &*val.as_js_object_ptr() };
if obj.is_function() {
+38 -2
View File
@@ -172,6 +172,8 @@ pub struct Vm {
pub(crate) exception_value: Option<JsValue>,
pub(crate) pending_exception: Option<JsValue>,
pub(crate) pending_error_kind: Option<&'static str>,
pub(crate) symbol_counter: u32,
pub(crate) symbol_descriptions: Vec<String>,
}
impl Vm {
@@ -199,10 +201,13 @@ impl Vm {
exception_value: None,
pending_exception: None,
pending_error_kind: None,
symbol_counter: 0,
symbol_descriptions: Vec::new(),
}
}
pub fn with_kernel(kernel: Arc<OxideKernel>) -> Self {
let obj_proto = P::clone(&kernel.builtin_world().object_proto);
Self {
regs: [JsValue::undefined(); 256],
pc: 0,
@@ -210,10 +215,10 @@ impl Vm {
constants: Vec::new(),
frames: Vec::with_capacity(128),
for_in_iters: Vec::new(),
kernel: Arc::clone(&kernel),
kernel,
interned_strings: Vec::new(),
epoch: Epoch::new(),
object_prototype: P::clone(&kernel.builtin_world().object_proto),
object_prototype: obj_proto,
math_rng_state: 0,
sub_modules: Vec::new(),
sub_module_constants: Vec::new(),
@@ -223,6 +228,8 @@ impl Vm {
exception_value: None,
pending_exception: None,
pending_error_kind: None,
symbol_counter: 0,
symbol_descriptions: Vec::new(),
}
}
@@ -308,6 +315,34 @@ impl Vm {
Constant::Null => JsValue::null(),
Constant::Undefined => JsValue::undefined(),
Constant::BytecodeFunc(idx) => self.create_function_object(*idx),
Constant::RegExp(pattern, flags) => {
let pat_si = self.kernel.string_forge().intern(pattern).0;
let flags_si = self.kernel.string_forge().intern(flags).0;
let pat_val = JsValue::string(pat_si, 0);
let flags_val = JsValue::string(flags_si, 0);
let native_fn = self.kernel.builtin_world().regexp_constructor.as_ptr() as *mut JsObject;
let ctor = unsafe { &*native_fn };
let ctor_fn = ctor.native_fn();
if ctor_fn.is_none() {
return 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: crate::native::NativeFn = unsafe { std::mem::transmute(ctor_fn.unwrap()) };
let result = func(self, &[0, 1, 2]);
self.regs[0] = saved_0;
self.regs[1] = saved_1;
self.regs[2] = saved_2;
match result {
Ok(val) => val,
Err(_) => JsValue::undefined(),
}
},
})
.collect()
}
@@ -706,6 +741,7 @@ impl Vm {
Constant::BytecodeFunc(idx) => {
self.create_function_object(*idx)
}
Constant::RegExp(_, _) => JsValue::undefined(),
})
.collect();