feat: 迭代器原型基建:%IteratorPrototype% 链 + 各集合迭代器原型
新增 %IteratorPrototype%(含 @@iterator 返回自身,经原型链被全部迭代器 继承,it[Symbol.iterator]() === it 恒等)与 %ArrayIteratorPrototype%/ %MapIteratorPrototype%/%SetIteratorPrototype%/%StringIteratorPrototype%/ %RegExpStringIteratorPrototype%(链到 %IteratorPrototype%);Array/Map/Set/ TA/String/matchAll 迭代器包装统一挂对应原型;补 Array/String 的 @@iterator 别名绑定。集合迭代器原型不含 return 方法(规范集合迭代器无 return)。
This commit is contained in:
@@ -70,6 +70,8 @@ pub fn bind_array(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
|
||||
if let Some(pos) = core.shape_forge().lookup_position(array_proto.shape_id(), si) {
|
||||
array_proto.set_data_meta(pos, PropAttributes::new(true, false, true));
|
||||
}
|
||||
// Array.prototype[@@iterator] 与 values 共享同一函数对象。
|
||||
super::bind_well_known_method_alias(core, array_proto, "values", 0);
|
||||
|
||||
let ctor_ptr = session.builtin_world().array_constructor.as_ptr() as *mut JsObject;
|
||||
bind_constructor!(core, global, "Array", ctor_ptr, oxide_builtins::array::array_constructor::<crate::vm::Vm>, 1, hash: true);
|
||||
|
||||
@@ -26,4 +26,18 @@ pub fn bind_iterator(core: &Arc<KernelCore>, session: &KernelSession, global: &m
|
||||
);
|
||||
|
||||
bind_global_value(core, global, "Iterator", JsValue::from_js_object(Box::into_raw(iterator)));
|
||||
|
||||
// %IteratorPrototype% 自身可迭代:@@iterator 返回 this,经原型链被所有
|
||||
// 集合迭代器继承(it[Symbol.iterator]() === it 恒等)。
|
||||
let iter_proto_ptr = session.builtin_world().iterator_proto.as_ptr() as *mut JsObject;
|
||||
let iter_proto = unsafe { &mut *iter_proto_ptr };
|
||||
crate::bindings::bind_well_known_method(
|
||||
session.builtin_world(),
|
||||
core,
|
||||
iter_proto,
|
||||
0,
|
||||
"iterator",
|
||||
oxide_builtins::iterator::iterator_symbol_iterator::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,16 @@ pub fn bind_string(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
|
||||
core,
|
||||
&[("toString", oxide_builtins::string::string_to_string::<crate::vm::Vm> as *const (), 0)],
|
||||
);
|
||||
// String.prototype[@@iterator]:逐 code point 迭代字符。
|
||||
super::bind_well_known_method(
|
||||
session.builtin_world(),
|
||||
core,
|
||||
proto,
|
||||
0,
|
||||
"iterator",
|
||||
oxide_builtins::string::string_symbol_iterator::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
);
|
||||
|
||||
let si_str = core.perm_interner().intern("String").0;
|
||||
let str_shape = core.shape_forge().make_shape(global.shape_id(), si_str);
|
||||
|
||||
@@ -380,6 +380,19 @@ fn bind_iterator_global(core: &Arc<KernelCore>, session: &KernelSession, global:
|
||||
&[("from", oxide_builtins::iterator::iterator_from::<crate::vm::Vm> as *const (), 1)],
|
||||
);
|
||||
bind_existing_global(core, global, "Iterator", JsValue::from_js_object(Box::into_raw(iterator)));
|
||||
|
||||
// %IteratorPrototype% 自身可迭代(@@iterator 返回 this,经原型链被全部集合迭代器继承)。
|
||||
let iter_proto_ptr = session.builtin_world().iterator_proto.as_ptr() as *mut JsObject;
|
||||
let iter_proto = unsafe { &mut *iter_proto_ptr };
|
||||
bind_well_known_method(
|
||||
session.builtin_world(),
|
||||
core,
|
||||
iter_proto,
|
||||
0,
|
||||
"iterator",
|
||||
oxide_builtins::iterator::iterator_symbol_iterator::<crate::vm::Vm> as *const (),
|
||||
0,
|
||||
);
|
||||
}
|
||||
|
||||
fn bind_stub_globals(core: &Arc<KernelCore>, session: &KernelSession, global: &mut JsObject) {
|
||||
|
||||
@@ -95,3 +95,84 @@ fn for_of_string_chars() {
|
||||
let result = eval(&mut vm, "var out = []; for (const c of 'abc') out.push(c); out.join('')").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "abc");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator_proto_chain_and_self_iteration() {
|
||||
let mut vm = Vm::new();
|
||||
let cases = [
|
||||
// 各家族迭代器自迭代恒等(%IteratorPrototype% 的 @@iterator 返回 this)。
|
||||
("var it = [1,2].values(); it[Symbol.iterator]() === it", true),
|
||||
("var it = new Map([['a',1]]).values(); it[Symbol.iterator]() === it", true),
|
||||
("var it = new Set([1]).values(); it[Symbol.iterator]() === it", true),
|
||||
("var it = new Uint8Array([1]).values(); it[Symbol.iterator]() === it", true),
|
||||
("var it = 'abc'[Symbol.iterator](); it[Symbol.iterator]() === it", true),
|
||||
("var it = 'ab'.matchAll(/a/g); it[Symbol.iterator]() === it", true),
|
||||
// Array/TA 共享 %ArrayIteratorPrototype%;Map/Set 各自原型内部共享。
|
||||
("Object.getPrototypeOf([].values()) === Object.getPrototypeOf([].entries())", true),
|
||||
("Object.getPrototypeOf(new Uint8Array(0).values()) === Object.getPrototypeOf([].values())", true),
|
||||
("Object.getPrototypeOf(new Map().values()) === Object.getPrototypeOf(new Map().keys())", true),
|
||||
("Object.getPrototypeOf(new Set().values()) === Object.getPrototypeOf(new Set().entries())", true),
|
||||
// %IteratorPrototype% 自身可迭代:其 @@iterator 返回 this。
|
||||
(
|
||||
"var P = Object.getPrototypeOf(Object.getPrototypeOf([].values())); P[Symbol.iterator]() === P",
|
||||
true,
|
||||
),
|
||||
// 原型链:%ArrayIteratorPrototype% → %IteratorPrototype% → Object.prototype。
|
||||
(
|
||||
"Object.getPrototypeOf(Object.getPrototypeOf([].values())) === \
|
||||
Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf([].values())))",
|
||||
false,
|
||||
),
|
||||
(
|
||||
"Object.getPrototypeOf(Object.getPrototypeOf([].values()))[Symbol.iterator] === \
|
||||
Object.getPrototypeOf(new Map().values())[Symbol.iterator]",
|
||||
true,
|
||||
),
|
||||
];
|
||||
for (src, expected) in cases {
|
||||
let result = eval(&mut vm, src).unwrap();
|
||||
assert_eq!(result.as_bool(), expected, "for {}", src);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_string_symbol_iterator_bound() {
|
||||
let mut vm = Vm::new();
|
||||
// G4 别名:Array/String 的 @@iterator 属性存在且可迭代。
|
||||
let bool_cases = [
|
||||
("[][Symbol.iterator] === [].values", true),
|
||||
("var out = []; for (const c of 'a\\u{1F600}b') out.push(c); out.length === 3", true),
|
||||
];
|
||||
for (src, expected) in bool_cases {
|
||||
let result = eval(&mut vm, src).unwrap();
|
||||
assert_eq!(result.as_bool(), expected, "for {}", src);
|
||||
}
|
||||
let str_cases = [
|
||||
("typeof 'abc'[Symbol.iterator]", "function"),
|
||||
("[...'ab'].join('')", "ab"),
|
||||
("Array.from('ab').join('')", "ab"),
|
||||
("[...[1,2,3]].join(',')", "1,2,3"),
|
||||
("Array.from([1,2]).join(',')", "1,2"),
|
||||
];
|
||||
for (src, expected) in str_cases {
|
||||
let result = eval(&mut vm, src).unwrap();
|
||||
assert_eq!(to_str(&vm, result), expected, "for {}", src);
|
||||
}
|
||||
// String 迭代器语义:null/undefined 抛 TypeError,对象走 ToString。
|
||||
let err = eval(&mut vm, "try { String.prototype[Symbol.iterator].call(null) } catch (e) { e.name }").unwrap();
|
||||
assert_eq!(to_str(&vm, err), "TypeError");
|
||||
let result = eval(&mut vm, "[...String.prototype[Symbol.iterator].call({toString: () => 'xy'})].join('')").unwrap();
|
||||
assert_eq!(to_str(&vm, result), "xy");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator_proto_object_proto_parent() {
|
||||
// 链:values() → %ArrayIteratorPrototype% → %IteratorPrototype% → Object.prototype。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf([].values()))) === Object.prototype",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user