feat: 遍历族方法 ToObject 装箱基元接收者并钉位 reg0 保 GC 根

This commit is contained in:
2026-10-09 09:21:49 +00:00
parent 582475363b
commit 484d9a9e11
5 changed files with 167 additions and 69 deletions
Generated
+19 -19
View File
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_builtins" name = "oxide_builtins"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"chrono", "chrono",
"fast-float", "fast-float",
@@ -1185,7 +1185,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_bytecode" name = "oxide_bytecode"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxide_log", "oxide_log",
@@ -1193,7 +1193,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cfg" name = "oxide_cfg"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_emit", "oxide_emit",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_cli" name = "oxide_cli"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"bumpalo", "bumpalo",
@@ -1226,7 +1226,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_code_cache" name = "oxide_code_cache"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"lru", "lru",
"oxide_bytecode", "oxide_bytecode",
@@ -1235,7 +1235,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_compiler" name = "oxide_compiler"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1255,7 +1255,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_dce" name = "oxide_dce"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1269,7 +1269,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_emit" name = "oxide_emit"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"oxc_allocator", "oxc_allocator",
@@ -1284,7 +1284,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_engine" name = "oxide_engine"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1296,7 +1296,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_ir" name = "oxide_ir"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_log", "oxide_log",
@@ -1305,7 +1305,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_kernel" name = "oxide_kernel"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1319,7 +1319,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_liveness" name = "oxide_liveness"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1331,7 +1331,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_log" name = "oxide_log"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"tracing", "tracing",
"tracing-appender", "tracing-appender",
@@ -1340,7 +1340,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_parser" name = "oxide_parser"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxc_allocator", "oxc_allocator",
"oxc_ast", "oxc_ast",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_regalloc" name = "oxide_regalloc"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_cfg", "oxide_cfg",
@@ -1371,7 +1371,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_runtime_api" name = "oxide_runtime_api"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"num-bigint", "num-bigint",
"num-traits", "num-traits",
@@ -1384,7 +1384,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_test262" name = "oxide_test262"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"oxide_bytecode", "oxide_bytecode",
"oxide_compiler", "oxide_compiler",
@@ -1402,7 +1402,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_types" name = "oxide_types"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"dashmap", "dashmap",
@@ -1415,7 +1415,7 @@ dependencies = [
[[package]] [[package]]
name = "oxide_vm" name = "oxide_vm"
version = "0.8.95" version = "0.8.96"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"chrono", "chrono",
+1 -1
View File
@@ -23,7 +23,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.8.95" version = "0.8.96"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
rust-version = "1.80" rust-version = "1.80"
+10 -2
View File
@@ -40,7 +40,15 @@ pub(crate) use array_ptr_len;
macro_rules! array_ptr_len3 { macro_rules! array_ptr_len3 {
($vm:expr, $args:expr) => {{ ($vm:expr, $args:expr) => {{
let this_val = $vm.reg($args[0]); // ToObject 装箱加 reg0 钉位:装箱体跨回调窗保 GC 根。call 转发形态的实参
// 寄存器集可占 reg0,占位时跳过钉位(装箱体按接收者值传递保活)。
let this_val = match oxide_runtime_api::to_object($vm.reg($args[0]), $vm) {
Ok(v) => v,
Err(msg) => return NativeResult::Err(crate::array::from::from_engine_error($vm, &msg)),
};
if !$args.contains(&0) {
$vm.set_reg(0, this_val);
}
let (arr_ptr, len, is_arr) = match get_this_arraylike($vm, this_val) { let (arr_ptr, len, is_arr) = match get_this_arraylike($vm, this_val) {
Ok(v) => v, Ok(v) => v,
Err(err) => { Err(err) => {
@@ -48,7 +56,7 @@ macro_rules! array_ptr_len3 {
return NativeResult::Err(err); return NativeResult::Err(err);
} }
}; };
(arr_ptr, len, is_arr) (arr_ptr, len, is_arr, this_val)
}}; }};
} }
pub(crate) use array_ptr_len3; pub(crate) use array_ptr_len3;
+17 -43
View File
@@ -2,7 +2,7 @@
use oxide_types::value::JsValue; use oxide_types::value::JsValue;
use oxide_runtime_api::{to_object, NativeResult, VmHost}; use oxide_runtime_api::{NativeResult, VmHost};
use crate::builtins_debug; use crate::builtins_debug;
use crate::builtins_error; use crate::builtins_error;
@@ -12,13 +12,12 @@ use super::common::{
check_array_create_len, get_this_arraylike, invoke_native_callback, js_array_index, require_callback, check_array_create_len, get_this_arraylike, invoke_native_callback, js_array_index, require_callback,
unexpected_tail_call_error, unexpected_tail_call_error,
}; };
use super::from::{array_species_create, create_data_property_or_throw, from_engine_error}; use super::from::{array_species_create, create_data_property_or_throw};
/// `Array.prototype.forEach(callback, thisArg)`:对每个元素调用 callback,返回 undefined。 /// `Array.prototype.forEach(callback, thisArg)`:对每个元素调用 callback,返回 undefined。
pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.forEach called with {} args", args.len()); builtins_debug!("Array.prototype.forEach called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
} }
@@ -57,8 +56,7 @@ pub fn array_for_each<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// 可按规范抛 TypeError。 /// 可按规范抛 TypeError。
pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.map called with {} args", args.len()); builtins_debug!("Array.prototype.map called with {} args", args.len());
let (arr_ptr, n, is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
} }
@@ -117,8 +115,7 @@ pub fn array_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// 可按规范抛 TypeError。 /// 可按规范抛 TypeError。
pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.filter called with {} args", args.len()); builtins_debug!("Array.prototype.filter called with {} args", args.len());
let (arr_ptr, n, is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.filter: invalid receiver"); builtins_error!("Array.prototype.filter: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -168,8 +165,7 @@ pub fn array_filter<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// 空数组且无初始值抛 TypeError。 /// 空数组且无初始值抛 TypeError。
pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.reduce called with {} args", args.len()); builtins_debug!("Array.prototype.reduce called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.reduce: invalid receiver"); builtins_error!("Array.prototype.reduce: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -231,8 +227,7 @@ pub fn array_reduce<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// `Array.prototype.find(callback, thisArg)`:返回首个 callback 为真的元素,否则 undefined。 /// `Array.prototype.find(callback, thisArg)`:返回首个 callback 为真的元素,否则 undefined。
pub fn array_find<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_find<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.find called with {} args", args.len()); builtins_debug!("Array.prototype.find called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.find: invalid receiver"); builtins_error!("Array.prototype.find: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -269,8 +264,7 @@ pub fn array_find<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// `Array.prototype.some(callback, thisArg)`:任一元素满足 callback 返回 true。 /// `Array.prototype.some(callback, thisArg)`:任一元素满足 callback 返回 true。
pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.some called with {} args", args.len()); builtins_debug!("Array.prototype.some called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.some: invalid receiver"); builtins_error!("Array.prototype.some: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -311,8 +305,7 @@ pub fn array_some<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// `Array.prototype.every(callback, thisArg)`:所有元素满足 callback 才返回 true。 /// `Array.prototype.every(callback, thisArg)`:所有元素满足 callback 才返回 true。
pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.every called with {} args", args.len()); builtins_debug!("Array.prototype.every called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.every: invalid receiver"); builtins_error!("Array.prototype.every: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -367,23 +360,8 @@ pub fn array_every<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// 可按规范抛 TypeError。 /// 可按规范抛 TypeError。
pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.flatMap called with {} args", args.len()); builtins_debug!("Array.prototype.flatMap called with {} args", args.len());
// ToObject:基元 this 装箱(null/undefined 抛 TypeError)。 // 接收者 ToObject 装箱并钉位 reg0(宏内收口),第四返回值作 o_val。
let this_val = match to_object(vm.reg(args[0]), vm) { let (arr_ptr, n, is_array, o_val) = array_ptr_len3!(vm, args);
Ok(v) => v,
Err(msg) => return NativeResult::Err(from_engine_error(vm, &msg)),
};
// 装箱体钉入返回寄存器:它只存于 Rust 局部,跨 length getter / species
// 用户窗口须保 GC 根。call 转发形态的实参寄存器集可占该槽,占位时跳过钉位
// (装箱体按接收者值传递保活)。结果 A 钉入后此槽让位,循环期装箱体按
// 接收者值传递保活。
if !args.contains(&0) {
vm.set_reg(0, this_val);
}
let (arr_ptr, n, is_array) = match get_this_arraylike(vm, this_val) {
Ok(v) => v,
Err(err) => return NativeResult::Err(err),
};
let o_val = this_val;
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.flatMap: invalid receiver"); builtins_error!("Array.prototype.flatMap: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -471,8 +449,7 @@ pub fn array_flat_map<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// `Array.prototype.findIndex(callback, thisArg)`:返回首个 callback 为真的索引,否则 -1。 /// `Array.prototype.findIndex(callback, thisArg)`:返回首个 callback 为真的索引,否则 -1。
pub fn array_find_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_find_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.findIndex called with {} args", args.len()); builtins_debug!("Array.prototype.findIndex called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.findIndex: invalid receiver"); builtins_error!("Array.prototype.findIndex: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -509,11 +486,10 @@ pub fn array_find_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// `Array.prototype.findLast(callback, thisArg)`:从后往前返回首个 callback 为真的元素。 /// `Array.prototype.findLast(callback, thisArg)`:从后往前返回首个 callback 为真的元素。
pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.findLast called with {} args", args.len()); builtins_debug!("Array.prototype.findLast called with {} args", args.len());
let (arr_ptr, n) = { let (arr_ptr, n, o_val) = {
let (arr_ptr, len, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, len, _is_array, o_val) = array_ptr_len3!(vm, args);
(arr_ptr, len as i32) (arr_ptr, len as i32, o_val)
}; };
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.findLast: invalid receiver"); builtins_error!("Array.prototype.findLast: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -550,8 +526,7 @@ pub fn array_find_last<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// `Array.prototype.reduceRight(callback, initialValue)`:从右到左累计归约。 /// `Array.prototype.reduceRight(callback, initialValue)`:从右到左累计归约。
pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.reduceRight called with {} args", args.len()); builtins_debug!("Array.prototype.reduceRight called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.reduceRight: invalid receiver"); builtins_error!("Array.prototype.reduceRight: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -612,8 +587,7 @@ pub fn array_reduce_right<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// Array.prototype.findLastIndex(callback, thisArg):从后往前返回首个 callback 为真的下标。 /// Array.prototype.findLastIndex(callback, thisArg):从后往前返回首个 callback 为真的下标。
pub fn array_find_last_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult { pub fn array_find_last_index<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
builtins_debug!("Array.prototype.findLastIndex called with {} args", args.len()); builtins_debug!("Array.prototype.findLastIndex called with {} args", args.len());
let (arr_ptr, n, _is_array) = array_ptr_len3!(vm, args); let (arr_ptr, n, _is_array, o_val) = array_ptr_len3!(vm, args);
let o_val = vm.reg(args[0]);
if args.len() < 2 { if args.len() < 2 {
builtins_error!("Array.prototype.findLastIndex: invalid receiver"); builtins_error!("Array.prototype.findLastIndex: invalid receiver");
return NativeResult::Err(array_type_error(vm, "callback is not a function")); return NativeResult::Err(array_type_error(vm, "callback is not a function"));
@@ -864,15 +864,131 @@ fn test_flat_arraylike_undefined_length() {
assert_eq!(out, "|0"); assert_eq!(out, "|0");
} }
// 引擎钉:flat 装箱基元 this——ToObject 后长度为 0,结果空真数组。 // 引擎钉:flat 装箱基元 this——ToObject 后长度为 0,结果空真数组;装箱串
// 长度 2,按单元遍历。
#[test] #[test]
fn test_flat_boxed_primitive_this() { fn test_flat_boxed_primitive_this() {
let out = eval_str( let out = eval_str(
"(() => { const r = Array.prototype.flat.call(true); \ "(() => { const r1 = Array.prototype.flat.call(true); \
return r.length + '|' + Array.isArray(r); })()", const r2 = Array.prototype.flat.call('ab'); \
return r1.length + '|' + Array.isArray(r1) + '|' + r2.join(',') + '|' + r2.length; })()",
) )
.unwrap(); .unwrap();
assert_eq!(out, "0|true"); assert_eq!(out, "0|true|a,b|2");
}
// 引擎钉:map 装箱串 this——ToObject 装箱后按单元遍历,结果真数组。
#[test]
fn test_map_boxed_string_this() {
let out = eval_str(
"(() => { const r = Array.prototype.map.call('ab', c => c); \
return r.join(',') + '|' + r.length; })()",
)
.unwrap();
assert_eq!(out, "a,b|2");
}
// 引擎钉:forEach 装箱串 this——回调按序接收单元,返回 undefined。
#[test]
fn test_for_each_boxed_string_this() {
let out = eval_str(
"(() => { const seen = []; \
const r = Array.prototype.forEach.call('ab', c => seen.push(c)); \
return seen.join(',') + '|' + (r === undefined); })()",
)
.unwrap();
assert_eq!(out, "a,b|true");
}
// 引擎钉:filter 装箱串 this——仅保留真值单元。
#[test]
fn test_filter_boxed_string_this() {
let out = eval_str(
"(() => { const r = Array.prototype.filter.call('ab', c => c === 'a'); \
return r.join(',') + '|' + r.length; })()",
)
.unwrap();
assert_eq!(out, "a|1");
}
// 引擎钉:reduce 装箱串 this——从左到右累计,初值空串。
#[test]
fn test_reduce_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.reduce.call('ab', (a, b) => a + b, ''); })()",
)
.unwrap();
assert_eq!(out, "ab");
}
// 引擎钉:reduceRight 装箱串 this——从右到左累计。
#[test]
fn test_reduce_right_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.reduceRight.call('ab', (a, b) => a + b, ''); })()",
)
.unwrap();
assert_eq!(out, "ba");
}
// 引擎钉:find 装箱串 this——返回首个真值单元。
#[test]
fn test_find_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.find.call('ab', c => c === 'b'); })()",
)
.unwrap();
assert_eq!(out, "b");
}
// 引擎钉:findIndex 装箱串 this——返回首个真值下标。
#[test]
fn test_find_index_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.findIndex.call('ab', c => c === 'a')); })()",
)
.unwrap();
assert_eq!(out, "0");
}
// 引擎钉:findLast 装箱串 this——返回末个真值单元。
#[test]
fn test_find_last_boxed_string_this() {
let out = eval_str(
"(() => { return Array.prototype.findLast.call('ab', c => c === 'b'); })()",
)
.unwrap();
assert_eq!(out, "b");
}
// 引擎钉:findLastIndex 装箱串 this——返回末个真值下标。
#[test]
fn test_find_last_index_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.findLastIndex.call('ab', c => c === 'b')); })()",
)
.unwrap();
assert_eq!(out, "1");
}
// 引擎钉:some 装箱串 this——任一单元真值即 true。
#[test]
fn test_some_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.some.call('ab', c => c === 'b')); })()",
)
.unwrap();
assert_eq!(out, "true");
}
// 引擎钉:every 装箱串 this——全单元真值才 true。
#[test]
fn test_every_boxed_string_this() {
let out = eval_str(
"(() => { return String(Array.prototype.every.call('ab', c => c !== 'x')); })()",
)
.unwrap();
assert_eq!(out, "true");
} }
// 引擎钉:flat 负 depth——ToIntegerOrInfinity 后归 0,不展开。 // 引擎钉:flat 负 depth——ToIntegerOrInfinity 后归 0,不展开。