Skip to main content

ganit_core/eval/functions/
mod.rs

1pub mod financial;
2pub mod logical;
3pub mod math;
4pub mod statistical;
5pub mod text;
6
7use std::collections::HashMap;
8use crate::eval::context::Context;
9use crate::parser::ast::Expr;
10use crate::types::{ErrorKind, Value};
11
12// ── EvalCtx ───────────────────────────────────────────────────────────────
13
14/// Bundles the variable context and function registry for use during evaluation.
15/// Passed to lazy functions so they can recursively evaluate sub-expressions.
16pub struct EvalCtx<'r> {
17    pub ctx: Context,
18    pub registry: &'r Registry,
19}
20
21impl<'r> EvalCtx<'r> {
22    pub fn new(ctx: Context, registry: &'r Registry) -> Self {
23        Self { ctx, registry }
24    }
25}
26
27// ── Function kinds ─────────────────────────────────────────────────────────
28
29/// A function that receives pre-evaluated arguments.
30/// Argument errors are caught before dispatch — the slice never contains `Value::Error`.
31pub type EagerFn = fn(&[Value]) -> Value;
32
33/// A function that receives raw AST nodes and controls its own evaluation order.
34/// Used for short-circuit operators like `IF`, `AND`, `OR`.
35pub type LazyFn  = fn(&[Expr], &mut EvalCtx<'_>) -> Value;
36
37pub enum FunctionKind {
38    Eager(EagerFn),
39    Lazy(LazyFn),
40}
41
42// ── Registry ──────────────────────────────────────────────────────────────
43
44/// The runtime registry of built-in and user-registered spreadsheet functions.
45pub struct Registry {
46    functions: HashMap<String, FunctionKind>,
47}
48
49impl Registry {
50    pub fn new() -> Self {
51        let mut r = Self { functions: HashMap::new() };
52        math::register_math(&mut r);
53        logical::register_logical(&mut r);
54        text::register_text(&mut r);
55        financial::register_financial(&mut r);
56        statistical::register_statistical(&mut r);
57        r
58    }
59
60    pub fn register_eager(&mut self, name: &str, f: EagerFn) {
61        self.functions.insert(name.to_uppercase(), FunctionKind::Eager(f));
62    }
63
64    pub fn register_lazy(&mut self, name: &str, f: LazyFn) {
65        self.functions.insert(name.to_uppercase(), FunctionKind::Lazy(f));
66    }
67
68    pub fn get(&self, name: &str) -> Option<&FunctionKind> {
69        self.functions.get(&name.to_uppercase())
70    }
71}
72
73impl Default for Registry {
74    fn default() -> Self {
75        Self::new()
76    }
77}
78
79/// Validate argument count for eager functions (args already evaluated to `&[Value]`).
80/// Returns `Some(Value::Error(ErrorKind::Value))` if the count is out of range.
81pub fn check_arity(args: &[Value], min: usize, max: usize) -> Option<Value> {
82    if args.len() < min || args.len() > max {
83        Some(Value::Error(ErrorKind::Value))
84    } else {
85        None
86    }
87}
88
89/// Validate argument count for lazy functions (args are `&[Expr]`).
90/// Returns `Some(Value::Error(ErrorKind::Value))` if the count is out of range.
91pub fn check_arity_len(count: usize, min: usize, max: usize) -> Option<Value> {
92    if count < min || count > max {
93        Some(Value::Error(ErrorKind::Value))
94    } else {
95        None
96    }
97}