expr/
parser.rs

1use crate::ast::node::Node;
2use crate::ast::program::Program;
3use crate::eval::Environment;
4use crate::functions::ExprCall;
5use crate::{ExprPest, Rule};
6use crate::{Context, Error, Result, Value};
7use pest::Parser as PestParser;
8use std::fmt;
9use std::fmt::{Debug, Formatter};
10
11/// Parse an expr program to be run later
12pub fn compile(code: &str) -> Result<Program> {
13    #[cfg(debug_assertions)]
14    pest::set_error_detail(true);
15    let pairs = ExprPest::parse(Rule::full, code).map_err(|e| Error::PestError(Box::new(e)))?;
16    Ok(pairs.into())
17}
18
19/// Main struct for parsing and evaluating expr programs
20///
21/// Example:
22///
23/// ```
24/// use expr::{Context, Parser};
25/// let ctx = Context::from_iter([("foo", 1), ("bar", 2)]);
26/// let p = Parser::new();
27/// assert_eq!(p.eval("foo + bar", &ctx).unwrap().to_string(), "3");
28/// ```
29#[deprecated(note = "Use `compile()` and `Environment` instead")]
30#[derive(Default)]
31pub struct Parser<'a> {
32    env: Environment<'a>,
33}
34
35#[allow(deprecated)]
36impl Debug for Parser<'_> {
37    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
38        f.debug_struct("ExprParser").finish()
39    }
40}
41
42#[allow(deprecated)]
43impl<'a> Parser<'a> {
44    /// Create a new parser with the default environment
45    pub fn new() -> Self {
46        Parser {
47            env: Environment::new(),
48        }
49    }
50
51    /// Add a function for expr programs to call
52    ///
53    /// Example:
54    /// ```
55    /// use std::collections::HashMap;
56    /// use expr::{Context, Parser, Value};
57    ///
58    /// let mut p = Parser::new();
59    /// let ctx = Context::default();
60    /// p.add_function("add", |c| {
61    ///   let mut sum = 0;
62    ///     for arg in c.args {
63    ///       if let Value::Number(n) = arg {
64    ///         sum += n;
65    ///        } else {
66    ///          panic!("Invalid argument: {arg:?}");
67    ///        }
68    ///     }
69    ///   Ok(sum.into())
70    /// });
71    /// assert_eq!(p.eval("add(1, 2, 3)", &ctx).unwrap().to_string(), "6");
72    /// ```
73    pub fn add_function<F>(&mut self, name: &str, f: F)
74    where
75        F: Fn(ExprCall) -> Result<Value> + 'a + Sync + Send,
76    {
77        self.env.add_function(name, Box::new(f));
78    }
79
80    /// Parse an expr program to be run later
81    pub fn compile(&self, code: &str) -> Result<Program> {
82        compile(code)
83    }
84
85    /// Run a compiled expr program
86    pub fn run(&self, program: Program, ctx: &Context) -> Result<Value> {
87        self.env.run(program, ctx)
88    }
89
90    /// Compile and run an expr program in one step
91    ///
92    /// Example:
93    /// ```
94    /// use std::collections::HashMap;
95    /// use expr::{Context, Parser};
96    /// let p = Parser::default();
97    /// let ctx = Context::default();
98    /// assert_eq!(p.eval("1 + 2", &ctx).unwrap().to_string(), "3");
99    /// ```
100    pub fn eval(&self, code: &str, ctx: &Context) -> Result<Value> {
101        self.env.eval(code, ctx)
102    }
103
104    pub fn eval_expr(&self, ctx: &Context, node: Node) -> Result<Value> {
105        self.env.eval_expr(ctx, node)
106    }
107}