mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
refactor: array 迭代与查找族拆出 iterate 模块
This commit is contained in:
@@ -0,0 +1,493 @@
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
use crate::builtins_debug;
|
||||
use crate::builtins_error;
|
||||
|
||||
use super::common::{
|
||||
array_ptr_len3, array_type_error, arraylike_get, arraylike_get_or_err, check_array_create_len, create_new_array,
|
||||
get_this_arraylike, invoke_native_callback, js_array_index, require_callback, unexpected_tail_call_error,
|
||||
};
|
||||
|
||||
/// `Array.prototype.forEach(callback, thisArg)`:对每个元素调用 callback,返回 undefined。
|
||||
pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.forEach called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(_) => {}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Array.prototype.map(callback, thisArg)`:对每个元素调用 callback 生成新数组。
|
||||
pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.map called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let new_arr = create_new_array(vm, n);
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(mapped) => unsafe {
|
||||
(*new_arr).set_prop_at(i, mapped);
|
||||
},
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*new_arr).set_prop_count(n);
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
|
||||
/// `Array.prototype.filter(callback, thisArg)`:保留 callback 返回真值的元素形成新数组。
|
||||
pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.filter called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let mut kept: Vec<JsValue> = Vec::new();
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if oxide_runtime_api::to_boolean(result_val) {
|
||||
kept.push(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
}
|
||||
}
|
||||
let new_arr = create_new_array(vm, kept.len());
|
||||
unsafe {
|
||||
for (i, val) in kept.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(kept.len());
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
|
||||
/// `Array.prototype.reduce(callback, initialValue)`:从左到右累计归约;
|
||||
/// 空数组且无初始值抛 TypeError。
|
||||
pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reduce called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if n == 0 && args.len() < 3 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let has_initial = args.len() > 2;
|
||||
let mut accumulator;
|
||||
let start_idx;
|
||||
if has_initial {
|
||||
accumulator = vm.reg(args[2]);
|
||||
start_idx = 0;
|
||||
} else {
|
||||
accumulator = arraylike_get_or_err!(vm, arr_ptr, 0);
|
||||
start_idx = 1;
|
||||
}
|
||||
let this_val = JsValue::undefined();
|
||||
for i in start_idx..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[accumulator, elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result) => accumulator = result,
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(accumulator)
|
||||
}
|
||||
|
||||
/// `Array.prototype.find(callback, thisArg)`:返回首个 callback 为真的元素,否则 undefined。
|
||||
pub fn array_find<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.find called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if oxide_runtime_api::to_boolean(result_val) {
|
||||
return NativeResult::Ok(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Array.prototype.some(callback, thisArg)`:任一元素满足 callback 返回 true。
|
||||
pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.some called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if oxide_runtime_api::to_boolean(result_val) {
|
||||
return NativeResult::Ok(JsValue::bool(true));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::bool(false))
|
||||
}
|
||||
|
||||
/// `Array.prototype.every(callback, thisArg)`:所有元素满足 callback 才返回 true。
|
||||
pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.every called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if !oxide_runtime_api::to_boolean(result_val) {
|
||||
return NativeResult::Ok(JsValue::bool(false));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::bool(true))
|
||||
}
|
||||
|
||||
/// `Array.prototype.flatMap(callback, thisArg)`:map 后把返回的数组展开一层。
|
||||
pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.flatMap called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let mut flat: Vec<JsValue> = Vec::new();
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result) => {
|
||||
if result.is_object() {
|
||||
let r_ptr = result.as_js_object_ptr();
|
||||
if !r_ptr.is_null() {
|
||||
let r = unsafe { &*r_ptr };
|
||||
if r.is_array() {
|
||||
let rn = r.prop_count() as usize;
|
||||
for j in 0..rn {
|
||||
flat.push(r.get_prop_at(j));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
flat.push(result);
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
let new_arr = create_new_array(vm, flat.len());
|
||||
unsafe {
|
||||
for (i, val) in flat.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(flat.len());
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
|
||||
/// `Array.prototype.findIndex(callback, thisArg)`:返回首个 callback 为真的索引,否则 -1。
|
||||
pub fn array_find_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findIndex called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(r) => {
|
||||
if oxide_runtime_api::to_boolean(r) {
|
||||
return NativeResult::Ok(js_array_index(i));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::int(-1))
|
||||
}
|
||||
|
||||
/// `Array.prototype.findLast(callback, thisArg)`:从后往前返回首个 callback 为真的元素。
|
||||
pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findLast called with {} args", args.len());
|
||||
let (arr_ptr, n) = {
|
||||
let (arr_ptr, len, _is_array) = array_ptr_len3!(vm, args);
|
||||
(arr_ptr, len as i32)
|
||||
};
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
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) };
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i), o_val]) {
|
||||
NativeResult::Ok(r) => {
|
||||
if oxide_runtime_api::to_boolean(r) {
|
||||
return NativeResult::Ok(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Array.prototype.reduceRight(callback, initialValue)`:从右到左累计归约。
|
||||
pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reduceRight called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let (mut acc, start_idx): (JsValue, i32) = if args.len() > 2 {
|
||||
(vm.reg(args[2]), n as i32 - 1)
|
||||
} else {
|
||||
if n == 0 {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
(unsafe { (*arr_ptr).get_prop_at(n - 1) }, n as i32 - 2)
|
||||
};
|
||||
for i in (0..=start_idx).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as usize) };
|
||||
match invoke_native_callback(vm, callback_val, JsValue::undefined(), &[acc, elem, JsValue::int(i), o_val]) {
|
||||
NativeResult::Ok(r) => acc = r,
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(acc)
|
||||
}
|
||||
|
||||
/// Array.prototype.findLastIndex(callback, thisArg):从后往前返回首个 callback 为真的下标。
|
||||
pub fn array_find_last_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findLastIndex called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in (0..n).rev() {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(r) => {
|
||||
if oxide_runtime_api::to_boolean(r) {
|
||||
return NativeResult::Ok(js_array_index(i));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::int(-1))
|
||||
}
|
||||
@@ -16,449 +16,8 @@ pub use from::*;
|
||||
mod element;
|
||||
pub use element::*;
|
||||
|
||||
/// `Array.prototype.forEach(callback, thisArg)`:对每个元素调用 callback,返回 undefined。
|
||||
pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.forEach called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(_) => {}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Array.prototype.map(callback, thisArg)`:对每个元素调用 callback 生成新数组。
|
||||
pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.map called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let new_arr = create_new_array(vm, n);
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(mapped) => unsafe {
|
||||
(*new_arr).set_prop_at(i, mapped);
|
||||
},
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
(*new_arr).set_prop_count(n);
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
|
||||
/// `Array.prototype.filter(callback, thisArg)`:保留 callback 返回真值的元素形成新数组。
|
||||
pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.filter called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.filter: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let mut kept: Vec<JsValue> = Vec::new();
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if oxide_runtime_api::to_boolean(result_val) {
|
||||
kept.push(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => return NativeResult::Err(err),
|
||||
NativeResult::TailCall { .. } => return unexpected_tail_call_error(vm),
|
||||
}
|
||||
}
|
||||
let new_arr = create_new_array(vm, kept.len());
|
||||
unsafe {
|
||||
for (i, val) in kept.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(kept.len());
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
|
||||
/// `Array.prototype.reduce(callback, initialValue)`:从左到右累计归约;
|
||||
/// 空数组且无初始值抛 TypeError。
|
||||
pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reduce called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if n == 0 && args.len() < 3 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let has_initial = args.len() > 2;
|
||||
let mut accumulator;
|
||||
let start_idx;
|
||||
if has_initial {
|
||||
accumulator = vm.reg(args[2]);
|
||||
start_idx = 0;
|
||||
} else {
|
||||
accumulator = arraylike_get_or_err!(vm, arr_ptr, 0);
|
||||
start_idx = 1;
|
||||
}
|
||||
let this_val = JsValue::undefined();
|
||||
for i in start_idx..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[accumulator, elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result) => accumulator = result,
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.reduce: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(accumulator)
|
||||
}
|
||||
|
||||
/// `Array.prototype.find(callback, thisArg)`:返回首个 callback 为真的元素,否则 undefined。
|
||||
pub fn array_find<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.find called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if oxide_runtime_api::to_boolean(result_val) {
|
||||
return NativeResult::Ok(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.find: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Array.prototype.some(callback, thisArg)`:任一元素满足 callback 返回 true。
|
||||
pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.some called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if oxide_runtime_api::to_boolean(result_val) {
|
||||
return NativeResult::Ok(JsValue::bool(true));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.some: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::bool(false))
|
||||
}
|
||||
|
||||
/// `Array.prototype.every(callback, thisArg)`:所有元素满足 callback 才返回 true。
|
||||
pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.every called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result_val) => {
|
||||
if !oxide_runtime_api::to_boolean(result_val) {
|
||||
return NativeResult::Ok(JsValue::bool(false));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.every: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::bool(true))
|
||||
}
|
||||
|
||||
/// `Array.prototype.flatMap(callback, thisArg)`:map 后把返回的数组展开一层。
|
||||
pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.flatMap called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
let mut flat: Vec<JsValue> = Vec::new();
|
||||
if let Err(err) = check_array_create_len(vm, n) {
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(result) => {
|
||||
if result.is_object() {
|
||||
let r_ptr = result.as_js_object_ptr();
|
||||
if !r_ptr.is_null() {
|
||||
let r = unsafe { &*r_ptr };
|
||||
if r.is_array() {
|
||||
let rn = r.prop_count() as usize;
|
||||
for j in 0..rn {
|
||||
flat.push(r.get_prop_at(j));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
flat.push(result);
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.flatMap: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
let new_arr = create_new_array(vm, flat.len());
|
||||
unsafe {
|
||||
for (i, val) in flat.iter().enumerate() {
|
||||
(*new_arr).set_prop_at(i, *val);
|
||||
}
|
||||
(*new_arr).set_prop_count(flat.len());
|
||||
}
|
||||
NativeResult::Ok(JsValue::from_js_object(new_arr))
|
||||
}
|
||||
|
||||
/// `Array.prototype.findIndex(callback, thisArg)`:返回首个 callback 为真的索引,否则 -1。
|
||||
pub fn array_find_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findIndex called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in 0..n {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(r) => {
|
||||
if oxide_runtime_api::to_boolean(r) {
|
||||
return NativeResult::Ok(js_array_index(i));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findIndex: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::int(-1))
|
||||
}
|
||||
|
||||
/// `Array.prototype.findLast(callback, thisArg)`:从后往前返回首个 callback 为真的元素。
|
||||
pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findLast called with {} args", args.len());
|
||||
let (arr_ptr, n) = {
|
||||
let (arr_ptr, len, _is_array) = array_ptr_len3!(vm, args);
|
||||
(arr_ptr, len as i32)
|
||||
};
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
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) };
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, JsValue::int(i), o_val]) {
|
||||
NativeResult::Ok(r) => {
|
||||
if oxide_runtime_api::to_boolean(r) {
|
||||
return NativeResult::Ok(elem);
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findLast: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// `Array.prototype.reduceRight(callback, initialValue)`:从右到左累计归约。
|
||||
pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.reduceRight called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let (mut acc, start_idx): (JsValue, i32) = if args.len() > 2 {
|
||||
(vm.reg(args[2]), n as i32 - 1)
|
||||
} else {
|
||||
if n == 0 {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "Reduce of empty array with no initial value"));
|
||||
}
|
||||
(unsafe { (*arr_ptr).get_prop_at(n - 1) }, n as i32 - 2)
|
||||
};
|
||||
for i in (0..=start_idx).rev() {
|
||||
let elem = unsafe { (*arr_ptr).get_prop_at(i as usize) };
|
||||
match invoke_native_callback(vm, callback_val, JsValue::undefined(), &[acc, elem, JsValue::int(i), o_val]) {
|
||||
NativeResult::Ok(r) => acc = r,
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.reduceRight: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(acc)
|
||||
}
|
||||
mod iterate;
|
||||
pub use iterate::*;
|
||||
|
||||
/// `Array.prototype.sort(compareFn)`:原地排序。默认按字符串字典序;
|
||||
/// 提供比较函数时按其返回值(<0/=0/>0)排序,回调抛错则中止。
|
||||
@@ -698,44 +257,6 @@ pub fn array_iterator_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
NativeResult::Ok(crate::iterator::make_iter_result(vm, value, false))
|
||||
}
|
||||
|
||||
/// Array.prototype.findLastIndex(callback, thisArg):从后往前返回首个 callback 为真的下标。
|
||||
pub fn array_find_last_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.findLastIndex called with {} args", args.len());
|
||||
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args);
|
||||
let o_val = vm.reg(args[0]);
|
||||
if args.len() < 2 {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return NativeResult::Err(array_type_error(vm, "callback is not a function"));
|
||||
}
|
||||
let callback_val = match require_callback(vm, vm.reg(args[1])) {
|
||||
Ok(callback) => callback,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
};
|
||||
let this_val = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||
for i in (0..n).rev() {
|
||||
let elem = arraylike_get_or_err!(vm, arr_ptr, i);
|
||||
match invoke_native_callback(vm, callback_val, this_val, &[elem, js_array_index(i), o_val]) {
|
||||
NativeResult::Ok(r) => {
|
||||
if oxide_runtime_api::to_boolean(r) {
|
||||
return NativeResult::Ok(js_array_index(i));
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
builtins_error!("Array.prototype.findLastIndex: invalid receiver");
|
||||
return unexpected_tail_call_error(vm);
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(JsValue::int(-1))
|
||||
}
|
||||
|
||||
/// Array.prototype.toReversed():返回元素逆序的新数组,原数组不变。
|
||||
pub fn array_to_reversed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.toReversed called with {} args", args.len());
|
||||
|
||||
Reference in New Issue
Block a user