From e30444e89b64bc375a8bd851c8e77a93f40f54db Mon Sep 17 00:00:00 2001 From: Michael Schimmel Date: Sun, 22 Feb 2026 09:39:13 +0100 Subject: [PATCH] Refactor math functions to a separate module Move the `register_math` function and its associated logic into a new `math` module. This improves organization and separation of concerns within the RTL AST. --- src/ast/rtl/core.rs | 74 -------------------- src/ast/rtl/math.rs | 162 ++++++++++++++++++++++++++++++++++++++++++++ src/ast/rtl/mod.rs | 2 + 3 files changed, 164 insertions(+), 74 deletions(-) create mode 100644 src/ast/rtl/math.rs diff --git a/src/ast/rtl/core.rs b/src/ast/rtl/core.rs index 4fcced3..bedae24 100644 --- a/src/ast/rtl/core.rs +++ b/src/ast/rtl/core.rs @@ -471,78 +471,4 @@ 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, - })); - - let prng = env.prng.clone(); - env.register_native("random", random_ty, Purity::SideEffectFree, move |_| { - Value::Float(prng.borrow_mut().f64()) - }); - - let seed_ty = StaticType::Function(Box::new(Signature { - params: StaticType::Tuple(vec![StaticType::Int]), - ret: StaticType::Void, - })); - - let prng_seed = env.prng.clone(); - env.register_native("seed!", seed_ty, Purity::Impure, move |args| { - if let Value::Int(s) = args[0] { - prng_seed.borrow_mut().seed(s as u64); - } - Value::Void - }); } diff --git a/src/ast/rtl/math.rs b/src/ast/rtl/math.rs new file mode 100644 index 0000000..4ae3b27 --- /dev/null +++ b/src/ast/rtl/math.rs @@ -0,0 +1,162 @@ +use crate::ast::compiler::optimizer::Purity; +use crate::ast::environment::Environment; +use crate::ast::types::{Signature, StaticType, Value}; +use std::f64::consts; + +pub fn register(env: &Environment) { + // Constants + env.register_constant("PI", StaticType::Float, Value::Float(consts::PI)); + env.register_constant("E", StaticType::Float, Value::Float(consts::E)); + + // Helper to get f64 from Value (Int or Float) + fn to_f64(v: &Value) -> Option { + match v { + Value::Float(f) => Some(*f), + Value::Int(i) => Some(*i as f64), + _ => None, + } + } + + // Unary functions (float -> float) + let register_unary = |name: &'static str, f: fn(f64) -> f64| { + let ty = StaticType::Function(Box::new(Signature { + params: StaticType::Tuple(vec![StaticType::Float]), + ret: StaticType::Float, + })); + env.register_native(name, ty, Purity::Pure, move |args| { + if let Some(x) = to_f64(&args[0]) { + Value::Float(f(x)) + } else { + Value::Void + } + }); + }; + + // Unary functions (float -> int) + let register_to_int = |name: &'static str, f: fn(f64) -> f64| { + let ty = StaticType::Function(Box::new(Signature { + params: StaticType::Tuple(vec![StaticType::Float]), + ret: StaticType::Int, + })); + env.register_native(name, ty, Purity::Pure, move |args| { + if let Some(x) = to_f64(&args[0]) { + Value::Int(f(x) as i64) + } else { + Value::Void + } + }); + }; + + register_unary("sqrt", f64::sqrt); + register_unary("sin", f64::sin); + register_unary("cos", f64::cos); + register_unary("tan", f64::tan); + register_unary("asin", f64::asin); + register_unary("acos", f64::acos); + register_unary("atan", f64::atan); + register_unary("exp", f64::exp); + register_unary("ln", f64::ln); + register_unary("log10", f64::log10); + register_unary("fract", f64::fract); + + // Rounding functions returning Int + register_to_int("round", f64::round); + register_to_int("floor", f64::floor); + register_to_int("ceil", f64::ceil); + register_to_int("trunc", f64::trunc); + + // Binary functions (float, float -> float) + let register_binary = |name: &'static str, f: fn(f64, f64) -> f64| { + let ty = StaticType::Function(Box::new(Signature { + params: StaticType::Tuple(vec![StaticType::Float, StaticType::Float]), + ret: StaticType::Float, + })); + env.register_native(name, ty, Purity::Pure, move |args| { + if let (Some(a), Some(b)) = (to_f64(&args[0]), to_f64(&args[1])) { + Value::Float(f(a, b)) + } else { + Value::Void + } + }); + }; + + register_binary("atan2", f64::atan2); + register_binary("pow", f64::powf); + register_binary("log", f64::log); + + // Specialized abs to handle Int -> Int, Float -> Float + let abs_ty = StaticType::Function(Box::new(Signature { + params: StaticType::Tuple(vec![StaticType::Any]), + ret: StaticType::Any, + })); + env.register_native("abs", abs_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, + } + }); + + // Variadic min / max + let variadic_ty = StaticType::Function(Box::new(Signature { + params: StaticType::Any, + ret: StaticType::Any, + })); + + env.register_native("min", 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 let Some(ord) = arg.partial_cmp(&best) + && ord == std::cmp::Ordering::Less + { + best = arg.clone(); + } + } + best + }); + + env.register_native("max", variadic_ty, Purity::Pure, |args| { + if args.is_empty() { + return Value::Void; + } + let mut best = args[0].clone(); + for arg in &args[1..] { + if let Some(ord) = arg.partial_cmp(&best) + && ord == std::cmp::Ordering::Greater + { + best = arg.clone(); + } + } + best + }); + + // Random + let random_ty = StaticType::Function(Box::new(Signature { + params: StaticType::Tuple(vec![]), + ret: StaticType::Float, + })); + + let prng = env.prng.clone(); + env.register_native("random", random_ty, Purity::SideEffectFree, move |_| { + Value::Float(prng.borrow_mut().f64()) + }); + + let seed_ty = StaticType::Function(Box::new(Signature { + params: StaticType::Tuple(vec![StaticType::Int]), + ret: StaticType::Void, + })); + + let prng_seed = env.prng.clone(); + env.register_native("seed!", seed_ty, Purity::Impure, move |args| { + if let Value::Int(s) = args[0] { + prng_seed.borrow_mut().seed(s as u64); + } + Value::Void + }); +} diff --git a/src/ast/rtl/mod.rs b/src/ast/rtl/mod.rs index 75d0847..ec23604 100644 --- a/src/ast/rtl/mod.rs +++ b/src/ast/rtl/mod.rs @@ -1,6 +1,7 @@ pub mod core; pub mod datetime; pub mod intrinsics; +pub mod math; pub mod type_registry; use crate::ast::environment::Environment; @@ -8,4 +9,5 @@ use crate::ast::environment::Environment; pub fn register(env: &Environment) { core::register(env); datetime::register(env); + math::register(env); }