This repository has been archived on 2026-09-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
OxideJS/crates/oxide_vm/src/builtins/math.rs
T
2026-06-25 18:32:09 +08:00

156 lines
4.2 KiB
Rust

use oxide_types::value::JsValue;
use crate::coercion;
use crate::vm::Vm;
use oxide_runtime_api::NativeResult;
fn num(vm: &Vm, reg: u8) -> f64 {
coercion::to_number(vm.reg(reg))
}
fn arg1(vm: &Vm, args: &[u8]) -> f64 {
if args.len() < 2 {
f64::NAN
} else {
num(vm, args[1])
}
}
fn arg2(vm: &Vm, args: &[u8]) -> (f64, f64) {
(
if args.len() > 1 { num(vm, args[1]) } else { f64::NAN },
if args.len() > 2 { num(vm, args[2]) } else { f64::NAN },
)
}
pub fn math_abs(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return NativeResult::Ok(JsValue::float(f64::NAN));
}
let x = vm.reg(args[1]);
if x.is_int() {
NativeResult::Ok(JsValue::int(x.as_int().abs()))
} else {
NativeResult::Ok(JsValue::float(num(vm, args[1]).abs()))
}
}
macro_rules! math_unary {
($name:ident, $op:ident) => {
pub fn $name(vm: &mut Vm, args: &[u8]) -> NativeResult {
NativeResult::Ok(JsValue::float(arg1(vm, args).$op()))
}
};
}
math_unary!(math_acos, acos);
math_unary!(math_acosh, acosh);
math_unary!(math_asin, asin);
math_unary!(math_asinh, asinh);
math_unary!(math_atan, atan);
math_unary!(math_atanh, atanh);
math_unary!(math_cbrt, cbrt);
math_unary!(math_ceil, ceil);
math_unary!(math_cos, cos);
math_unary!(math_cosh, cosh);
math_unary!(math_exp, exp);
math_unary!(math_expm1, exp_m1);
math_unary!(math_floor, floor);
math_unary!(math_log, ln);
math_unary!(math_log10, log10);
math_unary!(math_log1p, ln_1p);
math_unary!(math_log2, log2);
math_unary!(math_sin, sin);
math_unary!(math_sinh, sinh);
math_unary!(math_sqrt, sqrt);
math_unary!(math_tan, tan);
math_unary!(math_tanh, tanh);
math_unary!(math_trunc, trunc);
pub fn math_atan2(vm: &mut Vm, args: &[u8]) -> NativeResult {
let (a, b) = arg2(vm, args);
NativeResult::Ok(JsValue::float(a.atan2(b)))
}
pub fn math_round(vm: &mut Vm, args: &[u8]) -> NativeResult {
let x = arg1(vm, args);
let r = if x < 0.0 { (x - 0.5).ceil() } else { (x + 0.5).floor() };
NativeResult::Ok(JsValue::float(r))
}
pub fn math_sign(vm: &mut Vm, args: &[u8]) -> NativeResult {
let x = arg1(vm, args);
if x.is_nan() {
NativeResult::Ok(JsValue::float(f64::NAN))
} else if x > 0.0 {
NativeResult::Ok(JsValue::int(1))
} else if x < 0.0 {
NativeResult::Ok(JsValue::int(-1))
} else {
NativeResult::Ok(JsValue::float(x))
}
}
pub fn math_clz32(vm: &mut Vm, args: &[u8]) -> NativeResult {
let n = arg1(vm, args) as u32;
NativeResult::Ok(JsValue::int(n.leading_zeros() as i32))
}
pub fn math_fround(vm: &mut Vm, args: &[u8]) -> NativeResult {
NativeResult::Ok(JsValue::float(arg1(vm, args) as f32 as f64))
}
pub fn math_hypot(vm: &mut Vm, args: &[u8]) -> NativeResult {
let (a, b) = arg2(vm, args);
NativeResult::Ok(JsValue::float(a.hypot(b)))
}
pub fn math_imul(vm: &mut Vm, args: &[u8]) -> NativeResult {
let (a, b) = arg2(vm, args);
NativeResult::Ok(JsValue::int((a as i32).wrapping_mul(b as i32)))
}
pub fn math_pow(vm: &mut Vm, args: &[u8]) -> NativeResult {
let (a, b) = arg2(vm, args);
NativeResult::Ok(JsValue::float(a.powf(b)))
}
pub fn math_max(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return NativeResult::Ok(JsValue::float(f64::NEG_INFINITY));
}
let mut m = f64::NEG_INFINITY;
for &r in args.iter().skip(1) {
let x = num(vm, r);
if x.is_nan() {
return NativeResult::Ok(JsValue::float(f64::NAN));
}
if x > m {
m = x;
}
}
NativeResult::Ok(JsValue::float(m))
}
pub fn math_min(vm: &mut Vm, args: &[u8]) -> NativeResult {
if args.len() < 2 {
return NativeResult::Ok(JsValue::float(f64::INFINITY));
}
let mut m = f64::INFINITY;
for &r in args.iter().skip(1) {
let x = num(vm, r);
if x.is_nan() {
return NativeResult::Ok(JsValue::float(f64::NAN));
}
if x < m {
m = x;
}
}
NativeResult::Ok(JsValue::float(m))
}
pub fn math_random(vm: &mut Vm, _args: &[u8]) -> NativeResult {
vm.step_rng();
NativeResult::Ok(JsValue::float(vm.math_rng_value()))
}