add Expr builder. add ExecOptions. add len()

This commit is contained in:
fengcen 2016-11-20 16:04:06 +08:00
parent 1c7cd61b59
commit 032e57df43
6 changed files with 406 additions and 236 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "eval" name = "eval"
version = "0.1.1" version = "0.2.0"
description = "Expression evaluator" description = "Expression evaluator"
keywords = ["expression", "evaluate", "evaluator", "expr", "template"] keywords = ["expression", "evaluate", "evaluator", "expr", "template"]
authors = ["fengcen <fengcen.love@gmail.com>"] authors = ["fengcen <fengcen.love@gmail.com>"]
@ -15,5 +15,6 @@ name = "eval"
path = "src/lib.rs" path = "src/lib.rs"
[dependencies] [dependencies]
serde = "^0.8"
serde_json = "^0.8" serde_json = "^0.8"
quick-error = "^1.1" quick-error = "^1.1"

View File

@ -1,7 +1,7 @@
eval eval
=== ===
[![docs](https://docs.rs/eval/badge.svg?version=0.1.1 "docs")](https://docs.rs/eval) [![docs](https://docs.rs/eval/badge.svg?version=0.2.0 "docs")](https://docs.rs/eval)
Eval is a powerful expression evaluator. Eval is a powerful expression evaluator.
@ -11,7 +11,7 @@ Eval is a powerful expression evaluator.
Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=` `==` Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=` `==`
`+` `-` `*` `/` `%` `&&` `||` `n..m`. `+` `-` `*` `/` `%` `&&` `||` `n..m`.
Built-in functions: `min()` `max()` `is_empty()`. Built-in functions: `min()` `max()` `len()` `is_empty()`.
## Where can eval be used? ## Where can eval be used?
* Template engine * Template engine
@ -22,7 +22,7 @@ Add dependency to Cargo.toml
```toml ```toml
[dependencies] [dependencies]
eval = "^0.1" eval = "^0.2"
``` ```
In your `main.rs` or `lib.rs`: In your `main.rs` or `lib.rs`:
@ -47,22 +47,24 @@ assert_eq!(eval("2 / 2 + 3 / 3"), Ok(to_value(2.0)));
You can eval with context: You can eval with context:
``` ```
use eval::{eval_with_context, Context, to_value}; use eval::{Expr, to_value};
let mut context = Context::new(); assert_eq!(Expr::new("foo == bar")
context.insert("foo".to_owned(), to_value(true)); .value("foo", true)
context.insert("bar".to_owned(), to_value(true)); .value("bar", true)
assert_eq!(eval_with_context("foo == bar", &context), Ok(to_value(true))); .exec(),
Ok(to_value(true)));
``` ```
You can eval with functions: You can eval with function:
``` ```
use eval::{eval_with_functions, Functions, Function, to_value}; use eval::{Expr, to_value};
let mut functions = Functions::new(); assert_eq!(Expr::new("say_hello()")
functions.insert("say_hello".to_owned(), Function::new(|_| Ok(to_value("Hello world!")))); .function("say_hello", |_| Ok(to_value("Hello world!")))
assert_eq!(eval_with_functions("say_hello()", &functions), Ok(to_value("Hello world!"))); .exec(),
Ok(to_value("Hello world!")));
``` ```
You can create an array with `[]`: You can create an array with `[]`:
@ -71,7 +73,6 @@ You can create an array with `[]`:
use eval::{eval, to_value}; use eval::{eval, to_value};
assert_eq!(eval("[1, 2, 3, 4, 5]"), Ok(to_value(vec![1, 2, 3, 4, 5]))); assert_eq!(eval("[1, 2, 3, 4, 5]"), Ok(to_value(vec![1, 2, 3, 4, 5])));
``` ```
You can create an integer array with `n..m`: You can create an integer array with `n..m`:
@ -80,7 +81,6 @@ You can create an integer array with `n..m`:
use eval::{eval, to_value}; use eval::{eval, to_value};
assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4]))); assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
``` ```
## License ## License

View File

