File: from_3rd.rs

package info (click to toggle)
rust-fasteval 0.2.4-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 952 kB
  • sloc: python: 14; makefile: 8
file content (125 lines) | stat: -rw-r--r-- 5,586 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use fasteval::{Parser, Compiler, Evaler, Error, Slab, CachedCallbackNamespace, eval_compiled_ref};

use std::str::from_utf8;

fn evalns_cb(name:&str, args:Vec<f64>) -> Option<f64> {
    match name {
        "w" => Some(0.0),
        "x" => Some(1.0),
        "y" => Some(2.0),
        "y7" => Some(2.7),
        "z" => Some(3.0),
        "foo" => Some(args[0]*10.0),
        "bar" => Some(args[0]+args[1]),
        _ => None,
    }
}

fn chk_ok(expr_str:&str, expect_compile_str:&str, expect_slab_str:&str, expect_eval:f64) {
    let mut slab = Slab::new();
    let expr = Parser::new().parse(expr_str, &mut slab.ps).unwrap().from(&slab.ps);
    let instr = expr.compile(&slab.ps, &mut slab.cs);

    assert_eq!(format!("{:?}",instr), expect_compile_str);
    assert_eq!(format!("{:?}",slab), expect_slab_str);

    (|| -> Result<(),Error> {
        let mut ns = CachedCallbackNamespace::new(evalns_cb);
        assert_eq!(eval_compiled_ref!(&instr, &slab, &mut ns), expect_eval);

        // Make sure Instruction eval matches normal eval:
        assert_eq!(eval_compiled_ref!(&instr, &slab, &mut ns), expr.eval(&slab, &mut ns).unwrap());

        Ok(())
    })().unwrap();
}

fn chk_perr(expr_str:&str, expect_err:Error) {
    let mut slab = Slab::new();
    let res = Parser::new().parse(expr_str, &mut slab.ps);
    assert_eq!(res, Err(expect_err));
}

fn chk_eerr(expr_str:&str, expect_err:Error) {
    let mut slab = Slab::new();
    let expr = Parser::new().parse(expr_str, &mut slab.ps).unwrap().from(&slab.ps);
    let instr = expr.compile(&slab.ps, &mut slab.cs);
    let mut ns = CachedCallbackNamespace::new(evalns_cb);
    assert_eq!(instr.eval(&slab, &mut ns), Err(expect_err));
}

#[test]
fn meval() {
    chk_perr("", Error::EofWhileParsing("value".to_string()));
    chk_perr("(", Error::EofWhileParsing("value".to_string()));
    chk_perr("0(", Error::UnparsedTokensRemaining("(".to_string()));
    chk_eerr("e", Error::Undefined("e".to_string()));
    chk_perr("1E", Error::ParseF64("1E".to_string()));
    chk_perr("1e+", Error::ParseF64("1e+".to_string()));
    chk_perr("()", Error::InvalidValue);
    chk_perr("2)", Error::UnparsedTokensRemaining(")".to_string()));
    chk_perr("2^", Error::EofWhileParsing("value".to_string()));
    chk_perr("(((2)", Error::EofWhileParsing("parentheses".to_string()));
    chk_perr("f(2,)", Error::InvalidValue);
    chk_perr("f(,2)", Error::InvalidValue);

    chk_ok("round(sin (pi()) * cos(0))",
"IConst(0.0)",
"Slab{ exprs:{ 0:Expression { first: EStdFunc(EFuncPi), pairs: [] }, 1:Expression { first: EConstant(0.0), pairs: [] }, 2:Expression { first: EStdFunc(EFuncSin(ExpressionI(0))), pairs: [ExprPair(EMul, EStdFunc(EFuncCos(ExpressionI(1))))] }, 3:Expression { first: EStdFunc(EFuncRound { modulus: None, expr: ExpressionI(2) }), pairs: [] } }, vals:{}, instrs:{} }",
0.0);

    chk_ok("max(1.)",
"IConst(1.0)",
"Slab{ exprs:{ 0:Expression { first: EConstant(1.0), pairs: [] }, 1:Expression { first: EStdFunc(EFuncMax { first: ExpressionI(0), rest: [] }), pairs: [] } }, vals:{}, instrs:{} }",
1.0);

    chk_ok("max(1., 2., -1)",
"IConst(2.0)",
"Slab{ exprs:{ 0:Expression { first: EConstant(1.0), pairs: [] }, 1:Expression { first: EConstant(2.0), pairs: [] }, 2:Expression { first: EConstant(-1.0), pairs: [] }, 3:Expression { first: EStdFunc(EFuncMax { first: ExpressionI(0), rest: [ExpressionI(1), ExpressionI(2)] }), pairs: [] } }, vals:{}, instrs:{} }",
2.0);

    chk_ok("sin(1.) + cos(2.)",
"IConst(0.4253241482607541)",
"Slab{ exprs:{ 0:Expression { first: EConstant(1.0), pairs: [] }, 1:Expression { first: EConstant(2.0), pairs: [] }, 2:Expression { first: EStdFunc(EFuncSin(ExpressionI(0))), pairs: [ExprPair(EAdd, EStdFunc(EFuncCos(ExpressionI(1))))] } }, vals:{}, instrs:{} }",
(1f64).sin() + (2f64).cos());





}

#[test]
fn overflow_stack() {
    chk_perr(from_utf8(&[b'('; 1]).unwrap(), Error::EofWhileParsing("value".to_string()));
    chk_perr(from_utf8(&[b'('; 2]).unwrap(), Error::EofWhileParsing("value".to_string()));
    chk_perr(from_utf8(&[b'('; 4]).unwrap(), Error::EofWhileParsing("value".to_string()));
    chk_perr(from_utf8(&[b'('; 8]).unwrap(), Error::EofWhileParsing("value".to_string()));
    chk_perr(from_utf8(&[b'('; 16]).unwrap(), Error::EofWhileParsing("value".to_string()));
    chk_perr(from_utf8(&[b'('; 32]).unwrap(), Error::EofWhileParsing("value".to_string()));
    chk_perr(from_utf8(&[b'('; 33]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 64]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 128]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 256]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 512]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 1024]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 2048]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 4096]).unwrap(), Error::TooDeep);
    chk_perr(from_utf8(&[b'('; 8192]).unwrap(), Error::TooLong);

    // Test custom safety parse limits:
    assert_eq!(Parser{expr_len_limit:fasteval::parser::DEFAULT_EXPR_LEN_LIMIT,
                      expr_depth_limit:31}.parse(
                        from_utf8(&[b'('; 32]).unwrap(),
                        &mut Slab::new().ps
                      ),
               Err(Error::TooDeep));

    assert_eq!(Parser{expr_len_limit:8,
                      expr_depth_limit:fasteval::parser::DEFAULT_EXPR_DEPTH_LIMIT}.parse(
                        from_utf8(&[b'('; 32]).unwrap(),
                        &mut Slab::new().ps
                      ),
               Err(Error::TooLong));
}