mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 七构造器绑定 Symbol.species 静态访问器
This commit is contained in:
@@ -802,10 +802,12 @@ fn symbol_split_undefined_limit_full() {
|
||||
#[test]
|
||||
fn symbol_match_all_species_matcher_and_cached_lastindex() {
|
||||
let mut vm = Vm::new();
|
||||
// matcher 经物种构造;lastIndex 只从 R 读一次并写入 matcher。
|
||||
// matcher 经物种构造;lastIndex 只从 R 读一次并写入 matcher。静态 species 是
|
||||
// getter-only 访问器,简单赋值静默失效(set 为 undefined),须 defineProperty
|
||||
// 重定义为数据属性才能覆写。
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(() => { var r = /b/g; r.lastIndex = 2; var ctorCalls = 0; r.constructor[Symbol.species] = function() { ctorCalls += 1; return /b/g; }; var it = r[Symbol.matchAll]('abc'); return ctorCalls + '/' + it.__mal_re__.lastIndex; })()",
|
||||
"(() => { var r = /b/g; r.lastIndex = 2; var ctorCalls = 0; Object.defineProperty(r.constructor, Symbol.species, { value: function() { ctorCalls += 1; return /b/g; }, configurable: true }); var it = r[Symbol.matchAll]('abc'); return ctorCalls + '/' + it.__mal_re__.lastIndex; })()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(to_str(&vm, result), "1/2");
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_types::value::JsValue;
|
||||
use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
let allocator = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||
vm.run(&Arc::new(module))
|
||||
}
|
||||
|
||||
/// 七构造器 `Symbol.species` 静态 getter 的规范描述符面:
|
||||
/// `{ get, set:undefined, enumerable:false, configurable:true }`、`get.length === 0`、
|
||||
/// `get.name === "get [Symbol.species]"`,getter 返回 receiver。
|
||||
fn assert_species_accessor(ctor_name: &str) {
|
||||
let mut vm = Vm::new();
|
||||
let source = format!(
|
||||
"var d = Object.getOwnPropertyDescriptor({ctor_name}, Symbol.species); \
|
||||
d !== undefined && d.set === undefined && d.enumerable === false && d.configurable === true && \
|
||||
typeof d.get === 'function' && d.get.length === 0 && d.get.name === 'get [Symbol.species]' && \
|
||||
d.get.call({ctor_name}) === {ctor_name} && d.get.call('x') === 'x'"
|
||||
);
|
||||
let result = eval(&mut vm, &source).unwrap();
|
||||
assert!(result.as_bool(), "{ctor_name} species accessor descriptor mismatch");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn array_buffer_species_accessor_descriptor() {
|
||||
assert_species_accessor("ArrayBuffer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_species_accessor_descriptor() {
|
||||
assert_species_accessor("Map");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_species_accessor_descriptor() {
|
||||
assert_species_accessor("Set");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regexp_species_accessor_descriptor() {
|
||||
assert_species_accessor("RegExp");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn promise_species_accessor_descriptor() {
|
||||
assert_species_accessor("Promise");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typed_array_abstract_species_descriptor_and_chain_read() {
|
||||
// 抽象构造器 own 访问器;具体构造器无 own(gOPD 为 undefined),链上读回自身。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"var d = Object.getOwnPropertyDescriptor(TypedArray, Symbol.species); \
|
||||
d !== undefined && d.set === undefined && d.enumerable === false && d.configurable === true && \
|
||||
d.get.name === 'get [Symbol.species]' && d.get.length === 0 && \
|
||||
TypedArray[Symbol.species] === TypedArray && \
|
||||
Object.getOwnPropertyDescriptor(Uint8Array, Symbol.species) === undefined && \
|
||||
Uint8Array[Symbol.species] === Uint8Array && \
|
||||
Object.getOwnPropertyDescriptor(BigUint64Array, Symbol.species) === undefined && \
|
||||
BigUint64Array[Symbol.species] === BigUint64Array",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn species_subclasses_resolve_own_constructor() {
|
||||
// 派生类无 own @@species,沿静态原型链命中基类同一 getter,receiver 为自身。
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"class SubMap extends Map {} \
|
||||
class SubSet extends Set {} \
|
||||
class SubBuf extends ArrayBuffer {} \
|
||||
class SubRe extends RegExp {} \
|
||||
class SubP extends Promise {} \
|
||||
SubMap[Symbol.species] === SubMap && SubSet[Symbol.species] === SubSet && \
|
||||
SubBuf[Symbol.species] === SubBuf && SubRe[Symbol.species] === SubRe && SubP[Symbol.species] === SubP && \
|
||||
Object.getOwnPropertyDescriptor(SubMap, Symbol.species) === undefined",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
Reference in New Issue
Block a user