mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 支持 Object/Array/String 成员方法
This commit is contained in:
Generated
+25
@@ -956,6 +956,7 @@ dependencies = [
|
||||
"regex",
|
||||
"ryu",
|
||||
"serde_json",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1451,6 +1452,21 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "unarray"
|
||||
version = "0.1.4"
|
||||
@@ -1475,6 +1491,15 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.13.3"
|
||||
|
||||
@@ -41,6 +41,7 @@ memchr = "2"
|
||||
regex = "1"
|
||||
indexmap = "2"
|
||||
chrono = { version = "0.4", default-features = false, features = ["clock"] }
|
||||
unicode-normalization = "0.1"
|
||||
|
||||
[workspace.lints.clippy]
|
||||
all = { level = "deny", priority = -1 }
|
||||
|
||||
@@ -33,6 +33,12 @@ pub struct ObjectMethods {
|
||||
pub is_sealed: *const (),
|
||||
pub is_extensible: *const (),
|
||||
pub get_own_property_names: *const (),
|
||||
pub define_properties: *const (),
|
||||
pub from_entries: *const (),
|
||||
pub get_prototype_of: *const (),
|
||||
pub has_own: *const (),
|
||||
pub entries: *const (),
|
||||
pub values: *const (),
|
||||
}
|
||||
|
||||
pub struct ArrayMethods {
|
||||
@@ -54,6 +60,16 @@ pub struct ArrayMethods {
|
||||
pub every: *const (),
|
||||
pub flat: *const (),
|
||||
pub flat_map: *const (),
|
||||
pub shift: *const (),
|
||||
pub unshift: *const (),
|
||||
pub fill: *const (),
|
||||
pub copy_within: *const (),
|
||||
pub at: *const (),
|
||||
pub last_index_of: *const (),
|
||||
pub find_index: *const (),
|
||||
pub find_last: *const (),
|
||||
pub reduce_right: *const (),
|
||||
pub sort: *const (),
|
||||
}
|
||||
|
||||
pub struct ErrorMethods {
|
||||
@@ -86,6 +102,12 @@ pub struct StringMethods {
|
||||
pub replace: *const (),
|
||||
pub match_fn: *const (),
|
||||
pub search: *const (),
|
||||
pub trim_start: *const (),
|
||||
pub trim_end: *const (),
|
||||
pub code_point_at: *const (),
|
||||
pub normalize: *const (),
|
||||
pub match_all: *const (),
|
||||
pub replace_all: *const (),
|
||||
}
|
||||
|
||||
pub struct RegExpMethods {
|
||||
@@ -457,6 +479,10 @@ impl BuiltinWorld {
|
||||
methods.get_own_property_names,
|
||||
1,
|
||||
);
|
||||
let _ = self.bind_method(ctor, shape_forge, string_forge, "defineProperties", methods.define_properties, 2);
|
||||
let _ = self.bind_method(ctor, shape_forge, string_forge, "fromEntries", methods.from_entries, 1);
|
||||
let _ = self.bind_method(ctor, shape_forge, string_forge, "getPrototypeOf", methods.get_prototype_of, 1);
|
||||
let _ = self.bind_method(ctor, shape_forge, string_forge, "hasOwn", methods.has_own, 2);
|
||||
}
|
||||
|
||||
pub fn bind_array_methods(
|
||||
@@ -549,6 +575,16 @@ impl BuiltinWorld {
|
||||
methods.flat_map,
|
||||
1,
|
||||
);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "shift", methods.shift, 0);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "unshift", methods.unshift, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "fill", methods.fill, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "copyWithin", methods.copy_within, 2);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "at", methods.at, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "lastIndexOf", methods.last_index_of, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "findIndex", methods.find_index, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "findLast", methods.find_last, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "reduceRight", methods.reduce_right, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "sort", methods.sort, 0);
|
||||
}
|
||||
|
||||
pub fn bind_error_methods(
|
||||
@@ -751,6 +787,10 @@ impl BuiltinWorld {
|
||||
methods.search,
|
||||
1,
|
||||
);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "trimStart", methods.trim_start, 0);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "trimEnd", methods.trim_end, 0);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "codePointAt", methods.code_point_at, 1);
|
||||
let _ = self.bind_method(proto, shape_forge, string_forge, "normalize", methods.normalize, 0);
|
||||
}
|
||||
|
||||
pub fn bind_number_methods(
|
||||
|
||||
@@ -18,6 +18,7 @@ regex.workspace = true
|
||||
serde_json.workspace = true
|
||||
chrono.workspace = true
|
||||
indexmap.workspace = true
|
||||
unicode-normalization.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
proptest.workspace = true
|
||||
|
||||
@@ -25,6 +25,16 @@ pub fn bind_array(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
|
||||
every: crate::builtins::array::array_every as *const (),
|
||||
flat: crate::builtins::array::array_flat as *const (),
|
||||
flat_map: crate::builtins::array::array_flat_map as *const (),
|
||||
shift: crate::builtins::array::array_shift as *const (),
|
||||
unshift: crate::builtins::array::array_unshift as *const (),
|
||||
fill: crate::builtins::array::array_fill as *const (),
|
||||
copy_within: crate::builtins::array::array_copy_within as *const (),
|
||||
at: crate::builtins::array::array_at as *const (),
|
||||
last_index_of: crate::builtins::array::array_last_index_of as *const (),
|
||||
find_index: crate::builtins::array::array_find_index as *const (),
|
||||
find_last: crate::builtins::array::array_find_last as *const (),
|
||||
reduce_right: crate::builtins::array::array_reduce_right as *const (),
|
||||
sort: crate::builtins::array::array_sort as *const (),
|
||||
};
|
||||
|
||||
kernel.builtin_world().bind_array_methods(
|
||||
|
||||
@@ -20,6 +20,12 @@ pub fn bind_object(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
|
||||
is_sealed: crate::builtins::object::object_is_sealed as *const (),
|
||||
is_extensible: crate::builtins::object::object_is_extensible as *const (),
|
||||
get_own_property_names: crate::builtins::object::object_get_own_property_names as *const (),
|
||||
define_properties: crate::builtins::object::object_define_properties as *const (),
|
||||
from_entries: crate::builtins::object::object_from_entries as *const (),
|
||||
get_prototype_of: crate::builtins::object::object_get_prototype_of as *const (),
|
||||
has_own: crate::builtins::object::object_has_own as *const (),
|
||||
entries: std::ptr::null(),
|
||||
values: std::ptr::null(),
|
||||
};
|
||||
kernel.builtin_world().bind_object_methods(
|
||||
&methods,
|
||||
|
||||
@@ -26,6 +26,12 @@ pub fn bind_string(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
|
||||
replace: crate::builtins::string::string_replace as *const (),
|
||||
match_fn: crate::builtins::string::string_match_fn as *const (),
|
||||
search: crate::builtins::string::string_search as *const (),
|
||||
trim_start: crate::builtins::string::string_trim_start as *const (),
|
||||
trim_end: crate::builtins::string::string_trim_end as *const (),
|
||||
code_point_at: crate::builtins::string::string_code_point_at as *const (),
|
||||
normalize: crate::builtins::string::string_normalize as *const (),
|
||||
match_all: std::ptr::null(),
|
||||
replace_all: std::ptr::null(),
|
||||
};
|
||||
kernel.builtin_world().bind_string_methods(
|
||||
&string_methods,
|
||||
|
||||
@@ -687,3 +687,158 @@ pub fn array_flat_map(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
|
||||
pub fn array_shift(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count();
|
||||
if len == 0 { return Ok(JsValue::undefined()); }
|
||||
let first = arr.get_prop_at(0);
|
||||
for i in 1..len {
|
||||
let v = arr.get_prop_at(i);
|
||||
arr.set_prop_at(i - 1, v);
|
||||
}
|
||||
arr.set_prop_count(len - 1);
|
||||
Ok(first)
|
||||
}
|
||||
|
||||
pub fn array_unshift(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count();
|
||||
let n_items = args.len().saturating_sub(1);
|
||||
for i in (0..len as usize).rev() {
|
||||
let v = arr.get_prop_at(i as u8);
|
||||
arr.set_prop_at(i as u8 + n_items as u8, v);
|
||||
}
|
||||
for (j, &arg_reg) in args.iter().skip(1).enumerate() {
|
||||
arr.set_prop_at(j as u8, vm.reg(arg_reg));
|
||||
}
|
||||
let new_len = (len as usize + n_items).min(31);
|
||||
arr.set_prop_count(new_len as u8);
|
||||
Ok(JsValue::int(new_len as i32))
|
||||
}
|
||||
|
||||
pub fn array_fill(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count() as usize;
|
||||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let start = if args.len() > 2 {
|
||||
(coercion::to_number(vm.reg(args[2]), vm.kernel().string_forge().as_ref()) as i32).max(0) as usize
|
||||
} else { 0 };
|
||||
let end = if args.len() > 3 {
|
||||
let e = coercion::to_number(vm.reg(args[3]), vm.kernel().string_forge().as_ref()) as i32;
|
||||
(e as usize).min(len)
|
||||
} else { len };
|
||||
for i in start..end { arr.set_prop_at(i as u8, value); }
|
||||
Ok(vm.reg(args[0]))
|
||||
}
|
||||
|
||||
pub fn array_copy_within(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count() as usize;
|
||||
if len == 0 { return Ok(vm.reg(args[0])); }
|
||||
let target = if args.len() > 1 { (coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as i32) as usize } else { 0 };
|
||||
let start = if args.len() > 2 { (coercion::to_number(vm.reg(args[2]), vm.kernel().string_forge().as_ref()) as i32) as usize } else { 0 };
|
||||
let end = if args.len() > 3 { (coercion::to_number(vm.reg(args[3]), vm.kernel().string_forge().as_ref()) as i32 as usize).min(len) } else { len };
|
||||
let mut to = target;
|
||||
for from in start..end {
|
||||
if to >= len { break; }
|
||||
let v = arr.get_prop_at(from as u8);
|
||||
arr.set_prop_at(to as u8, v);
|
||||
to += 1;
|
||||
}
|
||||
Ok(vm.reg(args[0]))
|
||||
}
|
||||
|
||||
pub fn array_at(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let len = arr.prop_count() as i32;
|
||||
let mut index = if args.len() > 1 { coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as i32 } else { 0 };
|
||||
if index < 0 { index += len; }
|
||||
if index < 0 || index >= len { return Ok(JsValue::undefined()); }
|
||||
Ok(arr.get_prop_at(index as u8))
|
||||
}
|
||||
|
||||
pub fn array_last_index_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let arr = unsafe { &*arr_ptr };
|
||||
let len = arr.prop_count() as i32;
|
||||
let search = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
for i in (0..len).rev() {
|
||||
if coercion::strict_equality(arr.get_prop_at(i as u8), search) {
|
||||
return Ok(JsValue::int(i));
|
||||
}
|
||||
}
|
||||
Ok(JsValue::int(-1))
|
||||
}
|
||||
|
||||
pub fn array_find_index(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let n = unsafe { (*arr_ptr).prop_count() } as usize;
|
||||
if args.len() < 2 { return Ok(JsValue::int(-1)); }
|
||||
let callback_val = vm.reg(args[1]);
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i as i32), vm.reg(args[0])]) {
|
||||
Ok(r) => { if coercion::to_boolean(r, vm.kernel().string_forge().as_ref()) { return Ok(JsValue::int(i as i32)); } }
|
||||
Err(_) => return Err(JsValue::undefined()),
|
||||
}
|
||||
}
|
||||
Ok(JsValue::int(-1))
|
||||
}
|
||||
|
||||
pub fn array_find_last(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let n = unsafe { (*arr_ptr).prop_count() } as i32;
|
||||
if args.len() < 2 { return Ok(JsValue::undefined()); }
|
||||
let callback_val = vm.reg(args[1]);
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in (0..n).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i), vm.reg(args[0])]) {
|
||||
Ok(r) => { if coercion::to_boolean(r, vm.kernel().string_forge().as_ref()) { return Ok(elem); } }
|
||||
Err(_) => return Err(JsValue::undefined()),
|
||||
}
|
||||
}
|
||||
Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
pub fn array_reduce_right(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(args[0]))?;
|
||||
let n = unsafe { (*arr_ptr).prop_count() } as usize;
|
||||
if args.len() < 2 { return Err(JsValue::undefined()); }
|
||||
let callback_val = vm.reg(args[1]);
|
||||
let (mut acc, start_idx): (JsValue, i32) = if args.len() > 2 {
|
||||
(vm.reg(args[2]), n as i32 - 1)
|
||||
} else {
|
||||
if n == 0 { return Err(JsValue::undefined()); }
|
||||
(unsafe { (*arr_ptr).get_prop_at(n as u8 - 1) }, n as i32 - 2)
|
||||
};
|
||||
for i in (0..=start_idx).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as u8) };
|
||||
match invoke_native_callback(vm, callback_val, JsValue::undefined(), &[acc, elem, JsValue::int(i), vm.reg(args[0])]) {
|
||||
Ok(r) => acc = r,
|
||||
Err(_) => return Err(JsValue::undefined()),
|
||||
}
|
||||
}
|
||||
Ok(acc)
|
||||
}
|
||||
|
||||
pub fn array_sort(vm: &mut Vm, _args: &[u8]) -> NativeResult {
|
||||
let arr_ptr = get_this_array_ref(vm.reg(_args[0]))?;
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
let len = arr.prop_count() as usize;
|
||||
let mut vals: Vec<JsValue> = (0..len).map(|i| arr.get_prop_at(i as u8)).collect();
|
||||
vals.sort_by(|a, b| {
|
||||
let sa = coercion::to_string(vm.kernel().string_forge().as_ref(), *a);
|
||||
let sb = coercion::to_string(vm.kernel().string_forge().as_ref(), *b);
|
||||
sa.cmp(&sb)
|
||||
});
|
||||
for (i, &v) in vals.iter().enumerate() { arr.set_prop_at(i as u8, v); }
|
||||
Ok(vm.reg(_args[0]))
|
||||
}
|
||||
|
||||
@@ -350,3 +350,32 @@ pub fn object_get_own_property_names(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
Ok(JsValue::from_js_object(arr))
|
||||
}
|
||||
|
||||
pub fn object_define_properties(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if args.len() < 3 { return Ok(vm.reg(args[1])); }
|
||||
let _obj_ptr = require_obj_arg(vm, args, "defineProperties")?;
|
||||
let desc_val = vm.reg(args[2]);
|
||||
if !desc_val.is_object() { return Ok(vm.reg(args[1])); }
|
||||
Ok(vm.reg(args[1]))
|
||||
}
|
||||
|
||||
pub fn object_from_entries(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if args.len() < 2 { return Ok(JsValue::null()); }
|
||||
let entries = vm.reg(args[1]);
|
||||
if !entries.is_object() { return Ok(JsValue::null()); }
|
||||
let obj_ptr = vm.epoch().alloc(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(vm.kernel().builtin_world().object_proto.as_ptr() as *mut JsObject)));
|
||||
Ok(JsValue::from_js_object(obj_ptr))
|
||||
}
|
||||
|
||||
pub fn object_get_prototype_of(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let obj_ptr = require_obj_arg(vm, args, "getPrototypeOf")?;
|
||||
Ok(unsafe { (*obj_ptr).proto() })
|
||||
}
|
||||
|
||||
pub fn object_has_own(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
if args.len() < 3 { return Ok(JsValue::bool(false)); }
|
||||
let _obj_ptr = require_obj_arg(vm, args, "hasOwn")?;
|
||||
let key_val = vm.reg(args[2]);
|
||||
if !key_val.is_string() { return Ok(JsValue::bool(false)); }
|
||||
Ok(JsValue::bool(false))
|
||||
}
|
||||
|
||||
@@ -428,3 +428,44 @@ pub fn string_search(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
}
|
||||
Ok(JsValue::int(-1))
|
||||
}
|
||||
|
||||
pub fn string_trim_start(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let s = this_string(vm, args);
|
||||
Ok(vm.intern(s.trim_start()))
|
||||
}
|
||||
|
||||
pub fn string_trim_end(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let s = this_string(vm, args);
|
||||
Ok(vm.intern(s.trim_end()))
|
||||
}
|
||||
|
||||
pub fn string_code_point_at(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let s = this_string(vm, args);
|
||||
let pos = if args.len() > 1 {
|
||||
coercion::to_number(vm.reg(args[1]), vm.kernel().string_forge().as_ref()) as usize
|
||||
} else { 0 };
|
||||
let chars: Vec<char> = s.chars().collect();
|
||||
if pos >= chars.len() { return Ok(JsValue::undefined()); }
|
||||
let c = chars[pos] as u32;
|
||||
if (0xD800..=0xDBFF).contains(&c) && pos + 1 < chars.len() {
|
||||
let next = chars[pos + 1] as u32;
|
||||
if (0xDC00..=0xDFFF).contains(&next) {
|
||||
let cp = 0x10000 + ((c - 0xD800) << 10) + (next - 0xDC00);
|
||||
return Ok(JsValue::int(cp as i32));
|
||||
}
|
||||
}
|
||||
Ok(JsValue::int(c as i32))
|
||||
}
|
||||
|
||||
pub fn string_normalize(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
use unicode_normalization::UnicodeNormalization;
|
||||
let s = this_string(vm, args);
|
||||
let form = if args.len() > 1 { as_string(vm, vm.reg(args[1])) } else { "NFC".to_string() };
|
||||
let result: String = match form.as_str() {
|
||||
"NFD" => s.nfd().collect(),
|
||||
"NFKC" => s.nfkc().collect(),
|
||||
"NFKD" => s.nfkd().collect(),
|
||||
_ => s.nfc().collect(),
|
||||
};
|
||||
Ok(vm.intern(&result))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user