mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-27 04:01:11 +08:00
fix: with 三步序位复原并三法回落同类型构造
This commit is contained in:
@@ -137,6 +137,14 @@ fn create_typed_array<H: VmHost>(
|
|||||||
vm.alloc_object(obj)
|
vm.alloc_object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TypedArrayCreateSameType 单长度参数形态:按 O 的类型建同长度新对象
|
||||||
|
/// (规范上忽略 species,toReversed/toSorted/with 的交付语义)。
|
||||||
|
fn create_same_type_typed_array<H: VmHost>(vm: &mut H, kind: TypedArrayKind, length: usize) -> *mut JsObject {
|
||||||
|
let bpe = kind.bytes_per_element();
|
||||||
|
let buffer = JsValue::from_js_object(new_array_buffer(vm, vec![0; length * bpe]));
|
||||||
|
create_typed_array(vm, kind, buffer, 0, length)
|
||||||
|
}
|
||||||
|
|
||||||
fn typed_array_data_ptr(obj: &JsObject) -> Option<*mut TypedArrayData> {
|
fn typed_array_data_ptr(obj: &JsObject) -> Option<*mut TypedArrayData> {
|
||||||
if !obj.is_typed_array_obj() {
|
if !obj.is_typed_array_obj() {
|
||||||
return None;
|
return None;
|
||||||
@@ -1585,18 +1593,12 @@ pub fn typed_array_to_locale_string<H: VmHost>(vm: &mut H, args: &[u8]) -> Nativ
|
|||||||
NativeResult::Ok(vm.new_string(&parts.join(",")))
|
NativeResult::Ok(vm.new_string(&parts.join(",")))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `%TypedArray%.prototype.toReversed()`:返回元素反转的、经 species 构造的
|
/// `%TypedArray%.prototype.toReversed()`:返回元素反转的 TypedArrayCreateSameType
|
||||||
/// 新 TypedArray(原对象不变)。
|
/// 新 TypedArray(同类型、忽略 species;原对象不变)。
|
||||||
pub fn typed_array_to_reversed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn typed_array_to_reversed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
let view = native_try!(get_typed_array_data(vm, this_val));
|
let view = native_try!(get_typed_array_data(vm, this_val));
|
||||||
let a = native_try!(typed_array_species_create(
|
let a = JsValue::from_js_object(create_same_type_typed_array(vm, view.kind, view.length));
|
||||||
vm,
|
|
||||||
this_val,
|
|
||||||
view.kind,
|
|
||||||
vec![JsValue::int(view.length as i32)],
|
|
||||||
Some(view.length),
|
|
||||||
));
|
|
||||||
for i in 0..view.length {
|
for i in 0..view.length {
|
||||||
let elem = native_try!(ta_read(vm, view, view.length - 1 - i));
|
let elem = native_try!(ta_read(vm, view, view.length - 1 - i));
|
||||||
native_try!(set_typed_array_element(vm, a, i, elem));
|
native_try!(set_typed_array_element(vm, a, i, elem));
|
||||||
@@ -1604,8 +1606,8 @@ pub fn typed_array_to_reversed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
|
|||||||
NativeResult::Ok(a)
|
NativeResult::Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `%TypedArray%.prototype.toSorted(comparefn)`:返回元素排序后的、经 species
|
/// `%TypedArray%.prototype.toSorted(comparefn)`:返回元素排序后的
|
||||||
/// 构造的新 TypedArray(原对象不变)。
|
/// TypedArrayCreateSameType 新 TypedArray(同类型、忽略 species;原对象不变)。
|
||||||
pub fn typed_array_to_sorted<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn typed_array_to_sorted<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
let view = native_try!(get_typed_array_data(vm, this_val));
|
let view = native_try!(get_typed_array_data(vm, this_val));
|
||||||
@@ -1665,22 +1667,17 @@ pub fn typed_array_to_sorted<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
|||||||
if let Some(err) = sort_error {
|
if let Some(err) = sort_error {
|
||||||
return NativeResult::Err(err);
|
return NativeResult::Err(err);
|
||||||
}
|
}
|
||||||
let a = native_try!(typed_array_species_create(
|
let a = JsValue::from_js_object(create_same_type_typed_array(vm, view.kind, vals.len()));
|
||||||
vm,
|
|
||||||
this_val,
|
|
||||||
view.kind,
|
|
||||||
vec![JsValue::int(vals.len() as i32)],
|
|
||||||
Some(vals.len()),
|
|
||||||
));
|
|
||||||
for (k, v) in vals.into_iter().enumerate() {
|
for (k, v) in vals.into_iter().enumerate() {
|
||||||
native_try!(set_typed_array_element(vm, a, k, v));
|
native_try!(set_typed_array_element(vm, a, k, v));
|
||||||
}
|
}
|
||||||
NativeResult::Ok(a)
|
NativeResult::Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `%TypedArray%.prototype.with(index, value)`:返回替换指定索引元素后的、经
|
/// `%TypedArray%.prototype.with(index, value)`:返回替换指定索引元素后的
|
||||||
/// species 构造的新 TypedArray;负索引从尾部折算,折算后越界抛 RangeError
|
/// TypedArrayCreateSameType 新 TypedArray(同类型、忽略 species)。
|
||||||
/// (先于 value 的类型转换)。
|
/// 负索引从尾部折算;value 的类型转换(ToNumber/ToBigInt,副作用对后续源元素读
|
||||||
|
/// 可见)先于越界 RangeError。
|
||||||
pub fn typed_array_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn typed_array_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||||
let view = native_try!(get_typed_array_data(vm, this_val));
|
let view = native_try!(get_typed_array_data(vm, this_val));
|
||||||
@@ -1701,21 +1698,17 @@ pub fn typed_array_with<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
} else {
|
} else {
|
||||||
view.length as f64 + relative_index
|
view.length as f64 + relative_index
|
||||||
};
|
};
|
||||||
|
// 规范步 7/8:value 先转换(副作用/抛错原样上抛),步 9 才做越界检查。
|
||||||
|
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
||||||
|
let replacement = native_try!(ta_element_value(vm, view.kind, value));
|
||||||
if actual_index.is_nan() || actual_index < 0.0 || actual_index >= view.length as f64 {
|
if actual_index.is_nan() || actual_index < 0.0 || actual_index >= view.length as f64 {
|
||||||
return NativeResult::Err(range_error(vm, "Invalid typed array index"));
|
return NativeResult::Err(range_error(vm, "Invalid typed array index"));
|
||||||
}
|
}
|
||||||
let index = actual_index as usize;
|
let index = actual_index as usize;
|
||||||
let value = if args.len() > 2 { vm.reg(args[2]) } else { JsValue::undefined() };
|
let a = JsValue::from_js_object(create_same_type_typed_array(vm, view.kind, view.length));
|
||||||
let a = native_try!(typed_array_species_create(
|
// 目标索引写已转换的 value(副作用已先于源读发生),其余索引顺序拷源元素。
|
||||||
vm,
|
|
||||||
this_val,
|
|
||||||
view.kind,
|
|
||||||
vec![JsValue::int(view.length as i32)],
|
|
||||||
Some(view.length),
|
|
||||||
));
|
|
||||||
// 目标索引写 value(经目标元素类型转换),其余索引顺序拷源元素。
|
|
||||||
for i in 0..view.length {
|
for i in 0..view.length {
|
||||||
let elem = if i == index { value } else { native_try!(ta_read(vm, view, i)) };
|
let elem = if i == index { replacement } else { native_try!(ta_read(vm, view, i)) };
|
||||||
native_try!(set_typed_array_element(vm, a, i, elem));
|
native_try!(set_typed_array_element(vm, a, i, elem));
|
||||||
}
|
}
|
||||||
NativeResult::Ok(a)
|
NativeResult::Ok(a)
|
||||||
|
|||||||
@@ -552,8 +552,8 @@ fn typed_array_species_insufficient_length_throws() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typed_array_species_non_ctor_and_non_ta_throws() {
|
fn typed_array_species_non_ctor_and_non_ta_throws() {
|
||||||
// species 构造结果非 TypedArray(filter 得空函数构造体 / toSorted 得普通对象)
|
// species 构造结果非 TypedArray(filter 得空函数构造体 / map 得普通对象)
|
||||||
// 抛 TypeError。
|
// 抛 TypeError(toReversed/toSorted/with 走 SameType 忽略 species,不在其列)。
|
||||||
let mut vm = Vm::new();
|
let mut vm = Vm::new();
|
||||||
let result = eval(
|
let result = eval(
|
||||||
&mut vm,
|
&mut vm,
|
||||||
@@ -564,7 +564,7 @@ fn typed_array_species_non_ctor_and_non_ta_throws() {
|
|||||||
catch (e) { t = e instanceof TypeError; } \
|
catch (e) { t = e instanceof TypeError; } \
|
||||||
var r = new Uint8Array(1); \
|
var r = new Uint8Array(1); \
|
||||||
r.constructor = { [Symbol.species]: function () { return {}; } }; \
|
r.constructor = { [Symbol.species]: function () { return {}; } }; \
|
||||||
try { r.toSorted(); t = t && false; } \
|
try { r.map(function (v) { return v; }); t = t && false; } \
|
||||||
catch (e) { t = t && e instanceof TypeError; } \
|
catch (e) { t = t && e instanceof TypeError; } \
|
||||||
return t; })()",
|
return t; })()",
|
||||||
)
|
)
|
||||||
@@ -653,17 +653,21 @@ fn typed_array_species_use_default_ctor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typed_array_species_immutable_methods_same_shape() {
|
fn typed_array_same_type_immutable_methods_ignore_species() {
|
||||||
// toReversed/toSorted/with 同走 species 构造(长度 = 源长度)。
|
// toReversed/toSorted/with 走 TypedArrayCreateSameType(规范语义:忽略
|
||||||
|
// species):species 构造器不被调用,结果为接收者同类型的内建实例。
|
||||||
let mut vm = Vm::new();
|
let mut vm = Vm::new();
|
||||||
let result = eval(
|
let result = eval(
|
||||||
&mut vm,
|
&mut vm,
|
||||||
"(function () { var ta = new Uint8Array([1, 2, 3]); var seen; \
|
"(function () { var ta = new Uint8Array([1, 2, 3]); var called; \
|
||||||
ta.constructor = { [Symbol.species]: function (n) { \
|
ta.constructor = { [Symbol.species]: function (n) { \
|
||||||
seen = n; return new Uint8Array(n); } }; \
|
called = true; return new Int32Array(n); } }; \
|
||||||
var r = ta.toReversed(); var so = ta.toSorted(); var w = ta.with(1, 9); \
|
var r = ta.toReversed(); var so = ta.toSorted(); var w = ta.with(1, 9); \
|
||||||
return r.length === 3 && r.at(0) === 3 && so.at(0) === 1 && \
|
return called === undefined && \
|
||||||
w.at(1) === 9 && seen === 3; })()",
|
Object.getPrototypeOf(r) === Uint8Array.prototype && \
|
||||||
|
Object.getPrototypeOf(so) === Uint8Array.prototype && \
|
||||||
|
Object.getPrototypeOf(w) === Uint8Array.prototype && \
|
||||||
|
r.length === 3 && r.at(0) === 3 && so.at(0) === 1 && w.at(1) === 9; })()",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(result.as_bool());
|
assert!(result.as_bool());
|
||||||
|
|||||||
Reference in New Issue
Block a user