From b38c102c1d07d81db7856bced8180a2bdcf781b7 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Fri, 15 Mar 2019 17:11:31 +0200 Subject: [PATCH] Complete rewrite of crate. Simple tokenizer and treeifyer (Or however the compiler people call these.). --- rustfmt.toml | 5 + src/builtin/mod.rs | 200 ----------- src/configuration/mod.rs | 13 + src/error/mod.rs | 139 +++----- src/expr/mod.rs | 152 -------- src/function/mod.rs | 37 -- src/lib-old.rs | 692 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 700 +------------------------------------ src/math/mod.rs | 206 ----------- src/node/mod.rs | 107 ------ src/operator/mod.rs | 367 ++++++++------------ src/reboot/mod.rs | 0 src/token/mod.rs | 82 +++++ src/tree/mod.rs | 729 +++++---------------------------------- src/value/mod.rs | 6 + 15 files changed, 1097 insertions(+), 2338 deletions(-) create mode 100644 rustfmt.toml delete mode 100644 src/builtin/mod.rs create mode 100644 src/configuration/mod.rs delete mode 100644 src/expr/mod.rs delete mode 100644 src/function/mod.rs create mode 100644 src/lib-old.rs delete mode 100644 src/math/mod.rs delete mode 100644 src/node/mod.rs delete mode 100644 src/reboot/mod.rs create mode 100644 src/token/mod.rs create mode 100644 src/value/mod.rs diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..966d4aa --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,5 @@ +edition = "2018" +reorder_imports=true +reorder_modules=true +format_strings=true +merge_imports=true \ No newline at end of file diff --git a/src/builtin/mod.rs b/src/builtin/mod.rs deleted file mode 100644 index 60f0156..0000000 --- a/src/builtin/mod.rs +++ /dev/null @@ -1,200 +0,0 @@ - -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("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.insert("converge".to_owned(), create_converge_function()); - functions - } -} - -fn expect_number_f64(value: &Value) -> Result { - if let Some(number) = value.as_f64() { - Ok(number) - } else { - Err(Error::Custom(format!("Expected number that can be represented as f64. But the given is: {:?}", value))) - } -} - -fn expect_normal_f64(number: f64) -> Result { - if number.is_normal() { - Ok(number) - } else { - Err(Error::Custom(format!("Expected normal number. But the given is: {:?}", number))) - } -} - -fn expect_finite_f64(number: f64) -> Result { - if number.is_finite() { - Ok(number) - } else { - Err(Error::Custom(format!("Expected finite number. But the given is: {:?}", number))) - } -} - -#[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 = 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(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))) - } - } - }), - } -} - -fn create_array_function() -> Function { - Function::new(|values| Ok(to_value(values))) -} - -/// Converges exponentially agains `conv_y`, starting from `start_y`. -/// The first four parameters parameterize a function `f`, the last one is the `x`-value where the function should be evaluated. -/// The result of the call is `f(x)`. -/// -/// The parameters `start_x` and `start_y` set the starting point of the function. -/// It holds that `f(start_x) = start_y`. -/// The parameter `conv_y` is the convergence target value. -/// It is never reached (assuming no numerical errors). -/// The parameter `step_x` is the "speed" of the convergence, that is how fast the function converges against `conv_y`. -/// In detail, the absolute difference between `start_y` and `conv_y` halves if `x` is increased by `step_x`. -/// -/// All parameters are expected to be numbers. -/// The parameters `start_x`, `start_y` and `conv_y` are expected to be finite. -/// The parameter `step_x` is expected to be `normal`. -/// -/// # Examples -/// -/// The function `2^(-x)` is expressed as `conv(0, 1, 1, 0, x)`. -/// This is the same as `converge(1, 0.5, 1, 0, x)`. -fn create_converge_function() -> Function { - Function { - max_args: Some(5), - min_args: Some(5), - compiled: Box::new(|values| { - let start_x = expect_finite_f64(expect_number_f64(&values[0])?)?; - let start_y = expect_finite_f64(expect_number_f64(&values[1])?)?; - let step_x = expect_normal_f64(expect_number_f64(&values[2])?)?; - let conv_y = expect_finite_f64(expect_number_f64(&values[3])?)?; - let x = expect_number_f64(&values[4])?; - - let units = (x - start_x) / step_x; - let interpolation_factor = 2.0_f64.powf(-units); - Ok(to_value(interpolation_factor * start_y + (1.0 - interpolation_factor) * conv_y)) - }), - } -} - -#[cfg(test)] -mod test { - use crate::{Expr, to_value}; - - #[test] - fn test_conv() { - let valid_test_cases = vec![ - ("converge(0, 4, 10, 0, 0)", "4.0"), - ("converge(0, 4, 10, 0, 10)", "2.0"), - ("converge(0, 4, 10, 0, 5)", "2.8284271247461900976033774484193961571393437507538961"), - ("converge(0, 4, 10, 0, 20)", "1.0"), - ("converge(0, 4, 10, 0, 0-10)", "8.0"), - ]; - - for (term, result) in valid_test_cases { - assert_eq!(Expr::new(format!("({term} < {result} * 1.0001) && ({term} > {result} / 1.0001)", term = term, result = result)).exec(), Ok(to_value(true))); - } - } -} \ No newline at end of file diff --git a/src/configuration/mod.rs b/src/configuration/mod.rs new file mode 100644 index 0000000..730a413 --- /dev/null +++ b/src/configuration/mod.rs @@ -0,0 +1,13 @@ +use crate::{error::Error, value::Value}; + +pub trait Configuration { + fn get_value(&self, identifier: &str) -> Result; +} + +pub struct EmptyConfiguration; + +impl Configuration for EmptyConfiguration { + fn get_value(&self, identifier: &str) -> Result { + Err(Error::IdentifierNotFound) + } +} diff --git a/src/error/mod.rs b/src/error/mod.rs index 0be42d1..320add2 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -1,95 +1,54 @@ +use crate::value::Value; -use serde_json::Value; -use operator::Operator; +#[derive(Debug, PartialEq)] +pub enum Error { + WrongArgumentAmount { + expected: usize, + actual: usize, + }, + ExpectedNumber { + actual: Value, + }, + /// The given expression is empty + EmptyExpression, -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 a boolean but the given value isn't. - ExpectedBoolean(value: Value) { - display("Expected a boolean, found: {}", value) - } - /// Expected ident. - ExpectedIdentifier { - display("Expected ident.") - } - /// Expected array. - ExpectedArray { - display("Expected array.") - } - /// Expected object. - ExpectedObject { - display("Expected object.") - } - /// Expect number. - ExpectedNumber { - display("Expected number.") - } - /// 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 range expression like `1..2..3` - InvalidRange(ident: String) { - display("Invalid range expression: {}", ident) - } - /// Can not add child node. - CanNotAddChild { - display("Can not add child node.") - } - /// Custom error. - Custom(detail: String) { - display("{}", detail) - } + /// Tried to evaluate the root node. + /// The root node should only be used as dummy node. + EvaluatedRootNode, + + /// Tried to append a child to a leaf node. + /// Leaf nodes cannot have children. + AppendedToLeafNode, + + /// Tried to append a child to a node such that the precedence of the child is not higher. + PrecedenceViolation, + + /// An identifier operation did not find its value in the configuration. + IdentifierNotFound, +} + +impl Error { + pub fn wrong_argument_amount(actual: usize, expected: usize) -> Self { + Error::WrongArgumentAmount { actual, expected } + } + + pub fn expected_number(actual: Value) -> Self { + Error::ExpectedNumber { actual } + } +} + +pub fn expect_argument_amount(actual: usize, expected: usize) -> Result<(), Error> { + if actual == expected { + Ok(()) + } else { + Err(Error::wrong_argument_amount(actual, expected)) + } +} + +pub fn expect_number(actual: &Value) -> Result { + match actual { + Value::Number(number) => Ok(*number), + _ => Err(Error::expected_number(actual.clone())), } } diff --git a/src/expr/mod.rs b/src/expr/mod.rs deleted file mode 100644 index c79e99e..0000000 --- a/src/expr/mod.rs +++ /dev/null @@ -1,152 +0,0 @@ - -use {Function, Functions, Context, Contexts, Compiled, Value}; -use tree::Tree; -use error::Error; -use serde::Serialize; -use to_value; -use std::fmt; - - -/// Expression builder -pub struct Expr { - expression: String, - compiled: Option, - functions: Functions, - contexts: Contexts, -} - -impl Expr { - /// Create an expression. - pub fn new>(expr: T) -> Expr { - Expr { - expression: expr.into(), - compiled: None, - functions: Functions::new(), - contexts: create_empty_contexts(), - } - } - - /// Set function. - pub fn function(mut self, name: T, function: F) -> Expr - where T: Into, - F: 'static + Fn(Vec) -> Result + Sync + Send - { - self.functions.insert(name.into(), Function::new(function)); - self - } - - /// Set value. - pub fn value(mut self, name: T, value: V) -> Expr - where T: Into, - V: Serialize - { - self.contexts.last_mut().unwrap().insert(name.into(), to_value(value)); - self - } - - /// Compile an expression. - /// An expression can be compiled only once and then invoked multiple times with different context and function. - /// You can also execute a expression without compile. - pub fn compile(mut self) -> Result { - self.compiled = Some(Tree::new(self.expression.clone()).compile()?); - Ok(self) - } - - /// Execute the expression. - pub fn exec(&self) -> Result { - if self.compiled.is_none() { - Tree::new(self.expression.clone()).compile()?(&self.contexts, &self.functions) - } else { - self.compiled.as_ref().unwrap()(&self.contexts, &self.functions) - } - } - - fn get_compiled(&self) -> Option<&Compiled> { - self.compiled.as_ref() - } -} - -impl Clone for Expr { - /// Returns a copy of the value. Notice that functions can not be cloned. The cloned expr's functions will be empty. - fn clone(&self) -> Expr { - Expr { - expression: self.expression.clone(), - compiled: if self.compiled.is_some() { - Some(Tree::new(self.expression.clone()).compile().unwrap()) - } else { - None - }, - contexts: self.contexts.clone(), - functions: Functions::new(), - } - } -} - -impl fmt::Debug for Expr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(formatter, "{:?}", self.expression) - } -} - - -/// Execute options -pub struct ExecOptions<'a> { - expr: &'a Expr, - contexts: Option<&'a [Context]>, - functions: Option<&'a Functions>, -} - -impl<'a> ExecOptions<'a> { - /// Create an option. - pub fn new(expr: &'a Expr) -> ExecOptions<'a> { - ExecOptions { - expr: expr, - contexts: None, - functions: None, - } - } - - /// Set contexts. - pub fn contexts(&mut self, contexts: &'a [Context]) -> &'a mut ExecOptions { - self.contexts = Some(contexts); - self - } - - /// Set functions. - pub fn functions(&mut self, functions: &'a Functions) -> &'a mut ExecOptions { - self.functions = Some(functions); - self - } - - /// Execute the compiled expression. - pub fn exec(&self) -> Result { - let empty_contexts = create_empty_contexts(); - let empty_functions = Functions::new(); - - let contexts = if self.contexts.is_some() { - self.contexts.unwrap() - } else { - &empty_contexts - }; - - let functions = if self.functions.is_some() { - self.functions.unwrap() - } else { - &empty_functions - }; - - let compiled = self.expr.get_compiled(); - if compiled.is_none() { - Tree::new(self.expr.expression.clone()).compile()?(contexts, functions) - } else { - compiled.unwrap()(contexts, functions) - } - } -} - - -fn create_empty_contexts() -> Contexts { - let mut contexts = Contexts::new(); - contexts.push(Context::new()); - contexts -} diff --git a/src/function/mod.rs b/src/function/mod.rs deleted file mode 100644 index c6ce043..0000000 --- a/src/function/mod.rs +++ /dev/null @@ -1,37 +0,0 @@ - -use std::fmt; -use serde_json::Value; -use error::Error; - - -/// Custom function -pub struct Function { - /// Maximum number of arguments. - pub max_args: Option, - /// Minimum number of arguments. - pub min_args: Option, - /// Accept values and return a result which contains a value. - pub compiled: Box) -> Result + Sync + Send>, -} - -impl Function { - /// Create a function with a closure. - pub fn new(closure: F) -> Function - where F: 'static + Fn(Vec) -> Result + 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) - } -} diff --git a/src/lib-old.rs b/src/lib-old.rs new file mode 100644 index 0000000..cd48851 --- /dev/null +++ b/src/lib-old.rs @@ -0,0 +1,692 @@ +//! Eval is a powerful expression evaluator. +//! +//! Supported operators: `!` `!=` `""` `''` `()` `[]` `.` `,` `>` `<` `>=` `<=` +//! `==` `+` unary/binary `-` `*` `/` `%` `&&` `||` `n..m`. +//! +//! Built-in functions: `min()` `max()` `len()` `is_empty()` `array()` `converge()`. +//! +//! ## Examples +//! +//! You can do mathematical calculations with supported operators: +//! +//! ``` +//! use evalexpr::{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 evalexpr::{Expr, to_value}; +//! +//! assert_eq!(Expr::new("foo == bar") +//! .value("foo", true) +//! .value("bar", true) +//! .exec(), +//! Ok(to_value(true))); +//! ``` +//! +//! You can access data like javascript by using `.` and `[]`. `[]` supports expression. +//! +//! ``` +//! use evalexpr::{Expr, to_value}; +//! use std::collections::HashMap; +//! +//! let mut object = HashMap::new(); +//! object.insert("foos", vec!["Hello", "world", "!"]); +//! +//! assert_eq!(Expr::new("object.foos[2-1] == 'world'") // Access field `foos` and index `2-1` +//! .value("object", object) +//! .exec(), +//! Ok(to_value(true))); +//! ``` +//! +//! You can eval with function: +//! +//! ``` +//! use evalexpr::{Expr, to_value}; +//! +//! 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 `array()`: +//! +//! ``` +//! use evalexpr::{eval, to_value}; +//! +//! assert_eq!(eval("array(1, 2, 3, 4, 5)"), Ok(to_value(vec![1, 2, 3, 4, 5]))); +//! ``` +//! +//! You can create an integer array with `n..m`: +//! +//! ``` +//! use evalexpr::{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 a boolean. Check whether the value is empty or not. +//! +//! ### array() +//! Accept multiple arguments and return an array. +//! +//! ### converge() +//! See `builtin::create_converge_function()`. +//! +//! +#![recursion_limit="100"] +#![deny(missing_docs)] +#![cfg_attr(all(feature = "unstable", test), feature(test))] + +#[macro_use] +extern crate quick_error; +extern crate serde; +extern crate serde_json; + +mod math; +mod function; +mod operator; +mod node; +mod tree; +mod error; +mod builtin; +mod expr; + +mod reboot; + +pub use expr::ExecOptions; +pub use serde_json::Value; +pub use error::Error; +pub use function::Function; +pub use expr::Expr; + +use std::collections::HashMap; +use serde_json::to_value as json_to_value; +use serde::Serialize; + +/// Convert variable to `serde_json::Value` +pub fn to_value(v: S) -> Value { + json_to_value(v).unwrap() +} + +/// Custom context. +pub type Context = HashMap; +/// Custom contexts. The value of the last context is searched first. +pub type Contexts = Vec; +/// Custom functions. +pub type Functions = HashMap; + +/// Evaluates the value of an expression. +pub fn eval(expr: &str) -> Result { + Expr::new(expr).compile()?.exec() +} + + +type Compiled = Box Result>; + + + +#[cfg(test)] +mod tests { + use to_value; + use error::Error; + use Expr; + use tree::Tree; + use Value; + use eval; + use std::collections::HashMap; + + #[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_len_array() { + assert_eq!(eval("len(array(2, 3, 4, 5, 6))"), Ok(to_value(5))); + } + + #[test] + fn test_null_and_number() { + assert_eq!(eval("hos != 0"), Ok(to_value(true))); + assert_eq!(eval("hos > 0"), Ok(to_value(false))); + } + + #[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))); + } + + #[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("array(1, 2, 3, 4)"), Ok(to_value(vec![1, 2, 3, 4]))); + } + + #[test] + fn test_range() { + assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4]))); + } + + #[test] + fn test_range_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_object_access() { + let mut object = HashMap::new(); + object.insert("foo", "Foo, hello world!"); + object.insert("bar", "Bar, hello world!"); + assert_eq!( + Expr::new("object.foo == 'Foo, hello world!'") + .value("object", object) + .exec(), + Ok(to_value(true)) + ); + } + + #[test] + fn test_object_dynamic_access() { + let mut object = HashMap::new(); + object.insert("foo", "Foo, hello world!"); + object.insert("bar", "Bar, hello world!"); + assert_eq!( + Expr::new("object['foo'] == 'Foo, hello world!'") + .value("object", object) + .exec(), + Ok(to_value(true)) + ); + } + + #[test] + fn test_object_dynamic_access_2() { + let mut object = HashMap::new(); + object.insert("foo", "Foo, hello world!"); + object.insert("bar", "Bar, hello world!"); + assert_eq!( + Expr::new("object[foo] == 'Foo, hello world!'") + .value("object", object) + .value("foo", "foo") + .exec(), + Ok(to_value(true)) + ); + } + + #[test] + fn test_path() { + assert_eq!(Expr::new("array[2-2].foo[2-2]").exec(), Ok(Value::Null)); + } + + #[test] + fn test_array_access() { + let array = vec!["hello", "world", "!"]; + assert_eq!( + Expr::new( + "array[1-1] == 'hello' && array[1] == 'world' && array[2] == '!'", + ).value("array", array) + .exec(), + Ok(to_value(true)) + ); + } + + #[test] + fn test_builtin_is_empty() { + assert_eq!( + Expr::new("is_empty(array)") + .value("array", Vec::::new()) + .exec(), + Ok(to_value(true)) + ); + } + + #[test] + fn test_builtin_min() { + assert_eq!( + Expr::new("min(array)") + .value("array", vec![23, 34, 45, 2]) + .exec(), + Ok(to_value(2)) + ); + } + + #[test] + fn test_custom_function() { + assert_eq!( + Expr::new("output()") + .function( + "output", + |_| Ok(to_value("This is custom function's output")), + ) + .exec(), + Ok(to_value("This is custom function's output")) + ); + } + + #[test] + fn test_error_start_with_non_value_operator() { + let mut tree = Tree { + raw: "+ + 5".to_owned(), + ..Default::default() + }; + + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); + + assert_eq!(tree.parse_node(), Err(Error::StartWithNonValueOperator)); + } + + #[test] + fn test_error_duplicate_operator() { + let mut tree = Tree { + raw: "5 + + 5".to_owned(), + ..Default::default() + }; + + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); + + assert_eq!(tree.parse_node(), Err(Error::DuplicateOperatorNode)); + } + + #[test] + fn test_error_duplicate_value() { + let mut tree = Tree { + raw: "2 + 6 5".to_owned(), + ..Default::default() + }; + + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); + + assert_eq!(tree.parse_node(), Err(Error::DuplicateValueNode)); + } + + #[test] + fn test_error_unpaired_brackets() { + let mut tree = Tree { + raw: "(2 + 3)) * 5".to_owned(), + ..Default::default() + }; + + tree.parse_pos().unwrap(); + + assert_eq!(tree.parse_operators(), Err(Error::UnpairedBrackets)); + } + + #[test] + fn test_error_comma() { + let mut tree = Tree { + raw: ", 2 + 5".to_owned(), + ..Default::default() + }; + + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); + + assert_eq!(tree.parse_node(), Err(Error::CommaNotWithFunction)); + } + + #[test] + fn test_eval_issue_2() { + assert_eq!(eval("2 * (4 + 0) + 4"), Ok(to_value(12))); + assert_eq!(eval("2 * (2 + 2) + (1 + 3)"), Ok(to_value(12))); + assert_eq!(eval("2 * (4) + (4)"), Ok(to_value(12))); + } + + #[test] + fn test_unary_minus() { + assert_eq!(eval("3 + -4"), Ok(to_value(-1))); + assert_eq!(eval("3+-4"), Ok(to_value(-1))); + assert_eq!(eval("true && !false"), Ok(to_value(true))); + assert_eq!(eval("!true || !true"), Ok(to_value(false))); + assert_eq!(eval("-5 + -4"), Ok(to_value(-9))); + assert_eq!(eval("-3-4"), Ok(to_value(-7))); + } +} + +#[cfg(all(feature = "unstable", test))] +mod benches { + extern crate test; + use eval; + use tree::Tree; + use Expr; + + #[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 tree = Tree { + raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), + ..Default::default() + }; + + b.iter(|| tree.parse_pos().unwrap()); + } + + #[bench] + fn bench_parse_operators(b: &mut test::Bencher) { + let mut tree = Tree { + raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), + ..Default::default() + }; + + tree.parse_pos().unwrap(); + b.iter(|| tree.parse_operators().unwrap()); + } + + #[bench] + fn bench_parse_nodes(b: &mut test::Bencher) { + let mut tree = Tree { + raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), + ..Default::default() + }; + + tree.parse_pos().unwrap(); + tree.parse_operators().unwrap(); + b.iter(|| tree.parse_node().unwrap()); + } + + #[bench] + fn bench_compile(b: &mut test::Bencher) { + 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(); + }); + } + + #[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] + fn bench_eval(b: &mut test::Bencher) { + b.iter(|| eval("(2 + (3 + 4) + (6 + (6 + 7)) + 5)")); + } +} diff --git a/src/lib.rs b/src/lib.rs index 76433cb..e8bc8c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,692 +1,28 @@ -//! Eval is a powerful expression evaluator. -//! -//! Supported operators: `!` `!=` `""` `''` `()` `[]` `.` `,` `>` `<` `>=` `<=` -//! `==` `+` unary/binary `-` `*` `/` `%` `&&` `||` `n..m`. -//! -//! Built-in functions: `min()` `max()` `len()` `is_empty()` `array()` `converge()`. -//! -//! ## 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::{Expr, to_value}; -//! -//! assert_eq!(Expr::new("foo == bar") -//! .value("foo", true) -//! .value("bar", true) -//! .exec(), -//! Ok(to_value(true))); -//! ``` -//! -//! You can access data like javascript by using `.` and `[]`. `[]` supports expression. -//! -//! ``` -//! use eval::{Expr, to_value}; -//! use std::collections::HashMap; -//! -//! let mut object = HashMap::new(); -//! object.insert("foos", vec!["Hello", "world", "!"]); -//! -//! assert_eq!(Expr::new("object.foos[2-1] == 'world'") // Access field `foos` and index `2-1` -//! .value("object", object) -//! .exec(), -//! Ok(to_value(true))); -//! ``` -//! -//! You can eval with function: -//! -//! ``` -//! use eval::{Expr, to_value}; -//! -//! 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 `array()`: -//! -//! ``` -//! use eval::{eval, to_value}; -//! -//! assert_eq!(eval("array(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]))); -//! ``` -//! -//! ## 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 a boolean. Check whether the value is empty or not. -//! -//! ### array() -//! Accept multiple arguments and return an array. -//! -//! ### converge() -//! See `builtin::create_converge_function()`. -//! -//! -#![recursion_limit="100"] -#![deny(missing_docs)] -#![cfg_attr(all(feature = "unstable", test), feature(test))] +use configuration::EmptyConfiguration; +use error::Error; +use value::Value; -#[macro_use] -extern crate quick_error; -extern crate serde; -extern crate serde_json; - -mod math; -mod function; -mod operator; -mod node; -mod tree; +mod configuration; mod error; -mod builtin; -mod expr; +mod operator; +mod token; +mod tree; +mod value; -mod reboot; - -pub use expr::ExecOptions; -pub use serde_json::Value; -pub use error::Error; -pub use function::Function; -pub use expr::Expr; - -use std::collections::HashMap; -use serde_json::to_value as json_to_value; -use serde::Serialize; - -/// Convert variable to `serde_json::Value` -pub fn to_value(v: S) -> Value { - json_to_value(v).unwrap() +pub fn eval(string: &str) -> Result { + tree::tokens_to_operator_tree(token::tokenize(string))?.eval(&EmptyConfiguration) } -/// Custom context. -pub type Context = HashMap; -/// Custom contexts. The value of the last context is searched first. -pub type Contexts = Vec; -/// Custom functions. -pub type Functions = HashMap; - -/// Evaluates the value of an expression. -pub fn eval(expr: &str) -> Result { - Expr::new(expr).compile()?.exec() -} - - -type Compiled = Box Result>; - - - #[cfg(test)] -mod tests { - use to_value; - use error::Error; - use Expr; - use tree::Tree; - use Value; - use eval; - use std::collections::HashMap; +mod test { + use crate::{eval, value::Value}; #[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_len_array() { - assert_eq!(eval("len(array(2, 3, 4, 5, 6))"), Ok(to_value(5))); - } - - #[test] - fn test_null_and_number() { - assert_eq!(eval("hos != 0"), Ok(to_value(true))); - assert_eq!(eval("hos > 0"), Ok(to_value(false))); - } - - #[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))); - } - - #[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("array(1, 2, 3, 4)"), Ok(to_value(vec![1, 2, 3, 4]))); - } - - #[test] - fn test_range() { - assert_eq!(eval("0..5"), Ok(to_value(vec![0, 1, 2, 3, 4]))); - } - - #[test] - fn test_range_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_object_access() { - let mut object = HashMap::new(); - object.insert("foo", "Foo, hello world!"); - object.insert("bar", "Bar, hello world!"); - assert_eq!( - Expr::new("object.foo == 'Foo, hello world!'") - .value("object", object) - .exec(), - Ok(to_value(true)) - ); - } - - #[test] - fn test_object_dynamic_access() { - let mut object = HashMap::new(); - object.insert("foo", "Foo, hello world!"); - object.insert("bar", "Bar, hello world!"); - assert_eq!( - Expr::new("object['foo'] == 'Foo, hello world!'") - .value("object", object) - .exec(), - Ok(to_value(true)) - ); - } - - #[test] - fn test_object_dynamic_access_2() { - let mut object = HashMap::new(); - object.insert("foo", "Foo, hello world!"); - object.insert("bar", "Bar, hello world!"); - assert_eq!( - Expr::new("object[foo] == 'Foo, hello world!'") - .value("object", object) - .value("foo", "foo") - .exec(), - Ok(to_value(true)) - ); - } - - #[test] - fn test_path() { - assert_eq!(Expr::new("array[2-2].foo[2-2]").exec(), Ok(Value::Null)); - } - - #[test] - fn test_array_access() { - let array = vec!["hello", "world", "!"]; - assert_eq!( - Expr::new( - "array[1-1] == 'hello' && array[1] == 'world' && array[2] == '!'", - ).value("array", array) - .exec(), - Ok(to_value(true)) - ); - } - - #[test] - fn test_builtin_is_empty() { - assert_eq!( - Expr::new("is_empty(array)") - .value("array", Vec::::new()) - .exec(), - Ok(to_value(true)) - ); - } - - #[test] - fn test_builtin_min() { - assert_eq!( - Expr::new("min(array)") - .value("array", vec![23, 34, 45, 2]) - .exec(), - Ok(to_value(2)) - ); - } - - #[test] - fn test_custom_function() { - assert_eq!( - Expr::new("output()") - .function( - "output", - |_| Ok(to_value("This is custom function's output")), - ) - .exec(), - Ok(to_value("This is custom function's output")) - ); - } - - #[test] - fn test_error_start_with_non_value_operator() { - let mut tree = Tree { - raw: "+ + 5".to_owned(), - ..Default::default() - }; - - tree.parse_pos().unwrap(); - tree.parse_operators().unwrap(); - - assert_eq!(tree.parse_node(), Err(Error::StartWithNonValueOperator)); - } - - #[test] - fn test_error_duplicate_operator() { - let mut tree = Tree { - raw: "5 + + 5".to_owned(), - ..Default::default() - }; - - tree.parse_pos().unwrap(); - tree.parse_operators().unwrap(); - - assert_eq!(tree.parse_node(), Err(Error::DuplicateOperatorNode)); - } - - #[test] - fn test_error_duplicate_value() { - let mut tree = Tree { - raw: "2 + 6 5".to_owned(), - ..Default::default() - }; - - tree.parse_pos().unwrap(); - tree.parse_operators().unwrap(); - - assert_eq!(tree.parse_node(), Err(Error::DuplicateValueNode)); - } - - #[test] - fn test_error_unpaired_brackets() { - let mut tree = Tree { - raw: "(2 + 3)) * 5".to_owned(), - ..Default::default() - }; - - tree.parse_pos().unwrap(); - - assert_eq!(tree.parse_operators(), Err(Error::UnpairedBrackets)); - } - - #[test] - fn test_error_comma() { - let mut tree = Tree { - raw: ", 2 + 5".to_owned(), - ..Default::default() - }; - - tree.parse_pos().unwrap(); - tree.parse_operators().unwrap(); - - assert_eq!(tree.parse_node(), Err(Error::CommaNotWithFunction)); - } - - #[test] - fn test_eval_issue_2() { - assert_eq!(eval("2 * (4 + 0) + 4"), Ok(to_value(12))); - assert_eq!(eval("2 * (2 + 2) + (1 + 3)"), Ok(to_value(12))); - assert_eq!(eval("2 * (4) + (4)"), Ok(to_value(12))); - } - - #[test] - fn test_unary_minus() { - assert_eq!(eval("3 + -4"), Ok(to_value(-1))); - assert_eq!(eval("3+-4"), Ok(to_value(-1))); - assert_eq!(eval("true && !false"), Ok(to_value(true))); - assert_eq!(eval("!true || !true"), Ok(to_value(false))); - assert_eq!(eval("-5 + -4"), Ok(to_value(-9))); - assert_eq!(eval("-3-4"), Ok(to_value(-7))); - } -} - -#[cfg(all(feature = "unstable", test))] -mod benches { - extern crate test; - use eval; - use tree::Tree; - use Expr; - - #[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 tree = Tree { - raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), - ..Default::default() - }; - - b.iter(|| tree.parse_pos().unwrap()); - } - - #[bench] - fn bench_parse_operators(b: &mut test::Bencher) { - let mut tree = Tree { - raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), - ..Default::default() - }; - - tree.parse_pos().unwrap(); - b.iter(|| tree.parse_operators().unwrap()); - } - - #[bench] - fn bench_parse_nodes(b: &mut test::Bencher) { - let mut tree = Tree { - raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), - ..Default::default() - }; - - tree.parse_pos().unwrap(); - tree.parse_operators().unwrap(); - b.iter(|| tree.parse_node().unwrap()); - } - - #[bench] - fn bench_compile(b: &mut test::Bencher) { - 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(); - }); - } - - #[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] - fn bench_eval(b: &mut test::Bencher) { - b.iter(|| eval("(2 + (3 + 4) + (6 + (6 + 7)) + 5)")); + fn test_simple_examples() { + assert_eq!(eval("3"), Ok(Value::Number(3.0))); + assert_eq!(eval("1+3"), Ok(Value::Number(4.0))); + assert_eq!(eval("3+1"), Ok(Value::Number(4.0))); + assert_eq!(eval("3-5"), Ok(Value::Number(-2.0))); + assert_eq!(eval("5-3"), Ok(Value::Number(2.0))); } } diff --git a/src/math/mod.rs b/src/math/mod.rs deleted file mode 100644 index 93d16ea..0000000 --- a/src/math/mod.rs +++ /dev/null @@ -1,206 +0,0 @@ - -use serde_json::Value; -use to_value; -use error::Error; - -pub trait Math { - fn add(&self, &Value) -> Result; - fn mul(&self, &Value) -> Result; - fn sub(&self, &Value) -> Result; - fn div(&self, &Value) -> Result; - fn rem(&self, &Value) -> Result; - fn eq(&self, &Value) -> Result; - fn ne(&self, &Value) -> Result; - fn gt(&self, &Value) -> Result; - fn lt(&self, &Value) -> Result; - fn ge(&self, &Value) -> Result; - fn le(&self, &Value) -> Result; - fn and(&self, &Value) -> Result; - fn or(&self, &Value) -> Result; -} - -impl Math for Value { - fn add(&self, value: &Value) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - if self.is_null() || value.is_null() { - return Ok(to_value(false)); - } - 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 { - if self.is_null() || value.is_null() { - return Ok(to_value(false)); - } - 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 { - if self.is_null() || value.is_null() { - return Ok(to_value(false)); - } - 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 { - if self.is_null() || value.is_null() { - return Ok(to_value(false)); - } - 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 { - 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 { - 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::Number(ref n) => n.as_f64().unwrap(), - _ => 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) - } -} diff --git a/src/node/mod.rs b/src/node/mod.rs deleted file mode 100644 index 5ed1a01..0000000 --- a/src/node/mod.rs +++ /dev/null @@ -1,107 +0,0 @@ - -use operator::Operator; -use error::Error; -use Function; - - -#[derive(Debug, Clone, PartialEq)] -pub struct Node { - pub operator: Operator, - pub children: Vec, - pub closed: bool, -} - -impl Node { - pub fn new(operator: Operator) -> Node { - Node { - 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_full_children(&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_arithmetic(&self) -> bool { - return !self.closed && self.operator.can_have_child() && self.operator.can_have_child() - } - - pub fn is_unclosed_function(&self) -> bool { - match self.operator { - Operator::Function(_) => !self.closed, - _ => false, - } - } - - pub fn is_unclosed_square_bracket(&self) -> bool { - match self.operator { - Operator::LeftSquareBracket(_) => !self.closed, - _ => false, - } - } - - pub fn is_left_square_bracket(&self) -> bool { - match self.operator { - Operator::LeftSquareBracket(_) => true, - _ => false, - } - } - - pub fn is_dot(&self) -> bool { - match self.operator { - Operator::Dot(_) => true, - _ => 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() - } -} diff --git a/src/operator/mod.rs b/src/operator/mod.rs index ed55a7f..cf5e872 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -1,228 +1,165 @@ +use crate::{configuration::Configuration, error::*, value::Value}; -use std::str::FromStr; -use serde_json::Value; -use to_value; -use error::Error; -use node::Node; +pub trait Operator { + /// Returns the precedence of the operator. + /// A high precedence means that the operator has priority to be deeper in the tree. + // Make this a const fn once #57563 is resolved + fn precedence(&self) -> i32; + /// True if this operator is a leaf, meaning it accepts no arguments. + // Make this a const fn once #57563 is resolved + fn is_leaf(&self) -> bool { + self.argument_amount() == 0 + } -#[derive(Debug, Clone, PartialEq)] -pub enum Operator { - Neg(u8), - 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), - Dot(u8), - LeftParenthesis, - RightParenthesis, - LeftSquareBracket(u8), - RightSquareBracket, - DoubleQuotes, - SingleQuote, - WhiteSpace, - Comma, - Function(String), - Identifier(String), - Value(Value), + /// Returns the amount of arguments required by this operator. + // Make this a const fn once #57563 is resolved + fn argument_amount(&self) -> usize; + + /// Evaluates the operator with the given arguments and configuration. + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result; } -impl Operator { - pub fn is_identifier(&self) -> bool { - match *self { - Operator::Identifier(_) => true, - _ => false, - } - } +pub struct RootNode; +pub struct Add; +pub struct Sub; +pub struct Mul; +pub struct Div; - pub fn can_at_beginning(&self) -> bool { - match *self { - Operator::Neg(_) | - Operator::Not(_) | - Operator::Function(_) | - Operator::LeftParenthesis => true, - _ => false, - } - } +pub struct Const { + value: Value, +} - pub fn get_max_args(&self) -> Option { - 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(_) | Operator::Neg(_) => Some(1), - Operator::Function(_) => None, - _ => Some(0), - } - } - - pub fn get_min_args(&self) -> Option { - 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(_) | Operator::Neg(_) => Some(1), - Operator::Function(_) => None, - _ => Some(0), - } - } - - pub fn get_priority(&self) -> u8 { - match *self { - Operator::Neg(priority) | - 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_left_square_bracket(&self) -> bool { - match *self { - Operator::LeftSquareBracket(_) => true, - _ => false, - } - } - - pub fn is_dot(&self) -> bool { - match *self { - Operator::Dot(_) => 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::Not(_) | - Operator::Neg(_) | - Operator::Dot(_) | - Operator::LeftSquareBracket(_) | - 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(100), - _ => panic!("not bracket"), - } - } - - pub fn to_node(&self) -> Node { - Node::new(self.clone()) - } - - pub fn children_to_node(&self, children: Vec) -> Node { - let mut node = self.to_node(); - node.children = children; - node - } - - pub fn get_identifier(&self) -> &str { - match *self { - Operator::Identifier(ref ident) => ident, - _ => panic!("not identifier"), - } +impl Const { + pub fn new(value: Value) -> Self { + Self { value } } } -impl FromStr for Operator { - type Err = Error; +pub struct Identifier { + identifier: String, +} - fn from_str(raw: &str) -> Result { - 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(100)), - "]" => Ok(Operator::RightSquareBracket), - "." => Ok(Operator::Dot(100)), - "\"" => 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())), - } +impl Identifier { + pub fn new(identifier: String) -> Self { + Self { identifier } + } +} + +impl Operator for RootNode { + fn precedence(&self) -> i32 { + i32::min_value() + } + + fn argument_amount(&self) -> usize { + 1 + } + + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { + Err(Error::EvaluatedRootNode) + } +} + +impl Operator for Add { + fn precedence(&self) -> i32 { + 95 + } + + fn argument_amount(&self) -> usize { + 2 + } + + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 2)?; + let a = expect_number(&arguments[0])?; + let b = expect_number(&arguments[1])?; + + Ok(Value::Number(a + b)) + } +} + +impl Operator for Sub { + fn precedence(&self) -> i32 { + 95 + } + + fn argument_amount(&self) -> usize { + 2 + } + + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 2)?; + let a = expect_number(&arguments[0])?; + let b = expect_number(&arguments[1])?; + + Ok(Value::Number(a - b)) + } +} + +impl Operator for Mul { + fn precedence(&self) -> i32 { + 100 + } + + fn argument_amount(&self) -> usize { + 2 + } + + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 2)?; + let a = expect_number(&arguments[0])?; + let b = expect_number(&arguments[1])?; + + Ok(Value::Number(a * b)) + } +} + +impl Operator for Div { + fn precedence(&self) -> i32 { + 100 + } + + fn argument_amount(&self) -> usize { + 2 + } + + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 2)?; + let a = expect_number(&arguments[0])?; + let b = expect_number(&arguments[1])?; + + Ok(Value::Number(a / b)) + } +} + +impl Operator for Const { + fn precedence(&self) -> i32 { + 200 + } + + fn argument_amount(&self) -> usize { + 0 + } + + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 0)?; + + Ok(self.value.clone()) + } +} + +impl Operator for Identifier { + fn precedence(&self) -> i32 { + 200 + } + + fn argument_amount(&self) -> usize { + 0 + } + + fn eval(&self, arguments: &[Value], configuration: &Configuration) -> Result { + expect_argument_amount(arguments.len(), 0)?; + + configuration.get_value(&self.identifier) } } diff --git a/src/reboot/mod.rs b/src/reboot/mod.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/token/mod.rs b/src/token/mod.rs new file mode 100644 index 0000000..7dacd90 --- /dev/null +++ b/src/token/mod.rs @@ -0,0 +1,82 @@ +#[derive(Clone, PartialEq)] +pub enum Token { + // Single character tokens + Plus, + Minus, + Star, + Slash, + Whitespace, + + // Complex tokens + Identifier(String), + Number(f64), + Boolean(bool), +} + +enum PartialToken { + Token(Token), + Literal(String), +} + +// Make this a const fn as soon as match gets stable (issue #57563) +fn char_to_token(c: char) -> PartialToken { + match c { + '+' => PartialToken::Token(Token::Plus), + '-' => PartialToken::Token(Token::Minus), + '*' => PartialToken::Token(Token::Star), + '/' => PartialToken::Token(Token::Slash), + c => { + if c.is_whitespace() { + PartialToken::Token(Token::Whitespace) + } else { + PartialToken::Literal(c.to_string()) + } + } + } +} + +/// Converts a string to a vector of partial tokens. +fn str_to_tokens(string: &str) -> Vec { + let mut result = Vec::new(); + for c in string.chars() { + let partial_token = char_to_token(c); + + let if_let_successful = + if let (Some(PartialToken::Literal(last)), PartialToken::Literal(literal)) = + (result.last_mut(), &partial_token) + { + last.push_str(literal); + true + } else { + false + }; + + if !if_let_successful { + result.push(partial_token); + } + } + result +} + +/// Resolves all literals in the given vector of partial tokens by converting them to complex tokens. +fn resolve_literals(tokens: &Vec) -> Vec { + tokens + .iter() + .map(|token| match token { + PartialToken::Token(token) => token.clone(), + PartialToken::Literal(literal) => { + if let Ok(number) = literal.parse::() { + Token::Number(number) + } else if let Ok(boolean) = literal.parse::() { + Token::Boolean(boolean) + } else { + Token::Identifier(literal.to_string()) + } + } + }) + .collect() +} + +pub fn tokenize(string: &str) -> Vec { + resolve_literals(&str_to_tokens(string)) +} diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 2456dd6..335ca90 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1,673 +1,104 @@ +use crate::{configuration::Configuration, error::Error, operator::*, value::Value}; +use std::mem; +use token::Token; -use std::str::FromStr; -use std::clone::Clone; -use serde_json::Value; -use to_value; -use math::Math; -use operator::Operator; -use node::Node; -use {Context, Functions}; -use error::Error; -use Compiled; -use builtin::BuiltIn; - - -#[derive(Default)] -pub struct Tree { - pub raw: String, - pub pos: Vec, - pub operators: Vec, - pub node: Option, +pub struct Node { + children: Vec, + operator: Box, } -impl Tree { - pub fn new>(raw: T) -> Tree { - Tree { raw: raw.into(), ..Default::default() } - } - - pub fn parse_pos(&mut self) -> Result<(), Error> { - let mut found_quote = false; - let mut pos = Vec::new(); - - for (index, cur) in self.raw.chars().enumerate() { - match cur { - '(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' | - '[' | ']' | '.' | '%' | '&' | '|' => { - if !found_quote { - pos.push(index); - pos.push(index + 1); - } - } - '"' => { - found_quote = !found_quote; - pos.push(index); - pos.push(index + 1); - } - _ => (), - } +impl Node { + fn new(operator: Box) -> Self { + Self { + children: Vec::new(), + operator, } - - pos.push(self.raw.len()); - - self.pos = pos; - 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 quote = None; - let mut prev = String::new(); - let mut number = String::new(); + fn root_node() -> Self { + Self { + children: Vec::new(), + operator: Box::new(RootNode), + } + } - for pos_ref in &self.pos { - let pos = *pos_ref; - if pos == 0 { - continue; - } else { - start = end; - end = pos; - } + pub fn eval(&self, configuration: &Configuration) -> Result { + let mut arguments = Vec::new(); + for child in self.children() { + arguments.push(child.eval(configuration)?); + } + self.operator().eval(&arguments, configuration) + } - let raw = self.raw[start..end].to_owned(); + pub fn children(&self) -> &[Node] { + &self.children + } - if raw.is_empty() { - continue; - } + pub fn operator(&self) -> &Box { + &self.operator + } - 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; - } + fn has_correct_amount_of_children(&self) -> bool { + self.children().len() == self.operator().argument_amount() + } + + fn insert_back_prioritized(&mut self, mut operator: Box) -> Result<(), Error> { + if self.operator().precedence() < operator.precedence() { + if self.operator().is_leaf() { + Err(Error::AppendedToLeafNode) + } else if self.has_correct_amount_of_children() { + if self.children.last_mut().unwrap().operator().precedence() < operator.precedence() + { + self.children + .last_mut() + .unwrap() + .insert_back_prioritized(operator) + } else { + let mut new_node = Node::new(operator); + let last_child = self.children.pop().unwrap(); + self.children.push(new_node); + let new_node = self.children.last_mut().unwrap(); + + if new_node.operator().is_leaf() { + Err(Error::AppendedToLeafNode) } else { - quote = Some(operator); - prev.clear(); - continue; + new_node.children.push(last_child); + Ok(()) } } - _ => (), - }; - - if quote.is_some() { - prev += &raw; - continue; + } else { + self.children.push(Node::new(operator)); + Ok(()) } - - if parse_number(&raw).is_some() || operator.is_dot() { - number += &raw; - continue; - } else if !number.is_empty() { - operators.push(Operator::from_str(&number).unwrap()); - number.clear(); - } - - 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::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() - .to_owned())); - operators.push(operator); - continue; - } else { - operators.push(prev_operator); - } - } - } - Operator::RightParenthesis => parenthesis -= 1, - Operator::WhiteSpace => continue, - _ => (), - } - - prev = raw; - operators.push(operator); - } - - if !number.is_empty() { - operators.push(Operator::from_str(&number).unwrap()); - } - - if parenthesis != 0 { - Err(Error::UnpairedBrackets) } else { - self.operators = operators; - Ok(()) + Err(Error::PrecedenceViolation) } } - - pub fn parse_node(&mut self) -> Result<(), Error> { - let mut parsing_nodes = Vec::::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::Dot(priority) | - Operator::LeftSquareBracket(priority) | - Operator::Rem(priority) => { - if !parsing_nodes.is_empty() { - let prev = parsing_nodes.pop().unwrap(); - if prev.is_value_or_full_children() { - 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 => 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_value_to_last_node(&mut parsing_nodes, operator)?, - _ => (), - } - } - - self.node = Some(get_final_node(parsing_nodes)?); - Ok(()) - } - - pub fn compile(mut self) -> Result { - self.parse_pos()?; - self.parse_operators()?; - self.parse_node()?; - let node = self.node.unwrap(); - let builtin = BuiltIn::new(); - - Ok(Box::new(move |contexts, functions| -> Result { - return exec_node(&node, &builtin, contexts, functions); - - fn exec_node(node: &Node, - builtin: &Functions, - contexts: &[Context], - functions: &Functions) - -> Result { - match node.operator { - Operator::Add(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .add(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Mul(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .mul(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Sub(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .sub(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Div(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .div(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Rem(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .rem(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Eq(_) => { - 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(), builtin, contexts, functions)?, - &exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Gt(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .gt(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Lt(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .lt(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Ge(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .ge(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Le(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .le(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::And(_) => { - exec_node(&node.get_first_child(), builtin, contexts, functions) - ? - .and(&exec_node(&node.get_last_child(), builtin, contexts, functions)?) - } - Operator::Or(_) => { - exec_node(&node.get_first_child(), builtin, contexts, 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 { - builtin.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, builtin, contexts, 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(), builtin, contexts, functions)?; - match value { - Value::Bool(boolean) => Ok(Value::Bool(!boolean)), - Value::Null => Ok(Value::Bool(true)), - _ => Err(Error::ExpectedBoolean(value)), - } - } - Operator::Dot(_) => { - let mut value = None; - for child in &node.children { - if value.is_none() { - let name = exec_node(child, builtin, contexts, functions)?; - if name.is_string() { - value = find(contexts, name.as_str().unwrap()); - if value.is_none() { - return Ok(Value::Null); - } - } else if name.is_object() { - value = Some(name); - } else if name.is_null() { - return Ok(Value::Null); - } else { - return Err(Error::ExpectedObject); - } - } else { - if child.operator.is_identifier() { - value = value.as_ref() - .unwrap() - .get(child.operator.get_identifier()) - .cloned(); - } else { - return Err(Error::ExpectedIdentifier); - } - } - } - - if value.is_some() { - return Ok(value.unwrap()); - } else { - return Ok(Value::Null); - } - } - Operator::LeftSquareBracket(_) => { - let mut value = None; - for child in &node.children { - let name = exec_node(child, builtin, contexts, functions)?; - if value.is_none() { - if name.is_string() { - value = find(contexts, name.as_str().unwrap()); - if value.is_none() { - return Ok(Value::Null); - } - } else if name.is_array() { - value = Some(name); - } else if name.is_object() { - value = Some(name); - } else if name.is_null() { - return Ok(Value::Null); - } else { - return Err(Error::ExpectedArray); - } - } else if value.as_ref().unwrap().is_object() { - if name.is_string() { - value = value.as_ref() - .unwrap() - .get(name.as_str().unwrap()) - .cloned(); - } else { - return Err(Error::ExpectedIdentifier); - } - } else { - if name.is_u64() { - if value.as_ref().unwrap().is_array() { - value = value.as_ref() - .unwrap() - .as_array() - .unwrap() - .get(name.as_u64().unwrap() as usize) - .cloned(); - } else { - return Err(Error::ExpectedArray); - } - } else { - return Err(Error::ExpectedNumber); - } - } - } - if value.is_some() { - return Ok(value.unwrap()); - } else { - return Ok(Value::Null); - } - } - 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())), - } - } - })) - } } -fn append_value_to_last_node(parsing_nodes: &mut Vec, - operator: &Operator) - -> Result<(), Error> { - let mut node = operator.to_node(); - node.closed = true; +pub fn tokens_to_operator_tree(tokens: Vec) -> Result { + let mut root = Node::root_node(); - if let Some(mut prev) = parsing_nodes.pop() { - if prev.is_dot() { - prev.add_child(node); - prev.closed = true; - parsing_nodes.push(prev); - } else if prev.is_left_square_bracket() { - parsing_nodes.push(prev); - parsing_nodes.push(node); - } else if prev.is_value_or_full_children() { - return Err(Error::DuplicateValueNode); - } else if prev.is_enough() { - parsing_nodes.push(prev); - parsing_nodes.push(node); - } else if prev.operator.can_have_child() { - prev.add_child(node); - parsing_nodes.push(prev); - } else { - return Err(Error::CanNotAddChild); + for token in tokens { + let operator: Option> = match token { + Token::Plus => Some(Box::new(Add)), + Token::Minus => Some(Box::new(Sub)), + Token::Star => Some(Box::new(Mul)), + Token::Slash => Some(Box::new(Div)), + Token::Whitespace => None, + Token::Identifier(identifier) => Some(Box::new(Identifier::new(identifier))), + Token::Number(number) => Some(Box::new(Const::new(Value::Number(number)))), + Token::Boolean(boolean) => Some(Box::new(Const::new(Value::Boolean(boolean)))), + }; + + if let Some(operator) = operator { + root.insert_back_prioritized(operator); } + } + + if root.children().len() == 1 { + Ok(root.children.pop().unwrap()) } else { - parsing_nodes.push(node); - } - - Ok(()) -} - -fn get_final_node(mut parsing_nodes: Vec) -> Result { - if parsing_nodes.is_empty() { - return Err(Error::NoFinalNode); - } - - while parsing_nodes.len() != 1 { - let last = parsing_nodes.pop().unwrap(); - let mut prev = parsing_nodes.pop().unwrap(); - if prev.operator.can_have_child() { - prev.add_child(last); - parsing_nodes.push(prev); - } else { - return Err(Error::CanNotAddChild); - } - } - - Ok(parsing_nodes.pop().unwrap()) -} - -fn close_bracket(parsing_nodes: &mut Vec, bracket: Operator) -> Result<(), Error> { - loop { - let mut current = parsing_nodes.pop().unwrap(); - let mut prev = parsing_nodes.pop().unwrap(); - - if current.operator.is_left_square_bracket() { - return Err(Error::BracketNotWithFunction); - } else if prev.operator.is_left_square_bracket() { - prev.add_child(current); - prev.closed = true; - parsing_nodes.push(prev); - break; - } else 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 if penult.is_unclosed_arithmetic() { - 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) -> 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 { - let moveout_node = was_robed.moveout_last_node(); - rober.add_child(moveout_node); - vec![was_robed, rober] -} - -fn find(contexts: &[Context], key: &str) -> Option { - for context in contexts.iter().rev() { - match context.get(key) { - Some(value) => return Some(value.clone()), - None => continue, - } - } - - None -} - -fn is_range(ident: &str) -> bool { - ident.contains("..") -} - -fn parse_range(ident: &str) -> Result { - let segments = ident.split("..").collect::>(); - if segments.len() != 2 { - Err(Error::InvalidRange(ident.to_owned())) - } else { - let start = segments[0].parse::(); - let end = segments[1].parse::(); - - 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::InvalidRange(ident.to_owned())) - } + Err(Error::EmptyExpression) } } - -fn parse_number(ident: &str) -> Option { - let number = ident.parse::(); - if number.is_ok() { - return Some(to_value(number.unwrap())); - } - - let number = ident.parse::(); - if number.is_ok() { - return Some(to_value(number.unwrap())); - } - - let number = ident.parse::(); - if number.is_ok() { - return Some(to_value(number.unwrap())); - } - - None -} diff --git a/src/value/mod.rs b/src/value/mod.rs new file mode 100644 index 0000000..35525dc --- /dev/null +++ b/src/value/mod.rs @@ -0,0 +1,6 @@ +#[derive(Clone, Debug, PartialEq)] +pub enum Value { + String(String), + Number(f64), + Boolean(bool), +}