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

View File

@ -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

View File

@ -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,11 +49,9 @@ 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) {
} else if value.gt(prev.as_ref().unwrap())? == to_value(true) {
prev = Ok(value)
}
}
} else {
prev = Ok(value);
}
@ -64,11 +63,9 @@ 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) {
} 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)))
}
}
}),
}

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: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=`
//! `==` `+` `-` `*` `/` `%` `&&` `||` `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<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>;
/// Eval functions.
/// Custom functions.
pub type Functions = HashMap<String, Function>;
/// Evaluates the value of an expression.
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>
/// 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())
}
type Compiled = Box<Fn(&[Context], &Functions) -> Result<Value, Error>>;
/// 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)]
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::<String>::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::<String>::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]

View File

@ -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<usize>,
pub operators: Vec<Operator>,
pub node: Option<Node>,
}
impl Expression {
pub fn new<T: Into<String>>(raw: T) -> Result<Expression, Error> {
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<T: Into<String>>(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,12 +117,10 @@ impl Expression {
prev = raw;
}
continue;
} else {
if prev == "!" || prev == ">" || prev == "<" {
} else if prev == "!" || prev == ">" || prev == "<" {
operators.push(Operator::from_str(&prev).unwrap());
prev.clear();
}
}
if (raw == "&" || raw == "|") && (prev == "&" || prev == "|") {
if raw == prev {
@ -234,86 +232,90 @@ impl Expression {
Ok(())
}
pub fn compile(&self) -> Box<Fn(ContextsRef, &Functions, &Functions) -> Result<Value, Error>> {
let node = self.node.clone().unwrap();
pub fn compile(mut self) -> Result<Compiled, Error> {
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> {
return exec_node(&node, contexts, buildin, functions);
Ok(Box::new(move |contexts, functions| -> Result<Value, Error> {
return exec_node(&node, &builtin, contexts, functions);
fn exec_node(node: &Node,
contexts: ContextsRef,
buildin: &Functions,
builtin: &Functions,
contexts: &[Context],
functions: &Functions)
-> Result<Value, Error> {
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,8 +429,7 @@ fn close_bracket(parsing_nodes: &mut Vec<Node>, bracket: Operator) -> Result<(),
parsing_nodes.push(current);
}
break;
} else {
if !prev.closed {
} else if !prev.closed {
prev.add_child(current);
if prev.is_enough() {
prev.closed = true;
@ -443,7 +444,7 @@ fn close_bracket(parsing_nodes: &mut Vec<Node>, bracket: Operator) -> Result<(),
return Err(Error::StartWithNonValueOperator);
}
}
}
Ok(())
}
@ -476,8 +477,7 @@ fn close_comma(parsing_nodes: &mut Vec<Node>) -> Result<(), Error> {
} else {
return Err(Error::CommaNotWithFunction);
}
} else {
if !prev.closed {
} else if !prev.closed {
prev.add_child(current);
if prev.is_enough() {
prev.closed = true;
@ -492,7 +492,6 @@ fn close_comma(parsing_nodes: &mut Vec<Node>) -> Result<(), Error> {
return Err(Error::StartWithNonValueOperator);
}
}
}
Ok(())
}
@ -502,7 +501,7 @@ fn rob_to(mut was_robed: Node, mut rober: Node) -> Vec<Node> {
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() {
let value = get(context, key);
match value {