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:
Michael Schimmel
2026-02-22 08:49:14 +01:00
parent 589c13896f
commit df06c51205
2 changed files with 80 additions and 0 deletions
+66
View File
@@ -471,4 +471,70 @@ fn register_logic(env: &Environment) {
_ => 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)
}
});
}
+14
View File
@@ -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)]
pub struct Signature {
pub params: StaticType,