Skip to main content

polyspec_crudui_validator/expr/
expression.rs

1//! Public facade for the CRUDUI expression engine: string → tokens → AST → value.
2//!
3//! The pipeline is strictly staged (GRAMMAR §0): never split a string to
4//! evaluate, never eval. `evaluate` returns a boolean condition result;
5//! `evaluate_value` returns a ternary's branch value and the boolean condition
6//! result for everything else (JS `evaluateExpressionValue` parity — the shared
7//! 4-language fixture is generated from the JS engine).
8
9use serde_json::Value;
10
11use super::ast::Node;
12use super::error::ParseError;
13use super::evaluator::Evaluator;
14use super::lexer::Lexer;
15use super::parser::Parser;
16use super::token::Token;
17
18/// Stateless entry points for the CRUDUI expression engine.
19pub struct Expression;
20
21impl Expression {
22    /// Tokenize an expression. WHITESPACE excluded; ends with EOF.
23    pub fn tokenize(expression: &str) -> Result<Vec<Token>, ParseError> {
24        Lexer::new(expression).tokenize()
25    }
26
27    /// Parse an expression into its AST.
28    pub fn parse(expression: &str) -> Result<Node, ParseError> {
29        let tokens = Self::tokenize(expression)?;
30        Parser::new(tokens).parse()
31    }
32
33    /// Evaluate to a truthy boolean (show/display call site).
34    pub fn evaluate(
35        expression: &str,
36        form_data: &Value,
37        current_path: &[String],
38        row_keys: &[usize],
39    ) -> Result<bool, ParseError> {
40        let ast = Self::parse(expression)?;
41        Ok(Evaluator::new(form_data, current_path, row_keys).evaluate(&ast))
42    }
43
44    /// Evaluate to the raw value (class/style/number/null call site).
45    pub fn evaluate_value(
46        expression: &str,
47        form_data: &Value,
48        current_path: &[String],
49        row_keys: &[usize],
50    ) -> Result<Value, ParseError> {
51        let ast = Self::parse(expression)?;
52        Ok(Evaluator::new(form_data, current_path, row_keys).evaluate_value(&ast))
53    }
54}