Struct Parser

Source
pub struct Parser {
    pub expr_len_limit: usize,
    pub expr_depth_limit: usize,
}

Fields§

§expr_len_limit: usize§expr_depth_limit: usize

Implementations§

Source§

impl Parser

Source

pub const fn new() -> Self

Examples found in repository?
examples/compile.rs (line 7)
6fn main() -> Result<(), fasteval3::Error> {
7    let parser = fasteval3::Parser::new();
8    let mut slab = fasteval3::Slab::new();
9    let mut map = BTreeMap::new();
10
11    let expr_str = "sin(deg/360 * 2*pi())";
12    let compiled = parser
13        .parse(expr_str, &mut slab.ps)?
14        .from(&slab.ps)
15        .compile(&slab.ps, &mut slab.cs, &mut EmptyNamespace);
16    for deg in 0..360 {
17        map.insert(String::from("deg"), f64::from(deg));
18        // When working with compiled constant expressions, you can use the
19        // eval_compiled*!() macros to save a function call:
20        let val = fasteval3::eval_compiled!(compiled, &slab, &mut map);
21        eprintln!("sin({deg}°) = {val}");
22    }
23
24    Ok(())
25}
More examples
Hide additional examples
examples/slab.rs (line 6)
5fn main() -> Result<(), fasteval3::Error> {
6    let parser = fasteval3::Parser::new();
7    let mut slab = fasteval3::Slab::new();
8
9    // See the `parse` documentation to understand why we use `from` like this:
10    let expr_ref = parser.parse("x + 1", &mut slab.ps)?.from(&slab.ps);
11
12    // Let's evaluate the expression a couple times with different 'x' values:
13
14    let mut map: BTreeMap<String, f64> = BTreeMap::new();
15    map.insert(String::from("x"), 1.0);
16    let val = expr_ref.eval(&slab, &mut map)?;
17    assert!((val - 2.0).abs() < f64::EPSILON);
18
19    map.insert(String::from("x"), 2.5);
20    let val = expr_ref.eval(&slab, &mut map)?;
21    assert!((val - 3.5).abs() < f64::EPSILON);
22
23    // Now, let's re-use the Slab for a new expression.
24    // (This is much cheaper than allocating a new Slab.)
25    // The Slab gets cleared by 'parse()', so you must avoid using
26    // the old expr_ref after parsing the new expression.
27    // One simple way to avoid this problem is to shadow the old variable:
28
29    let expr_ref = parser.parse("x * 10", &mut slab.ps)?.from(&slab.ps);
30
31    let val = expr_ref.eval(&slab, &mut map)?;
32    assert!((val - 25.0).abs() < f64::EPSILON);
33
34    Ok(())
35}
examples/internals.rs (line 5)
4fn main() -> Result<(), fasteval3::Error> {
5    let parser = fasteval3::Parser::new();
6    let mut slab = fasteval3::Slab::new();
7
8    let expr_str = "sin(deg/360 * 2*pi())";
9    let expr_ref = parser.parse(expr_str, &mut slab.ps)?.from(&slab.ps);
10
11    // Let's take a look at the parsed AST inside the Slab:
12    // If you find this structure confusing, take a look at the compilation
13    // AST below because it is simpler.
14    assert_eq!(
15        format!("{:?}", slab.ps),
16        r#"ParseSlab{ exprs:{ 0:Expression { first: EStdFunc(EVar("deg")), pairs: [ExprPair(EDiv, EConstant(360.0)), ExprPair(EMul, EConstant(2.0)), ExprPair(EMul, EStdFunc(EFuncPi))] }, 1:Expression { first: EStdFunc(EFuncSin(ExpressionI(0))), pairs: [] } }, vals:{} }"#
17    );
18    // Pretty-Print:
19    // ParseSlab{
20    //     exprs:{
21    //         0:Expression { first: EStdFunc(EVar("deg")),
22    //                        pairs: [ExprPair(EDiv, EConstant(360.0)),
23    //                                ExprPair(EMul, EConstant(2.0)),
24    //                                ExprPair(EMul, EStdFunc(EFuncPi))]
25    //                      },
26    //         1:Expression { first: EStdFunc(EFuncSin(ExpressionI(0))),
27    //                        pairs: [] }
28    //                      },
29    //     vals:{}
30    // }
31
32    let compiled = expr_ref.compile(&slab.ps, &mut slab.cs, &mut EmptyNamespace);
33
34    // Let's take a look at the compilation results and the AST inside the Slab:
35    // Notice that compilation has performed constant-folding: 1/360 * 2*pi = 0.017453292519943295
36    // In the results below: IFuncSin(...) represents the sin function.
37    //                       InstructionI(1) represents the Instruction stored at index 1.
38    //                       IMul(...) represents the multiplication operator.
39    //                       'C(0.017...)' represents a constant value of 0.017... .
40    //                       IVar("deg") represents a variable named "deg".
41    assert_eq!(format!("{compiled:?}"), "IFuncSin(InstructionI(1))");
42    assert_eq!(
43        format!("{:?}", slab.cs),
44        r#"CompileSlab{ instrs:{ 0:IVar("deg"), 1:IMul(InstructionI(0), C(0.017453292519943295)) } }"#
45    );
46
47    Ok(())
48}
examples/repl.rs (line 55)
54fn repl() {
55    let parser = Parser::new();
56    let mut slab = Slab::new();
57    let mut ns_stack = vec![BTreeMap::new()];
58
59    let stdin = io::stdin();
60    
61    loop {
62        eprint!(">>> ");
63        io::stderr().flush().unwrap();
64
65        let mut ans_key = String::from("_");
66
67        let mut line: String = if let Some(Ok(string)) = stdin.lock().lines().next() {
68            string.trim().to_owned()
69        } else {
70            break
71        };
72
73        if line.is_empty() {
74            continue;
75        }
76
77        let pieces: Vec<&str> = line.split_whitespace().collect();
78        if pieces[0] == "let" {
79            if pieces.len() < 4 || pieces[2] != "=" {
80                eprintln!("incorrect 'let' syntax.  Should be: let x = ...");
81                continue;
82            }
83            ans_key = pieces[1].to_owned();
84            line = pieces[3..].join(" ");
85        } else if pieces[0] == "push" {
86            ns_stack.push(BTreeMap::new());
87            eprintln!("Entered scope[{}]", ns_stack.len() - 1);
88            continue;
89        } else if pieces[0] == "pop" {
90            let mut return_value = std::f64::NAN;
91            let mut has_return_value = false;
92            if let Some(v) = ns_stack.last().unwrap().get(&ans_key) {
93                return_value = *v;
94                has_return_value = true;
95            }
96
97            ns_stack.pop();
98            eprintln!("Exited scope[{}]", ns_stack.len());
99            if ns_stack.is_empty() {
100                ns_stack.push(BTreeMap::new());
101            } // All scopes have been removed.  Add a new one.
102
103            if has_return_value {
104                ns_stack.last_mut().unwrap().insert(ans_key, return_value);
105            }
106
107            continue;
108        }
109
110        let expr_ref = match parser.parse(&line, &mut slab.ps) {
111            Ok(expr_i) => slab.ps.get_expr(expr_i),
112            Err(err) => {
113                eprintln!("parse error: {err}");
114                continue;
115            }
116        };
117
118        let ans = match expr_ref.eval(&slab, &mut ns_stack) {
119            Ok(val) => val,
120            Err(err) => {
121                eprintln!("eval error: {err}");
122                continue;
123            }
124        };
125
126        println!("{ans}");
127        ns_stack.last_mut().unwrap().insert(ans_key, ans);
128    }
129
130    println!();
131}
Source

