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));
}
}