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
//! This crate is specifically used for one thing: turning expressions inside of a string
//! into a value. This crate acts as a scientific calculator, and includes several functions.
//! 
//! If you need a portion of the calculator changed or removed, please fork it, and make your
//! changes. We encourage others to change RSC to their liking. You do not need to attribute
//! anything to us. This is MIT licensed software.
//! 
//! Anyone can easily create a [Calculator](computer/struct.Computer.html) and begin working with expressions. Calculators
//! also remember variables using a HashMap. You can create and begin using the Calculator like so:
//! ```
//! extern crate rsc;
//! 
//! use rsc::computer::Computer;
//!
//! fn main() {
//!     let mut c = Computer::new();
//!
//!     assert!(c.eval("x = 5").unwrap() == 5.0);
//!     assert!(c.eval("x^2").unwrap() == 25.0);
//! }
//! ```
//! 
//! In most cases a simple `eval` should be all you need, but just as many times you may need
//! to directly access the tokens and AST. Some reasons may include:
//! * For performance or caching; lexing and parsing an expression only once, to calculate it later hundreds
//! of times in a loop.
//! * Better error messages or visual information for what is happening.
//! ```
//! extern crate rsc;
//! 
//! use rsc::lexer::tokenize;
//! use rsc::parser::{Expr, parse};
//! use rsc::computer::Computer;
//! 
//! fn main() {
//!     let expr = "x^2";
//!     let tokens = tokenize(expr).unwrap();
//!     let ast = parse(&tokens).unwrap();
//!     let mut computer = Computer::new();
//!     
//!     for x in 2..=5 {
//!         let mut ast = ast.clone();
//!         ast.replace(&Expr::Identifier("x"), &Expr::Constant(x as f64), false);
//!         println!("{}", computer.compute(&ast).unwrap());
//!     }
//! }
//! 
//! // Output:
//! // 4
//! // 9
//! // 16
//! // 25
//! ```

#![feature(test)]

extern crate test;

pub mod lexer;
pub mod parser;
pub mod computer;

#[derive(Debug, Clone)]
pub enum EvalError {
    ComputeError(computer::ComputeError),
    ParserError(parser::ParserError),
    LexerError(lexer::LexerError),
}

/// Turn an expression inside a string into a number.
/// If you are looking for more control, you may want to use
/// the `lexer`, `parser`, and `computer` modules individually.
/// ```
/// assert_eq!(eval("3.1 + 2.2"), Ok(5.3));
/// ```
pub fn eval(input: &str) -> Result<f64, EvalError> {
    match lexer::tokenize(input) {
        Ok(tokens) => match parser::parse(&tokens) {
            Ok(ast) => match computer::Computer::new().compute(&ast) {
                Ok(num) => Ok(num),
                Err(compute_err) => Err(EvalError::ComputeError(compute_err)),
            }
            Err(parser_err) => Err(EvalError::ParserError(parser_err)),
        }
        Err(lexer_err) => Err(EvalError::LexerError(lexer_err)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use self::test::Bencher;

    static INPUT: &'static str = "sqrt((6.1--2.22)^2 + (-24-10.5)^2)";

    #[bench]
    fn bench_eval(b: &mut Bencher) {
        b.iter(|| eval(INPUT).unwrap());
    }

    #[bench]
    fn bench_tokenize(b: &mut Bencher) {
        b.iter(|| lexer::tokenize(INPUT).unwrap());
    }

    #[bench]
    fn bench_parse(b: &mut Bencher) {
        let tokens = lexer::tokenize(INPUT).unwrap();
        b.iter(|| parser::parse(&tokens).unwrap());
    }

    #[bench]
    fn bench_compute(b: &mut Bencher) {
        let ast = parser::parse(&lexer::tokenize(INPUT).unwrap()).unwrap();
        let mut computer = computer::Computer::new();
        b.iter(|| computer.compute(&ast));
    }
}