mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 实现最小 BigInt 子集(字面量/算术/比较/构造器,Temporal 前置)
This commit is contained in:
@@ -13,8 +13,25 @@ impl Vm {
|
||||
self.regs[rd] = JsValue::float(lv.as_int() as f64 + rv.as_int() as f64);
|
||||
return Ok(());
|
||||
}
|
||||
if lv.is_bigint() && rv.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lv) + self.bigint_value(rv));
|
||||
return Ok(());
|
||||
}
|
||||
// 注意:不能在此前置检查 BigInt 混合(`lv.is_bigint() || rv.is_bigint()`)——
|
||||
// 对象操作数(如 `{valueOf: () => 2n}`)需先 ToPrimitive 再判定,混合检查
|
||||
// 必须放在 coerce 之后。
|
||||
let lhs = self.coerce_primitive_bounded(lv, false)?;
|
||||
let rhs = self.coerce_primitive_bounded(rv, false)?;
|
||||
if lhs.is_bigint() && rhs.is_bigint() {
|
||||
// 包装对象 coerce 后暴露双 BigInt(如 Object(2n) + 2n)。
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lhs) + self.bigint_value(rhs));
|
||||
return Ok(());
|
||||
}
|
||||
if lhs.is_bigint() != rhs.is_bigint() {
|
||||
// 包装对象 coerce 后暴露 BigInt:与另一非 BigInt 操作数混合加法必须抛
|
||||
// TypeError(规范不允许 BigInt 与 Number/String 相加)。
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
if lhs.is_string() || rhs.is_string() {
|
||||
let lbytes = if lhs.is_string() { unsafe { (*lhs.as_string_ptr()).len() } } else { 0 };
|
||||
let rbytes = if rhs.is_string() { unsafe { (*rhs.as_string_ptr()).len() } } else { 0 };
|
||||
@@ -38,7 +55,12 @@ impl Vm {
|
||||
#[inline(always)]
|
||||
pub(crate) fn dispatch_neg(&mut self, rd: usize, a: usize) -> Result<(), String> {
|
||||
vm_trace!("NEG rd={} r{}={:?}", rd, a, self.regs[a]);
|
||||
let v = self.coerce_number_bounded(self.regs[a])?;
|
||||
let v = self.regs[a];
|
||||
if v.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(-self.bigint_value(v));
|
||||
return Ok(());
|
||||
}
|
||||
let v = self.coerce_number_bounded(v)?;
|
||||
self.regs[rd] = JsValue::float(-v);
|
||||
Ok(())
|
||||
}
|
||||
@@ -46,7 +68,12 @@ impl Vm {
|
||||
#[inline(always)]
|
||||
pub(crate) fn dispatch_unary_plus(&mut self, rd: usize, a: usize) -> Result<(), String> {
|
||||
vm_trace!("UNARY_PLUS rd={} r{}={:?}", rd, a, self.regs[a]);
|
||||
let v = self.coerce_number_bounded(self.regs[a])?;
|
||||
let v = self.regs[a];
|
||||
if v.is_bigint() {
|
||||
// 一元 + 对 BigInt 必须抛 TypeError(ToNumber(BigInt) 在隐式路径禁止)。
|
||||
return self.raise_type_error("Cannot convert a BigInt value to a number");
|
||||
}
|
||||
let v = self.coerce_number_bounded(v)?;
|
||||
self.regs[rd] = JsValue::float(v);
|
||||
Ok(())
|
||||
}
|
||||
@@ -59,8 +86,19 @@ impl Vm {
|
||||
self.regs[rd] = JsValue::float(lv.as_int() as f64 + rv.as_int() as f64);
|
||||
return Ok(());
|
||||
}
|
||||
if lv.is_bigint() && rv.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lv) + self.bigint_value(rv));
|
||||
return Ok(());
|
||||
}
|
||||
let lhs = self.coerce_primitive_bounded(lv, false)?;
|
||||
let rhs = self.coerce_primitive_bounded(rv, false)?;
|
||||
if lhs.is_bigint() && rhs.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lhs) + self.bigint_value(rhs));
|
||||
return Ok(());
|
||||
}
|
||||
if lhs.is_bigint() != rhs.is_bigint() {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
if lhs.is_string() || rhs.is_string() {
|
||||
let lbytes = if lhs.is_string() { unsafe { (*lhs.as_string_ptr()).len() } } else { 0 };
|
||||
let rbytes = if rhs.is_string() { unsafe { (*rhs.as_string_ptr()).len() } } else { 0 };
|
||||
@@ -90,9 +128,22 @@ impl Vm {
|
||||
self.regs[rd] = JsValue::float(lv.as_int() as f64 - rv.as_int() as f64);
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_number_bounded(lv)?;
|
||||
let r = self.coerce_number_bounded(rv)?;
|
||||
self.regs[rd] = JsValue::float(l - r);
|
||||
if lv.is_bigint() && rv.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lv) - self.bigint_value(rv));
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_primitive_bounded(lv, false)?;
|
||||
let r = self.coerce_primitive_bounded(rv, false)?;
|
||||
if l.is_bigint() && r.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(l) - self.bigint_value(r));
|
||||
return Ok(());
|
||||
}
|
||||
if l.is_bigint() != r.is_bigint() {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
let ln = coercion::to_number(l);
|
||||
let rn = coercion::to_number(r);
|
||||
self.regs[rd] = JsValue::float(ln - rn);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -105,9 +156,22 @@ impl Vm {
|
||||
self.regs[rd] = JsValue::float(lv.as_int() as f64 * rv.as_int() as f64);
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_number_bounded(lv)?;
|
||||
let r = self.coerce_number_bounded(rv)?;
|
||||
self.regs[rd] = JsValue::float(l * r);
|
||||
if lv.is_bigint() && rv.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lv) * self.bigint_value(rv));
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_primitive_bounded(lv, false)?;
|
||||
let r = self.coerce_primitive_bounded(rv, false)?;
|
||||
if l.is_bigint() && r.is_bigint() {
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(l) * self.bigint_value(r));
|
||||
return Ok(());
|
||||
}
|
||||
if l.is_bigint() != r.is_bigint() {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
let ln = coercion::to_number(l);
|
||||
let rn = coercion::to_number(r);
|
||||
self.regs[rd] = JsValue::float(ln * rn);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -120,9 +184,30 @@ impl Vm {
|
||||
self.regs[rd] = JsValue::float(lv.as_int() as f64 / rv.as_int() as f64);
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_number_bounded(lv)?;
|
||||
let r = self.coerce_number_bounded(rv)?;
|
||||
self.regs[rd] = JsValue::float(l / r);
|
||||
if lv.is_bigint() && rv.is_bigint() {
|
||||
let r = self.bigint_value(rv);
|
||||
if r == 0 {
|
||||
return self.raise_error_kind("RangeError", "Division by zero");
|
||||
}
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lv) / r);
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_primitive_bounded(lv, false)?;
|
||||
let r = self.coerce_primitive_bounded(rv, false)?;
|
||||
if l.is_bigint() && r.is_bigint() {
|
||||
let rv = self.bigint_value(r);
|
||||
if rv == 0 {
|
||||
return self.raise_error_kind("RangeError", "Division by zero");
|
||||
}
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(l) / rv);
|
||||
return Ok(());
|
||||
}
|
||||
if l.is_bigint() != r.is_bigint() {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
let ln = coercion::to_number(l);
|
||||
let rn = coercion::to_number(r);
|
||||
self.regs[rd] = JsValue::float(ln / rn);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -135,9 +220,30 @@ impl Vm {
|
||||
self.regs[rd] = JsValue::float(lv.as_int() as f64 % rv.as_int() as f64);
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_number_bounded(lv)?;
|
||||
let r = self.coerce_number_bounded(rv)?;
|
||||
self.regs[rd] = JsValue::float(l % r);
|
||||
if lv.is_bigint() && rv.is_bigint() {
|
||||
let r = self.bigint_value(rv);
|
||||
if r == 0 {
|
||||
return self.raise_error_kind("RangeError", "Division by zero");
|
||||
}
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(lv) % r);
|
||||
return Ok(());
|
||||
}
|
||||
let l = self.coerce_primitive_bounded(lv, false)?;
|
||||
let r = self.coerce_primitive_bounded(rv, false)?;
|
||||
if l.is_bigint() && r.is_bigint() {
|
||||
let rv = self.bigint_value(r);
|
||||
if rv == 0 {
|
||||
return self.raise_error_kind("RangeError", "Division by zero");
|
||||
}
|
||||
self.regs[rd] = self.new_bigint(self.bigint_value(l) % rv);
|
||||
return Ok(());
|
||||
}
|
||||
if l.is_bigint() != r.is_bigint() {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
let ln = coercion::to_number(l);
|
||||
let rn = coercion::to_number(r);
|
||||
self.regs[rd] = JsValue::float(ln % rn);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ impl Vm {
|
||||
vm_trace!("LT rd={} r{}={:?} r{}={:?}", rd, a, self.regs[a], b, self.regs[b]);
|
||||
let va = self.coerce_primitive_bounded(self.regs[a], false)?;
|
||||
let vb = self.coerce_primitive_bounded(self.regs[b], false)?;
|
||||
if (va.is_bigint() || vb.is_bigint()) && (va.is_symbol() || vb.is_symbol()) {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
match coercion::relational_compare(va, vb) {
|
||||
Some(r) => self.regs[rd] = JsValue::bool(r),
|
||||
None => {
|
||||
@@ -44,6 +47,9 @@ impl Vm {
|
||||
vm_trace!("GT rd={} r{}={:?} r{}={:?}", rd, a, self.regs[a], b, self.regs[b]);
|
||||
let va = self.coerce_primitive_bounded(self.regs[a], false)?;
|
||||
let vb = self.coerce_primitive_bounded(self.regs[b], false)?;
|
||||
if (va.is_bigint() || vb.is_bigint()) && (va.is_symbol() || vb.is_symbol()) {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
match coercion::relational_compare(vb, va) {
|
||||
Some(r) => self.regs[rd] = JsValue::bool(r),
|
||||
None => {
|
||||
@@ -59,6 +65,9 @@ impl Vm {
|
||||
vm_trace!("LTE rd={} r{}={:?} r{}={:?}", rd, a, self.regs[a], b, self.regs[b]);
|
||||
let va = self.coerce_primitive_bounded(self.regs[a], false)?;
|
||||
let vb = self.coerce_primitive_bounded(self.regs[b], false)?;
|
||||
if (va.is_bigint() || vb.is_bigint()) && (va.is_symbol() || vb.is_symbol()) {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
match coercion::relational_compare(vb, va) {
|
||||
Some(r) => self.regs[rd] = JsValue::bool(!r),
|
||||
None => {
|
||||
@@ -74,6 +83,9 @@ impl Vm {
|
||||
vm_trace!("GTE rd={} r{}={:?} r{}={:?}", rd, a, self.regs[a], b, self.regs[b]);
|
||||
let va = self.coerce_primitive_bounded(self.regs[a], false)?;
|
||||
let vb = self.coerce_primitive_bounded(self.regs[b], false)?;
|
||||
if (va.is_bigint() || vb.is_bigint()) && (va.is_symbol() || vb.is_symbol()) {
|
||||
return self.raise_type_error("Cannot mix BigInt and other types, use explicit conversions");
|
||||
}
|
||||
match coercion::relational_compare(va, vb) {
|
||||
Some(r) => self.regs[rd] = JsValue::bool(!r),
|
||||
None => {
|
||||
|
||||
@@ -36,6 +36,8 @@ impl Vm {
|
||||
"string"
|
||||
} else if val.is_symbol() {
|
||||
"symbol"
|
||||
} else if val.is_bigint() {
|
||||
"bigint"
|
||||
} else if val.is_object() {
|
||||
let obj = unsafe { &*val.as_js_object_ptr() };
|
||||
if obj.is_function() {
|
||||
|
||||
@@ -65,6 +65,11 @@ impl Vm {
|
||||
let proto = unsafe { &*proto_ptr };
|
||||
return self.ordinary_get(proto, prop_name_si, val).map(Some);
|
||||
}
|
||||
if val.is_bigint() {
|
||||
let proto_ptr = self.session.builtin_world().bigint_proto.as_ptr() as *mut JsObject;
|
||||
let proto = unsafe { &*proto_ptr };
|
||||
return self.ordinary_get(proto, prop_name_si, val).map(Some);
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user