From f1c4b33735db693f11c7d9aed00045081bdc16fb Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sun, 16 Aug 2026 16:38:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Iterator.prototype=20=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E5=99=A8=E6=96=B9=E6=B3=95=EF=BC=88map/filte?= =?UTF-8?q?r/take/drop/flatMap=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_builtins/src/iterator.rs | 610 ++++++++++ crates/oxide_vm/src/bindings/mod.rs | 50 + crates/oxide_vm/src/generator.rs | 9 +- .../oxide_vm/tests/builtins_iterator_tests.rs | 1031 +++++++++++++++++ 4 files changed, 1696 insertions(+), 4 deletions(-) diff --git a/crates/oxide_builtins/src/iterator.rs b/crates/oxide_builtins/src/iterator.rs index 1ff30d3b..b6a22c70 100644 --- a/crates/oxide_builtins/src/iterator.rs +++ b/crates/oxide_builtins/src/iterator.rs @@ -8,6 +8,13 @@ use oxide_runtime_api::{to_object, NativeResult, VmHost}; const INNER_PROP: &str = "__inner__"; const INDEX_PROP: &str = "__index__"; const MODE_PROP: &str = "__mode__"; +const NEXT_CACHE_PROP: &str = "__next__"; +const KIND_PROP: &str = "__kind__"; +const STATE_PROP: &str = "__state__"; +const COUNTER_PROP: &str = "__counter__"; +const CALLBACK_PROP: &str = "__callback__"; +const INNER_ITER_PROP: &str = "__inner_iter__"; +const INNER_NEXT_PROP: &str = "__inner_next__"; /// `Iterator` 构造逻辑:不是构造函数,`new Iterator()` / `Iterator()` 均抛 TypeError; /// subclass `super()` 路径放行并返回 undefined(原型由调用方按 newTarget 设置)。 @@ -284,6 +291,190 @@ fn counter_number(counter: i64) -> JsValue { } } +// ── 返回迭代器 5 方法(map/filter/take/drop/flatMap)── + +/// Iterator helper 的 kind 编码:wrapper `__kind__` 槽存枚举值, +/// `%IteratorHelperPrototype%` 的单一 next/return/throw 读槽后按 kind 分发 +/// (复用 Map/Set 迭代器 `__mode__` 分发模式)。判别值稳定,改动须同步 `from_i32`。 +#[derive(Clone, Copy, PartialEq)] +#[repr(i32)] +pub(crate) enum IteratorHelperKind { + Map = 0, + Filter = 1, + Take = 2, + Drop = 3, + FlatMap = 4, +} + +impl IteratorHelperKind { + fn from_i32(value: i32) -> Self { + match value { + 0 => Self::Map, + 1 => Self::Filter, + 2 => Self::Take, + 3 => Self::Drop, + 4 => Self::FlatMap, + _ => Self::Map, + } + } +} + +/// 读 wrapper 整型槽;槽缺失或类型不符时返回 `fallback`。 +fn read_slot_int(vm: &mut H, obj: &JsObject, si: u32, fallback: i32) -> i32 { + match vm.ordinary_get(obj, si, JsValue::undefined()) { + Ok(v) if v.is_int() => v.as_int(), + Ok(v) if v.is_double() => v.as_double() as i32, + _ => fallback, + } +} + +/// 读 wrapper 浮点槽(take/drop 的 remaining);槽缺失时返回 `fallback`。 +fn read_slot_double(vm: &mut H, obj: &JsObject, si: u32, fallback: f64) -> f64 { + match vm.ordinary_get(obj, si, JsValue::undefined()) { + Ok(v) if v.is_double() => v.as_double(), + Ok(v) if v.is_int() => v.as_int() as f64, + _ => fallback, + } +} + +/// 读 wrapper 计数器槽为 i64(map/filter/flatMap 的元素计数,可能溢出 i32)。 +fn read_counter(vm: &mut H, obj: &JsObject, si: u32) -> i64 { + match vm.ordinary_get(obj, si, JsValue::undefined()) { + Ok(v) if v.is_int() => v.as_int() as i64, + Ok(v) if v.is_double() => v.as_double() as i64, + _ => 0, + } +} + +/// ToIntegerOrInfinity 近似:ToNumber 后向零截断,保留 ±∞;NaN 判定由调用方 +/// 在截断前语义等价地做(`trunc(NaN)` 仍为 NaN)。ToNumber 抛错透传原异常值。 +fn to_integer_or_infinity(vm: &mut H, value: JsValue) -> Result { + let num = vm.coerce_number_bounded(value).map_err(|e| engine_error(vm, &e))?; + Ok(num.trunc()) +} + +/// take/drop 的共享前置:`this` 非对象 → TypeError;limit 经 ToIntegerOrInfinity +/// 校验(NaN/负值 → RangeError,ToNumber 抛错透传),校验失败均先关底层 +/// (2024 规范更新:参数校验失败也执行 IteratorClose,且不读 next)。 +/// +/// # 返回 +/// - `Ok((iterated, next, int_limit))`:GetIteratorDirect 结果 + 截断后的 limit +/// (±∞ 用 f64 哨兵表示)。 +fn validate_limit_and_get_direct( + vm: &mut H, this_val: JsValue, limit: JsValue, +) -> Result<(JsValue, JsValue, f64), JsValue> { + if !this_val.is_object() { + return Err(crate::error::create_type_error(vm, "Iterator.prototype method called on non-object")); + } + let int_limit = match to_integer_or_infinity(vm, limit) { + Ok(n) => n, + Err(v) => { + let _ = iterator_close_record(vm, this_val, Some(v)); + return Err(v); + } + }; + if int_limit.is_nan() || int_limit < 0.0 { + let err = crate::error::create_range_error(vm, "Iterator.prototype method requires a non-negative limit"); + let _ = iterator_close_record(vm, this_val, Some(err)); + return Err(err); + } + get_iterator_direct(vm, this_val).map(|(iterated, next)| (iterated, next, int_limit)) +} + +/// GetIteratorFlattenable(reject-primitives):把 flatMap 的 mapper 返回值解析为 +/// 内层迭代器记录(对象 + 缓存 next)。 +/// +/// 不能复用 [`get_iterator`]:后者对 Array 等内建集合直接返回原值、不走 +/// `@@iterator`,而 flattenable 要求数组经 `@@iterator` 产出内层迭代器。 +/// +/// # 步骤 +/// 1. 非对象 → TypeError(原始值一律拒绝,含字符串)。 +/// 2. `@@iterator` 可调用 → 调用,结果非对象 → TypeError;getter/call 抛错透传。 +/// 3. `@@iterator` 为 null/undefined → 回退原对象自身作迭代器(鸭子 next)。 +/// 4. `@@iterator` 为其它不可调用值 → TypeError。 +/// +/// # 返回 +/// - `Ok((iter, next))`:内层迭代器 + GetIteratorDirect 缓存的 next。 +fn get_iterator_flattenable(vm: &mut H, value: JsValue) -> Result<(JsValue, JsValue), JsValue> { + if !value.is_object() { + return Err(crate::error::create_type_error(vm, "iterator mapper result is not an object")); + } + let obj = unsafe { &*value.as_js_object_ptr() }; + let sym_iter_si = make_well_known_symbol_key(0); + let method = match vm.ordinary_get(obj, sym_iter_si, value) { + Ok(m) => m, + Err(err) => return Err(engine_error(vm, &err)), + }; + let inner = if is_callable(method) { + let it = vm.call_function_sync(method, value, &[]).map_err(|e| engine_error(vm, &e))?; + if !it.is_object() { + return Err(crate::error::create_type_error( + vm, + "iterator mapper result @@iterator returned a non-object", + )); + } + it + } else if method.is_undefined() || method.is_null() { + value + } else { + return Err(crate::error::create_type_error(vm, "iterator mapper result @@iterator is not callable")); + }; + get_iterator_direct(vm, inner) +} + +/// 创建 Iterator helper 结果对象:空对象挂 `%IteratorHelperPrototype%`,写 +/// `__inner__`/`__next__`/`__kind__`/`__state__`/`__counter__`/`__callback__` +/// 槽;flatMap 的内层槽初始为 undefined。next/return/throw 挂在共享原型上, +/// wrapper 不设 own 方法(与集合迭代器 wrapper 同构,GC 经 shape 属性槽自动遍历)。 +/// +/// # 参数 +/// - `counter`:map/filter/flatMap 传 `0`(int 计数),take/drop 传 +/// `float(int_limit)`(f64 remaining,`+∞` 为哨兵)。 +fn make_iterator_helper( + vm: &mut H, inner: JsValue, next: JsValue, kind: IteratorHelperKind, callback: JsValue, counter: JsValue, +) -> JsValue { + let helper_proto = vm.session().builtin_world().iterator_helper_proto.as_ptr() as *mut JsObject; + let wrapper = vm + .epoch() + .alloc(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(helper_proto))); + let wrapper_obj = unsafe { &mut *wrapper }; + let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0; + let next_si = vm.kernel_core().perm_interner().intern(NEXT_CACHE_PROP).0; + let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0; + let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0; + let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0; + let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0; + let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0; + let inner_next_si = vm.kernel_core().perm_interner().intern(INNER_NEXT_PROP).0; + vm.set_or_create_prop_value(wrapper_obj, inner_si, inner); + vm.set_or_create_prop_value(wrapper_obj, next_si, next); + vm.set_or_create_prop_value(wrapper_obj, kind_si, JsValue::int(kind as i32)); + vm.set_or_create_prop_value(wrapper_obj, state_si, JsValue::int(0)); + vm.set_or_create_prop_value(wrapper_obj, counter_si, counter); + vm.set_or_create_prop_value(wrapper_obj, callback_si, callback); + vm.set_or_create_prop_value(wrapper_obj, inner_iter_si, JsValue::undefined()); + vm.set_or_create_prop_value(wrapper_obj, inner_next_si, JsValue::undefined()); + JsValue::from_js_object(wrapper) +} + +/// 校验 wrapper 对象形态:`this` 非对象或非 helper wrapper(无 `__inner__` 槽) +/// → TypeError,等价规范的 RequireInternalSlot 检查。 +/// +/// # 返回 +/// - `Ok(inner)`:底层迭代器值(wrapper `__inner__` 槽)。 +fn validate_helper_this(vm: &mut H, this_val: JsValue, method: &str) -> Result { + if !this_val.is_object() { + return Err(crate::error::create_type_error(vm, &format!("{method} called on non-object"))); + } + let obj = unsafe { &*this_val.as_js_object_ptr() }; + let inner_si = vm.kernel_core().perm_interner().intern(INNER_PROP).0; + let inner = vm.ordinary_get(obj, inner_si, this_val).map_err(|e| engine_error(vm, &e))?; + if !inner.is_object() { + return Err(crate::error::create_type_error(vm, &format!("{method} called on non-iterator-helper"))); + } + Ok(inner) +} + // ── 终端 6 方法 ── /// `%Iterator.prototype%.forEach(procedure)`:消费全部元素,逐个调用 procedure。 @@ -535,6 +726,425 @@ fn make_array_from_list(vm: &mut H, items: &[JsValue]) -> JsValue { JsValue::from_js_object(arr) } +// ── 返回迭代器 5 方法 + %IteratorHelperPrototype% 状态机 ── + +/// `%Iterator.prototype%.map(mapper)`:逐元素 `mapper(value, counter)`,产出 +/// helper wrapper。 +/// +/// # 步骤 +/// 1. 共享前置:`this` 对象校验 + 回调可调用校验(失败关底层)+ GetIteratorDirect。 +/// 2. 建 Map wrapper(`__kind__`=0,回调存 `__callback__` 槽,计数从 0 起)。 +pub fn iterator_map(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let callback = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let (iterated, next) = match validate_terminal_and_get_direct(vm, this_val, callback) { + Ok(pair) => pair, + Err(v) => return NativeResult::Err(v), + }; + NativeResult::Ok(make_iterator_helper( + vm, + iterated, + next, + IteratorHelperKind::Map, + callback, + JsValue::int(0), + )) +} + +/// `%Iterator.prototype%.filter(predicate)`:谓词 truthy 的元素才产出, +/// 计数每元素 +1(含被过滤元素)。 +/// +/// # 步骤 +/// 1. 共享前置:`this` 对象校验 + 谓词可调用校验(失败关底层)+ GetIteratorDirect。 +/// 2. 建 Filter wrapper(`__kind__`=1)。 +pub fn iterator_filter(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let callback = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let (iterated, next) = match validate_terminal_and_get_direct(vm, this_val, callback) { + Ok(pair) => pair, + Err(v) => return NativeResult::Err(v), + }; + NativeResult::Ok(make_iterator_helper( + vm, + iterated, + next, + IteratorHelperKind::Filter, + callback, + JsValue::int(0), + )) +} + +/// `%Iterator.prototype%.take(limit)`:最多产出 limit 个元素,达标即关底层。 +/// +/// # 步骤 +/// 1. limit 经 ToIntegerOrInfinity 校验(NaN/负值 → RangeError 且关底层)。 +/// 2. 建 Take wrapper(`__counter__` 槽存 f64 remaining,+∞ 哨兵)。 +/// 3. next:remaining 为 0 → 关底层返回 done;否则递减后逐元素产出。 +pub fn iterator_take(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let limit = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let (iterated, next, int_limit) = match validate_limit_and_get_direct(vm, this_val, limit) { + Ok(triple) => triple, + Err(v) => return NativeResult::Err(v), + }; + NativeResult::Ok(make_iterator_helper( + vm, + iterated, + next, + IteratorHelperKind::Take, + JsValue::undefined(), + JsValue::float(int_limit), + )) +} + +/// `%Iterator.prototype%.drop(limit)`:跳过 limit 个元素后透传,永不主动关底层。 +/// +/// # 步骤 +/// 1. limit 经 ToIntegerOrInfinity 校验(NaN/负值 → RangeError 且关底层)。 +/// 2. 建 Drop wrapper(`__counter__` 槽存 f64 remaining,+∞ 哨兵)。 +/// 3. next:remaining>0 时循环跳过(耗尽不关底层),之后直通底层。 +pub fn iterator_drop(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let limit = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let (iterated, next, int_limit) = match validate_limit_and_get_direct(vm, this_val, limit) { + Ok(triple) => triple, + Err(v) => return NativeResult::Err(v), + }; + NativeResult::Ok(make_iterator_helper( + vm, + iterated, + next, + IteratorHelperKind::Drop, + JsValue::undefined(), + JsValue::float(int_limit), + )) +} + +/// `%Iterator.prototype%.flatMap(mapper)`:mapper 返回值经 GetIteratorFlattenable +/// 展开为内层迭代器,逐元素产出后再取外层下一元素。 +/// +/// # 步骤 +/// 1. 共享前置:`this` 对象校验 + 回调可调用校验(失败关底层)+ GetIteratorDirect。 +/// 2. 建 FlatMap wrapper(`__kind__`=4,内层槽初始为 undefined)。 +/// 3. next:内层活跃 → 步内层产出;内层耗尽 → 清槽后步外层 → mapper → +/// GetIteratorFlattenable 建新内层。 +pub fn iterator_flat_map(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let callback = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let (iterated, next) = match validate_terminal_and_get_direct(vm, this_val, callback) { + Ok(pair) => pair, + Err(v) => return NativeResult::Err(v), + }; + NativeResult::Ok(make_iterator_helper( + vm, + iterated, + next, + IteratorHelperKind::FlatMap, + callback, + JsValue::int(0), + )) +} + +/// `%IteratorHelperPrototype%.next`:读 wrapper `__kind__` 分发 5 种推进循环, +/// 统一完成态短路与重入守卫。 +/// +/// # 步骤 +/// 1. `__state__`=2(完成)→ 直接返回 `{undefined, true}`(return 不再转发)。 +/// 2. `__state__`=1(重入)→ TypeError(等价 GeneratorValidate 的 executing 检查)。 +/// 3. 置 1 后按 kind 推进:产出值 → 置回 0 返回 `{value, false}`;耗尽/错误 → 置 2 +/// 后返回 done / 透传异常(规范生成器 body 终止即 completed,后续调用短路)。 +pub fn iterator_helper_next(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let inner = match validate_helper_this(vm, this_val, "Iterator helper next") { + Ok(v) => v, + Err(v) => return NativeResult::Err(v), + }; + let helper = unsafe { &mut *this_val.as_js_object_ptr() }; + let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0; + let state = read_slot_int(vm, helper, state_si, 2); + if state == 2 { + return NativeResult::Ok(make_iter_result(vm, JsValue::undefined(), true)); + } + if state == 1 { + return NativeResult::Err(crate::error::create_type_error(vm, "Iterator helper is already executing")); + } + let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0; + let kind = IteratorHelperKind::from_i32(read_slot_int(vm, helper, kind_si, 0)); + vm.set_or_create_prop_value(helper, state_si, JsValue::int(1)); + let next_si = vm.kernel_core().perm_interner().intern(NEXT_CACHE_PROP).0; + let next = vm.ordinary_get(helper, next_si, this_val).unwrap_or(JsValue::undefined()); + let step = match kind { + IteratorHelperKind::Map => helper_step_map(vm, this_val, helper, inner, next), + IteratorHelperKind::Filter => helper_step_filter(vm, this_val, helper, inner, next), + IteratorHelperKind::Take => helper_step_take(vm, helper, inner, next), + IteratorHelperKind::Drop => helper_step_drop(vm, helper, inner, next), + IteratorHelperKind::FlatMap => helper_step_flat_map(vm, this_val, helper, inner, next), + }; + match step { + Ok(Some(value)) => { + vm.set_or_create_prop_value(helper, state_si, JsValue::int(0)); + NativeResult::Ok(make_iter_result(vm, value, false)) + } + Ok(None) => { + vm.set_or_create_prop_value(helper, state_si, JsValue::int(2)); + NativeResult::Ok(make_iter_result(vm, JsValue::undefined(), true)) + } + Err(exc) => { + vm.set_or_create_prop_value(helper, state_si, JsValue::int(2)); + NativeResult::Err(exc) + } + } +} + +/// `%IteratorHelperPrototype%.return`:关闭底层迭代器后置完成,返回 +/// `{undefined, true}`。 +/// +/// # 步骤 +/// 1. 完成态 → 直接返回 done(return 不重复转发)。 +/// 2. 重入(执行中)→ TypeError。 +/// 3. 置完成;flatMap 先关内层(return 语义:内层关闭错误优先于外层)再关外层; +/// 关闭抛错 → 传播,此后 next/return/throw 全部短路。 +pub fn iterator_helper_return(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let inner = match validate_helper_this(vm, this_val, "Iterator helper return") { + Ok(v) => v, + Err(v) => return NativeResult::Err(v), + }; + let helper = unsafe { &mut *this_val.as_js_object_ptr() }; + let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0; + let state = read_slot_int(vm, helper, state_si, 2); + if state == 2 { + return NativeResult::Ok(make_iter_result(vm, JsValue::undefined(), true)); + } + if state == 1 { + return NativeResult::Err(crate::error::create_type_error(vm, "Iterator helper is already executing")); + } + vm.set_or_create_prop_value(helper, state_si, JsValue::int(2)); + let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0; + if IteratorHelperKind::from_i32(read_slot_int(vm, helper, kind_si, 0)) == IteratorHelperKind::FlatMap { + let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0; + if let Ok(inner_iter) = vm.ordinary_get(helper, inner_iter_si, this_val) { + if inner_iter.is_object() { + // 内层关闭出错:以该错误关外层(外层 return 错误被吞),传播内层错误。 + if let Err(inner_err) = iterator_close_record(vm, inner_iter, None) { + let _ = iterator_close_record(vm, inner, Some(inner_err)); + return NativeResult::Err(inner_err); + } + } + } + } + match iterator_close_record(vm, inner, None) { + Ok(()) => NativeResult::Ok(make_iter_result(vm, JsValue::undefined(), true)), + Err(v) => NativeResult::Err(v), + } +} + +/// `%IteratorHelperPrototype%.throw(value)`:把 value 作为异常注入 helper。 +/// +/// # 步骤 +/// 1. 完成态 → 直接抛 value(GeneratorResumeAbrupt 的 completed 分支)。 +/// 2. 重入(执行中)→ TypeError。 +/// 3. 置完成;flatMap 先内层后外层关底层(原值恒胜出),再抛 value。 +pub fn iterator_helper_throw(vm: &mut H, args: &[u8]) -> NativeResult { + let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] }); + let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() }; + let inner = match validate_helper_this(vm, this_val, "Iterator helper throw") { + Ok(v) => v, + Err(v) => return NativeResult::Err(v), + }; + let helper = unsafe { &mut *this_val.as_js_object_ptr() }; + let state_si = vm.kernel_core().perm_interner().intern(STATE_PROP).0; + let state = read_slot_int(vm, helper, state_si, 2); + if state == 2 { + return NativeResult::Err(value); + } + if state == 1 { + return NativeResult::Err(crate::error::create_type_error(vm, "Iterator helper is already executing")); + } + vm.set_or_create_prop_value(helper, state_si, JsValue::int(2)); + let kind_si = vm.kernel_core().perm_interner().intern(KIND_PROP).0; + if IteratorHelperKind::from_i32(read_slot_int(vm, helper, kind_si, 0)) == IteratorHelperKind::FlatMap { + let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0; + if let Ok(inner_iter) = vm.ordinary_get(helper, inner_iter_si, this_val) { + if inner_iter.is_object() { + // throw 语义:原值胜出,内层/外层关闭错误均被吞。 + let _ = iterator_close_record(vm, inner_iter, Some(value)); + } + } + } + let _ = iterator_close_record(vm, inner, Some(value)); + NativeResult::Err(value) +} + +/// Map 推进:底层 step → `mapper(value, counter)` → 产出 mapped。mapper 抛错 +/// 关底层后透传原值;底层 step 错误不关(规范 IteratorStepValue 字面)。 +fn helper_step_map( + vm: &mut H, this_val: JsValue, helper: &mut JsObject, inner: JsValue, next: JsValue, +) -> Result, JsValue> { + let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0; + let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0; + let mapper = vm.ordinary_get(helper, callback_si, this_val).unwrap_or(JsValue::undefined()); + let counter = read_counter(vm, helper, counter_si); + let value = match iterator_record_step(vm, next, inner) { + Ok(Some(v)) => v, + Ok(None) => return Ok(None), + Err(v) => return Err(v), + }; + let cb_args = [value, counter_number(counter)]; + match vm.call_function_sync(mapper, JsValue::undefined(), &cb_args) { + Ok(mapped) => { + vm.set_or_create_prop_value(helper, counter_si, counter_number(counter + 1)); + Ok(Some(mapped)) + } + Err(err) => { + let exc = engine_error(vm, &err); + let _ = iterator_close_record(vm, inner, Some(exc)); + Err(exc) + } + } +} + +/// Filter 推进:底层 step → `predicate(value, counter)`;truthy 产出 value, +/// falsy 继续。counter 每元素 +1(含被过滤元素);谓词抛错关底层后透传原值。 +fn helper_step_filter( + vm: &mut H, this_val: JsValue, helper: &mut JsObject, inner: JsValue, next: JsValue, +) -> Result, JsValue> { + let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0; + let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0; + let predicate = vm.ordinary_get(helper, callback_si, this_val).unwrap_or(JsValue::undefined()); + let mut counter = read_counter(vm, helper, counter_si); + loop { + let value = match iterator_record_step(vm, next, inner) { + Ok(Some(v)) => v, + Ok(None) => return Ok(None), + Err(v) => return Err(v), + }; + let cb_args = [value, counter_number(counter)]; + match vm.call_function_sync(predicate, JsValue::undefined(), &cb_args) { + Ok(selected) => { + counter += 1; + vm.set_or_create_prop_value(helper, counter_si, counter_number(counter)); + if oxide_runtime_api::to_boolean(selected) { + return Ok(Some(value)); + } + } + Err(err) => { + let exc = engine_error(vm, &err); + let _ = iterator_close_record(vm, inner, Some(exc)); + return Err(exc); + } + } + } +} + +/// Take 推进:`__counter__` 槽存 f64 remaining;为 0 时关底层返回 done, +/// 否则递减后逐元素产出。自然耗尽或 limit 达标后的完成态短路使 return 不再转发。 +fn helper_step_take( + vm: &mut H, helper: &mut JsObject, inner: JsValue, next: JsValue, +) -> Result, JsValue> { + let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0; + let remaining = read_slot_double(vm, helper, counter_si, f64::INFINITY); + if remaining == 0.0 { + // remaining 归零:正常完成形态关底层(return 错误胜出)。 + return match iterator_close_record(vm, inner, None) { + Ok(()) => Ok(None), + Err(v) => Err(v), + }; + } + let remaining = if remaining == f64::INFINITY { f64::INFINITY } else { remaining - 1.0 }; + let value = match iterator_record_step(vm, next, inner) { + Ok(Some(v)) => v, + Ok(None) => return Ok(None), + Err(v) => return Err(v), + }; + vm.set_or_create_prop_value(helper, counter_si, JsValue::float(remaining)); + Ok(Some(value)) +} + +/// Drop 推进:先跳过 remaining 个元素(耗尽不关底层),随后直通底层产出。 +fn helper_step_drop( + vm: &mut H, helper: &mut JsObject, inner: JsValue, next: JsValue, +) -> Result, JsValue> { + let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0; + let mut remaining = read_slot_double(vm, helper, counter_si, 0.0); + while remaining > 0.0 { + if remaining != f64::INFINITY { + remaining -= 1.0; + } + match iterator_record_step(vm, next, inner) { + Ok(Some(_)) => {} + Ok(None) => return Ok(None), + Err(v) => return Err(v), + } + } + // 跳过完成:remaining 归 0,之后每次 next 直通底层。 + vm.set_or_create_prop_value(helper, counter_si, JsValue::float(0.0)); + let value = match iterator_record_step(vm, next, inner) { + Ok(Some(v)) => v, + Ok(None) => return Ok(None), + Err(v) => return Err(v), + }; + Ok(Some(value)) +} + +/// FlatMap 推进:内层活跃则步内层产出;内层耗尽则清槽回外层取下一映射。 +/// 内层步错只关外层(规范 IfAbruptCloseIterator(innerValue, iterated)), +/// 外层步错不关;mapper/flattenable 抛错关外层后透传原值。 +fn helper_step_flat_map( + vm: &mut H, this_val: JsValue, helper: &mut JsObject, outer: JsValue, outer_next: JsValue, +) -> Result, JsValue> { + let counter_si = vm.kernel_core().perm_interner().intern(COUNTER_PROP).0; + let callback_si = vm.kernel_core().perm_interner().intern(CALLBACK_PROP).0; + let inner_iter_si = vm.kernel_core().perm_interner().intern(INNER_ITER_PROP).0; + let inner_next_si = vm.kernel_core().perm_interner().intern(INNER_NEXT_PROP).0; + let mapper = vm.ordinary_get(helper, callback_si, this_val).unwrap_or(JsValue::undefined()); + let mut counter = read_counter(vm, helper, counter_si); + loop { + let inner_iter = vm.ordinary_get(helper, inner_iter_si, this_val).unwrap_or(JsValue::undefined()); + if inner_iter.is_object() { + let inner_next = vm.ordinary_get(helper, inner_next_si, this_val).unwrap_or(JsValue::undefined()); + match iterator_record_step(vm, inner_next, inner_iter) { + Ok(Some(v)) => return Ok(Some(v)), + Ok(None) => { + // 内层自然耗尽:不关内层(规范只置 innerAlive=false),清槽回外层。 + vm.set_or_create_prop_value(helper, inner_iter_si, JsValue::undefined()); + vm.set_or_create_prop_value(helper, inner_next_si, JsValue::undefined()); + continue; + } + Err(v) => { + let _ = iterator_close_record(vm, outer, Some(v)); + return Err(v); + } + } + } + let value = match iterator_record_step(vm, outer_next, outer) { + Ok(Some(v)) => v, + Ok(None) => return Ok(None), + Err(v) => return Err(v), + }; + let cb_args = [value, counter_number(counter)]; + let mapped = match vm.call_function_sync(mapper, JsValue::undefined(), &cb_args) { + Ok(m) => m, + Err(err) => { + let exc = engine_error(vm, &err); + let _ = iterator_close_record(vm, outer, Some(exc)); + return Err(exc); + } + }; + let (inner_it, inner_next_fn) = match get_iterator_flattenable(vm, mapped) { + Ok(pair) => pair, + Err(v) => { + let _ = iterator_close_record(vm, outer, Some(v)); + return Err(v); + } + }; + counter += 1; + vm.set_or_create_prop_value(helper, counter_si, counter_number(counter)); + vm.set_or_create_prop_value(helper, inner_iter_si, inner_it); + vm.set_or_create_prop_value(helper, inner_next_si, inner_next_fn); + } +} + /// `%IteratorPrototype%[@@iterator]`:返回 this(迭代器对象自迭代)。 /// /// 挂在 `%IteratorPrototype%` 上,所有集合迭代器经原型链继承,保证 diff --git a/crates/oxide_vm/src/bindings/mod.rs b/crates/oxide_vm/src/bindings/mod.rs index c87689bf..ad460062 100644 --- a/crates/oxide_vm/src/bindings/mod.rs +++ b/crates/oxide_vm/src/bindings/mod.rs @@ -458,6 +458,56 @@ fn bind_iterator_protos(core: &Arc, session: &KernelSession) { ); } + // %IteratorPrototype% 的 5 个返回迭代器方法(建 wrapper 挂 + // %IteratorHelperPrototype%):map/filter/take/drop/flatMap,length 均为 1。 + let si_map = core.perm_interner().intern("map").0; + if core.shape_forge().lookup_position(iter_proto.shape_id(), si_map).is_none() { + apply_binding_table( + world, + iter_proto, + core, + &[ + ("map", oxide_builtins::iterator::iterator_map:: as *const (), 1), + ("filter", oxide_builtins::iterator::iterator_filter:: as *const (), 1), + ("take", oxide_builtins::iterator::iterator_take:: as *const (), 1), + ("drop", oxide_builtins::iterator::iterator_drop:: as *const (), 1), + ("flatMap", oxide_builtins::iterator::iterator_flat_map:: as *const (), 1), + ], + ); + } + + // %IteratorHelperPrototype%:wrapper 结果对象的共享原型(链到 + // %IteratorPrototype%),绑 next/return/throw 三方法(throw length=1, + // next/return 为 0)+ @@toStringTag 数据属性 "Iterator Helper"。 + let helper_proto_ptr = world.iterator_helper_proto.as_ptr() as *mut JsObject; + let helper_proto = unsafe { &mut *helper_proto_ptr }; + let si_next = core.perm_interner().intern("next").0; + if core.shape_forge().lookup_position(helper_proto.shape_id(), si_next).is_none() { + apply_binding_table( + world, + helper_proto, + core, + &[ + ("next", oxide_builtins::iterator::iterator_helper_next:: as *const (), 0), + ( + "return", + oxide_builtins::iterator::iterator_helper_return:: as *const (), + 0, + ), + ("throw", oxide_builtins::iterator::iterator_helper_throw:: as *const (), 1), + ], + ); + } + if core + .shape_forge() + .lookup_position(helper_proto.shape_id(), sym_to_string_tag) + .is_none() + { + let sf = core.perm_interner().as_ref(); + let tag = JsValue::perm_string(sf.string_ptr(sf.intern("Iterator Helper").0)); + bind_well_known_data_property(core, helper_proto, 9, tag, PropAttributes::new(false, false, true)); + } + // %ArrayIteratorPrototype% 服务 Array/TA 两族;Map/Set 共用按 `__mode__` // 分发的实现;%RegExpStringIteratorPrototype% 供 matchAll。 bind_iterator_proto_next( diff --git a/crates/oxide_vm/src/generator.rs b/crates/oxide_vm/src/generator.rs index f5705a79..15c4b5ba 100644 --- a/crates/oxide_vm/src/generator.rs +++ b/crates/oxide_vm/src/generator.rs @@ -728,10 +728,11 @@ pub(crate) fn init_generator_intrinsics(vm: &mut Vm) { let sf = vm.kernel_core.perm_interner().as_ref(); let sh = vm.kernel_core.shape_forge().as_ref(); let fn_proto_val = vm.session.builtin_world().fn_proto_val(); - let object_proto_val = JsValue::from_js_object(vm.session.builtin_world().object_proto.as_ptr() as *mut JsObject); - - // %GeneratorPrototype%:proto = Object.prototype,方法 next/return/throw/@@iterator。 - let mut gen_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, object_proto_val)); + // %GeneratorPrototype%:proto = %IteratorPrototype%(生成器是迭代器,继承 + // @@iterator 与 Iterator helper 方法),方法 next/return/throw。 + let iterator_proto_val = + JsValue::from_js_object(vm.session.builtin_world().iterator_proto.as_ptr() as *mut JsObject); + let mut gen_proto = Box::new(JsObject::new_empty(EMPTY_SHAPE_ID, iterator_proto_val)); oxide_kernel::bind_methods_static!( &mut gen_proto, sf, diff --git a/crates/oxide_vm/tests/builtins_iterator_tests.rs b/crates/oxide_vm/tests/builtins_iterator_tests.rs index 634bc05b..21a4741f 100644 --- a/crates/oxide_vm/tests/builtins_iterator_tests.rs +++ b/crates/oxide_vm/tests/builtins_iterator_tests.rs @@ -1013,3 +1013,1034 @@ fn iterator_terminal_rebound_after_full_reset() { assert_eq!(result.as_bool(), expected, "for {}", src); } } + +// ── 返回迭代器 5 方法(map/filter/take/drop/flatMap)+ helper 状态机 ── + +#[test] +fn iterator_helper_map_filter_basic() { + // map/filter 正常路径:产出、counter 实参、回调 this 为 undefined。 + let mut vm = Vm::new(); + let str_cases = [ + ("[...Iterator.from([1, 2, 3]).map(function (v) { return v * 2; })].join(',')", "2,4,6"), + // 数组迭代器(非 from 包装)同样可消费。 + ("[...[1, 2, 3].values().map(function (v) { return v + 10; })].join(',')", "11,12,13"), + // filter 只产出 truthy 元素。 + ( + "[...Iterator.from([1, 2, 3, 4]).filter(function (v) { return v % 2 === 0; })].join(',')", + "2,4", + ), + // 谓词返回值被 ToBoolean 化。 + ("[...Iterator.from([0, 1, 2]).filter(function (v) { return v; })].join(',')", "1,2"), + // map 回调收 (value, counter)。 + ( + "var pairs = []; \ + var it = Iterator.from(['a', 'b']).map(function (v, i) { pairs.push(v + i); return v; }); \ + var x; \ + while (!(x = it.next()).done) {} \ + pairs.join(',')", + "a0,b1", + ), + // filter 计数含被过滤元素(0 被过滤但占用计数 0,命中元素用计数 1)。 + ( + "var pairs = []; \ + var it = Iterator.from([0, 1, 2]).filter(function (v, i) { pairs.push(i); return v > 0; }); \ + var x; \ + while (!(x = it.next()).done) {} \ + pairs.join(',')", + "0,1,2", + ), + ]; + for (src, expected) in str_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(to_str(&vm, result), expected, "for {}", src); + } + let bool_cases = [ + // 回调 this 为 undefined。 + ( + "var captured; Iterator.from([1]).map(function () { captured = this; return 1; }).next(); \ + captured === undefined", + true, + ), + // 空迭代立即 done。 + ("Iterator.from([]).map(function (v) { return v; }).next().done", true), + // 方法 length 均为 1。 + ("Iterator.prototype.map.length === 1 && Iterator.prototype.filter.length === 1", true), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_take_drop_basic() { + // take/drop 正常路径:计数边界、limit 校验、自然耗尽。 + let mut vm = Vm::new(); + let str_cases = [ + ("[...Iterator.from([1, 2, 3]).take(2)].join(',')", "1,2"), + ("[...Iterator.from([1, 2, 3]).take(5)].join(',')", "1,2,3"), + ("[...Iterator.from([1, 2, 3]).take(0)].join(',')", ""), + ("[...Iterator.from([1, 2, 3]).take(Infinity)].join(',')", "1,2,3"), + ("[...Iterator.from([1, 2, 3]).drop(2)].join(',')", "3"), + ("[...Iterator.from([1, 2, 3]).drop(0)].join(',')", "1,2,3"), + ("[...Iterator.from([1, 2, 3]).drop(10)].join(',')", ""), + ("[...Iterator.from([1, 2, 3]).drop(Infinity)].join(',')", ""), + // 链式组合。 + ("[...Iterator.from([1, 2, 3, 4, 5]).drop(1).take(3)].join(',')", "2,3,4"), + ]; + for (src, expected) in str_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(to_str(&vm, result), expected, "for {}", src); + } + let bool_cases = [ + // -0.5 → trunc(-0) 合法;null → 0 合法。 + ("[...Iterator.from([1]).take(-0.5)].join(',') === ''", true), + ("[...Iterator.from([1, 2]).take(null)].join(',') === ''", true), + ("[...Iterator.from([1, 2]).drop(null)].join(',') === '1,2'", true), + // limit 经 valueOf/toString 强制转换。 + ( + "var n = { valueOf: function () { return 1; } }; \ + [...Iterator.from([1, 2]).take(n)].join(',') === '1'", + true, + ), + ( + "var n = { toString: function () { return '1'; } }; \ + [...Iterator.from([1, 2]).drop(n)].join(',') === '2'", + true, + ), + // 方法 length 均为 1。 + ("Iterator.prototype.take.length === 1 && Iterator.prototype.drop.length === 1", true), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_take_drop_limit_validation() { + // NaN/负值/缺失 limit → RangeError 且关底层;ToNumber 抛错原值透传且关底层; + // next getter 在 limit 校验前不被读取。 + let mut vm = Vm::new(); + let bool_cases = [ + // take()/take(undefined)/NaN/-1 → RangeError。 + ( + "var closed = 0; \ + var c = { __proto__: Iterator.prototype, get next() { throw new RangeError('read'); }, \ + return() { closed++; return {}; } }; \ + var ok = false; \ + try { c.take(); } catch (e) { ok = e instanceof RangeError; } \ + ok && closed === 1", + true, + ), + ( + "var closed = 0; \ + var c = { __proto__: Iterator.prototype, get next() { throw new RangeError('read'); }, \ + return() { closed++; return {}; } }; \ + var ok = false; \ + try { c.take(NaN); } catch (e) { ok = e instanceof RangeError; } \ + ok && closed === 1", + true, + ), + ( + "var closed = 0; \ + var c = { __proto__: Iterator.prototype, get next() { throw new RangeError('read'); }, \ + return() { closed++; return {}; } }; \ + var ok = false; \ + try { c.drop(-1); } catch (e) { ok = e instanceof RangeError; } \ + ok && closed === 1", + true, + ), + // limit valueOf 抛错:原异常透传且关底层。 + ( + "var closed = 0; \ + var c = { __proto__: Iterator.prototype, get next() { throw new RangeError('read'); }, \ + return() { closed++; return {}; } }; \ + var boom = new RangeError('boom'); \ + var ok = false; \ + try { c.take({ valueOf: function () { throw boom; } }); } catch (e) { ok = e === boom; } \ + ok && closed === 1", + true, + ), + // 校验失败不读 next(getter 抛错也不触发)。 + ( + "var closed = 0; var read = false; \ + var c = { __proto__: Iterator.prototype, \ + get next() { read = true; return function () {}; }, \ + return() { closed++; return {}; } }; \ + var ok = false; \ + try { c.take(-1); } catch (e) { ok = e instanceof RangeError; } \ + ok && closed === 1 && read === false", + true, + ), + // this 非对象:直接 TypeError,不读 limit/不关。 + ( + "var ok = false; \ + try { Iterator.prototype.take.call(1, 0); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_take_exhaustion_closes() { + // take 达标即关底层(return 被调用);自然耗尽不关;关后再调 next 全短路。 + let mut vm = Vm::new(); + let bool_cases = [ + // take(0):首个 next 即关底层(return 抛错传播)。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; throw new RangeError('boom'); } \ + } \ + var it = new CI().take(0); \ + var threw = false; \ + try { it.next(); } catch (e) { threw = e instanceof RangeError; } \ + it.next().done && threw && closed === 1", + true, + ), + // take(1):取 1 个后第二次 next 关底层。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().take(1); \ + it.next().value === 1 && it.next().done && closed === 1", + true, + ), + // take(5) 但底层 3 个:自然耗尽不关底层。 + ( + "var closed = 0; \ + var i = 0; \ + class CI extends Iterator { \ + next() { i++; return i <= 3 ? { done: false, value: i } : { done: true, value: undefined }; } \ + return() { closed++; return {}; } \ + } \ + var out = 0; \ + var it = new CI().take(5); \ + var x; \ + while (!(x = it.next()).done) out += x.value; \ + out === 6 && closed === 0", + true, + ), + // return 方法转发:显式 return() 关底层且只关一次。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().take(100); \ + it.return(); it.return(); \ + closed === 1", + true, + ), + // return getter 抛错:return() 时该错误胜出。 + ( + "class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + get return() { throw new RangeError('boom'); } \ + } \ + var it = new CI().take(1); \ + it.next(); \ + var threw = false; \ + try { it.return(); } catch (e) { threw = e instanceof RangeError; } \ + threw", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_drop_exhaustion_no_close() { + // drop 耗尽/跳过永不主动关底层;return() 转发仍生效。 + let mut vm = Vm::new(); + let bool_cases = [ + // drop(10) 消耗 3 个元素后自然耗尽,return 不被调用。 + ( + "var closed = 0; \ + var i = 0; \ + class CI extends Iterator { \ + next() { i++; return i <= 3 ? { done: false, value: i } : { done: true, value: undefined }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().drop(10); \ + var x; \ + while (!(x = it.next()).done) {} \ + closed === 0", + true, + ), + // 显式 return() 关底层且只关一次。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().drop(1); \ + it.return(); it.return(); \ + closed === 1", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_flat_map_semantics() { + // flatMap 正常路径:数组/生成器/纯 next 对象展开、回退路径、原始值拒绝。 + let mut vm = Vm::new(); + let str_cases = [ + // mapper 返回数组:经 @@iterator 展开。 + ("[...Iterator.from([1, 2]).flatMap(function (v) { return [v, v * 10]; })].join(',')", "1,10,2,20"), + // mapper 返回生成器。 + ( + "[...Iterator.from([1, 2]).flatMap(function (v) { return (function* () { yield v; yield v + 1; })(); })].join(',')", + "1,2,2,3", + ), + // mapper 返回纯 next 对象(无 @@iterator,回退鸭子 next)。 + ( + "function* h() { yield 0; yield 1; yield 2; } \ + var it = Iterator.from([1]).flatMap(function () { \ + var n = h(); \ + return { [Symbol.iterator]: null, next: function () { return n.next(); } }; \ + }); \ + [...it].join(',')", + "0,1,2", + ), + // 空数组内层:跳过并继续外层。 + ("[...Iterator.from([1, 2]).flatMap(function () { return []; })].join(',')", ""), + // counter 只按外层元素递增。 + ( + "var pairs = []; \ + var it = Iterator.from(['a', 'b']).flatMap(function (v, i) { pairs.push(v + i); return [v]; }); \ + var x; \ + while (!(x = it.next()).done) {} \ + pairs.join(',')", + "a0,b1", + ), + // 字符串包装对象可展开(对象走 @@iterator)。 + ("[...Iterator.from([1]).flatMap(function () { return new String('ab'); })].join(',')", "a,b"), + ]; + for (src, expected) in str_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(to_str(&vm, result), expected, "for {}", src); + } + let bool_cases = [ + // 已关闭的生成器作内层:首次 next 即 done,直接回到外层。 + ( + "function* g() { yield 0; yield 1; yield 2; } \ + var closed = g(); \ + closed.return(); \ + closed.return = function () { throw new RangeError('boom'); }; \ + var it = g().flatMap(function (v) { return closed; }); \ + it.next().done", + true, + ), + // mapper 返回原始值(含字符串)→ TypeError。 + ( + "var it = Iterator.from([1]).flatMap(function () { return 5; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + ( + "var it = Iterator.from([1]).flatMap(function () { return 'str'; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + // @@iterator 非 null/undefined 且不可调用 → TypeError。 + ( + "var it = Iterator.from([1]).flatMap(function () { return { [Symbol.iterator]: 0, next: function () {} }; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + // @@iterator 结果非对象 → TypeError。 + ( + "var it = Iterator.from([1]).flatMap(function () { return { [Symbol.iterator]: function () { return 5; } }; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + // 方法 length 为 1。 + ("Iterator.prototype.flatMap.length === 1", true), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_wrapper_proto_and_shape() { + // wrapper 挂 %IteratorHelperPrototype%:instanceof Iterator、原型链、 + // 三方法 + @@toStringTag、无 own next。 + let mut vm = Vm::new(); + let bool_cases = [ + ("Iterator.from([1]).map(function (x) { return x; }) instanceof Iterator", true), + ( + "var it = Iterator.from([1]).filter(function () { return true; }); \ + Object.getPrototypeOf(it)[Symbol.toStringTag] === 'Iterator Helper'", + true, + ), + ( + "var it = Iterator.from([1]).take(1); \ + Object.getPrototypeOf(it) !== Iterator.prototype \ + && Object.getPrototypeOf(Object.getPrototypeOf(it)) === Iterator.prototype", + true, + ), + ( + "var p = Object.getPrototypeOf(Iterator.from([1]).map(function (x) { return x; })); \ + typeof p.next === 'function' && typeof p.return === 'function' && typeof p.throw === 'function'", + true, + ), + // next/return length 0,throw length 1。 + ( + "var p = Object.getPrototypeOf(Iterator.from([1]).map(function (x) { return x; })); \ + p.next.length === 0 && p.return.length === 0 && p.throw.length === 1", + true, + ), + // helper 原型经原型链可迭代(%IteratorPrototype% 的 @@iterator)。 + ( + "var p = Object.getPrototypeOf(Iterator.from([1]).map(function (x) { return x; })); \ + p[Symbol.iterator]() === p", + true, + ), + // 5 方法 name/描述符。 + ( + "Iterator.prototype.map.name === 'map' && Iterator.prototype.filter.name === 'filter' \ + && Iterator.prototype.take.name === 'take' && Iterator.prototype.drop.name === 'drop' \ + && Iterator.prototype.flatMap.name === 'flatMap'", + true, + ), + ( + "var d = Object.getOwnPropertyDescriptor(Iterator.prototype, 'map'); \ + d.writable === true && d.enumerable === false && d.configurable === true", + true, + ), + // this 非对象 → TypeError。 + ( + "try { Iterator.prototype.map.call(1, function () {}); false } \ + catch (e) { e instanceof TypeError }", + true, + ), + // 非 helper 对象调用原型 next → TypeError。 + ( + "var p = Object.getPrototypeOf(Iterator.from([1]).map(function (x) { return x; })); \ + var ok = false; \ + try { p.next.call({}); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_return_throw_state_machine() { + // return/throw 三方法状态机:转发、完成态短路、错误胜出。 + let mut vm = Vm::new(); + let bool_cases = [ + // return 转发底层且只关一次。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().map(function (x) { return x; }); \ + it.next(); \ + it.return(); it.return(); \ + closed === 1 && it.next().done", + true, + ), + // 自然耗尽后 return 不转发。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: true, value: undefined }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().map(function (x) { return x; }); \ + it.next(); \ + it.return(); \ + closed === 0", + true, + ), + // 底层 return 抛错:return() 传播该错误,此后 next 全 done。 + ( + "class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { throw new RangeError('boom'); } \ + } \ + var it = new CI().map(function (x) { return x; }); \ + var threw = false; \ + try { it.return(); } catch (e) { threw = e instanceof RangeError; } \ + threw && it.next().done && it.return().done", + true, + ), + // throw 注入:置完成 + 关底层 + 原值传播。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().map(function (x) { return x; }); \ + var ok = false; \ + try { it.throw(42); } catch (e) { ok = e === 42; } \ + ok && closed === 1 && it.next().done", + true, + ), + // 完成态 throw:直接抛值(不关底层)。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: true, value: undefined }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().map(function (x) { return x; }); \ + it.next(); \ + var ok = false; \ + try { it.throw(7); } catch (e) { ok = e === 7; } \ + ok && closed === 0", + true, + ), + // throw 时底层 return 也抛错:原值胜出。 + ( + "class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { throw new RangeError('close'); } \ + } \ + var it = new CI().map(function (x) { return x; }); \ + var ok = false; \ + try { it.throw(42); } catch (e) { ok = e === 42; } \ + ok", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_flat_map_return_closes_inner_then_outer() { + // flatMap 内层活跃时 return:先关内层再关外层;内层 return 错误优先胜出。 + let mut vm = Vm::new(); + let bool_cases = [ + ( + "var innerClosed = 0; var outerClosed = 0; \ + var it = Iterator.from([1]).flatMap(function (v) { \ + return { next: function () { return { done: false, value: 1 }; }, \ + return: function () { innerClosed++; return {}; } }; \ + }); \ + it.next(); \ + it.return(); \ + innerClosed === 1", + true, + ), + // 外层 return 错误传播(内层正常关闭后)。 + ( + "var outerClosed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { outerClosed++; throw new RangeError('boom'); } \ + } \ + var it = new CI().flatMap(function (v) { \ + return { next: function () { return { done: false, value: 1 }; }, \ + return: function () { return {}; } }; \ + }); \ + it.next(); \ + var threw = false; \ + try { it.return(); } catch (e) { threw = e instanceof RangeError; } \ + threw && outerClosed === 1", + true, + ), + // 内层 return 错误优先于外层。 + ( + "var innerClosed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { return {}; } \ + } \ + var it = new CI().flatMap(function (v) { \ + return { next: function () { return { done: false, value: 1 }; }, \ + return: function () { innerClosed++; throw new RangeError('inner'); } }; \ + }); \ + it.next(); \ + var ok = false; \ + try { it.return(); } catch (e) { ok = e instanceof RangeError; } \ + ok && innerClosed === 1", + true, + ), + // 内层未起步(未 next)时 return 只关外层。 + ( + "var outerClosed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { outerClosed++; return {}; } \ + } \ + var it = new CI().flatMap(function (v) { return [v]; }); \ + it.return(); \ + outerClosed === 1", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_reentrancy_guard() { + // 5 方法重入守卫:推进期间再调 next → TypeError,且底层不被二次推进。 + let mut vm = Vm::new(); + let bool_cases = [ + // map:mapper 内重入。 + ( + "var enterCount = 0; \ + var gen = (function* () { yield 1; })(); \ + var it = gen.map(function (v) { enterCount++; it.next(); return v; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok && enterCount === 1", + true, + ), + // filter:谓词内重入。 + ( + "var enterCount = 0; \ + var gen = (function* () { yield 1; })(); \ + var it = gen.filter(function (v) { enterCount++; it.next(); return true; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok && enterCount === 1", + true, + ), + // take:底层 next 内重入。 + ( + "var enterCount = 0; \ + class CI extends Iterator { \ + next() { enterCount++; it.next(); return { done: false, value: 1 }; } \ + } \ + var it = new CI().take(100); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok && enterCount === 1", + true, + ), + // drop:底层 next 内重入。 + ( + "var enterCount = 0; \ + class CI extends Iterator { \ + next() { enterCount++; it.next(); return { done: false, value: 1 }; } \ + } \ + var it = new CI().drop(0); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok && enterCount === 1", + true, + ), + // flatMap:mapper 内重入。 + ( + "var enterCount = 0; \ + var gen = (function* () { yield 1; })(); \ + var it = gen.flatMap(function (v) { enterCount++; it.next(); return [v]; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok && enterCount === 1", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_callback_error_passthrough() { + // 回调抛错:原值透传(任意类型不二次包装),且关底层。 + let mut vm = Vm::new(); + let bool_cases = [ + // 非 Error 原值 42 透传。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; return {}; } \ + } \ + var it = new CI().map(function () { throw 42; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e === 42; } \ + ok && closed === 1", + true, + ), + // filter 谓词抛错同样处理。 + ( + "var sentinel = new RangeError('boom'); \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { return {}; } \ + } \ + var it = new CI().filter(function () { throw sentinel; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e === sentinel; } \ + ok", + true, + ), + // 回调抛错且底层 return 也抛错:原错误胜出。 + ( + "class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { throw new RangeError('close'); } \ + } \ + var it = new CI().map(function () { throw 42; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e === 42; } \ + ok", + true, + ), + // 回调抛错后 helper 完成:再调 next 全 done。 + ( + "class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { return {}; } \ + } \ + var it = new CI().map(function () { throw 42; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e === 42; } \ + ok && it.next().done", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_validation_failure_closes() { + // 回调不可调用:抛 TypeError 且关底层,且不读 next(2024 规范更新)。 + let mut vm = Vm::new(); + let bool_cases = [ + ( + "var closed = 0; \ + var c = { __proto__: Iterator.prototype, get next() { throw new RangeError('read'); }, \ + return() { closed++; return {}; } }; \ + var ok = false; \ + try { c.map(); } catch (e) { ok = e instanceof TypeError; } \ + ok && closed === 1", + true, + ), + ( + "var closed = 0; \ + var c = { __proto__: Iterator.prototype, get next() { throw new RangeError('read'); }, \ + return() { closed++; return {}; } }; \ + var ok = false; \ + try { c.flatMap({}); } catch (e) { ok = e instanceof TypeError; } \ + ok && closed === 1", + true, + ), + ( + "var closed = 0; var read = false; \ + var c = { __proto__: Iterator.prototype, \ + get next() { read = true; return function () {}; }, \ + return() { closed++; return {}; } }; \ + var ok = false; \ + try { c.filter(null); } catch (e) { ok = e instanceof TypeError; } \ + ok && closed === 1 && read === false", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_get_next_only_once_and_parallel() { + // next getter 只在建 wrapper 时读一次;底层可被并行推进(共享同一底层)。 + let mut vm = Vm::new(); + let bool_cases = [ + // 5 方法各自只读一次 next。 + ( + "var gets = 0; \ + class C extends Iterator { \ + get next() { gets++; return function () { return { done: true, value: undefined }; }; } \ + } \ + new C().map(function (x) { return x; }); \ + new C().filter(function () { return true; }); \ + new C().take(1); \ + new C().drop(1); \ + new C().flatMap(function () { return []; }); \ + gets === 5", + true, + ), + // 底层直接推进后 helper 从当前位置继续。 + ( + "var it = (function* () { for (var i = 0; i < 5; ++i) yield i; })(); \ + var mapped = it.map(function (x) { return x; }); \ + it.next(); \ + mapped.next().value === 1 && mapped.next().value === 2", + true, + ), + // 底层提前关闭后 helper 立即 done。 + ( + "var it = (function* () { for (var i = 0; i < 5; ++i) yield i; })(); \ + var mapped = it.map(function (x) { return x; }); \ + it.return(); \ + mapped.next().done", + true, + ), + // 底层 next 返回非对象:helper next 抛 TypeError(不关底层)。 + ( + "class CI extends Iterator { \ + next() { return null; } \ + return() { throw new RangeError('boom'); } \ + } \ + var it = new CI().map(function (x) { return x; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + // flatMap 内层 next 抛错:关外层不关内层。 + ( + "var outerClosed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { outerClosed++; return {}; } \ + } \ + var innerClosed = 0; \ + var it = new CI().flatMap(function (v) { \ + return { next: function () { throw new RangeError('inner'); }, \ + return: function () { innerClosed++; return {}; } }; \ + }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof RangeError; } \ + ok && outerClosed === 1 && innerClosed === 0", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_generator_proto_chain() { + // %GeneratorPrototype% 链到 %IteratorPrototype%:生成器可调用全部 helper。 + let mut vm = Vm::new(); + let bool_cases = [ + ( + "Object.getPrototypeOf(Object.getPrototypeOf(function* () {}.prototype)) === Iterator.prototype", + true, + ), + ( + "var gen = (function* () { yield 1; yield 2; })(); \ + Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(gen))) === Iterator.prototype", + true, + ), + // 生成器实例直接可用 5 helper。 + ( + "var g = (function* () { yield 1; yield 2; yield 3; })(); \ + [...g.map(function (x) { return x * 2; })].join(',') === '2,4,6'", + true, + ), + ( + "var g = (function* () { yield 1; yield 2; yield 3; })(); \ + [...g.filter(function (x) { return x > 1; })].join(',') === '2,3'", + true, + ), + ( + "var g = (function* () { yield 1; yield 2; yield 3; })(); \ + [...g.take(2)].join(',') === '1,2'", + true, + ), + ( + "var g = (function* () { yield 1; yield 2; yield 3; })(); \ + [...g.drop(1)].join(',') === '2,3'", + true, + ), + ( + "var g = (function* () { yield 1; })(); \ + [...g.flatMap(function (x) { return [x, x]; })].join(',') === '1,1'", + true, + ), + // 生成器结果对象是 Iterator。 + ("(function* () {})().map(function (x) { return x; }) instanceof Iterator", true), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_plain_call_and_edge_cases() { + // 非 Iterator 子类但实现迭代协议的 this(.call 路径)、已耗尽底层、 + // next getter 抛错、非可调用底层 next。 + let mut vm = Vm::new(); + let bool_cases = [ + // .call 在纯 next 对象上可用(this-plain-iterator)。 + ( + "var it = { next: function () { var i = 0; return function () { i++; \ + return i <= 2 ? { done: false, value: i } : { done: true }; }; }() }; \ + var m = Iterator.prototype.map.call(it, function (x) { return x * 2; }); \ + var out = []; \ + var x; \ + while (!(x = m.next()).done) out.push(x.value); \ + out.join(',') === '2,4'", + true, + ), + // 已耗尽底层:map 结果首个 next 即 done。 + ( + "var it = (function* () {})(); \ + it.next(); \ + it.map(function (x) { return x; }).next().done", + true, + ), + // next getter 在方法调用时抛错:原错误透传(回调合法时读 next)。 + ( + "class TI extends Iterator { get next() { throw new RangeError('boom'); } } \ + var ok = false; \ + try { new TI().map(function (x) { return x; }); } catch (e) { ok = e instanceof RangeError; } \ + ok", + true, + ), + // 底层 next 非可调用:建 wrapper 成功,首个 helper next 抛 TypeError。 + ( + "var it = Iterator.prototype.map.call({ next: 0 }, function (x) { return x; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok", + true, + ), + // 底层在 map 之前被关闭:helper next 立即 done。 + ( + "var it = (function* () { yield 1; })(); \ + it.return(); \ + var m = it.map(function (x) { return x; }); \ + m.next().done", + true, + ), + // 链式 map×3 的 return 逐层关闭到底层。 + ( + "var closed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { closed++; throw new RangeError('boom'); } \ + } \ + var it = new CI().map(function (x) { return x; }).map(function (x) { return x; }); \ + var threw = false; \ + try { it.return(); } catch (e) { threw = e instanceof RangeError; } \ + threw && closed === 1", + true, + ), + // flatMap 内层返回 [Symbol.iterator]: 0(不可调用)→ TypeError 且关外层。 + ( + "var outerClosed = 0; \ + class CI extends Iterator { \ + next() { return { done: false, value: 1 }; } \ + return() { outerClosed++; return {}; } \ + } \ + var it = new CI().flatMap(function () { return { [Symbol.iterator]: 0, next: function () {} }; }); \ + var ok = false; \ + try { it.next(); } catch (e) { ok = e instanceof TypeError; } \ + ok && outerClosed === 1", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +} + +#[test] +fn iterator_helper_rebound_after_full_reset() { + // dirty reset 后 5 返回迭代器方法 + helper 原型三方法重绑正确。 + let mut vm = Vm::new(); + unsafe { &mut *(vm.session().builtin_world().iterator_proto.as_ptr() as *mut JsObject) }.bump_generation(); + vm.full_reset(); + let bool_cases = [ + ( + "var out = []; \ + var it = Iterator.from([1, 2, 3]).map(function (v) { return v * 2; }); \ + var x; \ + while (!(x = it.next()).done) out.push(x.value); \ + out.join(',') === '2,4,6'", + true, + ), + ( + "var it = Iterator.from([1, 2, 3]).filter(function (v) { return v % 2 === 1; }); \ + [...it].join(',') === '1,3'", + true, + ), + ( + "var it = Iterator.from([1, 2, 3]).take(2); \ + [...it].join(',') === '1,2'", + true, + ), + ( + "var it = Iterator.from([1, 2, 3]).drop(1); \ + [...it].join(',') === '2,3'", + true, + ), + ( + "var it = Iterator.from([1, 2]).flatMap(function (v) { return [v, v]; }); \ + [...it].join(',') === '1,1,2,2'", + true, + ), + ( + "var it = Iterator.from([1]).map(function (x) { return x; }); \ + Object.getPrototypeOf(it)[Symbol.toStringTag] === 'Iterator Helper'", + true, + ), + // 生成器原型链在 reset 后仍指向新 %IteratorPrototype%。 + ( + "Object.getPrototypeOf(Object.getPrototypeOf(function* () {}.prototype)) === Iterator.prototype", + true, + ), + // helper 三方法可用。 + ( + "var it = Iterator.from([1, 2]).map(function (x) { return x; }); \ + it.return().done === true", + true, + ), + ]; + for (src, expected) in bool_cases { + let result = eval(&mut vm, src).unwrap(); + assert_eq!(result.as_bool(), expected, "for {}", src); + } +}