use crate::prelude::*;
pub fn make_module() -> KMap {
use KValue::Number;
let result = KMap::with_type("core.number");
macro_rules! number_fn {
($fn:ident) => {
number_fn!(stringify!($fn), $fn)
};
($name:expr, $fn:ident) => {
result.add_fn($name, |ctx| {
let expected_error = "|Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(n), []) => Ok(Number(n.$fn())),
(instance, args) => {
unexpected_args_after_instance(expected_error, instance, args)
}
}
});
};
}
macro_rules! number_f64_fn {
($fn:ident) => {
number_f64_fn!(stringify!($fn), $fn)
};
($name:expr, $fn:ident) => {
result.add_fn($name, |ctx| {
let expected_error = "|Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(n), []) => Ok(Number(f64::from(n).$fn().into())),
(instance, args) => {
unexpected_args_after_instance(expected_error, instance, args)
}
}
});
};
}
macro_rules! bitwise_fn {
($name:ident, $op:tt) => {
result.add_fn(stringify!($name), |ctx| {
let expected_error = "|Number, Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(a), [Number(b)]) => Ok((i64::from(a) $op i64::from(b)).into()),
(instance, args) => {
unexpected_args_after_instance(expected_error, instance, args)
}
}
})
};
}
macro_rules! bitwise_fn_positive_arg {
($name:ident, $op:tt) => {
result.add_fn(stringify!($name), |ctx| {
let expected_error = "|Number, Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(a), [Number(b)]) if *b >= 0 => {
Ok((i64::from(a) $op i64::from(b)).into())
}
(instance, args) => {
unexpected_args_after_instance(expected_error, instance, args)
}
}
})
};
}
number_fn!(abs);
number_f64_fn!(acos);
number_f64_fn!(acosh);
bitwise_fn!(and, &);
number_f64_fn!(asin);
number_f64_fn!(asinh);
number_f64_fn!(atan);
number_f64_fn!(atanh);
result.add_fn("atan2", |ctx| {
let expected_error = "|Number, Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(y), [Number(x)]) => Ok(f64::from(y).atan2(f64::from(x)).into()),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
number_fn!(ceil);
result.add_fn("clamp", |ctx| {
let expected_error = "|Number, Number, Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(x), [Number(a), Number(b)]) => Ok(Number(*a.max(b.min(x)))),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
number_f64_fn!(cos);
number_f64_fn!(cosh);
number_f64_fn!("degrees", to_degrees);
result.insert("e", std::f64::consts::E);
number_f64_fn!(exp);
number_f64_fn!(exp2);
result.add_fn("flip_bits", |ctx| {
let expected_error = "|Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(n), []) => Ok((!n.to_bits() as i64).into()),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
number_fn!(floor);
result.insert("infinity", Number(f64::INFINITY.into()));
result.add_fn("is_nan", |ctx| {
let expected_error = "|Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(n), []) => Ok(n.is_nan().into()),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
result.add_fn("lerp", |ctx| {
let expected_error = "|Number, Number, Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(a), [Number(b), Number(t)]) => {
let result = *a + (b - a) * *t;
Ok(result.into())
}
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
number_f64_fn!(ln);
number_f64_fn!(log2);
number_f64_fn!(log10);
result.add_fn("max", |ctx| {
let expected_error = "|Number, Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(a), [Number(b)]) => Ok(Number(*a.max(b))),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
result.add_fn("min", |ctx| {
let expected_error = "|Number, Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(a), [Number(b)]) => Ok(Number(*a.min(b))),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
result.insert("nan", f64::NAN);
result.insert("negative_infinity", f64::NEG_INFINITY);
bitwise_fn!(or, |);
result.insert("pi", std::f64::consts::PI);
result.insert("pi_2", std::f64::consts::FRAC_PI_2);
result.insert("pi_4", std::f64::consts::FRAC_PI_4);
number_f64_fn!("radians", to_radians);
number_f64_fn!(recip);
number_fn!(round);
bitwise_fn_positive_arg!(shift_left, <<);
bitwise_fn_positive_arg!(shift_right, >>);
number_f64_fn!(sin);
number_f64_fn!(sinh);
number_f64_fn!(sqrt);
number_f64_fn!(tan);
number_f64_fn!(tanh);
result.insert("tau", std::f64::consts::TAU);
result.add_fn("to_int", |ctx| {
let expected_error = "|Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(n), []) => Ok(i64::from(n).into()),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
result.add_fn("is_int", |ctx| {
let expected_error = "|Number|";
match ctx.instance_and_args(is_number, expected_error)? {
(Number(n), []) => Ok(n.is_i64().into()),
(instance, args) => unexpected_args_after_instance(expected_error, instance, args),
}
});
bitwise_fn!(xor, ^);
result
}
fn is_number(value: &KValue) -> bool {
matches!(value, KValue::Number(_))
}