feat: BigInt constructor ToPrimitive semantics, toString(radix), asIntN/asUintN; ctor [[Prototype]]=Function.prototype
This commit is contained in:
@@ -1,16 +1,10 @@
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
use oxide_runtime_api::{to_primitive, NativeResult, ToPrimitiveHint, VmHost};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// JS `BigInt()` 构造逻辑:把参数转成 BigInt 值。
|
||||
///
|
||||
/// 普通调用返回原始 BigInt;`new BigInt()` 抛 TypeError(BigInt 不可构造)。
|
||||
/// 参数转换规则(最小子集):
|
||||
/// - 无参数 → `0n`
|
||||
/// - BigInt → 原样返回
|
||||
/// - Number → 截断为整数(非整数抛 RangeError)
|
||||
/// - String → 解析十进制整数
|
||||
/// - Boolean → `0n`/`1n`
|
||||
/// - 其它类型 → TypeError
|
||||
/// JS `BigInt(value)` 构造逻辑(ES2020 §20.2.1.1):
|
||||
/// - `new BigInt()` 抛 TypeError(BigInt 不可 new)
|
||||
/// - 无参 → `0n`
|
||||
/// - 其余参数先 ToPrimitive(number),Number 走 NumberToBigInt,其余走 ToBigInt。
|
||||
pub fn bigint_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
if args.len() > 1 {
|
||||
let this_val = vm.reg(args[0]);
|
||||
@@ -22,31 +16,170 @@ pub fn bigint_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
));
|
||||
}
|
||||
}
|
||||
let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
match to_bigint_value(vm, val) {
|
||||
// 无参 BigInt() → 0n(注意 BigInt(undefined) 必须抛 TypeError)。
|
||||
if args.len() <= 1 {
|
||||
return NativeResult::Ok(vm.new_bigint(0));
|
||||
}
|
||||
let val = vm.reg(args[1]);
|
||||
// ToPrimitive(value, number):对象先出盒,用户 @@toPrimitive/valueOf/toString
|
||||
// 抛出的异常要原样传播(只触发一次,见 constructor-coercion 测试)。
|
||||
let prim = match to_primitive(val, ToPrimitiveHint::Number, vm) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return NativeResult::Err(exc);
|
||||
}
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Cannot convert value to a BigInt",
|
||||
));
|
||||
}
|
||||
};
|
||||
// 步骤 3:Type(prim) 为 Number → NumberToBigInt。
|
||||
if prim.is_int() {
|
||||
return NativeResult::Ok(vm.new_bigint(prim.as_int() as i128));
|
||||
}
|
||||
if prim.is_double() {
|
||||
let d = prim.as_double();
|
||||
if d.is_nan() || d.is_infinite() || d.trunc() != d {
|
||||
return NativeResult::Err(crate::error::create_range_error(
|
||||
vm,
|
||||
"The number cannot be converted to a BigInt because it is not an integer",
|
||||
));
|
||||
}
|
||||
// i128 暂存上限:超出范围的整数后续由任意精度表示补齐。
|
||||
if d < i128::MIN as f64 || d > i128::MAX as f64 {
|
||||
return NativeResult::Err(crate::error::create_range_error(
|
||||
vm,
|
||||
"The number is too large to be converted to a BigInt",
|
||||
));
|
||||
}
|
||||
return NativeResult::Ok(vm.new_bigint(d.trunc() as i128));
|
||||
}
|
||||
// 步骤 4:其它原始类型走 ToBigInt。
|
||||
match to_bigint(vm, prim) {
|
||||
Ok(v) => NativeResult::Ok(v),
|
||||
Err(err) => NativeResult::Err(err),
|
||||
Err(e) => NativeResult::Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// `BigInt.prototype.toString`:返回 BigInt 的十进制字符串。
|
||||
/// `BigInt.prototype.toString(radix)`:thisBigIntValue 后按 radix 输出。
|
||||
pub fn bigint_to_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(args[0]);
|
||||
if !this_val.is_bigint() {
|
||||
return NativeResult::Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"BigInt.prototype.toString called on incompatible receiver",
|
||||
));
|
||||
}
|
||||
let v = unsafe { oxide_runtime_api::bigint_data(this_val) };
|
||||
NativeResult::Ok(vm.new_string(&oxide_runtime_api::bigint_to_string(v)))
|
||||
let v = match this_bigint_value(vm, this_val) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return NativeResult::Err(e),
|
||||
};
|
||||
let radix = if args.len() > 1 {
|
||||
let radix_arg = vm.reg(args[1]);
|
||||
if radix_arg.is_undefined() {
|
||||
10u32
|
||||
} else {
|
||||
// radix 走 ToIntegerOrInfinity:ToNumber 拒绝 Symbol/BigInt,
|
||||
// 对象先 ToPrimitive(用户异常原样传播),NaN/±0 归 0。
|
||||
let raw = match coerce_number_or_throw(vm, radix_arg) {
|
||||
Ok(n) => n,
|
||||
Err(e) => return NativeResult::Err(e),
|
||||
};
|
||||
let r = if raw.is_nan() || raw == 0.0 {
|
||||
0.0
|
||||
} else if raw.is_infinite() {
|
||||
raw
|
||||
} else {
|
||||
raw.trunc()
|
||||
};
|
||||
if !(2.0..=36.0).contains(&r) {
|
||||
return NativeResult::Err(crate::error::create_range_error(
|
||||
vm,
|
||||
"toString() radix must be between 2 and 36",
|
||||
));
|
||||
}
|
||||
r as u32
|
||||
}
|
||||
} else {
|
||||
10u32
|
||||
};
|
||||
let text = i128_to_radix_string(vm.bigint_value(v), radix);
|
||||
NativeResult::Ok(vm.new_string(&text))
|
||||
}
|
||||
|
||||
/// `BigInt.prototype.toLocaleString`:返回与 toString() 相同的十进制字符串。
|
||||
pub fn bigint_to_locale_string<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
bigint_to_string(vm, args)
|
||||
}
|
||||
|
||||
/// `BigInt.prototype.valueOf`:返回包装的 BigInt 原始值。
|
||||
pub fn bigint_value_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(args[0]);
|
||||
match this_bigint_value(vm, this_val) {
|
||||
Ok(v) => NativeResult::Ok(v),
|
||||
Err(e) => NativeResult::Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// `BigInt.asIntN(bits, bigint)`:ToIndex(bits) + ToBigInt(bigint),
|
||||
/// 结果按二进制补码截断为 bits 位有符号整数。
|
||||
pub fn bigint_as_int_n<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let bits = match to_index(vm, args) {
|
||||
Ok(b) => b,
|
||||
Err(e) => return NativeResult::Err(e),
|
||||
};
|
||||
let arg = bigint_arg(vm, args);
|
||||
let val = match to_bigint(vm, arg) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return NativeResult::Err(e),
|
||||
};
|
||||
let v = vm.bigint_value(val);
|
||||
if bits == 0 {
|
||||
return NativeResult::Ok(vm.new_bigint(0));
|
||||
}
|
||||
if bits >= 127 {
|
||||
// i128 表示范围内 `2^bits` 恒大于 |v|:取模后符号位折叠回原值。
|
||||
return NativeResult::Ok(val);
|
||||
}
|
||||
let modulus = 1i128 << bits;
|
||||
let half = 1i128 << (bits - 1);
|
||||
let mut m = v % modulus;
|
||||
if m < 0 {
|
||||
m += modulus;
|
||||
}
|
||||
if m >= half {
|
||||
m -= modulus;
|
||||
}
|
||||
NativeResult::Ok(vm.new_bigint(m))
|
||||
}
|
||||
|
||||
/// `BigInt.asUintN(bits, bigint)`:按 `2^bits` 取模的无符号截断。
|
||||
pub fn bigint_as_uint_n<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let bits = match to_index(vm, args) {
|
||||
Ok(b) => b,
|
||||
Err(e) => return NativeResult::Err(e),
|
||||
};
|
||||
let arg = bigint_arg(vm, args);
|
||||
let val = match to_bigint(vm, arg) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return NativeResult::Err(e),
|
||||
};
|
||||
let v = vm.bigint_value(val);
|
||||
if bits == 0 {
|
||||
return NativeResult::Ok(vm.new_bigint(0));
|
||||
}
|
||||
if bits >= 128 {
|
||||
// i128 上限:非负值取模不变;负值结果超出表示范围,待任意精度补齐。
|
||||
return NativeResult::Ok(val);
|
||||
}
|
||||
let modulus = 1i128 << bits;
|
||||
let mut m = v % modulus;
|
||||
if m < 0 {
|
||||
m += modulus;
|
||||
}
|
||||
NativeResult::Ok(vm.new_bigint(m))
|
||||
}
|
||||
|
||||
/// thisBigIntValue:BigInt 原样返回;包装对象解盒;其它类型 TypeError。
|
||||
fn this_bigint_value<H: VmHost>(vm: &mut H, this_val: JsValue) -> Result<JsValue, JsValue> {
|
||||
if this_val.is_bigint() {
|
||||
return NativeResult::Ok(this_val);
|
||||
return Ok(this_val);
|
||||
}
|
||||
if this_val.is_object() {
|
||||
let ptr = this_val.as_js_object_ptr();
|
||||
@@ -54,78 +187,198 @@ pub fn bigint_value_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let obj = unsafe { &*ptr };
|
||||
if obj.proto().is_object() {
|
||||
let proto_ptr = obj.proto().as_js_object_ptr();
|
||||
let bigint_proto = vm.session().builtin_world().bigint_proto.as_ptr() as *mut oxide_types::object::JsObject;
|
||||
let bigint_proto =
|
||||
vm.session().builtin_world().bigint_proto.as_ptr() as *mut oxide_types::object::JsObject;
|
||||
if !proto_ptr.is_null() && std::ptr::eq(proto_ptr, bigint_proto) {
|
||||
let v = obj.get_prop_at(0);
|
||||
if v.is_bigint() {
|
||||
return NativeResult::Ok(v);
|
||||
return Ok(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
NativeResult::Err(crate::error::create_type_error(
|
||||
Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"BigInt.prototype.valueOf called on incompatible receiver",
|
||||
"BigInt.prototype method called on incompatible receiver",
|
||||
))
|
||||
}
|
||||
|
||||
/// 把原始值转为 BigInt 值(`BigInt(value)` 的参数转换)。
|
||||
fn to_bigint_value<H: VmHost>(vm: &mut H, val: JsValue) -> Result<JsValue, JsValue> {
|
||||
/// ToNumber 且拒绝 Symbol/BigInt(ToIntegerOrInfinity 的 ToNumber 语义)。
|
||||
fn coerce_number_or_throw<H: VmHost>(vm: &mut H, value: JsValue) -> Result<f64, JsValue> {
|
||||
let prim = match to_primitive(value, ToPrimitiveHint::Number, 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 number"));
|
||||
}
|
||||
};
|
||||
if prim.is_symbol() || prim.is_bigint() {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Cannot convert a Symbol or BigInt value to a number",
|
||||
));
|
||||
}
|
||||
Ok(oxide_runtime_api::to_number(prim))
|
||||
}
|
||||
|
||||
/// ToIndex(§7.1.17):ToIntegerOrInfinity 后必须为有限且 `[0, 2^53-1]` 内的整数。
|
||||
fn to_index<H: VmHost>(vm: &mut H, args: &[u8]) -> Result<usize, JsValue> {
|
||||
// ToIndex 作用在第一个参数(bits)上;缺省为 undefined。
|
||||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
let n = coerce_number_or_throw(vm, value)?;
|
||||
if n.is_nan() {
|
||||
return Ok(0);
|
||||
}
|
||||
// ToIntegerOrInfinity 先截断(-0.9 → -0,不越界);再检查有限且 [0, 2^53-1]。
|
||||
let int = if n == 0.0 { 0.0 } else if n.is_infinite() { n } else { n.trunc() };
|
||||
if !(0.0..=9007199254740991.0).contains(&int) {
|
||||
return Err(crate::error::create_range_error(vm, "Invalid index"));
|
||||
}
|
||||
Ok(int as usize)
|
||||
}
|
||||
|
||||
/// 取 asIntN/asUintN 的第二个参数;缺省为 undefined。
|
||||
fn bigint_arg<H: VmHost>(vm: &mut H, args: &[u8]) -> JsValue {
|
||||
if args.len() > 2 {
|
||||
vm.reg(args[2])
|
||||
} else {
|
||||
JsValue::undefined()
|
||||
}
|
||||
}
|
||||
|
||||
/// ToBigInt 抽象操作(§7.1.14):BigInt 原样;String → StringToBigInt;
|
||||
/// Boolean → 0/1;Number/Symbol/undefined/null → TypeError;对象先 ToPrimitive 再递归。
|
||||
fn to_bigint<H: VmHost>(vm: &mut H, val: JsValue) -> Result<JsValue, JsValue> {
|
||||
if val.is_bigint() {
|
||||
return Ok(val);
|
||||
}
|
||||
if val.is_undefined() {
|
||||
return Ok(vm.new_bigint(0));
|
||||
}
|
||||
if val.is_bool() {
|
||||
return Ok(vm.new_bigint(if val.as_bool() { 1 } else { 0 }));
|
||||
}
|
||||
if val.is_int() {
|
||||
return Ok(vm.new_bigint(val.as_int() as i128));
|
||||
// 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() {
|
||||
let d = val.as_double();
|
||||
if d.is_nan() || d.is_infinite() {
|
||||
return Err(crate::error::create_range_error(vm, "The number cannot be converted to a BigInt because it is not an integer"));
|
||||
}
|
||||
if d.trunc() != d {
|
||||
return Err(crate::error::create_range_error(vm, "The number cannot be converted to a BigInt because it is not an integer"));
|
||||
}
|
||||
return Ok(vm.new_bigint(d.trunc() as i128));
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Cannot convert a Number value to a BigInt",
|
||||
));
|
||||
}
|
||||
if val.is_string() {
|
||||
let s = unsafe { oxide_runtime_api::string_data(val) }.to_string();
|
||||
let s = s.trim();
|
||||
let sign = if let Some(rest) = s.strip_prefix('-') {
|
||||
(true, rest)
|
||||
} else if let Some(rest) = s.strip_prefix('+') {
|
||||
(false, rest)
|
||||
} else {
|
||||
(false, s)
|
||||
return match string_to_bigint(vm, &s) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
let (radix, digits) = if let Some(hex) = sign.1.strip_prefix("0x").or_else(|| sign.1.strip_prefix("0X")) {
|
||||
(16u32, hex)
|
||||
} else if let Some(oct) = sign.1.strip_prefix("0o").or_else(|| sign.1.strip_prefix("0O")) {
|
||||
(8u32, oct)
|
||||
} else if let Some(bin) = sign.1.strip_prefix("0b").or_else(|| sign.1.strip_prefix("0B")) {
|
||||
(2u32, bin)
|
||||
} else {
|
||||
(10u32, sign.1)
|
||||
};
|
||||
let magnitude = match i128::from_str_radix(digits, radix) {
|
||||
Ok(m) => m,
|
||||
}
|
||||
if val.is_object() {
|
||||
let prim = match to_primitive(val, ToPrimitiveHint::Default, vm) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return Err(crate::error::create_syntax_error(
|
||||
if let Some(exc) = vm.take_uncaught_value() {
|
||||
return Err(exc);
|
||||
}
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"Cannot convert string to BigInt: invalid integer literal",
|
||||
))
|
||||
"Cannot convert value to a BigInt",
|
||||
));
|
||||
}
|
||||
};
|
||||
return Ok(vm.new_bigint(if sign.0 { -magnitude } else { magnitude }));
|
||||
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(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",
|
||||
));
|
||||
}
|
||||
match i128::from_str_radix(digits, radix) {
|
||||
Ok(m) => Ok(vm.new_bigint(if neg { -m } else { m })),
|
||||
Err(_) => Err(crate::error::create_syntax_error(
|
||||
vm,
|
||||
"Cannot convert string to BigInt: invalid integer literal",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// 把 i128 按 radix 转成字符串(含负号前缀)。
|
||||
fn i128_to_radix_string(value: i128, radix: u32) -> String {
|
||||
let neg = value < 0;
|
||||
let mut mag = value.unsigned_abs();
|
||||
let chars = b"0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
let mut result = String::new();
|
||||
if mag == 0 {
|
||||
result.push('0');
|
||||
} else {
|
||||
let mut digits = Vec::new();
|
||||
while mag > 0 {
|
||||
digits.push(chars[(mag % radix as u128) as usize] as char);
|
||||
mag /= radix as u128;
|
||||
}
|
||||
for ch in digits.iter().rev() {
|
||||
result.push(*ch);
|
||||
}
|
||||
}
|
||||
if neg {
|
||||
result.insert(0, '-');
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@@ -516,6 +516,35 @@ fn wire_builtin_world_links(world: &BuiltinWorld) {
|
||||
wire_ctor_proto(&world.plain_date_time_constructor, &world.plain_date_time_proto);
|
||||
wire_ctor_proto(&world.bigint_constructor, &world.bigint_proto);
|
||||
|
||||
// 所有内置构造器的 [[Prototype]] 指向 %FunctionPrototype%(ECMA-262 §17:
|
||||
// 标准内置函数对象均继承 Function.prototype;此前仅 TypedArray 构造器设置过)。
|
||||
let fn_proto_val = world.fn_proto_val();
|
||||
for ctor in [
|
||||
&world.object_constructor,
|
||||
&world.array_constructor,
|
||||
&world.function_constructor,
|
||||
&world.string_constructor,
|
||||
&world.number_constructor,
|
||||
&world.boolean_constructor,
|
||||
&world.error_constructor,
|
||||
&world.symbol_constructor,
|
||||
&world.date_constructor,
|
||||
&world.set_constructor,
|
||||
&world.map_constructor,
|
||||
&world.regexp_constructor,
|
||||
&world.array_buffer_constructor,
|
||||
&world.data_view_constructor,
|
||||
&world.bigint_constructor,
|
||||
&world.instant_constructor,
|
||||
&world.plain_date_constructor,
|
||||
&world.plain_time_constructor,
|
||||
&world.duration_constructor,
|
||||
&world.zoned_date_time_constructor,
|
||||
&world.plain_date_time_constructor,
|
||||
] {
|
||||
set_proto_if_changed(ctor, fn_proto_val);
|
||||
}
|
||||
|
||||
let obj_proto_val = JsValue::from_js_object(world.object_proto.as_ptr() as *mut JsObject);
|
||||
let non_object_protos: [&P<JsObject>; 21] = [
|
||||
&world.array_proto,
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||
|
||||
use crate::bindings::{apply_binding_table, bind_global_value, configure_native_constructor};
|
||||
use oxide_kernel::kernel::{KernelCore, KernelSession};
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::object::{JsObject, PropAttributes};
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
/// 把 BigInt 构造器与原型方法绑定到 global。
|
||||
@@ -18,6 +18,24 @@ pub fn bind_bigint(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
|
||||
let proto = unsafe { &mut *proto_ptr };
|
||||
|
||||
configure_native_constructor(ctor, oxide_builtins::bigint::bigint_constructor::<crate::vm::Vm> as *const (), 1);
|
||||
// BigInt.length = 1,属性 { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }。
|
||||
let length_si = core.perm_interner().intern("length").0;
|
||||
let length_shape = core.shape_forge().make_shape(ctor.shape_id(), length_si);
|
||||
ctor.set_shape_id(length_shape);
|
||||
ctor.ensure_hash_props().push(JsValue::int(1));
|
||||
let length_pos = ctor.hash_props_vec().map_or(0, |v| v.len() as u32).saturating_sub(1);
|
||||
ctor.set_data_meta(length_pos, PropAttributes::new(false, false, true));
|
||||
|
||||
// 静态方法:asIntN / asUintN(length 均为 2)。
|
||||
apply_binding_table(
|
||||
world,
|
||||
ctor,
|
||||
core,
|
||||
&[
|
||||
("asIntN", oxide_builtins::bigint::bigint_as_int_n::<crate::vm::Vm> as *const (), 2),
|
||||
("asUintN", oxide_builtins::bigint::bigint_as_uint_n::<crate::vm::Vm> as *const (), 2),
|
||||
],
|
||||
);
|
||||
|
||||
apply_binding_table(
|
||||
world,
|
||||
@@ -25,9 +43,15 @@ pub fn bind_bigint(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
|
||||
core,
|
||||
&[
|
||||
("toString", oxide_builtins::bigint::bigint_to_string::<crate::vm::Vm> as *const (), 0),
|
||||
("toLocaleString", oxide_builtins::bigint::bigint_to_locale_string::<crate::vm::Vm> as *const (), 0),
|
||||
("valueOf", oxide_builtins::bigint::bigint_value_of::<crate::vm::Vm> as *const (), 0),
|
||||
],
|
||||
);
|
||||
|
||||
bind_global_value(core, global, "BigInt", JsValue::from_js_object(ctor_ptr));
|
||||
// 全局 BigInt 属性描述符:{ writable: true, enumerable: false, configurable: true }。
|
||||
let bigint_si = core.perm_interner().intern("BigInt").0;
|
||||
if let Some(pos) = core.shape_forge().lookup_position(global.shape_id(), bigint_si) {
|
||||
global.set_data_meta(pos, PropAttributes::new(true, false, true));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user