ganit_core/eval/functions/
mod.rs1pub mod date;
2pub mod engineering;
3pub mod financial;
4pub mod logical;
5pub mod math;
6pub mod operator;
7pub mod parser;
8pub mod statistical;
9pub mod text;
10
11use std::collections::HashMap;
12use crate::eval::context::Context;
13use crate::parser::ast::Expr;
14use crate::types::{ErrorKind, Value};
15
16pub struct EvalCtx<'r> {
21 pub ctx: Context,
22 pub registry: &'r Registry,
23}
24
25impl<'r> EvalCtx<'r> {
26 pub fn new(ctx: Context, registry: &'r Registry) -> Self {
27 Self { ctx, registry }
28 }
29}
30
31pub type EagerFn = fn(&[Value]) -> Value;
36
37pub type LazyFn = fn(&[Expr], &mut EvalCtx<'_>) -> Value;
40
41pub enum FunctionKind {
42 Eager(EagerFn),
43 Lazy(LazyFn),
44}
45
46#[derive(Debug)]
51pub struct FunctionMeta {
52 pub category: &'static str,
53 pub signature: &'static str,
54 pub description: &'static str,
55}
56
57pub struct Registry {
61 functions: HashMap<String, FunctionKind>,
62 metadata: HashMap<String, FunctionMeta>,
63}
64
65impl Registry {
66 pub fn new() -> Self {
67 let mut r = Self { functions: HashMap::new(), metadata: HashMap::new() };
68 math::register_math(&mut r);
69 logical::register_logical(&mut r);
70 text::register_text(&mut r);
71 financial::register_financial(&mut r);
72 statistical::register_statistical(&mut r);
73 operator::register_operator(&mut r);
74 date::register_date(&mut r);
75 parser::register_parser(&mut r);
76 engineering::register_engineering(&mut r);
77 r
78 }
79
80 pub fn register_eager(&mut self, name: &str, f: EagerFn, meta: FunctionMeta) {
83 let key = name.to_uppercase();
84 self.functions.insert(key.clone(), FunctionKind::Eager(f));
85 self.metadata.insert(key, meta);
86 }
87
88 pub fn register_lazy(&mut self, name: &str, f: LazyFn, meta: FunctionMeta) {
91 let key = name.to_uppercase();
92 self.functions.insert(key.clone(), FunctionKind::Lazy(f));
93 self.metadata.insert(key, meta);
94 }
95
96 pub fn register_internal(&mut self, name: &str, f: EagerFn) {
99 self.functions.insert(name.to_uppercase(), FunctionKind::Eager(f));
100 }
101
102 pub fn register_internal_lazy(&mut self, name: &str, f: LazyFn) {
105 self.functions.insert(name.to_uppercase(), FunctionKind::Lazy(f));
106 }
107
108 pub fn get(&self, name: &str) -> Option<&FunctionKind> {
109 self.functions.get(&name.to_uppercase())
110 }
111
112 pub fn list_functions(&self) -> impl Iterator<Item = (&str, &FunctionMeta)> {
115 self.metadata.iter().map(|(k, v)| (k.as_str(), v))
116 }
117}
118
119impl Default for Registry {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125pub fn check_arity(args: &[Value], min: usize, max: usize) -> Option<Value> {
129 if args.len() < min || args.len() > max {
130 Some(Value::Error(ErrorKind::NA))
131 } else {
132 None
133 }
134}
135
136pub fn check_arity_len(count: usize, min: usize, max: usize) -> Option<Value> {
139 if count < min || count > max {
140 Some(Value::Error(ErrorKind::NA))
141 } else {
142 None
143 }
144}
145
146#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn list_functions_matches_registry() {
154 let registry = Registry::new();
155 let listed: Vec<(&str, &FunctionMeta)> = registry.list_functions().collect();
156 assert!(!listed.is_empty(), "registry should expose at least one function");
157 for (name, _meta) in &listed {
159 assert!(
160 registry.get(name).is_some(),
161 "listed function {name} not found via get()"
162 );
163 }
164 assert_eq!(listed.len(), registry.metadata.len());
166 }
167}