From 032e57df43b5c826fa3da1975018770b1523f07e Mon Sep 17 00:00:00 2001 From: fengcen Date: Sun, 20 Nov 2016 16:04:06 +0800 Subject: [PATCH] add Expr builder. add ExecOptions. add len() --- Cargo.toml | 3 +- README.md | 30 ++-- src/builtin/mod.rs | 44 ++++-- src/expr/mod.rs | 152 +++++++++++++++++++ src/lib.rs | 254 ++++++++++++++++---------------- src/{expression => tree}/mod.rs | 159 ++++++++++---------- 6 files changed, 406 insertions(+), 236 deletions(-) create mode 100644 src/expr/mod.rs rename src/{expression => tree}/mod.rs (82%) diff --git a/Cargo.toml b/Cargo.toml index d9eab50..4764161 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eval" -version = "0.1.1" +version = "0.2.0" description = "Expression evaluator" keywords = ["expression", "evaluate", "evaluator", "expr", "template"] authors = ["fengcen "] @@ -15,5 +15,6 @@ name = "eval" path = "src/lib.rs" [dependencies] +serde = "^0.8" serde_json = "^0.8" quick-error = "^1.1" diff --git a/README.md b/README.md index f538452..b6ee0fe 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ 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. @@ -11,7 +11,7 @@ Eval is a powerful expression evaluator. Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=` `==` `+` `-` `*` `/` `%` `&&` `||` `n..m`. -Built-in functions: `min()` `max()` `is_empty()`. +Built-in functions: `min()` `max()` `len()` `is_empty()`. ## Where can eval be used? * Template engine @@ -22,7 +22,7 @@ Add dependency to Cargo.toml ```toml [dependencies] -eval = "^0.1" +eval = "^0.2" ``` 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: ``` -use eval::{eval_with_context, Context, to_value}; +use eval::{Expr, to_value}; -let mut context = Context::new(); -context.insert("foo".to_owned(), to_value(true)); -context.insert("bar".to_owned(), to_value(true)); -assert_eq!(eval_with_context("foo == bar", &context), Ok(to_value(true))); +assert_eq!(Expr::new("foo == bar") + .value("foo", true) + .value("bar", 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(); -functions.insert("say_hello".to_owned(), Function::new(|_| Ok(to_value("Hello world!")))); -assert_eq!(eval_with_functions("say_hello()", &functions), Ok(to_value("Hello world!"))); +assert_eq!(Expr::new("say_hello()") + .function("say_hello", |_| Ok(to_value("Hello world!"))) + .exec(), + Ok(to_value("Hello world!"))); ``` You can create an array with `[]`: @@ -71,7 +73,6 @@ You can create an array with `[]`: use eval::{eval, to_value}; 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`: @@ -80,7 +81,6 @@ You can create an integer array with `n..m`: use eval::{eval, to_value}; assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4]))); - ``` ## License diff --git a/src/builtin/mod.rs b/src/builtin/mod.rs index 346cb1d..a158b6d 100644 --- a/src/builtin/mod.rs +++ b/src/builtin/mod.rs @@ -11,6 +11,7 @@ impl BuiltIn { let mut functions = Functions::new(); functions.insert("min".to_owned(), create_min_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("array".to_owned(), create_array_function()); functions @@ -48,10 +49,8 @@ fn compare(compare: Compare) -> Function { if value.lt(prev.as_ref().unwrap())? == to_value(true) { prev = Ok(value) } - } else { - if value.gt(prev.as_ref().unwrap())? == to_value(true) { - prev = Ok(value) - } + } else if value.gt(prev.as_ref().unwrap())? == to_value(true) { + prev = Ok(value) } } else { prev = Ok(value); @@ -64,10 +63,8 @@ fn compare(compare: Compare) -> Function { if value.lt(prev.as_ref().unwrap())? == to_value(true) { prev = Ok(value) } - } else { - if value.gt(prev.as_ref().unwrap())? == to_value(true) { - prev = Ok(value) - } + } else if value.gt(prev.as_ref().unwrap())? == to_value(true) { + prev = Ok(value) } } else { prev = Ok(value); @@ -87,11 +84,32 @@ fn create_is_empty_fuction() -> Function { min_args: Some(1), compiled: Box::new(|values| { match *values.first().unwrap() { - Value::String(ref string) => Ok(Value::Bool(string.is_empty())), - Value::Array(ref array) => Ok(Value::Bool(array.is_empty())), - Value::Object(ref object) => Ok(Value::Bool(object.is_empty())), - Value::Null => Ok(Value::Bool(true)), - _ => Ok(Value::Bool(false)), + Value::String(ref string) => Ok(to_value(string.is_empty())), + Value::Array(ref array) => Ok(to_value(array.is_empty())), + Value::Object(ref object) => Ok(to_value(object.is_empty())), + Value::Null => Ok(to_value(true)), + _ => 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))) + } } }), } diff --git a/src/expr/mod.rs b/src/expr/mod.rs new file mode 100644 index 0000000..c79e99e --- /dev/null +++ b/src/expr/mod.rs @@ -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, + functions: Functions, + contexts: Contexts, +} + +impl Expr { + /// Create an expression. + pub fn new>(expr: T) -> Expr { + Expr { + expression: expr.into(), + compiled: None, + functions: Functions::new(), + contexts: create_empty_contexts(), + } + } + + /// Set function. + pub fn function(mut self, name: T, function: F) -> Expr + where T: Into, + F: 'static + Fn(Vec) -> Result + Sync + Send + { + self.functions.insert(name.into(), Function::new(function)); + self + } + + /// Set value. + pub fn value(mut self, name: T, value: V) -> Expr + where T: Into, + 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 { + self.compiled = Some(Tree::new(self.expression.clone()).compile()?); + Ok(self) + } + + /// Execute the expression. + pub fn exec(&self) -> Result { + 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 { + 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 +} diff --git a/src/lib.rs b/src/lib.rs index bb05d72..e00dbc7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,9 +3,9 @@ //! Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=` //! `==` `+` `-` `*` `/` `%` `&&` `||` `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: //! @@ -21,22 +21,24 @@ //! You can eval with context: //! //! ``` -//! use eval::{eval_with_context, Context, to_value}; +//! use eval::{Expr, to_value}; //! -//! let mut context = Context::new(); -//! context.insert("foo".to_owned(), to_value(true)); -//! context.insert("bar".to_owned(), to_value(true)); -//! assert_eq!(eval_with_context("foo == bar", &context), Ok(to_value(true))); +//! assert_eq!(Expr::new("foo == bar") +//! .value("foo", true) +//! .value("bar", 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(); -//! functions.insert("say_hello".to_owned(), Function::new(|_| Ok(to_value("Hello world!")))); -//! assert_eq!(eval_with_functions("say_hello()", &functions), Ok(to_value("Hello world!"))); +//! assert_eq!(Expr::new("say_hello()") +//! .function("say_hello", |_| Ok(to_value("Hello world!"))) +//! .exec(), +//! Ok(to_value("Hello world!"))); //! ``` //! //! You can create an array with `[]`: @@ -45,7 +47,6 @@ //! use eval::{eval, to_value}; //! //! 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`: @@ -54,9 +55,23 @@ //! use eval::{eval, to_value}; //! //! 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"] #![deny(missing_docs)] #![feature(proc_macro, test)] @@ -64,89 +79,51 @@ extern crate test; #[macro_use] extern crate quick_error; +extern crate serde; extern crate serde_json; - mod math; mod function; mod operator; mod node; -mod expression; +mod tree; mod error; mod builtin; +mod expr; - +pub use expr::ExecOptions; pub use serde_json::{Value, to_value}; pub use error::Error; pub use function::Function; - +pub use expr::Expr; use std::collections::HashMap; -use expression::Expression; -use builtin::BuiltIn; -type ContextsRef<'a> = &'a [Context]; - -/// Eval context. +/// Custom context. pub type Context = HashMap; -/// 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; -/// Eval functions. +/// Custom functions. pub type Functions = HashMap; /// Evaluates the value of an expression. pub fn eval(expr: &str) -> Result { - 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 { - let mut contexts = Contexts::new(); - contexts.push(context.clone()); - eval_with_contexts(expr, &contexts) -} -/// Evaluates the value of an expression with the given contexts.
-/// The value of the last context is searched first. -pub fn eval_with_contexts(expr: &str, contexts: ContextsRef) -> Result { - Expression::new(expr)?.compile()(contexts, &BuiltIn::new(), &Functions::new()) -} +type Compiled = Box Result>; -/// Evaluates the value of an expression with the given functions. -pub fn eval_with_functions(expr: &str, functions: &Functions) -> Result { - 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 { - 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.
-/// The value of the last context is searched first. -pub fn eval_with_contexts_and_functions(expr: &str, - contexts: ContextsRef, - functions: &Functions) - -> Result { - Expression::new(expr)?.compile()(contexts, &BuiltIn::new(), functions) -} #[cfg(test)] mod tests { use test; use serde_json::to_value; - use expression::Expression; use error::Error; - use Context; + use Expr; + use tree::Tree; use eval; - use eval_with_context; - use eval_with_functions; - use {Function, Functions}; + use std::collections::HashMap; #[test] fn test_add() { @@ -225,6 +202,28 @@ mod tests { 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] fn test_brackets_1() { assert_eq!(eval("(5) + (min(3, 4, 5)) + 20"), Ok(to_value(28))); @@ -405,81 +404,83 @@ mod tests { } #[test] - fn test_buildin_is_empty() { - let mut context = Context::new(); - context.insert("array".to_owned(), to_value(Vec::::new())); - assert_eq!(eval_with_context("is_empty(array)", &context), + fn test_builtin_is_empty() { + assert_eq!(Expr::new("is_empty(array)") + .value("array", Vec::::new()) + .compile() + .unwrap() + .exec(), Ok(to_value(true))); } #[test] - fn test_buildin_min() { - let mut context = Context::new(); - context.insert("array".to_owned(), to_value(vec![23, 34, 45, 2])); - assert_eq!(eval_with_context("min(array)", &context), Ok(to_value(2))); + fn test_builtin_min() { + assert_eq!(Expr::new("min(array)") + .value("array", vec![23, 34, 45, 2]) + .compile() + .unwrap() + .exec(), + Ok(to_value(2))); } #[test] fn test_custom_function() { - let mut functions = Functions::new(); - functions.insert("output".to_owned(), - Function::new(|_| Ok(to_value("This is custom function's output")))); - assert_eq!(eval_with_functions("output()", &functions), + assert_eq!(Expr::new("output()") + .function("output", + |_| Ok(to_value("This is custom function's output"))) + .compile() + .unwrap() + .exec(), Ok(to_value("This is custom function's output"))); } #[test] fn test_error_start_with_non_value_operator() { - let mut expr = Expression { - raw: "+ + 5".to_owned(), - pos: Vec::new(), - operators: Vec::new(), - node: None, - }; + let mut tree = Tree { raw: "+ + 5".to_owned(), ..Default::default() }; - expr.parse_pos().unwrap(); - expr.parse_operators().unwrap(); + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); - assert_eq!(expr.parse_node(), Err(Error::StartWithNonValueOperator)); + assert_eq!(tree.parse_node(), Err(Error::StartWithNonValueOperator)); } #[test] 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(); - expr.parse_operators().unwrap(); + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); - assert_eq!(expr.parse_node(), Err(Error::DuplicateOperatorNode)); + assert_eq!(tree.parse_node(), Err(Error::DuplicateOperatorNode)); } #[test] 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(); - expr.parse_operators().unwrap(); + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); - assert_eq!(expr.parse_node(), Err(Error::DuplicateValueNode)); + assert_eq!(tree.parse_node(), Err(Error::DuplicateValueNode)); } #[test] 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] 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(); - expr.parse_operators().unwrap(); + tree.parse_pos().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] fn bench_parse_pos(b: &mut test::Bencher) { - let mut expr = Expression { - raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), - ..Default::default() - }; + let mut tree = + Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() }; - b.iter(|| expr.parse_pos().unwrap()); + b.iter(|| tree.parse_pos().unwrap()); } #[bench] fn bench_parse_operators(b: &mut test::Bencher) { - let mut expr = Expression { - raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), - ..Default::default() - }; + let mut tree = + Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() }; - expr.parse_pos().unwrap(); - b.iter(|| expr.parse_operators().unwrap()); + tree.parse_pos().unwrap(); + b.iter(|| tree.parse_operators().unwrap()); } #[bench] fn bench_parse_nodes(b: &mut test::Bencher) { - let mut expr = Expression { - raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), - ..Default::default() - }; + let mut tree = + Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() }; - expr.parse_pos().unwrap(); - expr.parse_operators().unwrap(); - b.iter(|| expr.parse_node().unwrap()); + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); + b.iter(|| tree.parse_node().unwrap()); } #[bench] fn bench_compile(b: &mut test::Bencher) { - let mut expr = Expression { - raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), - ..Default::default() - }; + b.iter(|| { + let mut tree = + 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(); - expr.parse_operators().unwrap(); - expr.parse_node().unwrap(); - b.iter(|| expr.compile()); + #[bench] + fn bench_exec(b: &mut test::Bencher) { + let expr = Expr::new("(2 + (3 + 4) + (6 + (6 + 7)) + 5)").compile().unwrap(); + b.iter(|| expr.exec().unwrap()) } #[bench] diff --git a/src/expression/mod.rs b/src/tree/mod.rs similarity index 82% rename from src/expression/mod.rs rename to src/tree/mod.rs index 02faba9..fda6c54 100644 --- a/src/expression/mod.rs +++ b/src/tree/mod.rs @@ -7,49 +7,48 @@ use operator::Operator; use node::Node; use {Context, Functions}; use error::Error; -use ContextsRef; +use Compiled; +use builtin::BuiltIn; #[derive(Default)] -pub struct Expression { +pub struct Tree { pub raw: String, pub pos: Vec, pub operators: Vec, pub node: Option, } -impl Expression { - pub fn new>(raw: T) -> Result { - let mut expr = Expression { raw: raw.into(), ..Default::default() }; - - expr.parse_pos()?; - expr.parse_operators()?; - expr.parse_node()?; - Ok(expr) +impl Tree { + pub fn new>(raw: T) -> Tree { + Tree { raw: raw.into(), ..Default::default() } } pub fn parse_pos(&mut self) -> Result<(), Error> { let mut found_quote = false; + let mut pos = Vec::new(); for (index, cur) in self.raw.chars().enumerate() { match cur { '(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' | '[' | ']' | '%' | '&' | '|' => { if !found_quote { - self.pos.push(index); - self.pos.push(index + 1); + pos.push(index); + pos.push(index + 1); } } '"' => { found_quote = !found_quote; - self.pos.push(index); - self.pos.push(index + 1); + pos.push(index); + pos.push(index + 1); } _ => (), } } - self.pos.push(self.raw.len()); + pos.push(self.raw.len()); + + self.pos = pos; Ok(()) } @@ -62,7 +61,8 @@ impl Expression { let mut quote = None; let mut prev = String::new(); - for pos in self.pos.clone() { + for pos_ref in &self.pos { + let pos = *pos_ref; if pos == 0 { continue; } else { @@ -117,11 +117,9 @@ impl Expression { prev = raw; } continue; - } else { - if prev == "!" || prev == ">" || prev == "<" { - operators.push(Operator::from_str(&prev).unwrap()); - prev.clear(); - } + } else if prev == "!" || prev == ">" || prev == "<" { + operators.push(Operator::from_str(&prev).unwrap()); + prev.clear(); } if (raw == "&" || raw == "|") && (prev == "&" || prev == "|") { @@ -234,86 +232,90 @@ impl Expression { Ok(()) } - pub fn compile(&self) -> Box Result> { - let node = self.node.clone().unwrap(); + pub fn compile(mut self) -> Result { + 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 { - return exec_node(&node, contexts, buildin, functions); + Ok(Box::new(move |contexts, functions| -> Result { + return exec_node(&node, &builtin, contexts, functions); fn exec_node(node: &Node, - contexts: ContextsRef, - buildin: &Functions, + builtin: &Functions, + contexts: &[Context], functions: &Functions) -> Result { match node.operator { 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(_) => { - 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(_) => { - 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(_) => { - 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(_) => { - 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(_) => { - Math::eq(&exec_node(&node.get_first_child(), contexts, buildin, functions)?, - &exec_node(&node.get_last_child(), contexts, buildin, functions)?) + Math::eq(&exec_node(&node.get_first_child(), builtin, contexts, functions)?, + &exec_node(&node.get_last_child(), builtin, contexts, functions)?) } Operator::Ne(_) => { - Math::ne(&exec_node(&node.get_first_child(), contexts, buildin, functions)?, - &exec_node(&node.get_last_child(), contexts, buildin, functions)?) + Math::ne(&exec_node(&node.get_first_child(), builtin, contexts, functions)?, + &exec_node(&node.get_last_child(), builtin, contexts, functions)?) } 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(_) => { - 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(_) => { - 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(_) => { - 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(_) => { - 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(_) => { - 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) => { let function_option = if functions.contains_key(ident) { functions.get(ident) } else { - buildin.get(ident) + builtin.get(ident) }; if function_option.is_some() { @@ -321,7 +323,7 @@ impl Expression { node.check_function_args(function)?; let mut values = Vec::new(); for node in &node.children { - values.push(exec_node(node, contexts, buildin, functions)?); + values.push(exec_node(node, builtin, contexts, functions)?); } (function.compiled)(values) } else { @@ -331,7 +333,7 @@ impl Expression { Operator::Value(ref value) => Ok(value.clone()), Operator::Not(_) => { let value = - exec_node(&node.get_first_child(), contexts, buildin, functions)?; + exec_node(&node.get_first_child(), builtin, contexts, functions)?; match value { Value::Bool(boolean) => Ok(Value::Bool(!boolean)), Value::Null => Ok(Value::Bool(true)), @@ -354,7 +356,7 @@ impl Expression { _ => Err(Error::CanNotExec(node.operator.clone())), } } - }) + })) } } @@ -427,23 +429,22 @@ fn close_bracket(parsing_nodes: &mut Vec, bracket: Operator) -> Result<(), parsing_nodes.push(current); } break; - } else { - if !prev.closed { - prev.add_child(current); - if prev.is_enough() { - prev.closed = true; - } + } else if !prev.closed { + prev.add_child(current); + if prev.is_enough() { + prev.closed = true; + } - if !parsing_nodes.is_empty() { - parsing_nodes.push(prev); - } else { - return Err(Error::StartWithNonValueOperator); - } + if !parsing_nodes.is_empty() { + parsing_nodes.push(prev); } else { return Err(Error::StartWithNonValueOperator); } + } else { + return Err(Error::StartWithNonValueOperator); } } + Ok(()) } @@ -476,21 +477,19 @@ fn close_comma(parsing_nodes: &mut Vec) -> Result<(), Error> { } else { return Err(Error::CommaNotWithFunction); } - } else { - if !prev.closed { - prev.add_child(current); - if prev.is_enough() { - prev.closed = true; - } + } else if !prev.closed { + prev.add_child(current); + if prev.is_enough() { + prev.closed = true; + } - if !parsing_nodes.is_empty() { - parsing_nodes.push(prev); - } else { - return Err(Error::StartWithNonValueOperator); - } + if !parsing_nodes.is_empty() { + parsing_nodes.push(prev); } else { return Err(Error::StartWithNonValueOperator); } + } else { + return Err(Error::StartWithNonValueOperator); } } Ok(()) @@ -502,7 +501,7 @@ fn rob_to(mut was_robed: Node, mut rober: Node) -> Vec { vec![was_robed, rober] } -fn find(contexts: ContextsRef, key: &str) -> Option { +fn find(contexts: &[Context], key: &str) -> Option { for context in contexts.iter().rev() { let value = get(context, key); match value {