feat: 实现最小 BigInt 子集(字面量/算术/比较/构造器,Temporal 前置)

This commit is contained in:
爱特每羊队
2026-08-10 23:02:31 +08:00
parent 46b60ff003
commit 7e3d7b43b5
22 changed files with 706 additions and 32 deletions
+131
View File
@@ -0,0 +1,131 @@
use oxide_runtime_api::{NativeResult, VmHost};
use oxide_types::value::JsValue;
/// JS `BigInt()` 构造逻辑:把参数转成 BigInt 值。
///
/// 普通调用返回原始 BigInt;`new BigInt()` 抛 TypeError(BigInt 不可构造)。
/// 参数转换规则(最小子集):
/// - 无参数 → `0n`
/// - BigInt → 原样返回
/// - Number → 截断为整数(非整数抛 RangeError)
/// - String → 解析十进制整数
/// - Boolean → `0n`/`1n`
/// - 其它类型 → TypeError
pub fn bigint_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
if args.len() > 1 {
let this_val = vm.reg(args[0]);
if this_val.is_object() {
// new 语义:BigInt 不可 new,抛 TypeError。
return NativeResult::Err(crate::error::create_type_error(
vm,
"BigInt is not a constructor",
));
}
}
let val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
match to_bigint_value(vm, val) {
Ok(v) => NativeResult::Ok(v),
Err(err) => NativeResult::Err(err),
}
}
/// `BigInt.prototype.toString`:返回 BigInt 的十进制字符串。
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)))
}
/// `BigInt.prototype.valueOf`:返回包装的 BigInt 原始值。
pub fn bigint_value_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let this_val = vm.reg(args[0]);
if this_val.is_bigint() {
return NativeResult::Ok(this_val);
}
if this_val.is_object() {
let ptr = this_val.as_js_object_ptr();
if !ptr.is_null() {
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;
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);
}
}
}
}
}
NativeResult::Err(crate::error::create_type_error(
vm,
"BigInt.prototype.valueOf called on incompatible receiver",
))
}
/// 把原始值转为 BigInt 值(`BigInt(value)` 的参数转换)。
fn to_bigint_value<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));
}
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));
}
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)
};
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,
Err(_) => {
return Err(crate::error::create_syntax_error(
vm,
"Cannot convert string to BigInt: invalid integer literal",
))
}
};
return Ok(vm.new_bigint(if sign.0 { -magnitude } else { magnitude }));
}
Err(crate::error::create_type_error(
vm,
"Cannot convert value to a BigInt",
))
}
+2
View File
@@ -13,6 +13,8 @@ pub mod array;
pub mod array_buffer;
/// Boolean 内置对象实现(constructor 与 prototype 的 valueOf/toString)。
pub mod boolean;
/// BigInt 内置对象实现(constructor 与 prototype 的 toString)。
pub mod bigint;
/// builtins 层日志宏(`builtins_error`/`builtins_info` 等),target 为 `oxide::builtins`。
pub mod builtins_log;
/// DataView 内置对象实现(对 ArrayBuffer 的定点读写视图)。
+7
View File
@@ -310,6 +310,13 @@ pub fn object_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
obj_ref.set_prop_at(0, val);
return NativeResult::Ok(JsValue::from_js_object(obj));
}
if val.is_bigint() {
let proto = vm.session().builtin_world().bigint_proto.as_ptr() as *mut JsObject;
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(proto)));
let obj_ref = unsafe { &mut *obj };
obj_ref.set_prop_at(0, val);
return NativeResult::Ok(JsValue::from_js_object(obj));
}
let obj = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
NativeResult::Ok(JsValue::from_js_object(obj))
}
-4
View File
@@ -9,10 +9,6 @@ fn stub_error<H: VmHost>(vm: &mut H, name: &str) -> NativeResult {
pub fn proxy_stub<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
stub_error(vm, "Proxy")
}
/// `BigInt` 全局占位:始终抛 TypeError。BigInt 按设计延后实现。
pub fn bigint_stub<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
stub_error(vm, "BigInt")
}
/// `WeakMap` 全局占位:始终抛 TypeError。WeakMap 按设计延后实现。
pub fn weakmap_stub<H: VmHost>(vm: &mut H, _args: &[u8]) -> NativeResult {
stub_error(vm, "WeakMap")