mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 11:41:13 +08:00
fix: BigInt64Array/BigUint64Array 与 DataView BigInt 存取走真 BigInt 语义
TA 元素读写按 kind 分流:BigInt 类型走 ToBigInt(Number 入参抛 TypeError、 写入 mod 2^64 截断、读出为真 BigInt 值),数值类型走 ToNumber 且显式拒绝 BigInt 值;消除 64 位整数经 f64 中转的静默精度丢失。 - runtime_api 新增公共 to_bigint_full / string_to_bigint_full,bigint 构造器 与 asIntN/asUintN 改调公共版消除双实现 - sort/toSorted 默认序对 BigInt 类型按 i64/u64 值比较;reverse/copyWithin/ filter/toReversed/with 消除无谓数值中转 - 构造器第一参数非对象统一走 ToIndex(bool/null/BigInt/字符串),Symbol 抛 TypeError - DataView get/setBigInt64/getBigUint64 返回 BigInt 值、入参按 ToBigInt 校验 - 测试:精度往返 / TypeError / mod 2^64 / 字节序 / 排序 / 回调值类型断言
This commit is contained in:
@@ -234,95 +234,14 @@ fn bigint_arg<H: VmHost>(vm: &mut H, args: &[u8]) -> JsValue {
|
||||
|
||||
/// ToBigInt 抽象操作(§7.1.14):BigInt 原样;String → StringToBigInt;
|
||||
/// Boolean → 0/1;Number/Symbol/undefined/null → TypeError;对象先 ToPrimitive 再递归。
|
||||
///
|
||||
/// 语义主体在 `oxide_runtime_api::to_bigint_full`,此处只把 String 错误恢复为
|
||||
/// 对应 kind 的异常对象(用户回调抛出的原始值经 last_uncaught_value 透传)。
|
||||
fn to_bigint<H: VmHost>(vm: &mut H, val: JsValue) -> Result<JsValue, JsValue> {
|
||||
if val.is_bigint() {
|
||||
return Ok(val);
|
||||
match oxide_runtime_api::to_bigint_full(val, vm) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(vm
|
||||
.take_uncaught_value()
|
||||
.unwrap_or_else(|| crate::error::create_from_text(vm, &e))),
|
||||
}
|
||||
if val.is_bool() {
|
||||
return Ok(vm.new_bigint(BigInt::from(if val.as_bool() { 1 } else { 0 })));
|
||||
}
|
||||
if val.is_int() {
|
||||
// ToBigInt(Number) 抛 TypeError(与构造器不同:构造器先 ToPrimitive 再
|
||||
// NumberToBigInt;ToBigInt 直接拒绝 Number)。
|
||||
return Err(crate::error::create_type_error(vm, "Cannot convert a Number value to a BigInt"));
|
||||
}
|
||||
if val.is_double() {
|
||||
return Err(crate::error::create_type_error(vm, "Cannot convert a Number value to a BigInt"));
|
||||
}
|
||||
if val.is_string() {
|
||||
let s = oxide_runtime_api::to_string(val);
|
||||
return match string_to_bigint(vm, &s) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
}
|
||||
if val.is_object() {
|
||||
let prim = match to_primitive(val, ToPrimitiveHint::Default, vm) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return Err(exc);
|
||||
}
|
||||
return Err(crate::error::create_type_error(vm, "Cannot convert value to a BigInt"));
|
||||
}
|
||||
};
|
||||
return to_bigint(vm, prim);
|
||||
}
|
||||
// undefined / null / symbol。
|
||||
Err(crate::error::create_type_error(vm, "Cannot convert value to a BigInt"))
|
||||
}
|
||||
|
||||
/// StringToBigInt(§7.1.14 步骤):去首尾空白,可选 +/- 号与 0x/0o/0b 前缀;
|
||||
/// 空串 → 0n;非法 → SyntaxError。
|
||||
fn string_to_bigint<H: VmHost>(vm: &mut H, s: &str) -> Result<JsValue, JsValue> {
|
||||
let trimmed = s.trim();
|
||||
if trimmed.is_empty() {
|
||||
return Ok(vm.new_bigint(BigInt::from(0)));
|
||||
}
|
||||
let (neg, rest) = if let Some(r) = trimmed.strip_prefix('-') {
|
||||
(true, r)
|
||||
} else if let Some(r) = trimmed.strip_prefix('+') {
|
||||
(false, r)
|
||||
} else {
|
||||
(false, trimmed)
|
||||
};
|
||||
// StringIntegerLiteral:符号只允许出现在纯十进制前;0x/0o/0b 前缀前带
|
||||
// +/-(如 "-0x1")属于非法语法(test262 constructor-from-string-syntax-errors)。
|
||||
let (radix, digits) = if let Some(hex) = rest.strip_prefix("0x").or_else(|| rest.strip_prefix("0X")) {
|
||||
if neg {
|
||||
return Err(crate::error::create_syntax_error(
|
||||
vm,
|
||||
"Cannot convert string to BigInt: invalid integer literal",
|
||||
));
|
||||
}
|
||||
(16u32, hex)
|
||||
} else if let Some(oct) = rest.strip_prefix("0o").or_else(|| rest.strip_prefix("0O")) {
|
||||
if neg {
|
||||
return Err(crate::error::create_syntax_error(
|
||||
vm,
|
||||
"Cannot convert string to BigInt: invalid integer literal",
|
||||
));
|
||||
}
|
||||
(8u32, oct)
|
||||
} else if let Some(bin) = rest.strip_prefix("0b").or_else(|| rest.strip_prefix("0B")) {
|
||||
if neg {
|
||||
return Err(crate::error::create_syntax_error(
|
||||
vm,
|
||||
"Cannot convert string to BigInt: invalid integer literal",
|
||||
));
|
||||
}
|
||||
(2u32, bin)
|
||||
} else {
|
||||
(10u32, rest)
|
||||
};
|
||||
if digits.is_empty() {
|
||||
return Err(crate::error::create_syntax_error(
|
||||
vm,
|
||||
"Cannot convert string to BigInt: invalid integer literal",
|
||||
));
|
||||
}
|
||||
let m = BigInt::parse_bytes(digits.as_bytes(), radix).ok_or_else(|| {
|
||||
crate::error::create_syntax_error(vm, "Cannot convert string to BigInt: invalid integer literal")
|
||||
})?;
|
||||
Ok(vm.new_bigint(if neg { -m } else { m }))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user