ganit_core/eval/functions/
mod.rs1pub mod array;
2pub mod database;
3pub mod date;
4pub mod engineering;
5pub mod filter;
6pub mod financial;
7pub mod logical;
8pub mod lookup;
9pub mod math;
10pub mod operator;
11pub mod parser;
12pub mod statistical;
13pub mod text;
14
15use std::collections::HashMap;
16use crate::eval::context::Context;
17use crate::parser::ast::Expr;
18use crate::types::{ErrorKind, Value};
19
20pub struct EvalCtx<'r> {
25 pub ctx: Context,
26 pub registry: &'r Registry,
27}
28
29impl<'r> EvalCtx<'r> {
30 pub fn new(ctx: Context, registry: &'r Registry) -> Self {
31 Self { ctx, registry }
32 }
33}
34
35pub type EagerFn = fn(&[Value]) -> Value;
40
41pub type LazyFn = fn(&[Expr], &mut EvalCtx<'_>) -> Value;
44
45pub enum FunctionKind {
46 Eager(EagerFn),
47 Lazy(LazyFn),
48}
49
50#[derive(Debug)]
55pub struct FunctionMeta {
56 pub category: &'static str,
57 pub signature: &'static str,
58 pub description: &'static str,
59}
60
61pub struct Registry {
65 functions: HashMap<String, FunctionKind>,
66 metadata: HashMap<String, FunctionMeta>,
67}
68
69impl Registry {
70 pub fn new() -> Self {
71 let mut r = Self { functions: HashMap::new(), metadata: HashMap::new() };
72 math::register_math(&mut r);
73 logical::register_logical(&mut r);
74 text::register_text(&mut r);
75 financial::register_financial(&mut r);
76 statistical::register_statistical(&mut r);
77 operator::register_operator(&mut r);
78 date::register_date(&mut r);
79 parser::register_parser(&mut r);
80 engineering::register_engineering(&mut r);
81 filter::register_filter(&mut r);
82 array::register_array(&mut r);
83 database::register_database(&mut r);
84 lookup::register_lookup(&mut r);
85 r
86 }
87
88 pub fn register_eager(&mut self, name: &str, f: EagerFn, meta: FunctionMeta) {
91 let key = name.to_uppercase();
92 self.functions.insert(key.clone(), FunctionKind::Eager(f));
93 self.metadata.insert(key, meta);
94 }
95
96 pub fn register_lazy(&mut self, name: &str, f: LazyFn, meta: FunctionMeta) {
99 let key = name.to_uppercase();
100 self.functions.insert(key.clone(), FunctionKind::Lazy(f));
101 self.metadata.insert(key, meta);
102 }
103
104 pub fn register_internal(&mut self, name: &str, f: EagerFn) {
107 self.functions.insert(name.to_uppercase(), FunctionKind::Eager(f));
108 }
109
110 pub fn register_internal_lazy(&mut self, name: &str, f: LazyFn) {
113 self.functions.insert(name.to_uppercase(), FunctionKind::Lazy(f));
114 }
115
116 pub fn get(&self, name: &str) -> Option<&FunctionKind> {
117 self.functions.get(&name.to_uppercase())
118 }
119
120 pub fn list_functions(&self) -> impl Iterator<Item = (&str, &FunctionMeta)> {
123 self.metadata.iter().map(|(k, v)| (k.as_str(), v))
124 }
125}
126
127impl Default for Registry {
128 fn default() -> Self {
129 Self::new()
130 }
131}
132
133pub fn check_arity(args: &[Value], min: usize, max: usize) -> Option<Value> {
137 if args.len() < min || args.len() > max {
138 Some(Value::Error(ErrorKind::NA))
139 } else {
140 None
141 }
142}
143
144pub fn check_arity_len(count: usize, min: usize, max: usize) -> Option<Value> {
147 if count < min || count > max {
148 Some(Value::Error(ErrorKind::NA))
149 } else {
150 None
151 }
152}
153
154#[cfg(test)]
157mod tests {
158 use super::*;
159
160 #[test]
161 fn list_functions_matches_registry() {
162 let registry = Registry::new();
163 let listed: Vec<(&str, &FunctionMeta)> = registry.list_functions().collect();
164 assert!(!listed.is_empty(), "registry should expose at least one function");
165 for (name, _meta) in &listed {
167 assert!(
168 registry.get(name).is_some(),
169 "listed function {name} not found via get()"
170 );
171 }
172 assert_eq!(listed.len(), registry.metadata.len());
174 }
175}