@ -11,6 +11,7 @@ impl BuiltIn {
let mut functions = Functions::new(); let mut functions = Functions::new();
functions.insert("min".to_owned(), create_min_fuction()); functions.insert("min".to_owned(), create_min_fuction());
functions.insert("max".to_owned(), create_max_fuction()); functions.insert("max".to_owned(), create_max_fuction());
functions.insert("len".to_owned(), create_len_fuction());
functions.insert("is_empty".to_owned(), create_is_empty_fuction()); functions.insert("is_empty".to_owned(), create_is_empty_fuction());
functions.insert("array".to_owned(), create_array_function()); functions.insert("array".to_owned(), create_array_function());
functions functions
@ -48,10 +49,8 @@ fn compare(compare: Compare) -> Function {
if value.lt(prev.as_ref().unwrap())? == to_value(true) { if value.lt(prev.as_ref().unwrap())? == to_value(true) {
prev = Ok(value) prev = Ok(value)
} }
} else { } else if value.gt(prev.as_ref().unwrap())? == to_value(true) {
if value.gt(prev.as_ref().unwrap())? == to_value(true) { prev = Ok(value)
prev = Ok(value)
}
} }
} else { } else {
prev = Ok(value); prev = Ok(value);
@ -64,10 +63,8 @@ fn compare(compare: Compare) -> Function {
if value.lt(prev.as_ref().unwrap())? == to_value(true) { if value.lt(prev.as_ref().unwrap())? == to_value(true) {
prev = Ok(value) prev = Ok(value)
} }
} else { } else if value.gt(prev.as_ref().unwrap())? == to_value(true) {
if value.gt(prev.as_ref().unwrap())? == to_value(true) { prev = Ok(value)
prev = Ok(value)
}
} }
} else { } else {
prev = Ok(value); prev = Ok(value);
@ -87,11 +84,32 @@ fn create_is_empty_fuction() -> Function {
min_args: Some(1), min_args: Some(1),
compiled: Box::new(|values| { compiled: Box::new(|values| {
match *values.first().unwrap() { match *values.first().unwrap() {
Value::String(ref string) => Ok(Value::Bool(string.is_empty())), Value::String(ref string) => Ok(to_value(string.is_empty())),
Value::Array(ref array) => Ok(Value::Bool(array.is_empty())), Value::Array(ref array) => Ok(to_value(array.is_empty())),
Value::Object(ref object) => Ok(Value::Bool(object.is_empty())), Value::Object(ref object) => Ok(to_value(object.is_empty())),
Value::Null => Ok(Value::Bool(true)), Value::Null => Ok(to_value(true)),
_ => Ok(Value::Bool(false)), _ => Ok(to_value(false)),
}
}),
}
}
fn create_len_fuction() -> Function {
Function {
max_args: Some(1),
min_args: Some(1),
compiled: Box::new(|values| {
let value = values.first().unwrap();
match *value {
Value::String(ref string) => Ok(to_value(string.len())),
Value::Array(ref array) => Ok(to_value(array.len())),
Value::Object(ref object) => Ok(to_value(object.len())),
Value::Null => Ok(to_value(0)),
_ => {
Err(Error::Custom(format!("len() only accept string, array, object and \
null. But the given is: {:?}",
value)))
}
} }
}), }),
} }

152
src/expr/mod.rs Normal file
View File

