feat: 完整支持 Math 成员方法与常量

This commit is contained in:
爱特每羊队
2026-06-07 16:01:44 +08:00
parent aa0de137f7
commit 473d7b1a24
2 changed files with 260 additions and 67 deletions
+162 -67
View File
@@ -61,7 +61,7 @@ pub struct Vm {
pub math_rng_state: u64, pub math_rng_state: u64,
} }
pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) { fn bind_object(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let methods = ObjectMethods { let methods = ObjectMethods {
keys: crate::builtins::object::object_keys as *const (), keys: crate::builtins::object::object_keys as *const (),
create: crate::builtins::object::object_create as *const (), create: crate::builtins::object::object_create as *const (),
@@ -76,8 +76,6 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
kernel.shape_forge().as_ref(), kernel.shape_forge().as_ref(),
); );
let global_ptr = kernel.global_object().as_ptr() as *mut JsObject;
let global = unsafe { &mut *global_ptr };
let si_obj = kernel.string_forge().intern("Object").0; let si_obj = kernel.string_forge().intern("Object").0;
let obj_shape = kernel.shape_forge().make_shape(global.shape_id(), si_obj); let obj_shape = kernel.shape_forge().make_shape(global.shape_id(), si_obj);
let obj_val = JsValue::from_js_object( let obj_val = JsValue::from_js_object(
@@ -85,7 +83,9 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
); );
global.set_shape_id(obj_shape); global.set_shape_id(obj_shape);
global.push_prop(obj_val); global.push_prop(obj_val);
}
fn bind_array(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let _array_methods = ArrayMethods { let _array_methods = ArrayMethods {
push: crate::builtins::array::array_push as *const (), push: crate::builtins::array::array_push as *const (),
pop: crate::builtins::array::array_pop as *const (), pop: crate::builtins::array::array_pop as *const (),
@@ -120,7 +120,9 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
global.set_shape_id(arr_shape); global.set_shape_id(arr_shape);
global.ensure_hash_props().push(Box::new(arr_val)); global.ensure_hash_props().push(Box::new(arr_val));
global.bump_generation(); global.bump_generation();
}
fn bind_error(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let error_methods = ErrorMethods { let error_methods = ErrorMethods {
error: crate::builtins::error::error_constructor as *const (), error: crate::builtins::error::error_constructor as *const (),
type_error: crate::builtins::error::type_error_constructor as *const (), type_error: crate::builtins::error::type_error_constructor as *const (),
@@ -143,7 +145,9 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
global.set_shape_id(err_shape); global.set_shape_id(err_shape);
global.ensure_hash_props().push(Box::new(err_val)); global.ensure_hash_props().push(Box::new(err_val));
global.bump_generation(); global.bump_generation();
}
fn bind_string(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let string_methods = StringMethods { let string_methods = StringMethods {
index_of: crate::builtins::string::string_index_of as *const (), index_of: crate::builtins::string::string_index_of as *const (),
includes: crate::builtins::string::string_includes as *const (), includes: crate::builtins::string::string_includes as *const (),
@@ -179,7 +183,9 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
global.set_shape_id(str_shape); global.set_shape_id(str_shape);
global.ensure_hash_props().push(Box::new(str_val)); global.ensure_hash_props().push(Box::new(str_val));
global.bump_generation(); global.bump_generation();
}
fn bind_number(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let number_methods = NumberMethods { let number_methods = NumberMethods {
is_nan: crate::builtins::number::number_is_nan as *const (), is_nan: crate::builtins::number::number_is_nan as *const (),
is_finite: crate::builtins::number::number_is_finite as *const (), is_finite: crate::builtins::number::number_is_finite as *const (),
@@ -232,17 +238,17 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
pf_fn, pf_fn,
1 1
); );
}
fn bind_math(kernel: &Arc<OxideKernel>, global: &mut JsObject) {
let math_ptr = kernel.builtin_world().math_object.as_ptr() as *mut JsObject; let math_ptr = kernel.builtin_world().math_object.as_ptr() as *mut JsObject;
let math = unsafe { &mut *math_ptr }; let math = unsafe { &mut *math_ptr };
let sf = kernel.string_forge().as_ref();
let sh = kernel.shape_forge().as_ref();
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"abs", "abs",
crate::builtins::math::math_abs, crate::builtins::math::math_abs,
1 1
@@ -250,8 +256,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"acos", "acos",
crate::builtins::math::math_acos, crate::builtins::math::math_acos,
1 1
@@ -259,8 +265,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"asin", "asin",
crate::builtins::math::math_asin, crate::builtins::math::math_asin,
1 1
@@ -268,8 +274,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"atan", "atan",
crate::builtins::math::math_atan, crate::builtins::math::math_atan,
1 1
@@ -277,8 +283,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"atan2", "atan2",
crate::builtins::math::math_atan2, crate::builtins::math::math_atan2,
2 2
@@ -286,8 +292,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"cbrt", "cbrt",
crate::builtins::math::math_cbrt, crate::builtins::math::math_cbrt,
1 1
@@ -295,8 +301,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"ceil", "ceil",
crate::builtins::math::math_ceil, crate::builtins::math::math_ceil,
1 1
@@ -304,8 +310,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"cos", "cos",
crate::builtins::math::math_cos, crate::builtins::math::math_cos,
1 1
@@ -313,8 +319,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"cosh", "cosh",
crate::builtins::math::math_cosh, crate::builtins::math::math_cosh,
1 1
@@ -322,8 +328,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"exp", "exp",
crate::builtins::math::math_exp, crate::builtins::math::math_exp,
1 1
@@ -331,8 +337,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"floor", "floor",
crate::builtins::math::math_floor, crate::builtins::math::math_floor,
1 1
@@ -340,8 +346,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"hypot", "hypot",
crate::builtins::math::math_hypot, crate::builtins::math::math_hypot,
2 2
@@ -349,8 +355,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"imul", "imul",
crate::builtins::math::math_imul, crate::builtins::math::math_imul,
2 2
@@ -358,8 +364,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"log", "log",
crate::builtins::math::math_log, crate::builtins::math::math_log,
1 1
@@ -367,8 +373,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"log10", "log10",
crate::builtins::math::math_log10, crate::builtins::math::math_log10,
1 1
@@ -376,8 +382,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"log2", "log2",
crate::builtins::math::math_log2, crate::builtins::math::math_log2,
1 1
@@ -385,8 +391,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"max", "max",
crate::builtins::math::math_max, crate::builtins::math::math_max,
2 2
@@ -394,8 +400,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"min", "min",
crate::builtins::math::math_min, crate::builtins::math::math_min,
2 2
@@ -403,8 +409,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"pow", "pow",
crate::builtins::math::math_pow, crate::builtins::math::math_pow,
2 2
@@ -412,8 +418,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"random", "random",
crate::builtins::math::math_random, crate::builtins::math::math_random,
0 0
@@ -421,8 +427,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"round", "round",
crate::builtins::math::math_round, crate::builtins::math::math_round,
1 1
@@ -430,8 +436,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"sign", "sign",
crate::builtins::math::math_sign, crate::builtins::math::math_sign,
1 1
@@ -439,8 +445,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"sin", "sin",
crate::builtins::math::math_sin, crate::builtins::math::math_sin,
1 1
@@ -448,8 +454,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"sinh", "sinh",
crate::builtins::math::math_sinh, crate::builtins::math::math_sinh,
1 1
@@ -457,8 +463,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"sqrt", "sqrt",
crate::builtins::math::math_sqrt, crate::builtins::math::math_sqrt,
1 1
@@ -466,8 +472,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"tan", "tan",
crate::builtins::math::math_tan, crate::builtins::math::math_tan,
1 1
@@ -475,8 +481,8 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"tanh", "tanh",
crate::builtins::math::math_tanh, crate::builtins::math::math_tanh,
1 1
@@ -484,19 +490,93 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
bind_method!( bind_method!(
kernel.builtin_world(), kernel.builtin_world(),
math, math,
sf, kernel.string_forge().as_ref(),
sh, kernel.shape_forge().as_ref(),
"trunc", "trunc",
crate::builtins::math::math_trunc, crate::builtins::math::math_trunc,
1 1
); );
bind_method!(
kernel.builtin_world(),
math,
kernel.string_forge().as_ref(),
kernel.shape_forge().as_ref(),
"acosh",
crate::builtins::math::math_acosh,
1
);
bind_method!(
kernel.builtin_world(),
math,
kernel.string_forge().as_ref(),
kernel.shape_forge().as_ref(),
"asinh",
crate::builtins::math::math_asinh,
1
);
bind_method!(
kernel.builtin_world(),
math,
kernel.string_forge().as_ref(),
kernel.shape_forge().as_ref(),
"atanh",
crate::builtins::math::math_atanh,
1
);
bind_method!(
kernel.builtin_world(),
math,
kernel.string_forge().as_ref(),
kernel.shape_forge().as_ref(),
"clz32",
crate::builtins::math::math_clz32,
1
);
bind_method!(
kernel.builtin_world(),
math,
kernel.string_forge().as_ref(),
kernel.shape_forge().as_ref(),
"expm1",
crate::builtins::math::math_expm1,
1
);
bind_method!(
kernel.builtin_world(),
math,
kernel.string_forge().as_ref(),
kernel.shape_forge().as_ref(),
"fround",
crate::builtins::math::math_fround,
1
);
bind_method!(
kernel.builtin_world(),
math,
kernel.string_forge().as_ref(),
kernel.shape_forge().as_ref(),
"log1p",
crate::builtins::math::math_log1p,
1
);
let pi_val = JsValue::float(std::f64::consts::PI); for (name, val) in [
{ ("PI", std::f64::consts::PI),
let si_pi = sf.intern("PI").0; ("E", std::f64::consts::E),
let sh_pi = sh.make_shape(math.shape_id(), si_pi); ("LN10", std::f64::consts::LN_10),
math.set_shape_id(sh_pi); ("LN2", std::f64::consts::LN_2),
math.ensure_hash_props().push(Box::new(pi_val)); ("LOG10E", std::f64::consts::LOG10_E),
("LOG2E", std::f64::consts::LOG2_E),
("SQRT1_2", std::f64::consts::FRAC_1_SQRT_2),
("SQRT2", std::f64::consts::SQRT_2),
] {
let si = kernel.string_forge().as_ref().intern(name).0;
let sh_c = kernel
.shape_forge()
.as_ref()
.make_shape(math.shape_id(), si);
math.set_shape_id(sh_c);
math.ensure_hash_props().push(Box::new(JsValue::float(val)));
} }
let si_m = kernel.string_forge().intern("Math").0; let si_m = kernel.string_forge().intern("Math").0;
@@ -506,7 +586,9 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
global.set_shape_id(m_shape); global.set_shape_id(m_shape);
global.ensure_hash_props().push(Box::new(m_val)); global.ensure_hash_props().push(Box::new(m_val));
global.bump_generation(); global.bump_generation();
}
fn bind_function(kernel: &Arc<OxideKernel>) {
let function_methods = FunctionMethods { let function_methods = FunctionMethods {
call: crate::builtins::function::function_call as *const (), call: crate::builtins::function::function_call as *const (),
apply: crate::builtins::function::function_apply as *const (), apply: crate::builtins::function::function_apply as *const (),
@@ -519,6 +601,19 @@ pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
); );
} }
pub fn init_kernel_builtins(kernel: &Arc<OxideKernel>) {
let global_ptr = kernel.global_object().as_ptr() as *mut JsObject;
let global = unsafe { &mut *global_ptr };
bind_object(kernel, global);
bind_array(kernel, global);
bind_error(kernel, global);
bind_string(kernel, global);
bind_number(kernel, global);
bind_math(kernel, global);
bind_function(kernel);
}
impl Vm { impl Vm {
pub fn new() -> Self { pub fn new() -> Self {
let kernel = Arc::new(OxideKernel::new(KernelConfig::minimal())); let kernel = Arc::new(OxideKernel::new(KernelConfig::minimal()));
@@ -115,3 +115,101 @@ fn math_trunc() {
let result = eval(&mut vm, "Math.trunc(3.9)").unwrap(); let result = eval(&mut vm, "Math.trunc(3.9)").unwrap();
assert!((result.as_double() - 3.0).abs() < 0.0001); assert!((result.as_double() - 3.0).abs() < 0.0001);
} }
#[test]
fn math_acosh() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.acosh(1)").unwrap();
assert!((result.as_double() - 0.0).abs() < 0.0001);
}
#[test]
fn math_asinh() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.asinh(0)").unwrap();
assert!((result.as_double() - 0.0).abs() < 0.0001);
}
#[test]
fn math_atanh() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.atanh(0)").unwrap();
assert!((result.as_double() - 0.0).abs() < 0.0001);
}
#[test]
fn math_clz32() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.clz32(0)").unwrap();
assert_eq!(result.as_int(), 32);
}
#[test]
fn math_expm1() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.expm1(0)").unwrap();
assert!((result.as_double() - 0.0).abs() < 0.0001);
}
#[test]
fn math_fround() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.fround(1.5)").unwrap();
assert!((result.as_double() - 1.5).abs() < 0.0001);
}
#[test]
fn math_log1p() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.log1p(0)").unwrap();
assert!((result.as_double() - 0.0).abs() < 0.0001);
}
#[test]
fn math_constant_e() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.E").unwrap();
assert!((result.as_double() - std::f64::consts::E).abs() < 0.0001);
}
#[test]
fn math_constant_ln10() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.LN10").unwrap();
assert!((result.as_double() - std::f64::consts::LN_10).abs() < 0.0001);
}
#[test]
fn math_constant_ln2() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.LN2").unwrap();
assert!((result.as_double() - std::f64::consts::LN_2).abs() < 0.0001);
}
#[test]
fn math_constant_log10e() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.LOG10E").unwrap();
assert!((result.as_double() - std::f64::consts::LOG10_E).abs() < 0.0001);
}
#[test]
fn math_constant_log2e() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.LOG2E").unwrap();
assert!((result.as_double() - std::f64::consts::LOG2_E).abs() < 0.0001);
}
#[test]
fn math_constant_sqrt1_2() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.SQRT1_2").unwrap();
assert!((result.as_double() - std::f64::consts::FRAC_1_SQRT_2).abs() < 0.0001);
}
#[test]
fn math_constant_sqrt2() {
let mut vm = Vm::new();
let result = eval(&mut vm, "Math.SQRT2").unwrap();
assert!((result.as_double() - std::f64::consts::SQRT_2).abs() < 0.0001);
}