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, ComputedMap, 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    let computed_map = Arc::new(ComputedMap::new());
16    create_engine_with_spill(grid, spill_map, computed_map)
17}
18
19/// Create a Rhai engine with built-ins registered and shared maps.
20pub fn create_engine_with_spill(
21    grid: Arc<Grid>,
22    spill_map: Arc<SpillMap>,
23    computed_map: Arc<ComputedMap>,
24) -> Engine {
25    let mut engine = Engine::new();
26    crate::builtins::register_builtins(&mut engine, grid, spill_map, computed_map);
27    engine
28}
29
30/// Create a Rhai engine with built-ins registered.
31/// Optionally compiles custom functions from the provided script.
32/// Returns the engine, compiled AST (if any), and any error message.
33pub fn create_engine_with_functions(
34    grid: Arc<Grid>,
35    custom_script: Option<&str>,
36) -> (Engine, Option<AST>, Option<String>) {
37    let spill_map = Arc::new(SpillMap::new());
38    let computed_map = Arc::new(ComputedMap::new());
39    create_engine_with_functions_and_spill(grid, spill_map, computed_map, custom_script)
40}
41
42/// Create a Rhai engine with built-ins, custom functions, and shared maps.
43/// Returns the engine, compiled AST (if any), and any error message.
44pub fn create_engine_with_functions_and_spill(
45    grid: Arc<Grid>,
46    spill_map: Arc<SpillMap>,
47    computed_map: Arc<ComputedMap>,
48    custom_script: Option<&str>,
49) -> (Engine, Option<AST>, Option<String>) {
50    let engine = create_engine_with_spill(grid, spill_map, computed_map);
51
52    let (ast, error) = if let Some(script) = custom_script {
53        match engine.compile(script) {
54            Ok(ast) => (Some(ast), None),
55            Err(e) => (None, Some(format!("Error in custom functions: {}", e))),
56        }
57    } else {
58        (None, None)
59    };
60
61    (engine, ast, error)
62}
63
64/// Evaluate a formula, optionally with custom functions AST.
65pub fn eval_with_functions(
66    engine: &Engine,
67    formula: &str,
68    custom_ast: Option<&AST>,
69) -> Result<Dynamic, String> {
70    if let Some(ast) = custom_ast {
71        match engine.compile(formula) {
72            Ok(formula_ast) => {
73                let merged = ast.clone().merge(&formula_ast);
74                engine.eval_ast(&merged).map_err(|e| e.to_string())
75            }
76            Err(e) => Err(e.to_string()),
77        }
78    } else {
79        engine.eval(formula).map_err(|e| e.to_string())
80    }
81}