cel_rs/
program.rs

1use crate::parser::Expression;
2use crate::parser::cel::ExpressionParser;
3use std::fmt;
4use std::result::Result;
5use crate::context::Context;
6use crate::eval::{Bag, Eval};
7use crate::Value;
8
9pub struct Program {
10    expr: Expression
11}
12
13#[derive(Debug)]
14pub struct ParseError {
15    message: String,
16}
17
18
19impl fmt::Display for ParseError {
20    fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
21        write!(f, "{}", self.message)
22    }
23}
24
25impl Program {
26    pub fn new(source: &str) -> Result<Program, ParseError> {
27        match ExpressionParser::new().parse(source) {
28            Ok(expr) => Ok(Program {expr}),
29            Err(e) => Err(ParseError{message: format!("{}", e)}),
30        }
31    }
32
33    pub fn execute(self, context: &mut Context) -> bool {
34        self.eval(context).unpack().into()
35    }
36
37    pub fn eval(self, context: &mut Context) -> Value {
38        let e = Eval::default();
39        e.eval(self.expr, context).unpack()
40    }
41}
42
43
44
45#[cfg(test)]
46pub mod tests {
47    use std::rc::Rc;
48
49    use crate::{program, value::{FnValue, Overload}, Value};
50
51    macro_rules! string {
52        ($q:literal) => {
53            crate::Value::String(std::rc::Rc::new($q.into()))
54        };
55    }
56    macro_rules! eval_program {
57        ($expr:literal) => ({
58           eval_program!($expr, &mut crate::context::Context::default())
59        });
60        ($expr:literal, $ctx:expr) => ({
61            let program = crate::program::Program::new($expr);
62            assert!(program.is_ok(), "failed to create the program {:?}", program.err());
63            let program = program.unwrap();
64            program.eval($ctx)
65        });
66    }
67
68    #[test]
69    fn basic_test() {
70        assert_eq!(eval_program!(r#"r"""#), string!(""));
71    }
72
73    fn calc_string_string(lhs: &Value, rhs: &Value) -> Value {
74        Value::Null
75    }
76
77    #[test]
78    fn fn_test() {
79        let func = FnValue {
80            name: "calc",
81            overloads: &[
82                Overload {
83                    key: "calc_string",
84                    func: calc_string_string
85                }
86            ],
87        };
88        let mut ctx = program::Context::default()
89        .add_variable("a", Value::String(Rc::new("".into())))
90        .add_variable("b", Value::Int(0))
91        .add_variable("calc", crate::Value::Function(Rc::new(func)));
92        assert_eq!(eval_program!(r#"b.calc(a)"#, &mut ctx), string!(""));
93    }
94}