add Expr builder. add ExecOptions. add len()
This commit is contained in:
parent
1c7cd61b59
commit
032e57df43
@ -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"
|
||||||
|
30
README.md
30
README.md
@ -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
|
||||||
|
@ -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,11 +49,9 @@ 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,11 +63,9 @@ 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
152
src/expr/mod.rs
Normal 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
|
||||||
|
}
|
254
src/lib.rs
254
src/lib.rs
@ -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]
|
||||||
|
@ -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,12 +117,10 @@ 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 == "|") {
|
||||||
if raw == prev {
|
if raw == 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,8 +429,7 @@ 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;
|
||||||
@ -443,7 +444,7 @@ fn close_bracket(parsing_nodes: &mut Vec<Node>, bracket: Operator) -> Result<(),
|
|||||||
return Err(Error::StartWithNonValueOperator);
|
return Err(Error::StartWithNonValueOperator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,8 +477,7 @@ 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;
|
||||||
@ -492,7 +492,6 @@ fn close_comma(parsing_nodes: &mut Vec<Node>) -> Result<(), Error> {
|
|||||||
return Err(Error::StartWithNonValueOperator);
|
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 {
|
Loading…
Reference in New Issue
Block a user