init repository.

This commit is contained in:
fengcen 2016-11-17 00:12:26 +08:00
commit 1d84eea270
12 changed files with 1869 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
.DS_Store
*~
*#
*.o
*.so
*.swp
*.dylib
*.dSYM
*.dll
*.rlib
*.dummy
*.exe
*-test
target/
Cargo.lock

19
Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "eval"
version = "0.1.0"
description = "Expression evaluator"
keywords = ["expression", "evaluate", "evaluator", "expr"]
authors = ["fengcen <fengcen.love@gmail.com>"]
repository = "https://github.com/fengcen/eval.git"
homepage = "https://github.com/fengcen/eval"
documentation = "https://github.com/fengcen/eval"
readme = "README.md"
license = "MIT"
[lib]
name = "eval"
path = "src/lib.rs"
[dependencies]
serde_json = "^0.8"
quick-error = "^1.1"

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 fengcen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

84
README.md Normal file
View File

@ -0,0 +1,84 @@
eval
===
Expression evaluator for Rust.
## Features
Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=` `==`
`+` `-` `*` `/` `%` `&&` `||` `n..m`.
Built-in functions: `min()` `max()` `is_empty()`.
## Where can eval be used?
* Template engine
* ...
## Usage
Add dependency to Cargo.toml
```toml
[dependencies]
eval = "^0.1"
```
In your `main.rs` or `lib.rs`:
```rust
extern crate eval;
```
## Examples
You can do mathematical calculations with supported operators:
```
use eval::{eval, to_value};
assert_eq!(eval("1 + 2 + 3"), Ok(to_value(6)));
assert_eq!(eval("2 * 2 + 3"), Ok(to_value(7)));
assert_eq!(eval("2 / 2 + 3"), Ok(to_value(4.0)));
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};
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)));
```
You can eval with functions:
```
use eval::{eval_with_functions, Functions, Function, 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!")));
```
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`:
```
use eval::{eval, to_value};
assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
```
## License
eval is primarily distributed under the terms of the MIT license.
See [LICENSE](LICENSE) for details.

101
src/builtin/mod.rs Normal file
View File

@ -0,0 +1,101 @@
use {Function, Functions, Value, to_value};
use math::Math;
use error::Error;
pub struct BuiltIn {}
impl BuiltIn {
pub fn new() -> Functions {
let mut functions = Functions::new();
functions.insert("min".to_owned(), create_min_fuction());
functions.insert("max".to_owned(), create_max_fuction());
functions.insert("is_empty".to_owned(), create_is_empty_fuction());
functions.insert("array".to_owned(), create_array_function());
functions
}
}
#[derive(PartialEq)]
enum Compare {
Min,
Max
}
fn create_min_fuction() -> Function {
compare(Compare::Min)
}
fn create_max_fuction() -> Function {
compare(Compare::Max)
}
fn compare(compare: Compare) -> Function {
Function {
max_args: None,
min_args: Some(1),
compiled: Box::new(move |values| {
let mut prev: Result<Value, Error> = Err(Error::Custom("can't find min value.".to_owned()));
for value in values {
match value {
Value::Array(array) => {
for value in array {
if prev.is_ok() {
if compare == Compare::Min {
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 {
prev = Ok(value);
}
}
},
_ => {
if prev.is_ok() {
if compare == Compare::Min {
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 {
prev = Ok(value);
}
}
}
}
prev
})
}
}
fn create_is_empty_fuction() -> Function {
Function {
max_args: Some(1),
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))
}
})
}
}
fn create_array_function() -> Function {
Function::new(|values|Ok(to_value(values)))
}

75
src/error/mod.rs Normal file
View File

@ -0,0 +1,75 @@
use serde_json::Value;
use operator::Operator;
quick_error! {
/// Expression parsing error
#[derive(Debug, PartialEq)]
pub enum Error {
/// Unsupported operator yet.
UnsupportedOperator(operator: String) {
display("Unsupported operator: {:?}", operator)
}
/// This operator does not support execution.
CanNotExec(operator: Operator) {
display("This operator does not support execution: {:?}", operator)
}
/// Your expression may start with non-value operator like ( + * )
StartWithNonValueOperator {
display("Your expression may start with non-value operator like ( + * ).")
}
/// Unpaired brackets, left brackets count does not equal right brackets count
UnpairedBrackets {
display("Unpaired brackets, left brackets count does not equal right brackets count.")
}
/// Duplicate values node, you may have (2 3) but there is no operators between them
DuplicateValueNode {
display("Duplicate values node, you may have (2 3) but there is no operators between them.")
}
/// Duplicate operators node, you may have (+ +) but there is no values between them
DuplicateOperatorNode {
display("Duplicate operators node, you may have (+ +) but there is no values between them.")
}
/// You have a comma(,) , but there is no function in front of it.
CommaNotWithFunction {
display("You have a comma(,) , but there is no function in front of it.")
}
/// You have empty brackets () , but there is no function in front of it.
BracketNotWithFunction {
display("You have empty brackets () , but there is no function in front of it.")
}
/// Function not exists.
FunctionNotExists(ident: String) {
display("Function not exists: {}", ident)
}
/// Expected boolean type but the given value isn't.
NotBoolean(value: Value) {
display("Expected boolean type, found: {}", value)
}
/// Failed to parse, no final expression.
NoFinalNode {
display("Failed to parse, no final expression.")
}
/// The number of arguments is greater than the maximum limit.
ArgumentsGreater(max: usize) {
display("The number of arguments is greater than the maximum limit: {}", max)
}
/// The number of arguments is less than the minimum limit.
ArgumentsLess(min: usize) {
display("The number of arguments is less than the minimum limit: {}", min)
}
/// This two value types are different or do not support mathematical calculations.
UnsupportedTypes(a: String, b: String) {
display("This two value types are different or do not support mathematical calculations: {}, {}", a, b)
}
/// Invalid array expression like `1..2..3`
InvalidArray(ident: String) {
display("Invalid array expression: {}", ident)
}
/// Custom error.
Custom(detail: String) {
display("{}", detail)
}
}
}