@ -0,0 +1,152 @@
use {Function, Functions, Context, Contexts, Compiled, Value};
use tree::Tree;
use error::Error;
use serde::Serialize;
use to_value;
use std::fmt;
/// Expression builder
pub struct Expr {
expression: String,
compiled: Option<Compiled>,
functions: Functions,
contexts: Contexts,
}
impl Expr {
/// Create an expression.
pub fn new<T: Into<String>>(expr: T) -> Expr {
Expr {
expression: expr.into(),
compiled: None,
functions: Functions::new(),
contexts: create_empty_contexts(),
}
}
/// Set function.
pub fn function<T, F>(mut self, name: T, function: F) -> Expr
where T: Into<String>,
F: 'static + Fn(Vec<Value>) -> Result<Value, Error> + Sync + Send
{
self.functions.insert(name.into(), Function::new(function));
self
}
/// Set value.
pub fn value<T, V>(mut self, name: T, value: V) -> Expr
where T: Into<String>,
V: Serialize
{
self.contexts.last_mut().unwrap().insert(name.into(), to_value(value));
self
}
/// Compile an expression.
/// An expression can be compiled only once and then invoked multiple times with different context and function.
/// You can also execute a expression without compile.
pub fn compile(mut self) -> Result<Expr, Error> {
self.compiled = Some(Tree::new(self.expression.clone()).compile()?);
Ok(self)
}
/// Execute the expression.
pub fn exec(&self) -> Result<Value, Error> {
if self.compiled.is_none() {
Tree::new(self.expression.clone()).compile()?(&self.contexts, &self.functions)
} else {
self.compiled.as_ref().unwrap()(&self.contexts, &self.functions)
}
}
fn get_compiled(&self) -> Option<&Compiled> {
self.compiled.as_ref()
}
}
impl Clone for Expr {
/// Returns a copy of the value. Notice that functions can not be cloned. The cloned expr's functions will be empty.
fn clone(&self) -> Expr {
Expr {
expression: self.expression.clone(),
compiled: if self.compiled.is_some() {
Some(Tree::new(self.expression.clone()).compile().unwrap())
} else {
None
},
contexts: self.contexts.clone(),
functions: Functions::new(),
}
}
}
impl fmt::Debug for Expr {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(formatter, "{:?}", self.expression)
}
}
/// Execute options
pub struct ExecOptions<'a> {
expr: &'a Expr,
contexts: Option<&'a [Context]>,
functions: Option<&'a Functions>,
}
impl<'a> ExecOptions<'a> {
/// Create an option.
pub fn new(expr: &'a Expr) -> ExecOptions<'a> {
ExecOptions {
expr: expr,
contexts: None,
functions: None,
}
}
/// Set contexts.
pub fn contexts(&mut self, contexts: &'a [Context]) -> &'a mut ExecOptions {
self.contexts = Some(contexts);
self
}
/// Set functions.
pub fn functions(&mut self, functions: &'a Functions) -> &'a mut ExecOptions {
self.functions = Some(functions);
self
}
/// Execute the compiled expression.
pub fn exec(&self) -> Result<Value, Error> {
let empty_contexts = create_empty_contexts();
let empty_functions = Functions::new();
let contexts = if self.contexts.is_some() {
self.contexts.unwrap()
} else {
&empty_contexts
};
let functions = if self.functions.is_some() {
self.functions.unwrap()
} else {
&empty_functions
};
let compiled = self.expr.get_compiled();
if compiled.is_none() {
Tree::new(self.expr.expression.clone()).compile()?(contexts, functions)
} else {
compiled.unwrap()(contexts, functions)
}
}
}
fn create_empty_contexts() -> Contexts {
let mut contexts = Contexts::new();
contexts.push(Context::new());
contexts
}

View File

@ -3,9 +3,9 @@
//! Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=` //! Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=`
//! `==` `+` `-` `*` `/` `%` `&&` `||` `n..m`. //! `==` `+` `-` `*` `/` `%` `&&` `||` `n..m`.
//! //!
//! Built-in functions: `min()` `max()` `is_empty()`. //! Built-in functions: `min()` `max()` `len()` `is_empty()`.
//! //!
//! # Examples //! ## Examples
//! //!
//! You can do mathematical calculations with supported operators: //! You can do mathematical calculations with supported operators:
//! //!
@ -21,22 +21,24 @@
//! You can eval with context: //! You can eval with context:
//! //!
//! ``` //! ```
//! use eval::{eval_with_context, Context, to_value}; //! use eval::{Expr, to_value};
//! //!
//! let mut context = Context::new(); //! assert_eq!(Expr::new("foo == bar")
//! context.insert("foo".to_owned(), to_value(true)); //! .value("foo", true)
//! context.insert("bar".to_owned(), to_value(true)); //! .value("bar", true)
//! assert_eq!(eval_with_context("foo == bar", &context), Ok(to_value(true))); //! .exec(),
//! Ok(to_value(true)));
//! ``` //! ```
//! //!
//! You can eval with functions: //! You can eval with function:
//! //!
//! ``` //! ```
//! use eval::{eval_with_functions, Functions, Function, to_value}; //! use eval::{Expr, to_value};
//! //!
//! let mut functions = Functions::new(); //! assert_eq!(Expr::new("say_hello()")
//! functions.insert("say_hello".to_owned(), Function::new(|_| Ok(to_value("Hello world!")))); //! .function("say_hello", |_| Ok(to_value("Hello world!")))
//! assert_eq!(eval_with_functions("say_hello()", &functions), Ok(to_value("Hello world!"))); //! .exec(),
//! Ok(to_value("Hello world!")));
//! ``` //! ```
//! //!
//! You can create an array with `[]`: //! You can create an array with `[]`:
@ -45,7 +47,6 @@
//! use eval::{eval, to_value}; //! use eval::{eval, to_value};
//! //!
//! assert_eq!(eval("[1, 2, 3, 4, 5]"), Ok(to_value(vec![1, 2, 3, 4, 5]))); //! assert_eq!(eval("[1, 2, 3, 4, 5]"), Ok(to_value(vec![1, 2, 3, 4, 5])));
//!
//! ``` //! ```
//! //!
//! You can create an integer array with `n..m`: //! You can create an integer array with `n..m`:
@ -54,9 +55,23 @@
//! use eval::{eval, to_value}; //! use eval::{eval, to_value};
//! //!
//! assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4]))); //! assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
//!
//! ``` //! ```
//! //!
//! ## Built-in functions
//!
//! ### min()
//! Accept multiple arguments and return the minimum value.
//!
//! ### max()
//! Accept multiple arguments and return the maximum value.
//!
//! ### len()
//! Accept single arguments and return the length of value. Only accept String, Array, Object and Null.
//!
//! ### is_empty()
//! Accept single arguments and return the a boolean. Check whether the value is empty or not.
//!
//!
#![recursion_limit="100"] #![recursion_limit="100"]
#![deny(missing_docs)] #![deny(missing_docs)]
#![feature(proc_macro, test)] #![feature(proc_macro, test)]
@ -64,89 +79,51 @@ extern crate test;
#[macro_use] #[macro_use]
extern crate quick_error; extern crate quick_error;
extern crate serde;
extern crate serde_json; extern crate serde_json;
mod math; mod math;
mod function; mod function;
mod operator; mod operator;
mod node; mod node;
mod expression; mod tree;
mod error; mod error;
mod builtin; mod builtin;
mod expr;
pub use expr::ExecOptions;
pub use serde_json::{Value, to_value}; pub use serde_json::{Value, to_value};
pub use error::Error; pub use error::Error;
pub use function::Function; pub use function::Function;
pub use expr::Expr;
use std::collections::HashMap; use std::collections::HashMap;
use expression::Expression;
use builtin::BuiltIn;
type ContextsRef<'a> = &'a [Context]; /// Custom context.
/// Eval context.
pub type Context = HashMap<String, Value>; pub type Context = HashMap<String, Value>;
/// Eval contexts. The value of the last context is searched first. /// Custom contexts. The value of the last context is searched first.
pub type Contexts = Vec<Context>; pub type Contexts = Vec<Context>;
/// Eval functions. /// Custom functions.
pub type Functions = HashMap<String, Function>; pub type Functions = HashMap<String, Function>;
/// Evaluates the value of an expression. /// Evaluates the value of an expression.
pub fn eval(expr: &str) -> Result<Value, Error> { pub fn eval(expr: &str) -> Result<Value, Error> {
Expression::new(expr)?.compile()(&Contexts::new(), &BuiltIn::new(), &Functions::new()) Expr::new(expr).compile()?.exec()
} }
/// Evaluates the value of an expression with the given context.
pub fn eval_with_context(expr: &str, context: &Context) -> Result<Value, Error> {
let mut contexts = Contexts::new();
contexts.push(context.clone());
eval_with_contexts(expr, &contexts)
}
/// Evaluates the value of an expression with the given contexts.<br> type Compiled = Box<Fn(&[Context], &Functions) -> Result<Value, Error>>;
/// The value of the last context is searched first.
pub fn eval_with_contexts(expr: &str, contexts: ContextsRef) -> Result<Value, Error> {
Expression::new(expr)?.compile()(contexts, &BuiltIn::new(), &Functions::new())
}
/// Evaluates the value of an expression with the given functions.
pub fn eval_with_functions(expr: &str, functions: &Functions) -> Result<Value, Error> {
Expression::new(expr)?.compile()(&Contexts::new(), &BuiltIn::new(), functions)
}
/// Evaluates the value of an expression with the given context and functions.
pub fn eval_with_context_and_functions(expr: &str,
context: &Context,
functions: &Functions)
-> Result<Value, Error> {
let mut contexts = Contexts::new();
contexts.push(context.clone());
eval_with_contexts_and_functions(expr, &contexts, functions)
}
/// Evaluates the value of an expression with the given contexts and functions.<br>
/// The value of the last context is searched first.
pub fn eval_with_contexts_and_functions(expr: &str,
contexts: ContextsRef,
functions: &Functions)
-> Result<Value, Error> {
Expression::new(expr)?.compile()(contexts, &BuiltIn::new(), functions)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use test; use test;
use serde_json::to_value; use serde_json::to_value;
use expression::Expression;
use error::Error; use error::Error;
use Context; use Expr;
use tree::Tree;
use eval; use eval;
use eval_with_context; use std::collections::HashMap;
use eval_with_functions;
use {Function, Functions};
#[test] #[test]
fn test_add() { fn test_add() {
@ -225,6 +202,28 @@ mod tests {
assert_eq!(eval("max(30, 5, 245, 20) * 10"), Ok(to_value(2450))); assert_eq!(eval("max(30, 5, 245, 20) * 10"), Ok(to_value(2450)));
} }
#[test]
fn test_len_array() {
assert_eq!(eval("len([2, 3, 4, 5, 6])"), Ok(to_value(5)));
}
#[test]
fn test_len_string() {
assert_eq!(eval("len('Hello world!')"), Ok(to_value(12)));
}
#[test]
fn test_len_object() {
let mut object = HashMap::new();
object.insert("field1", "value1");
object.insert("field2", "value2");
object.insert("field3", "value3");
assert_eq!(Expr::new("len(object)")
.value("object", object)
.exec(),
Ok(to_value(3)));
}
#[test] #[test]
fn test_brackets_1() { fn test_brackets_1() {
assert_eq!(eval("(5) + (min(3, 4, 5)) + 20"), Ok(to_value(28))); assert_eq!(eval("(5) + (min(3, 4, 5)) + 20"), Ok(to_value(28)));
@ -405,81 +404,83 @@ mod tests {
} }
#[test] #[test]
fn test_buildin_is_empty() { fn test_builtin_is_empty() {
let mut context = Context::new(); assert_eq!(Expr::new("is_empty(array)")
context.insert("array".to_owned(), to_value(Vec::<String>::new())); .value("array", Vec::<String>::new())
assert_eq!(eval_with_context("is_empty(array)", &context), .compile()
.unwrap()
.exec(),
Ok(to_value(true))); Ok(to_value(true)));
} }
#[test] #[test]
fn test_buildin_min() { fn test_builtin_min() {
let mut context = Context::new(); assert_eq!(Expr::new("min(array)")
context.insert("array".to_owned(), to_value(vec![23, 34, 45, 2])); .value("array", vec![23, 34, 45, 2])
assert_eq!(eval_with_context("min(array)", &context), Ok(to_value(2))); .compile()
.unwrap()
.exec(),
Ok(to_value(2)));
} }
#[test] #[test]
fn test_custom_function() { fn test_custom_function() {
let mut functions = Functions::new(); assert_eq!(Expr::new("output()")
functions.insert("output".to_owned(), .function("output",
Function::new(|_| Ok(to_value("This is custom function's output")))); |_| Ok(to_value("This is custom function's output")))
assert_eq!(eval_with_functions("output()", &functions), .compile()
.unwrap()
.exec(),
Ok(to_value("This is custom function's output"))); Ok(to_value("This is custom function's output")));
} }
#[test] #[test]
fn test_error_start_with_non_value_operator() { fn test_error_start_with_non_value_operator() {
let mut expr = Expression { let mut tree = Tree { raw: "+ + 5".to_owned(), ..Default::default() };
raw: "+ + 5".to_owned(),
pos: Vec::new(),
operators: Vec::new(),
node: None,
};
expr.parse_pos().unwrap(); tree.parse_pos().unwrap();
expr.parse_operators().unwrap(); tree.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::StartWithNonValueOperator)); assert_eq!(tree.parse_node(), Err(Error::StartWithNonValueOperator));
} }
#[test] #[test]
fn test_error_duplicate_operator() { fn test_error_duplicate_operator() {
let mut expr = Expression { raw: "5 + + 5".to_owned(), ..Default::default() }; let mut tree = Tree { raw: "5 + + 5".to_owned(), ..Default::default() };
expr.parse_pos().unwrap(); tree.parse_pos().unwrap();
expr.parse_operators().unwrap(); tree.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::DuplicateOperatorNode)); assert_eq!(tree.parse_node(), Err(Error::DuplicateOperatorNode));
} }
#[test] #[test]
fn test_error_duplicate_value() { fn test_error_duplicate_value() {
let mut expr = Expression { raw: "2 + 6 5".to_owned(), ..Default::default() }; let mut tree = Tree { raw: "2 + 6 5".to_owned(), ..Default::default() };
expr.parse_pos().unwrap(); tree.parse_pos().unwrap();
expr.parse_operators().unwrap(); tree.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::DuplicateValueNode)); assert_eq!(tree.parse_node(), Err(Error::DuplicateValueNode));
} }
#[test] #[test]
fn test_error_unpaired_brackets() { fn test_error_unpaired_brackets() {
let mut expr = Expression { raw: "(2 + 3)) * 5".to_owned(), ..Default::default() }; let mut tree = Tree { raw: "(2 + 3)) * 5".to_owned(), ..Default::default() };
expr.parse_pos().unwrap(); tree.parse_pos().unwrap();
assert_eq!(expr.parse_operators(), Err(Error::UnpairedBrackets)); assert_eq!(tree.parse_operators(), Err(Error::UnpairedBrackets));
} }
#[test] #[test]
fn test_error_comma() { fn test_error_comma() {
let mut expr = Expression { raw: ", 2 + 5".to_owned(), ..Default::default() }; let mut tree = Tree { raw: ", 2 + 5".to_owned(), ..Default::default() };
expr.parse_pos().unwrap(); tree.parse_pos().unwrap();
expr.parse_operators().unwrap(); tree.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::CommaNotWithFunction)); assert_eq!(tree.parse_node(), Err(Error::CommaNotWithFunction));
} }
@ -490,48 +491,47 @@ mod tests {
#[bench] #[bench]
fn bench_parse_pos(b: &mut test::Bencher) { fn bench_parse_pos(b: &mut test::Bencher) {
let mut expr = Expression { let mut tree =
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
..Default::default()
};
b.iter(|| expr.parse_pos().unwrap()); b.iter(|| tree.parse_pos().unwrap());
} }
#[bench] #[bench]
fn bench_parse_operators(b: &mut test::Bencher) { fn bench_parse_operators(b: &mut test::Bencher) {
let mut expr = Expression { let mut tree =
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
..Default::default()
};
expr.parse_pos().unwrap(); tree.parse_pos().unwrap();
b.iter(|| expr.parse_operators().unwrap()); b.iter(|| tree.parse_operators().unwrap());
} }
#[bench] #[bench]
fn bench_parse_nodes(b: &mut test::Bencher) { fn bench_parse_nodes(b: &mut test::Bencher) {
let mut expr = Expression { let mut tree =
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
..Default::default()
};
expr.parse_pos().unwrap(); tree.parse_pos().unwrap();
expr.parse_operators().unwrap(); tree.parse_operators().unwrap();
b.iter(|| expr.parse_node().unwrap()); b.iter(|| tree.parse_node().unwrap());
} }
#[bench] #[bench]
fn bench_compile(b: &mut test::Bencher) { fn bench_compile(b: &mut test::Bencher) {
let mut expr = Expression { b.iter(|| {
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), let mut tree =
..Default::default() Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
}; tree.parse_pos().unwrap();
tree.parse_operators().unwrap();
tree.parse_node().unwrap();
tree.compile().unwrap();
});
}
expr.parse_pos().unwrap(); #[bench]
expr.parse_operators().unwrap(); fn bench_exec(b: &mut test::Bencher) {
expr.parse_node().unwrap(); let expr = Expr::new("(2 + (3 + 4) + (6 + (6 + 7)) + 5)").compile().unwrap();
b.iter(|| expr.compile()); b.iter(|| expr.exec().unwrap())
} }
#[bench] #[bench]

