From df06c51205748872c00b2214172dbc2b7d17cbe2 Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Sun, 22 Feb 2026 08:49:14 +0100 Subject: [PATCH] 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`. --- src/ast/rtl/core.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++ src/ast/types.rs | 14 ++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/ast/rtl/core.rs b/src/ast/rtl/core.rs index bedae24..f438b9e 100644 --- a/src/ast/rtl/core.rs +++ b/src/ast/rtl/core.rs @@ -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) + } + }); } diff --git a/src/ast/types.rs b/src/ast/types.rs index c36c0bf..d27483b 100644 --- a/src/ast/types.rs +++ b/src/ast/types.rs @@ -117,6 +117,20 @@ impl PartialEq for Value { } } +impl PartialOrd for Value { + fn partial_cmp(&self, other: &Self) -> Option { + 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,