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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
//! This [Rust] crate provides a simple math expression parsing and evaluation. Its main goal is to //! be convenient to use, while allowing for some flexibility. Currently works only with `f64` //! types. //! //! ## Simple examples //! //! ```rust //! extern crate meval; //! //! fn main() { //! let r = meval::eval_str("1 + 2").unwrap(); //! //! println!("1 + 2 = {}", r); //! } //! ``` //! //! Need to define a Rust function from an expression? No problem, use [`Expr`](struct.Expr.html) //! for this and more: //! //! ```rust //! extern crate meval; //! //! fn main() { //! let expr = meval::Expr::from_str("sin(pi * x)").unwrap(); //! let func = expr.bind("x").unwrap(); //! //! let vs: Vec<_> = (0..100+1).map(|i| func(i as f64 / 100.)).collect(); //! //! println!("sin(pi * x), 0 <= x <= 1: {:?}", vs); //! } //! ``` //! //! [`Expr::bind`](struct.Expr.html#method.bind) returns a boxed closure that is slightly less //! convenient than an unboxed closure since `Box<Fn(f64) -> f64>` does not implement `FnOnce`, //! `Fn` or `FnMut`. So to use it directly as a function argument where a closure is expected, it //! has to be manually dereferenced: //! //! ```rust //! let func = meval::Expr::from_str("x").unwrap().bind("x").unwrap(); //! let r = Some(2.).map(&*func); //! ``` //! //! Custom constants and functions? Define a context! //! //! ```rust //! let y = 1.; //! let expr = meval::Expr::from_str("phi(-2 * zeta + x)").unwrap(); //! //! // create a context with function definitions and variables //! let ctx = (meval::CustomFunc("phi", |x| x + y), ("zeta", -1.)); //! // bind function with builtins as well as custom context //! let func = expr.bind_with_context((meval::builtin(), ctx), "x").unwrap(); //! assert_eq!(func(2.), -2. * -1. + 2. + 1.); //! ``` //! //! For functions with 2, 3, and N variables use `CustomFunc2`, `CustomFunc3` and `CustomFuncN` //! respectively. //! //! If you need a custom function depending on mutable parameters, you will need to use a //! [`Cell`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html): //! //! ```rust //! use std::cell::Cell; //! let y = Cell::new(0.); //! let expr = meval::Expr::from_str("phi(x)").unwrap(); //! //! let ctx = meval::CustomFunc("phi", |x| x + y.get()); //! let func = expr.bind_with_context(ctx, "x").unwrap(); //! assert_eq!(func(2.), 2.); //! y.set(3.); //! assert_eq!(func(2.), 5.); //! ``` //! //! ## Supported expressions //! //! `meval` supports basic mathematical operations on floating point numbers: //! //! - binary operators: `+`, `-`, `*`, `/`, `^` (power) //! - unary operators: `+`, `-` //! //! It supports custom variables like `x`, `weight`, `C_0`, etc. A variable must start with //! `[a-zA-Z_]` and can contain only `[a-zA-Z0-9_]`. //! //! Build-ins (given by context `meval::builtin()`) currently supported: //! //! - functions implemented using functions of the same name in [Rust std library][std-float]: //! //! - `sqrt`, `abs` //! - `exp`, `ln` //! - `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2` //! - `sinh`, `cosh`, `tanh`, `asinh`, `acosh`, `atanh` //! - `floor`, `ceil`, `round` //! - `signum` //! //! - other functions: //! //! - `max(x, ...)`, `min(x, ...)`: maximum and minimumum of 1 or more numbers //! //! - constants: //! //! - `pi` //! - `e` //! //! ## Related projects //! //! This is a toy project of mine for learning Rust, and to be hopefully useful when writing //! command line scripts. For other similar projects see: //! //! - [rodolf0/tox](https://github.com/rodolf0/tox) //! //! [Rust]: https://www.rust-lang.org/ //! [std-float]: http://doc.rust-lang.org/stable/std/primitive.f64.html #[macro_use] extern crate nom; use std::fmt; pub mod tokenizer; pub mod shunting_yard; mod expr; pub use expr::*; pub use shunting_yard::RPNError; pub use tokenizer::ParseError; /// An error produced during parsing or evaluation. #[derive(Debug, Clone, PartialEq)] pub enum Error { UnknownVariable(String), Function(String, FuncEvalError), /// An error returned by the parser. ParseError(ParseError), /// The shunting-yard algorithm returned an error. RPNError(RPNError), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::UnknownVariable(ref name) => write!(f, "Evaluation error: unknown variable `{}`", name), Error::Function(ref name, ref e) => write!(f, "Evaluation error: function `{}`: {}", name, e), Error::ParseError(ref e) => write!(f, "Parse error: {:?}", e), Error::RPNError(ref e) => write!(f, "RPN error: {:?}", e), } } } impl From<ParseError> for Error { fn from(err: ParseError) -> Error { Error::ParseError(err) } } impl From<RPNError> for Error { fn from(err: RPNError) -> Error { Error::RPNError(err) } }