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