509
src/expression/mod.rs Normal file
View File

@ -0,0 +1,509 @@
use std::str::FromStr;
use std::clone::Clone;
use serde_json::{Value, to_value};
use math::Math;
use operator::Operator;
use node::Node;
use {Context, Functions};
use error::Error;
use ContextsRef;
#[derive(Default)]
pub struct Expression {
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)
}
pub fn parse_pos(&mut self) -> Result<(), Error> {
let mut found_quote = false;
for (index, cur) in self.raw.chars().enumerate() {
match cur {
'(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' |
'>' | '<' | '\'' | '[' | ']' | '%' | '&' | '|' => {
if ! found_quote {
self.pos.push(index);
self.pos.push(index + 1);
}
},
'"' => {
found_quote = ! found_quote;
self.pos.push(index);
self.pos.push(index + 1);
},
_ => ()
}
}
self.pos.push(self.raw.len());
Ok(())
}
pub fn parse_operators(&mut self) -> Result<(), Error> {
let mut operators = Vec::new();
let mut start;
let mut end = 0;
let mut parenthesis = 0;
let mut square_brackets = 0;
let mut quote = None;
let mut prev = String::new();
for pos in self.pos.clone() {
if pos == 0 {
continue;
} else {
start = end;
end = pos;
}
let raw = self.raw[start..end].to_owned();
let operator = Operator::from_str(&raw).unwrap();
match operator {
Operator::DoubleQuotes | Operator::SingleQuote => {
if quote.is_some() {
if quote.as_ref() == Some(&operator) {
operators.push(Operator::Value(to_value(&prev)));
prev.clear();
quote = None;
continue;
}
} else {
quote = Some(operator);
prev.clear();
continue;
}
},
_ => ()
};
if quote.is_some() {
prev += &raw;
continue;
}
if raw.is_empty() {
continue;
}
if raw == "=" {
if prev == "!" || prev == ">" || prev == "<" || prev == "=" {
prev.push_str("=");
operators.push(Operator::from_str(&prev).unwrap());
prev.clear();
} else {
prev = raw;
}
continue;
} else if raw == "!" || raw == ">" || raw == "<" {
if prev == "!" || prev == ">" || prev == "<" {
operators.push(Operator::from_str(&prev).unwrap());
prev.clear();
} else {
prev = raw;
}
continue;
} else {
if prev == "!" || prev == ">" || prev == "<" {
operators.push(Operator::from_str(&prev).unwrap());
prev.clear();
}
}
if (raw == "&" || raw == "|") && (prev == "&" || prev == "|") {
if raw == prev {
prev.push_str(&raw);
operators.push(Operator::from_str(&prev).unwrap());
prev.clear();
continue;
} else {
return Err(Error::UnsupportedOperator(prev));
}
} else if raw == "&" || raw == "|" {
prev = raw;
continue;
}
match operator {
Operator::LeftSquareBracket => {
square_brackets += 1;
operators.push(Operator::Function("array".to_owned()));
operators.push(operator);
continue;
},
Operator::LeftParenthesis => {
parenthesis += 1;
if ! operators.is_empty() {
let prev_operator = operators.pop().unwrap();
if prev_operator.is_identifier() {
operators.push(Operator::Function(prev_operator.get_identifier()));
operators.push(operator);
continue;
} else {
operators.push(prev_operator);
}
}
},
Operator::RightParenthesis => parenthesis -= 1,
Operator::RightSquareBracket => square_brackets -= 1,
Operator::WhiteSpace => continue,
_ => ()
}
prev = raw;
operators.push(operator);
}
if parenthesis != 0 || square_brackets != 0 {
Err(Error::UnpairedBrackets)
} else {
self.operators = operators;
Ok(())
}
}
pub fn compile(&self) -> Box<Fn(ContextsRef, &Functions, &Functions) -> Result<Value, Error>> {
let node = self.node.clone().unwrap();
Box::new(move |contexts, buildin, functions| -> Result<Value, Error> {
return exec_node(&node, contexts, buildin, functions);
fn exec_node(node: &Node, contexts: ContextsRef, buildin: &Functions, functions: &Functions) -> Result<Value, Error> {
match node.operator {
Operator::Add(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.add(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Mul(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.mul(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Sub(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.sub(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Div(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.div(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Rem(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.rem(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Eq(_) => Math::eq(&exec_node(&node.get_first_child(), contexts, buildin, functions)?, &exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Ne(_) => Math::ne(&exec_node(&node.get_first_child(), contexts, buildin, functions)?, &exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Gt(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.gt(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Lt(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.lt(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Ge(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.ge(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Le(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.le(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::And(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.and(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Or(_) => exec_node(&node.get_first_child(), contexts, buildin, functions)?.or(&exec_node(&node.get_last_child(), contexts, buildin, functions)?),
Operator::Function(ref ident) => {
let function_option = if functions.contains_key(ident) {
functions.get(ident)
} else {
buildin.get(ident)
};
if function_option.is_some() {
let function = function_option.unwrap();
node.check_function_args(function)?;
let mut values = Vec::new();
for node in &node.children {
values.push(exec_node(node, contexts, buildin, functions)?);
}
(function.compiled)(values)
} else {
Err(Error::FunctionNotExists(ident.to_owned()))
}
},
Operator::Value(ref value) => Ok(value.clone()),
Operator::Not(_) => {
let value = exec_node(&node.get_first_child(), contexts, buildin, functions)?;
match value {
Value::Bool(boolean) => Ok(Value::Bool(!boolean)),
Value::Null => Ok(Value::Bool(true)),
_ => Err(Error::NotBoolean(value))
}
},
Operator::Identifier(ref ident) => {
let number = parse_number(ident);
if number.is_some() {
Ok(number.unwrap())
} else if is_range(ident) {
parse_range(ident)
} else {
match find(contexts, ident) {
Some(value) => Ok(value),
None => Ok(Value::Null)
}
}
},
_ => Err(Error::CanNotExec(node.operator.clone()))
}
}
})
}
pub fn parse_node(&mut self) -> Result<(), Error> {
let mut parsing_nodes = Vec::<Node>::new();
for operator in &self.operators {
match *operator {
Operator::Add(priority) | Operator::Sub(priority) |
Operator::Mul(priority) | Operator::Div(priority) |
Operator::Not(priority) | Operator::Eq(priority) |
Operator::Ne(priority) | Operator::Gt(priority) |
Operator::Lt(priority) | Operator::Ge(priority) |
Operator::And(priority) | Operator::Or(priority) |
Operator::Le(priority) | Operator::Rem(priority) => {
if ! parsing_nodes.is_empty() {
let prev = parsing_nodes.pop().unwrap();
if prev.is_value_or_enough() {
if prev.operator.get_priority() < priority && ! prev.closed {
parsing_nodes.extend_from_slice(&rob_to(prev, operator.to_node()));
} else {
parsing_nodes.push(operator.children_to_node(vec![prev]));
}
} else if prev.operator.can_at_beginning() {
parsing_nodes.push(prev);
parsing_nodes.push(operator.to_node());
} else {
return Err(Error::DuplicateOperatorNode);
}
} else if operator.can_at_beginning() {
parsing_nodes.push(operator.to_node());
} else {
return Err(Error::StartWithNonValueOperator);
}
},
Operator::Function(_) | Operator::LeftParenthesis | Operator::LeftSquareBracket => parsing_nodes.push(operator.to_node()),
Operator::Comma => close_comma(&mut parsing_nodes)?,
Operator::RightParenthesis | Operator::RightSquareBracket => close_bracket(&mut parsing_nodes, operator.get_left())?,
Operator::Value(_) | Operator::Identifier(_) => append_child_to_last_node(&mut parsing_nodes, operator)?,
_ => ()
}
}
self.node = Some(get_final_node(parsing_nodes)?);
Ok(())
}
}
fn append_child_to_last_node(parsing_nodes: &mut Vec<Node>, operator: &Operator) -> Result<(), Error> {
let mut node = operator.to_node();
node.closed = true;
if let Some(mut prev) = parsing_nodes.pop() {
if prev.is_value_or_enough() {
return Err(Error::DuplicateValueNode);
} else if prev.is_enough() {
parsing_nodes.push(prev);
parsing_nodes.push(node);
} else {
prev.add_child(node);
parsing_nodes.push(prev);
}
} else {
parsing_nodes.push(node);
}
Ok(())
}
fn get_final_node(mut parsing_nodes: Vec<Node>) -> Result<Node, Error> {
if parsing_nodes.is_empty() {
return Err(Error::NoFinalNode)
}
while parsing_nodes.len() != 1 {
let mut last_node = parsing_nodes.pop().unwrap();
let mut prev_node = parsing_nodes.pop().unwrap();
prev_node.add_child(last_node);
last_node = prev_node;
parsing_nodes.push(last_node);
}
Ok(parsing_nodes.pop().unwrap())
}
fn close_bracket(parsing_nodes: &mut Vec<Node>, bracket: Operator) -> Result<(), Error> {
loop {
let mut current = parsing_nodes.pop().unwrap();
let mut prev = parsing_nodes.pop().unwrap();
if current.operator == bracket {
if prev.is_unclosed_function() {
prev.closed = true;
parsing_nodes.push(prev);
break;
} else {
return Err(Error::BracketNotWithFunction);
}
} else if prev.operator == bracket {
if ! current.closed {
current.closed = true;
}
if let Some(mut penult) = parsing_nodes.pop() {
if penult.is_unclosed_function() {
penult.closed = true;
penult.add_child(current);
parsing_nodes.push(penult);
} else {
parsing_nodes.push(penult);
parsing_nodes.push(current);
}
} else {
parsing_nodes.push(current);
}
break;
} 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);
}
} else {
return Err(Error::StartWithNonValueOperator);
}
}
}
Ok(())
}
fn close_comma(parsing_nodes: &mut Vec<Node>) -> Result<(), Error> {
if parsing_nodes.len() < 2 {
return Err(Error::CommaNotWithFunction);
}
loop {
let current = parsing_nodes.pop().unwrap();
let mut prev = parsing_nodes.pop().unwrap();
if current.operator == Operator::Comma {
parsing_nodes.push(prev);
break;
} else if current.operator.is_left() {
parsing_nodes.push(prev);
parsing_nodes.push(current);
break;
} else if prev.operator.is_left() {
if let Some(mut penult) = parsing_nodes.pop() {
if penult.is_unclosed_function() {
penult.add_child(current);
parsing_nodes.push(penult);
parsing_nodes.push(prev);
break;
} else {
return Err(Error::CommaNotWithFunction);
}
} else {
return Err(Error::CommaNotWithFunction);
}
} 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);
}
} else {
return Err(Error::StartWithNonValueOperator);
}
}
}
Ok(())
}
fn rob_to(mut was_robed: Node, mut rober: Node) -> Vec<Node> {
let moveout_node = was_robed.moveout_last_node();
rober.add_child(moveout_node);
vec![was_robed, rober]
}
fn find(contexts: ContextsRef, key: &str) -> Option<Value> {
for context in contexts.iter().rev() {
let value = get(context, key);
match value {
Some(_) => return value,
None => continue
}
}
None
}
fn get(context: &Context, key: &str) -> Option<Value> {
let mut keys = key.split('.').collect::<Vec<_>>();
let context_key = keys.remove(0);
let context_value_option = context.get(context_key);
if context_value_option.is_none() {
None
} else if ! keys.is_empty() {
match context_value_option.unwrap().search(&keys.join(".")) {
Some(value) => Some(value.clone()),
None => None
}
} else {
Some(context_value_option.unwrap().clone())
}
}
fn is_range(ident: &str) -> bool {
ident.contains("..")
}
fn parse_range(ident: &str) -> Result<Value, Error> {
let segments = ident.split("..").collect::<Vec<_>>();
if segments.len() != 2 {
Err(Error::InvalidArray(ident.to_owned()))
} else {
let start = segments[0].parse::<i64>();
let end = segments[1].parse::<i64>();
if start.is_ok() && end.is_ok() {
let mut array = Vec::new();
for n in start.unwrap()..end.unwrap() {
array.push(n);
}
Ok(to_value(array))
} else {
Err(Error::InvalidArray(ident.to_owned()))
}
}
}
fn parse_number(ident: &str) -> Option<Value> {
let number = ident.parse::<u64>();
if number.is_ok() {
return Some(to_value(number.unwrap()));
}
let number = ident.parse::<i64>();
if number.is_ok() {
return Some(to_value(number.unwrap()));
}
let number = ident.parse::<f64>();
if number.is_ok() {
return Some(to_value(number.unwrap()));
}
None
}

32
src/function/mod.rs Normal file
View File

@ -0,0 +1,32 @@
use std::fmt;
use serde_json::Value;
use error::Error;
/// Custom function
pub struct Function {
/// Maximum number of arguments.
pub max_args: Option<usize>,
/// Minimum number of arguments.
pub min_args: Option<usize>,
/// Accept values and return a result which contains a value.
pub compiled: Box<Fn(Vec<Value>) -> Result<Value, Error> + Sync + Send>
}
impl Function {
/// Create a function with a closure.
pub fn new<F>(closure: F) -> Function where F: 'static + Fn(Vec<Value>) -> Result<Value, Error> + Sync + Send {
Function {
max_args: None,
min_args: None,
compiled: Box::new(closure)
}
}
}
impl fmt::Debug for Function {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Function {{ max_args: {:?}, min_args: {:?} }}", self.max_args, self.min_args)
}
}

540
src/lib.rs Normal file
View File

@ -0,0 +1,540 @@
//! Expression evaluator.
//!
//! Supported operators: `!` `!=` `""` `''` `()` `[]` `,` `>` `<` `>=` `<=`
//! `==` `+` `-` `*` `/` `%` `&&` `||` `n..m`.
//!
//! Built-in functions: `min()` `max()` `is_empty()`.
//!
//! # Examples
//!
//! You can do mathematical calculations with supported operators:
//!
//! ```
//! use eval::{eval, to_value};
//!
//! assert_eq!(eval("1 + 2 + 3"), Ok(to_value(6)));
//! assert_eq!(eval("2 * 2 + 3"), Ok(to_value(7)));
//! assert_eq!(eval("2 / 2 + 3"), Ok(to_value(4.0)));
//! 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};
//!
//! 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)));
//! ```
//!
//! You can eval with functions:
//!
//! ```
//! use eval::{eval_with_functions, Functions, Function, 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!")));
//! ```
//!
//! 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`:
//!
//! ```
//! use eval::{eval, to_value};
//!
//! assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
//!
//! ```
//!
#![recursion_limit="100"]
#![deny(missing_docs)]
#![feature(proc_macro, test)]
extern crate test;
#[macro_use]
extern crate quick_error;
extern crate serde_json;
mod math;
mod function;
mod operator;
mod node;
mod expression;
mod error;
mod builtin;
pub use serde_json::{Value, to_value};
pub use error::Error;
pub use function::Function;
use std::collections::HashMap;
use expression::Expression;
use builtin::BuiltIn;
type ContextsRef<'a> = &'a [Context];
/// Eval context.
pub type Context = HashMap<String, Value>;
/// Eval contexts. The value of the last context is searched first.
pub type Contexts = Vec<Context>;
/// Eval 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())
}
/// 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())
}
/// 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 eval;
use eval_with_context;
use eval_with_functions;
use {Function, Functions};
#[test]
fn test_add() {
assert_eq!(eval("2 + 3"), Ok(to_value(5)));
}
#[test]
fn test_brackets_add() {
assert_eq!(eval("(2 + 3) + (3 + 5)"), Ok(to_value(13)));
}
#[test]
fn test_brackets_float_add() {
assert_eq!(eval("(2 + 3.2) + (3 + 5)"), Ok(to_value(13.2)));
}
#[test]
fn test_brackets_float_mul() {
assert_eq!(eval("(2 + 3.2) * 5"), Ok(to_value(26.0)));
}
#[test]
fn test_brackets_sub() {
assert_eq!(eval("(4 - 3) * 5"), Ok(to_value(5)));
}
#[test]
fn test_useless_brackets() {
assert_eq!(eval("2 + 3 + (5)"), Ok(to_value(10)));
}
#[test]
fn test_error_brackets_not_with_function() {
assert_eq!(eval("5 + ()"), Err(Error::BracketNotWithFunction));
}
#[test]
fn test_deep_brackets() {
assert_eq!(eval("(2 + (3 + 4) + (6 + (6 + 7)) + 5)"), Ok(to_value(33)));
}
#[test]
fn test_brackets_div() {
assert_eq!(eval("(4 / (2 + 2)) * 5"), Ok(to_value(5.0)));
}
#[test]
fn test_min() {
assert_eq!(eval("min(30, 5, 245, 20)"), Ok(to_value(5)));
}
#[test]
fn test_min_brackets() {
assert_eq!(eval("(min(30, 5, 245, 20) * 10 + (5 + 5) * 5)"), Ok(to_value(100)));
}
#[test]
fn test_min_and_mul() {
assert_eq!(eval("min(30, 5, 245, 20) * 10"), Ok(to_value(50)));
}
#[test]
fn test_max() {
assert_eq!(eval("max(30, 5, 245, 20)"), Ok(to_value(245)));
}
#[test]
fn test_max_brackets() {
assert_eq!(eval("(max(30, 5, 245, 20) * 10 + (5 + 5) * 5)"), Ok(to_value(2500)));
}
#[test]
fn test_max_and_mul() {
assert_eq!(eval("max(30, 5, 245, 20) * 10"), Ok(to_value(2450)));
}
#[test]
fn test_brackets_1() {
assert_eq!(eval("(5) + (min(3, 4, 5)) + 20"), Ok(to_value(28)));
}
#[test]
fn test_brackets_2() {
assert_eq!(eval("(((5) / 5))"), Ok(to_value(1.0)));
}
#[test]
fn test_string_add() {
assert_eq!(eval(r#""Hello"+", world!""#), Ok(to_value("Hello, world!")));
}
#[test]
fn test_equal() {
assert_eq!(eval("1 == 1"), Ok(to_value(true)));
}
#[test]
fn test_not_equal() {
assert_eq!(eval("1 != 2"), Ok(to_value(true)));
}
#[test]
fn test_multiple_equal() {
assert_eq!(eval("(1 == 2) == (2 == 3)"), Ok(to_value(true)));
}
#[test]
fn test_multiple_not_equal() {
assert_eq!(eval("(1 != 2) == (2 != 3)"), Ok(to_value(true)));
}
#[test]
fn test_greater_than() {
assert_eq!(eval("1 > 2"), Ok(to_value(false)));
assert_eq!(eval("2 > 1"), Ok(to_value(true)));
}
#[test]
fn test_less_than() {
assert_eq!(eval("2 < 1"), Ok(to_value(false)));
assert_eq!(eval("1 < 2"), Ok(to_value(true)));
}
#[test]
fn test_greater_and_less() {
assert_eq!(eval("(2 > 1) == (1 < 2)"), Ok(to_value(true)));
}
#[test]
fn test_ge() {
assert_eq!(eval("2 >= 1"), Ok(to_value(true)));
assert_eq!(eval("2 >= 2"), Ok(to_value(true)));
assert_eq!(eval("2 >= 3"), Ok(to_value(false)));
}
#[test]
fn test_le() {
assert_eq!(eval("2 <= 1"), Ok(to_value(false)));
assert_eq!(eval("2 <= 2"), Ok(to_value(true)));
assert_eq!(eval("2 <= 3"), Ok(to_value(true)));
}
#[test]
fn test_quotes() {
assert_eq!(eval(r#""1><2" + "3<>4""#), Ok(to_value("1><23<>4")));
assert_eq!(eval(r#""1==2" + "3--4""#), Ok(to_value("1==23--4")));
assert_eq!(eval(r#""1!=2" + "3>>4""#), Ok(to_value("1!=23>>4")));
assert_eq!(eval(r#""><1!=2" + "3>>4""#), Ok(to_value("><1!=23>>4")));
}
#[test]
fn test_single_quote() {
assert_eq!(eval(r#"'1><2' + '3<>4'"#), Ok(to_value("1><23<>4")));
assert_eq!(eval(r#"'1==2' + '3--4'"#), Ok(to_value("1==23--4")));
assert_eq!(eval(r#"'1!=2' + '3>>4'"#), Ok(to_value("1!=23>>4")));
assert_eq!(eval(r#"'!=1<>2' + '3>>4'"#), Ok(to_value("!=1<>23>>4")));
}
#[test]
fn test_single_and_double_quote() {
assert_eq!(eval(r#"' """" ' + ' """" '"#), Ok(to_value(r#" """" """" "#)));
}
#[test]
fn test_double_and_single_quote() {
assert_eq!(eval(r#"" '''' " + " '''' ""#), Ok(to_value(r#" '''' '''' "#)));
}
#[test]
fn test_array() {
assert_eq!(eval("[1, 2, 3, 4]"), Ok(to_value(vec![1, 2, 3, 4])));
assert_eq!(eval("array(1, 2, 3, 4)"), Ok(to_value(vec![1, 2, 3, 4])));
}
#[test]
fn test_array_ident() {
assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4])));
}
#[test]
fn test_array_ident_and_min() {
assert_eq!(eval("min(0..5)"), Ok(to_value(0)));
}
#[test]
fn test_rem_1() {
assert_eq!(eval("2 % 2"), Ok(to_value(0)));
}
#[test]
fn test_rem_2() {
assert_eq!(eval("5 % 56 % 5"), Ok(to_value(0)));
}
#[test]
fn test_rem_3() {
assert_eq!(eval("5.5 % 23"), Ok(to_value(5.5)));
}
#[test]
fn test_rem_4() {
assert_eq!(eval("23 % 5.5"), Ok(to_value(1.0)));
}
#[test]
fn test_and_1() {
assert_eq!(eval("3 > 2 && 2 > 1"), Ok(to_value(true)));
}
#[test]
fn test_and_2() {
assert_eq!(eval("3 == 2 && 2 == 1"), Ok(to_value(false)));
}
#[test]
fn test_and_3() {
assert_eq!(eval("3 > 2 && 2 == 1"), Ok(to_value(false)));
}
#[test]
fn test_or_1() {
assert_eq!(eval("3 > 2 || 2 > 1"), Ok(to_value(true)));
}
#[test]
fn test_or_2() {
assert_eq!(eval("3 < 2 || 2 < 1"), Ok(to_value(false)));
}
#[test]
fn test_or_3() {
assert_eq!(eval("3 > 2 || 2 < 1"), Ok(to_value(true)));
}
#[test]
fn test_or_4() {
assert_eq!(eval("3 < 2 || 2 > 1"), Ok(to_value(true)));
}
#[test]
fn test_not() {
assert_eq!(eval("!false"), Ok(to_value(true)));
assert_eq!(eval("!true"), Ok(to_value(false)));
assert_eq!(eval("!(1 != 2)"), Ok(to_value(false)));
assert_eq!(eval("!(1 == 2)"), Ok(to_value(true)));
assert_eq!(eval("!(1 == 2) == true"), Ok(to_value(true)));
}
#[test]
fn test_not_and_brackets() {
assert_eq!(eval("(!(1 == 2)) == true"), Ok(to_value(true)));
}
#[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), 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)));
}
#[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), 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
};
expr.parse_pos().unwrap();
expr.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::StartWithNonValueOperator));
}
#[test]
fn test_error_duplicate_operator() {
let mut expr = Expression {
raw: "5 + + 5".to_owned(),
..Default::default()
};
expr.parse_pos().unwrap();
expr.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::DuplicateOperatorNode));
}
#[test]
fn test_error_duplicate_value() {
let mut expr = Expression {
raw: "2 + 6 5".to_owned(),
..Default::default()
};
expr.parse_pos().unwrap();
expr.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::DuplicateValueNode));
}
#[test]
fn test_error_unpaired_brackets() {
let mut expr = Expression {
raw: "(2 + 3)) * 5".to_owned(),
..Default::default()
};
expr.parse_pos().unwrap();
assert_eq!(expr.parse_operators(), Err(Error::UnpairedBrackets));
}
#[test]
fn test_error_comma() {
let mut expr = Expression {
raw: ", 2 + 5".to_owned(),
..Default::default()
};
expr.parse_pos().unwrap();
expr.parse_operators().unwrap();
assert_eq!(expr.parse_node(), Err(Error::CommaNotWithFunction));
}
#[bench]
fn bench_deep_brackets(b: &mut test::Bencher) {
b.iter(|| eval("(2 + (3 + 4) + (6 + (6 + 7)) + 5)"));
}
#[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()
};
b.iter(|| expr.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()
};
expr.parse_pos().unwrap();
b.iter(|| expr.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()
};
expr.parse_pos().unwrap();
expr.parse_operators().unwrap();
b.iter(|| expr.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()
};
expr.parse_pos().unwrap();
expr.parse_operators().unwrap();
expr.parse_node().unwrap();
b.iter(|| expr.compile());
}
#[bench]
fn bench_eval(b: &mut test::Bencher) {
b.iter(|| eval("(2 + (3 + 4) + (6 + (6 + 7)) + 5)"));
}
}

195
src/math/mod.rs Normal file
View File

@ -0,0 +1,195 @@
use serde_json::{Value, to_value};
use error::Error;
pub trait Math {
fn add(&self, &Value) -> Result<Value, Error>;
fn mul(&self, &Value) -> Result<Value, Error>;
fn sub(&self, &Value) -> Result<Value, Error>;
fn div(&self, &Value) -> Result<Value, Error>;
fn rem(&self, &Value) -> Result<Value, Error>;
fn eq(&self, &Value) -> Result<Value, Error>;
fn ne(&self, &Value) -> Result<Value, Error>;
fn gt(&self, &Value) -> Result<Value, Error>;
fn lt(&self, &Value) -> Result<Value, Error>;
fn ge(&self, &Value) -> Result<Value, Error>;
fn le(&self, &Value) -> Result<Value, Error>;
fn and(&self, &Value) -> Result<Value, Error>;
fn or(&self, &Value) -> Result<Value, Error>;
}
impl Math for Value {
fn add(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
Ok(to_value(self.get_f64() + value.get_f64()))
} else if self.is_i64() || value.is_i64() {
Ok(to_value(self.get_i64() + value.get_i64()))
} else {
Ok(to_value(self.get_u64() + value.get_u64()))
}
} else if self.is_string() && value.is_string() {
Ok(to_value(self.get_string() + value.get_str()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn mul(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
Ok(to_value(self.get_f64() * value.get_f64()))
} else if self.is_i64() || value.is_i64() {
Ok(to_value(self.get_i64() * value.get_i64()))
} else {
Ok(to_value(self.get_u64() * value.get_u64()))
}
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn sub(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
Ok(to_value(self.get_f64() - value.get_f64()))
} else {
Ok(to_value(self.get_i64() - value.get_i64()))
}
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn div(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() / value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn rem(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
Ok(to_value(self.get_f64() % value.get_f64()))
} else if self.is_i64() || value.is_i64() {
Ok(to_value(self.get_i64() % value.get_i64()))
} else {
Ok(to_value(self.get_u64() % value.get_u64()))
}
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn eq(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() == value.get_f64()))
} else {
Ok(to_value(self == value))
}
}
fn ne(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() != value.get_f64()))
} else {
Ok(to_value(self != value))
}
}
fn gt(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() > value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn lt(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() < value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn ge(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() >= value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn le(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() <= value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn and(&self, value: &Value) -> Result<Value, Error> {
if self.is_boolean() && value.is_boolean() {
Ok(to_value(self.get_boolean() && value.get_boolean()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn or(&self, value: &Value) -> Result<Value, Error> {
if self.is_boolean() && value.is_boolean() {
Ok(to_value(self.get_boolean() || value.get_boolean()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
}
trait Type {
fn get_f64(&self) -> f64;
fn get_string(&self) -> String;
fn get_str(&self) -> &str;
fn get_u64(&self) -> u64;
fn get_i64(&self) -> i64;
fn get_boolean(&self) -> bool;
fn format(&self) -> String;
}
impl Type for Value {
fn get_f64(&self) -> f64 {
match *self {
Value::F64(f) => f,
Value::I64(f) => f as f64,
Value::U64(f) => f as f64,
_ => panic!("not a number")
}
}
fn get_string(&self) -> String {
self.as_str().unwrap().to_owned()
}
fn get_str(&self) -> &str {
self.as_str().unwrap()
}
fn get_u64(&self) -> u64 {
self.as_u64().unwrap()
}
fn get_i64(&self) -> i64 {
self.as_i64().unwrap()
}
fn get_boolean(&self) -> bool {
self.as_bool().unwrap()
}
fn format(&self) -> String {
format!("{:?}", self)
}
}

86
src/node/mod.rs Normal file
View File

@ -0,0 +1,86 @@
use operator::Operator;
use error::Error;
use Function;
#[derive(Debug, Clone, PartialEq)]
pub struct Node {
pub operator: Operator,
pub children: Vec<Node>,
pub closed: bool
}
impl Node {
pub fn new(operator: Operator) -> Node {
Node {
operator: operator,
children: Vec::new(),
closed: false
}
}
pub fn check_function_args(&self, function: &Function) -> Result<(), Error> {
let args_length = self.children.len();
if let Some(len) = function.max_args {
if args_length > len {
return Err(Error::ArgumentsGreater(len));
}
}
if let Some(len) = function.min_args {
if args_length < len {
return Err(Error::ArgumentsLess(len));
}
}
Ok(())
}
pub fn is_enough(&self) -> bool {
let num = self.operator.get_max_args();
if num.is_none() {
false
} else {
self.children.len() == num.unwrap()
}
}
pub fn is_value_or_enough(&self) -> bool {
if self.operator.is_value_or_ident() {
true
} else if self.operator.can_have_child() {
if self.closed {
true
} else {
self.is_enough()
}
} else {
false
}
}
pub fn is_unclosed_function(&self) -> bool {
match self.operator {
Operator::Function(_) => ! self.closed,
_ => false
}
}
pub fn add_child(&mut self, node: Node) {
self.children.push(node);
}
pub fn get_first_child(&self) -> Node {
self.children.first().unwrap().clone()
}
pub fn get_last_child(&self) -> Node {
self.children.last().unwrap().clone()
}
pub fn moveout_last_node(&mut self) -> Node {
self.children.pop().unwrap()
}
}

192
src/operator/mod.rs Normal file
View File

@ -0,0 +1,192 @@
use std::str::FromStr;
use serde_json::{Value, to_value};
use error::Error;
use node::Node;
#[derive(Debug, Clone, PartialEq)]
pub enum Operator {
Add(u8),
Mul(u8),
Sub(u8),
Div(u8),
Rem(u8),
Not(u8),
Eq(u8),
Ne(u8),
Gt(u8),
Lt(u8),
Ge(u8),
Le(u8),
And(u8),
Or(u8),
LeftParenthesis,
RightParenthesis,
LeftSquareBracket,
RightSquareBracket,
DoubleQuotes,
SingleQuote,
WhiteSpace,
Comma,
Function(String),
Identifier(String),
Value(Value)
}
impl Operator {
pub fn is_identifier(&self) -> bool {
match *self {
Operator::Identifier(_) => true,
_ => false
}
}
pub fn can_at_beginning(&self) -> bool {
match *self {
Operator::Not(_) | Operator::Function(_) | Operator::LeftParenthesis => true,
_ => false
}
}
pub fn get_max_args(&self) -> Option<usize> {
match *self {
Operator::Add(_) | Operator::Sub(_) |
Operator::Mul(_) | Operator::Div(_) |
Operator::Eq(_) | Operator::Ne(_) |
Operator::Gt(_) | Operator::Lt(_) |
Operator::Ge(_) | Operator::Le(_) |
Operator::And(_) | Operator::Or(_) |
Operator::Rem(_)=> Some(2),
Operator::Not(_) => Some(1),
Operator::Function(_) => None,
_ => Some(0)
}
}
pub fn get_min_args(&self) -> Option<usize> {
match *self {
Operator::Add(_) | Operator::Sub(_) |
Operator::Mul(_) | Operator::Div(_) |
Operator::Eq(_) | Operator::Ne(_) |
Operator::Gt(_) | Operator::Lt(_) |
Operator::Ge(_) | Operator::Le(_) |
Operator::And(_) | Operator::Or(_) |
Operator::Rem(_) => Some(2),
Operator::Not(_) => Some(1),
Operator::Function(_) => None,
_ => Some(0)
}
}
pub fn get_priority(&self) -> u8 {
match *self {
Operator::Add(priority) | Operator::Sub(priority) |
Operator::Div(priority) | Operator::Mul(priority) |
Operator::Eq(priority) | Operator::Ne(priority) |
Operator::Gt(priority) | Operator::Lt(priority) |
Operator::Ge(priority) | Operator::Le(priority) |
Operator::And(priority) | Operator::Or(priority) |
Operator::Rem(priority) => priority,
Operator::Value(_) | Operator::Identifier(_) => 0,
_ => 99
}
}
pub fn is_left_parenthesis(&self) -> bool {
*self == Operator::LeftParenthesis
}
pub fn is_not(&self) -> bool {
match *self {
Operator::Not(_) => true,
_ => false
}
}
pub fn is_value_or_ident(&self) -> bool {
match *self {
Operator::Value(_) | Operator::Identifier(_) => true,
_ => false
}
}
pub fn can_have_child(&self) -> bool {
match *self {
Operator::Function(_) | Operator::Add(_) |
Operator::Sub(_) | Operator::Div(_) |
Operator::Mul(_) | Operator::Rem(_) |
Operator::Eq(_) | Operator::Ne(_) |
Operator::Gt(_) | Operator::Lt(_) |
Operator::And(_) | Operator::Or(_) |
Operator::Ge(_) | Operator::Le(_) => true,
_ => false
}
}
pub fn is_left(&self) -> bool {
match *self {
Operator::LeftParenthesis | Operator::LeftSquareBracket => true,
_ => false
}
}
pub fn get_left(&self) -> Operator {
match *self {
Operator::RightParenthesis => Operator::LeftParenthesis,
Operator::RightSquareBracket => Operator::LeftSquareBracket,
_ => panic!("not bracket")
}
}
pub fn to_node(&self) -> Node {
Node::new(self.clone())
}
pub fn children_to_node(&self, children: Vec<Node>) -> Node {
let mut node = self.to_node();
node.children = children;
node
}
pub fn get_identifier(&self) -> String {
match *self {
Operator::Identifier(ref ident) => ident.to_owned(),
_ => panic!("not identifier")
}
}
}
impl FromStr for Operator {
type Err = Error;
fn from_str(raw: &str) -> Result<Operator, Error> {
match raw {
"+" => Ok(Operator::Add(8)),
"-" => Ok(Operator::Sub(8)),
"*" => Ok(Operator::Mul(10)),
"/" => Ok(Operator::Div(10)),
"%" => Ok(Operator::Rem(10)),
"(" => Ok(Operator::LeftParenthesis),
")" => Ok(Operator::RightParenthesis),
"[" => Ok(Operator::LeftSquareBracket),
"]" => Ok(Operator::RightSquareBracket),
"\"" => Ok(Operator::DoubleQuotes),
"'" => Ok(Operator::SingleQuote),
" " => Ok(Operator::WhiteSpace),
"," => Ok(Operator::Comma),
"!" => Ok(Operator::Not(99)),
"false" => Ok(Operator::Value(to_value(false))),
"true" => Ok(Operator::Value(to_value(true))),
"==" => Ok(Operator::Eq(6)),
"!=" => Ok(Operator::Ne(6)),
">" => Ok(Operator::Gt(6)),
"<" => Ok(Operator::Lt(6)),
">=" => Ok(Operator::Ge(6)),
"<=" => Ok(Operator::Le(6)),
"&&" => Ok(Operator::And(4)),
"||" => Ok(Operator::Or(2)),
_ => Ok(Operator::Identifier(raw.to_owned()))
}
}
}