pub fn parse( &self, expr_str: &str, slab: &mut ParseSlab, ) -> Result<ExpressionI, Error>

Use this function to parse an expression String. The Slab will be cleared first.

§Errors

Will return Err if length of expr_str exceeds limit.

Examples found in repository?
examples/compile.rs (line 13)
6fn main() -> Result<(), fasteval3::Error> {
7    let parser = fasteval3::Parser::new();
8    let mut slab = fasteval3::Slab::new();
9    let mut map = BTreeMap::new();
10
11    let expr_str = "sin(deg/360 * 2*pi())";
12    let compiled = parser
13        .parse(expr_str, &mut slab.ps)?
14        .from(&slab.ps)
15        .compile(&slab.ps, &mut slab.cs, &mut EmptyNamespace);
16    for deg in 0..360 {
17        map.insert(String::from("deg"), f64::from(deg));
18        // When working with compiled constant expressions, you can use the
19        // eval_compiled*!() macros to save a function call:
20        let val = fasteval3::eval_compiled!(compiled, &slab, &mut map);
21        eprintln!("sin({deg}°) = {val}");
22    }
23
24    Ok(())
25}
More examples
Hide additional examples
examples/slab.rs (line 10)
5fn main() -> Result<(), fasteval3::Error> {
6    let parser = fasteval3::Parser::new();
7    let mut slab = fasteval3::Slab::new();
8
9    // See the `parse` documentation to understand why we use `from` like this:
10    let expr_ref = parser.parse("x + 1", &mut slab.ps)?.from(&slab.ps);
11
12    // Let's evaluate the expression a couple times with different 'x' values:
13
14    let mut map: BTreeMap<String, f64> = BTreeMap::new();
15    map.insert(String::from("x"), 1.0);
16    let val = expr_ref.eval(&slab, &mut map)?;
17    assert!((val - 2.0).abs() < f64::EPSILON);
18
19    map.insert(String::from("x"), 2.5);
20    let val = expr_ref.eval(&slab, &mut map)?;
21    assert!((val - 3.5).abs() < f64::EPSILON);
22
23    // Now, let's re-use the Slab for a new expression.
24    // (This is much cheaper than allocating a new Slab.)
25    // The Slab gets cleared by 'parse()', so you must avoid using
26    // the old expr_ref after parsing the new expression.
27    // One simple way to avoid this problem is to shadow the old variable:
28
29    let expr_ref = parser.parse("x * 10", &mut slab.ps)?.from(&slab.ps);
30
31    let val = expr_ref.eval(&slab, &mut map)?;
32    assert!((val - 25.0).abs() < f64::EPSILON);
33
34    Ok(())
35}
examples/internals.rs (line 9)
4fn main() -> Result<(), fasteval3::Error> {
5    let parser = fasteval3::Parser::new();
6    let mut slab = fasteval3::Slab::new();
7
8    let expr_str = "sin(deg/360 * 2*pi())";
9    let expr_ref = parser.parse(expr_str, &mut slab.ps)?.from(&slab.ps);
10
11    // Let's take a look at the parsed AST inside the Slab:
12    // If you find this structure confusing, take a look at the compilation
13    // AST below because it is simpler.
14    assert_eq!(
15        format!("{:?}", slab.ps),
16        r#"ParseSlab{ exprs:{ 0:Expression { first: EStdFunc(EVar("deg")), pairs: [ExprPair(EDiv, EConstant(360.0)), ExprPair(EMul, EConstant(2.0)), ExprPair(EMul, EStdFunc(EFuncPi))] }, 1:Expression { first: EStdFunc(EFuncSin(ExpressionI(0))), pairs: [] } }, vals:{} }"#
17    );
18    // Pretty-Print:
19    // ParseSlab{
20    //     exprs:{
21    //         0:Expression { first: EStdFunc(EVar("deg")),
22    //                        pairs: [ExprPair(EDiv, EConstant(360.0)),
23    //                                ExprPair(EMul, EConstant(2.0)),
24    //                                ExprPair(EMul, EStdFunc(EFuncPi))]
25    //                      },
26    //         1:Expression { first: EStdFunc(EFuncSin(ExpressionI(0))),
27    //                        pairs: [] }
28    //                      },
29    //     vals:{}
30    // }
31
32    let compiled = expr_ref.compile(&slab.ps, &mut slab.cs, &mut EmptyNamespace);
33
34    // Let's take a look at the compilation results and the AST inside the Slab:
35    // Notice that compilation has performed constant-folding: 1/360 * 2*pi = 0.017453292519943295
36    // In the results below: IFuncSin(...) represents the sin function.
37    //                       InstructionI(1) represents the Instruction stored at index 1.
38    //                       IMul(...) represents the multiplication operator.
39    //                       'C(0.017...)' represents a constant value of 0.017... .
40    //                       IVar("deg") represents a variable named "deg".
41    assert_eq!(format!("{compiled:?}"), "IFuncSin(InstructionI(1))");
42    assert_eq!(
43        format!("{:?}", slab.cs),
44        r#"CompileSlab{ instrs:{ 0:IVar("deg"), 1:IMul(InstructionI(0), C(0.017453292519943295)) } }"#
45    );
46
47    Ok(())
48}
examples/repl.rs (line 110)
54fn repl() {
55    let parser = Parser::new();
56    let mut slab = Slab::new();
57    let mut ns_stack = vec![BTreeMap::new()];
58
59    let stdin = io::stdin();
60    
61    loop {
62        eprint!(">>> ");
63        io::stderr().flush().unwrap();
64
65        let mut ans_key = String::from("_");
66
67        let mut line: String = if let Some(Ok(string)) = stdin.lock().lines().next() {
68            string.trim().to_owned()
69        } else {
70            break
71        };
72
73        if line.is_empty() {
74            continue;
75        }
76
77        let pieces: Vec<&str> = line.split_whitespace().collect();
78        if pieces[0] == "let" {
79            if pieces.len() < 4 || pieces[2] != "=" {
80                eprintln!("incorrect 'let' syntax.  Should be: let x = ...");
81                continue;
82            }
83            ans_key = pieces[1].to_owned();
84            line = pieces[3..].join(" ");
85        } else if pieces[0] == "push" {
86            ns_stack.push(BTreeMap::new());
87            eprintln!("Entered scope[{}]", ns_stack.len() - 1);
88            continue;
89        } else if pieces[0] == "pop" {
90            let mut return_value = std::f64::NAN;
91            let mut has_return_value = false;
92            if let Some(v) = ns_stack.last().unwrap().get(&ans_key) {
93                return_value = *v;
94                has_return_value = true;
95            }
96
97            ns_stack.pop();
98            eprintln!("Exited scope[{}]", ns_stack.len());
99            if ns_stack.is_empty() {
100                ns_stack.push(BTreeMap::new());
101            } // All scopes have been removed.  Add a new one.
102
103            if has_return_value {
104                ns_stack.last_mut().unwrap().insert(ans_key, return_value);
105            }
106
107            continue;
108        }
109
110        let expr_ref = match parser.parse(&line, &mut slab.ps) {
111            Ok(expr_i) => slab.ps.get_expr(expr_i),
112            Err(err) => {
113                eprintln!("parse error: {err}");
114                continue;
115            }
116        };
117
118        let ans = match expr_ref.eval(&slab, &mut ns_stack) {
119            Ok(val) => val,
120            Err(err) => {
121                eprintln!("eval error: {err}");
122                continue;
123            }
124        };
125
126        println!("{ans}");
127        ns_stack.last_mut().unwrap().insert(ans_key, ans);
128    }
129
130    println!();
131}
Source

pub fn parse_noclear( &self, expr_str: &str, slab: &mut ParseSlab, ) -> Result<ExpressionI, Error>

This is exactly the same as parse() but the Slab will NOT be cleared. This is useful in performance-critical sections, when you know that you already have an empty Slab.

This function cannot return Result<&Expression> because it would prolong the mut ref. / That’s why we return an ExpressionI instead.

§Errors

Will return Err if length of expr_str exceeds limit.

Trait Implementations§

Source§

impl Default for Parser

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Parser

§

impl RefUnwindSafe for Parser

§

impl Send for Parser

§

impl Sync for Parser

§

impl Unpin for Parser

§

impl UnwindSafe for Parser

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.