View File

@ -7,49 +7,48 @@ use operator::Operator;
use node::Node; use node::Node;
use {Context, Functions}; use {Context, Functions};
use error::Error; use error::Error;
use ContextsRef; use Compiled;
use builtin::BuiltIn;
#[derive(Default)] #[derive(Default)]
pub struct Expression { pub struct Tree {
pub raw: String, pub raw: String,
pub pos: Vec<usize>, pub pos: Vec<usize>,
pub operators: Vec<Operator>, pub operators: Vec<Operator>,
pub node: Option<Node>, pub node: Option<Node>,
} }
impl Expression { impl Tree {
pub fn new<T: Into<String>>(raw: T) -> Result<Expression, Error> { pub fn new<T: Into<String>>(raw: T) -> Tree {
let mut expr = Expression { raw: raw.into(), ..Default::default() }; Tree { raw: raw.into(), ..Default::default() }
expr.parse_pos()?;
expr.parse_operators()?;
expr.parse_node()?;
Ok(expr)
} }
pub fn parse_pos(&mut self) -> Result<(), Error> { pub fn parse_pos(&mut self) -> Result<(), Error> {
let mut found_quote = false; let mut found_quote = false;
let mut pos = Vec::new();
for (index, cur) in self.raw.chars().enumerate() { for (index, cur) in self.raw.chars().enumerate() {
match cur { match cur {
'(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' | '(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' |
'[' | ']' | '%' | '&' | '|' => { '[' | ']' | '%' | '&' | '|' => {
if !found_quote { if !found_quote {
self.pos.push(index); pos.push(index);
self.pos.push(index + 1); pos.push(index + 1);
} }
} }
'"' => { '"' => {
found_quote = !found_quote; found_quote = !found_quote;
self.pos.push(index); pos.push(index);
self.pos.push(index + 1); pos.push(index + 1);
} }
_ => (), _ => (),
} }
} }
self.pos.push(self.raw.len()); pos.push(self.raw.len());
self.pos = pos;
Ok(()) Ok(())
} }
@ -62,7 +61,8 @@ impl Expression {
let mut quote = None; let mut quote = None;
let mut prev = String::new(); let mut prev = String::new();
for pos in self.pos.clone() { for pos_ref in &self.pos {
let pos = *pos_ref;
if pos == 0 { if pos == 0 {
continue; continue;
} else { } else {
@ -117,11 +117,9 @@ impl Expression {
prev = raw; prev = raw;
} }
continue; continue;
} else { } else if prev == "!" || prev == ">" || prev == "<" {
if prev == "!" || prev == ">" || prev == "<" { operators.push(Operator::from_str(&prev).unwrap());
operators.push(Operator::from_str(&prev).unwrap()); prev.clear();
prev.clear();
}
} }
if (raw == "&" || raw == "|") && (prev == "&" || prev == "|") { if (raw == "&" || raw == "|") && (prev == "&" || prev == "|") {
@ -234,86 +232,90 @@ impl Expression {
Ok(()) Ok(())
} }
pub fn compile(&self) -> Box<Fn(ContextsRef, &Functions, &Functions) -> Result<Value, Error>> { pub fn compile(mut self) -> Result<Compiled, Error> {
let node = self.node.clone().unwrap(); self.parse_pos()?;
self.parse_operators()?;
self.parse_node()?;
let node = self.node.unwrap();
let builtin = BuiltIn::new();
Box::new(move |contexts, buildin, functions| -> Result<Value, Error> { Ok(Box::new(move |contexts, functions| -> Result<Value, Error> {
return exec_node(&node, contexts, buildin, functions); return exec_node(&node, &builtin, contexts, functions);
fn exec_node(node: &Node, fn exec_node(node: &Node,
contexts: ContextsRef, builtin: &Functions,
buildin: &Functions, contexts: &[Context],
functions: &Functions) functions: &Functions)
-> Result<Value, Error> { -> Result<Value, Error> {
match node.operator { match node.operator {
Operator::Add(_) => { Operator::Add(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.add(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .add(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Mul(_) => { Operator::Mul(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.mul(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .mul(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Sub(_) => { Operator::Sub(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.sub(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .sub(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Div(_) => { Operator::Div(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.div(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .div(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Rem(_) => { Operator::Rem(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.rem(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .rem(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Eq(_) => { Operator::Eq(_) => {
Math::eq(&exec_node(&node.get_first_child(), contexts, buildin, functions)?, Math::eq(&exec_node(&node.get_first_child(), builtin, contexts, functions)?,
&exec_node(&node.get_last_child(), contexts, buildin, functions)?) &exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Ne(_) => { Operator::Ne(_) => {
Math::ne(&exec_node(&node.get_first_child(), contexts, buildin, functions)?, Math::ne(&exec_node(&node.get_first_child(), builtin, contexts, functions)?,
&exec_node(&node.get_last_child(), contexts, buildin, functions)?) &exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Gt(_) => { Operator::Gt(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.gt(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .gt(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Lt(_) => { Operator::Lt(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.lt(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .lt(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Ge(_) => { Operator::Ge(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.ge(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .ge(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Le(_) => { Operator::Le(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.le(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .le(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::And(_) => { Operator::And(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.and(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .and(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Or(_) => { Operator::Or(_) => {
exec_node(&node.get_first_child(), contexts, buildin, functions) exec_node(&node.get_first_child(), builtin, contexts, functions)
? ?
.or(&exec_node(&node.get_last_child(), contexts, buildin, functions)?) .or(&exec_node(&node.get_last_child(), builtin, contexts, functions)?)
} }
Operator::Function(ref ident) => { Operator::Function(ref ident) => {
let function_option = if functions.contains_key(ident) { let function_option = if functions.contains_key(ident) {
functions.get(ident) functions.get(ident)
} else { } else {
buildin.get(ident) builtin.get(ident)
}; };
if function_option.is_some() { if function_option.is_some() {
@ -321,7 +323,7 @@ impl Expression {
node.check_function_args(function)?; node.check_function_args(function)?;
let mut values = Vec::new(); let mut values = Vec::new();
for node in &node.children { for node in &node.children {
values.push(exec_node(node, contexts, buildin, functions)?); values.push(exec_node(node, builtin, contexts, functions)?);
} }
(function.compiled)(values) (function.compiled)(values)
} else { } else {
@ -331,7 +333,7 @@ impl Expression {
Operator::Value(ref value) => Ok(value.clone()), Operator::Value(ref value) => Ok(value.clone()),
Operator::Not(_) => { Operator::Not(_) => {
let value = let value =
exec_node(&node.get_first_child(), contexts, buildin, functions)?; exec_node(&node.get_first_child(), builtin, contexts, functions)?;
match value { match value {
Value::Bool(boolean) => Ok(Value::Bool(!boolean)), Value::Bool(boolean) => Ok(Value::Bool(!boolean)),
Value::Null => Ok(Value::Bool(true)), Value::Null => Ok(Value::Bool(true)),
@ -354,7 +356,7 @@ impl Expression {
_ => Err(Error::CanNotExec(node.operator.clone())), _ => Err(Error::CanNotExec(node.operator.clone())),
} }
} }
}) }))
} }
} }
@ -427,23 +429,22 @@ fn close_bracket(parsing_nodes: &mut Vec<Node>, bracket: Operator) -> Result<(),
parsing_nodes.push(current); parsing_nodes.push(current);
} }
break; break;
} else { } else if !prev.closed {
if !prev.closed { prev.add_child(current);
prev.add_child(current); if prev.is_enough() {
if prev.is_enough() { prev.closed = true;
prev.closed = true; }
}
if !parsing_nodes.is_empty() { if !parsing_nodes.is_empty() {
parsing_nodes.push(prev); parsing_nodes.push(prev);
} else {
return Err(Error::StartWithNonValueOperator);
}
} else { } else {
return Err(Error::StartWithNonValueOperator); return Err(Error::StartWithNonValueOperator);
} }
} else {
return Err(Error::StartWithNonValueOperator);
} }
} }
Ok(()) Ok(())
} }
@ -476,21 +477,19 @@ fn close_comma(parsing_nodes: &mut Vec<Node>) -> Result<(), Error> {
} else { } else {
return Err(Error::CommaNotWithFunction); return Err(Error::CommaNotWithFunction);
} }
} else { } else if !prev.closed {
if !prev.closed { prev.add_child(current);
prev.add_child(current); if prev.is_enough() {
if prev.is_enough() { prev.closed = true;
prev.closed = true; }
}
if !parsing_nodes.is_empty() { if !parsing_nodes.is_empty() {
parsing_nodes.push(prev); parsing_nodes.push(prev);
} else {
return Err(Error::StartWithNonValueOperator);
}
} else { } else {
return Err(Error::StartWithNonValueOperator); return Err(Error::StartWithNonValueOperator);
} }
} else {
return Err(Error::StartWithNonValueOperator);
} }
} }
Ok(()) Ok(())
@ -502,7 +501,7 @@ fn rob_to(mut was_robed: Node, mut rober: Node) -> Vec<Node> {
vec![was_robed, rober] vec![was_robed, rober]
} }
fn find(contexts: ContextsRef, key: &str) -> Option<Value> { fn find(contexts: &[Context], key: &str) -> Option<Value> {
for context in contexts.iter().rev() { for context in contexts.iter().rev() {
let value = get(context, key); let value = get(context, key);
match value { match value {