Add math and random functions
Register `abs`, `min`, `max`, and `random` functions to the environment. This also includes adding `PartialOrd` implementation for `Value` to support comparisons for `min` and `max`.
This commit is contained in:
@@ -471,4 +471,70 @@ fn register_logic(env: &Environment) {
|
|||||||
_ => Value::Void,
|
_ => Value::Void,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
register_math(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_math(env: &Environment) {
|
||||||
|
let math_unary_ty = StaticType::Function(Box::new(Signature {
|
||||||
|
params: StaticType::Tuple(vec![StaticType::Any]),
|
||||||
|
ret: StaticType::Any,
|
||||||
|
}));
|
||||||
|
|
||||||
|
env.register_native("abs", math_unary_ty, Purity::Pure, |args| {
|
||||||
|
if args.len() != 1 {
|
||||||
|
return Value::Void;
|
||||||
|
}
|
||||||
|
match args[0] {
|
||||||
|
Value::Int(i) => Value::Int(i.abs()),
|
||||||
|
Value::Float(f) => Value::Float(f.abs()),
|
||||||
|
_ => Value::Void,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let math_variadic_ty = StaticType::Function(Box::new(Signature {
|
||||||
|
params: StaticType::Any,
|
||||||
|
ret: StaticType::Any,
|
||||||
|
}));
|
||||||
|
|
||||||
|
env.register_native("min", math_variadic_ty.clone(), Purity::Pure, |args| {
|
||||||
|
if args.is_empty() {
|
||||||
|
return Value::Void;
|
||||||
|
}
|
||||||
|
let mut best = args[0].clone();
|
||||||
|
for arg in &args[1..] {
|
||||||
|
if *arg < best {
|
||||||
|
best = arg.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
best
|
||||||
|
});
|
||||||
|
|
||||||
|
env.register_native("max", math_variadic_ty, Purity::Pure, |args| {
|
||||||
|
if args.is_empty() {
|
||||||
|
return Value::Void;
|
||||||
|
}
|
||||||
|
let mut best = args[0].clone();
|
||||||
|
for arg in &args[1..] {
|
||||||
|
if *arg > best {
|
||||||
|
best = arg.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
best
|
||||||
|
});
|
||||||
|
|
||||||
|
let random_ty = StaticType::Function(Box::new(Signature {
|
||||||
|
params: StaticType::Tuple(vec![]),
|
||||||
|
ret: StaticType::Float,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Simple LCG (no dependencies required)
|
||||||
|
static mut SEED: u64 = 0x12345678;
|
||||||
|
env.register_native("random", random_ty, Purity::SideEffectFree, |_| {
|
||||||
|
unsafe {
|
||||||
|
SEED = SEED.wrapping_mul(6364136223846793005).wrapping_add(1);
|
||||||
|
let val = (SEED >> 32) as f64 / (u32::MAX as f64);
|
||||||
|
Value::Float(val)
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,6 +117,20 @@ impl PartialEq for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Value {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Int(a), Value::Int(b)) => a.partial_cmp(b),
|
||||||
|
(Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
|
||||||
|
(Value::Int(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
|
||||||
|
(Value::Float(a), Value::Int(b)) => a.partial_cmp(&(*b as f64)),
|
||||||
|
(Value::DateTime(a), Value::DateTime(b)) => a.partial_cmp(b),
|
||||||
|
(Value::Text(a), Value::Text(b)) => a.partial_cmp(b),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Signature {
|
pub struct Signature {
|
||||||
pub params: StaticType,
|
pub params: StaticType,
|
||||||
|
|||||||
Reference in New Issue
Block a user