Skip to main content

gridline_engine/engine/
eval.rs

1//! Rhai engine creation and formula evaluation.
2//!
3//! Creates the Rhai scripting engine with all spreadsheet built-in functions
4//! registered (SUM, AVERAGE, cell accessors, etc.). Also handles evaluation
5//! of formulas with optional user-defined custom functions from external files.
6
7use rhai::Engine;
8use std::sync::Arc;
9
10use super::{AST, Dynamic, Grid, SpillMap};
11
12/// Create a Rhai engine with built-ins registered.
13pub fn create_engine(grid: Arc<Grid>) -> Engine {
14    let spill_map = Arc::new(SpillMap::new());
15    create_engine_with_spill(grid, spill_map)
16}
17
18/// Create a Rhai engine with built-ins registered and a shared spill map.
19pub fn create_engine_with_spill(grid: Arc<Grid>, spill_map: Arc<SpillMap>) -> Engine {
20    let mut engine = Engine::new();
21    crate::builtins::register_builtins(&mut engine, grid, spill_map);
22    engine
23}
24
25/// Create a Rhai engine with built-ins registered.
26/// Optionally compiles custom functions from the provided script.
27/// Returns the engine, compiled AST (if any), and any error message.
28pub fn create_engine_with_functions(
29    grid: Arc<Grid>,
30    custom_script: Option<&str>,
31) -> (Engine, Option<AST>, Option<String>) {
32    let spill_map = Arc::new(SpillMap::new());
33    create_engine_with_functions_and_spill(grid, spill_map, custom_script)
34}
35
36/// Create a Rhai engine with built-ins, custom functions, and a shared spill map.
37/// Returns the engine, compiled AST (if any), and any error message.
38pub fn create_engine_with_functions_and_spill(
39    grid: Arc<Grid>,
40    spill_map: Arc<SpillMap>,
41    custom_script: Option<&str>,
42) -> (Engine, Option<AST>, Option<String>) {
43    let engine = create_engine_with_spill(grid, spill_map);
44
45    let (ast, error) = if let Some(script) = custom_script {
46        match engine.compile(script) {
47            Ok(ast) => (Some(ast), None),
48            Err(e) => (None, Some(format!("Error in custom functions: {}", e))),
49        }
50    } else {
51        (None, None)
52    };
53
54    (engine, ast, error)
55}
56
57/// Evaluate a formula, optionally with custom functions AST.
58pub fn eval_with_functions(
59    engine: &Engine,
60    formula: &str,
61    custom_ast: Option<&AST>,
62) -> Result<Dynamic, String> {
63    if let Some(ast) = custom_ast {
64        match engine.compile(formula) {
65            Ok(formula_ast) => {
66                let merged = ast.clone().merge(&formula_ast);
67                engine.eval_ast(&merged).map_err(|e| e.to_string())
68            }
69            Err(e) => Err(e.to_string()),
70        }
71    } else {
72        engine.eval(formula).map_err(|e| e.to_string())
73    }
74}