Complete rewrite of crate. Simple tokenizer and treeifyer (Or however the compiler people call these.).

This commit is contained in:
Sebastian Schmidt 2019-03-15 17:11:31 +02:00
parent c313ec8ce5
commit b38c102c1d
15 changed files with 1097 additions and 2338 deletions

5
rustfmt.toml Normal file
View File

@ -0,0 +1,5 @@
edition = "2018"
reorder_imports=true
reorder_modules=true
format_strings=true
merge_imports=true

View File

@ -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<f64, Error> {
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<f64, Error> {
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<f64, Error> {
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<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(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)));
}
}
}

13
src/configuration/mod.rs Normal file
View File

@ -0,0 +1,13 @@
use crate::{error::Error, value::Value};
pub trait Configuration {
fn get_value(&self, identifier: &str) -> Result<Value, Error>;
}
pub struct EmptyConfiguration;
impl Configuration for EmptyConfiguration {
fn get_value(&self, identifier: &str) -> Result<Value, Error> {
Err(Error::IdentifierNotFound)
}
}

View File

@ -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<f64, Error> {
match actual {
Value::Number(number) => Ok(*number),
_ => Err(Error::expected_number(actual.clone())),
}
}

View File

@ -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<Compiled>,
functions: Functions,
contexts: Contexts,
}
impl Expr {
/// Create an expression.
pub fn new<T: Into<String>>(expr: T) -> Expr {
Expr {
expression: expr.into(),
compiled: None,
functions: Functions::new(),
contexts: create_empty_contexts(),
}
}
/// Set function.
pub fn function<T, F>(mut self, name: T, function: F) -> Expr
where T: Into<String>,
F: 'static + Fn(Vec<Value>) -> Result<Value, Error> + Sync + Send
{
self.functions.insert(name.into(), Function::new(function));
self
}
/// Set value.
pub fn value<T, V>(mut self, name: T, value: V) -> Expr
where T: Into<String>,
V: Serialize
{
self.contexts.last_mut().unwrap().insert(name.into(), to_value(value));
self
}
/// Compile an expression.
/// An expression can be compiled only once and then invoked multiple times with different context and function.
/// You can also execute a expression without compile.
pub fn compile(mut self) -> Result<Expr, Error> {
self.compiled = Some(Tree::new(self.expression.clone()).compile()?);
Ok(self)
}
/// Execute the expression.
pub fn exec(&self) -> Result<Value, Error> {
if self.compiled.is_none() {
Tree::new(self.expression.clone()).compile()?(&self.contexts, &self.functions)
} else {
self.compiled.as_ref().unwrap()(&self.contexts, &self.functions)
}
}
fn get_compiled(&self) -> Option<&Compiled> {
self.compiled.as_ref()
}
}
impl Clone for Expr {
/// Returns a copy of the value. Notice that functions can not be cloned. The cloned expr's functions will be empty.
fn clone(&self) -> Expr {
Expr {
expression: self.expression.clone(),
compiled: if self.compiled.is_some() {
Some(Tree::new(self.expression.clone()).compile().unwrap())
} else {
None
},
contexts: self.contexts.clone(),
functions: Functions::new(),
}
}
}
impl fmt::Debug for Expr {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(formatter, "{:?}", self.expression)
}
}
/// Execute options
pub struct ExecOptions<'a> {
expr: &'a Expr,
contexts: Option<&'a [Context]>,
functions: Option<&'a Functions>,
}
impl<'a> ExecOptions<'a> {
/// Create an option.
pub fn new(expr: &'a Expr) -> ExecOptions<'a> {
ExecOptions {
expr: expr,
contexts: None,
functions: None,
}
}
/// Set contexts.
pub fn contexts(&mut self, contexts: &'a [Context]) -> &'a mut ExecOptions {
self.contexts = Some(contexts);
self
}
/// Set functions.
pub fn functions(&mut self, functions: &'a Functions) -> &'a mut ExecOptions {
self.functions = Some(functions);
self
}
/// Execute the compiled expression.
pub fn exec(&self) -> Result<Value, Error> {
let empty_contexts = create_empty_contexts();
let empty_functions = Functions::new();
let contexts = if self.contexts.is_some() {
self.contexts.unwrap()
} else {
&empty_contexts
};
let functions = if self.functions.is_some() {
self.functions.unwrap()
} else {
&empty_functions
};
let compiled = self.expr.get_compiled();
if compiled.is_none() {
Tree::new(self.expr.expression.clone()).compile()?(contexts, functions)
} else {
compiled.unwrap()(contexts, functions)
}
}
}
fn create_empty_contexts() -> Contexts {
let mut contexts = Contexts::new();
contexts.push(Context::new());
contexts
}

View File

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

692
src/lib-old.rs Normal file
View File

@ -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<S: Serialize>(v: S) -> Value {
json_to_value(v).unwrap()
}
/// Custom context.
pub type Context = HashMap<String, Value>;
/// Custom contexts. The value of the last context is searched first.
pub type Contexts = Vec<Context>;
/// Custom functions.
pub type Functions = HashMap<String, Function>;
/// Evaluates the value of an expression.
pub fn eval(expr: &str) -> Result<Value, Error> {
Expr::new(expr).compile()?.exec()
}
type Compiled = Box<Fn(&[Context], &Functions) -> Result<Value, Error>>;
#[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::<String>::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)"));
}
}

View File

@ -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<S: Serialize>(v: S) -> Value {
json_to_value(v).unwrap()
pub fn eval(string: &str) -> Result<Value, Error> {
tree::tokens_to_operator_tree(token::tokenize(string))?.eval(&EmptyConfiguration)
}
/// Custom context.
pub type Context = HashMap<String, Value>;
/// Custom contexts. The value of the last context is searched first.
pub type Contexts = Vec<Context>;
/// Custom functions.
pub type Functions = HashMap<String, Function>;
/// Evaluates the value of an expression.
pub fn eval(expr: &str) -> Result<Value, Error> {
Expr::new(expr).compile()?.exec()
}
type Compiled = Box<Fn(&[Context], &Functions) -> Result<Value, Error>>;
#[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::<String>::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)));
}
}

View File

@ -1,206 +0,0 @@
use serde_json::Value;
use 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_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<Value, Error> {
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<Value, Error> {
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<Value, Error> {
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<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::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)
}
}

View File

@ -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<Node>,
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()
}
}

View File

@ -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<Value, Error>;
}
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<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(_) | Operator::Neg(_) => 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(_) | 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>) -> 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<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(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<Value, Error> {
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<Value, Error> {
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<Value, Error> {
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<Value, Error> {
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<Value, Error> {
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<Value, Error> {
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<Value, Error> {
expect_argument_amount(arguments.len(), 0)?;
configuration.get_value(&self.identifier)
}
}

View File

82
src/token/mod.rs Normal file
View File

@ -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<PartialToken> {
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<PartialToken>) -> Vec<Token> {
tokens
.iter()
.map(|token| match token {
PartialToken::Token(token) => token.clone(),
PartialToken::Literal(literal) => {
if let Ok(number) = literal.parse::<f64>() {
Token::Number(number)
} else if let Ok(boolean) = literal.parse::<bool>() {
Token::Boolean(boolean)
} else {
Token::Identifier(literal.to_string())
}
}
})
.collect()
}
pub fn tokenize(string: &str) -> Vec<Token> {
resolve_literals(&str_to_tokens(string))
}

View File

@ -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<usize>,
pub operators: Vec<Operator>,
pub node: Option<Node>,
pub struct Node {
children: Vec<Node>,
operator: Box<dyn Operator>,
}
impl Tree {
pub fn new<T: Into<String>>(raw: T) -> Tree {
Tree { raw: raw.into(), ..Default::default() }
}
pub fn parse_pos(&mut self) -> Result<(), Error> {
let mut found_quote = false;
let mut pos = Vec::new();
for (index, cur) in self.raw.chars().enumerate() {
match cur {
'(' | ')' | '+' | '-' | '*' | '/' | ',' | ' ' | '!' | '=' | '>' | '<' | '\'' |
'[' | ']' | '.' | '%' | '&' | '|' => {
if !found_quote {
pos.push(index);
pos.push(index + 1);
}
}
'"' => {
found_quote = !found_quote;
pos.push(index);
pos.push(index + 1);
}
_ => (),
}
impl Node {
fn new(operator: Box<dyn Operator>) -> 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<Value, Error> {
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<dyn Operator> {
&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<dyn Operator>) -> 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::<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::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<Compiled, Error> {
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<Value, Error> {
return exec_node(&node, &builtin, contexts, functions);
fn exec_node(node: &Node,
builtin: &Functions,
contexts: &[Context],
functions: &Functions)
-> Result<Value, Error> {
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<Node>,
operator: &Operator)
-> Result<(), Error> {
let mut node = operator.to_node();
node.closed = true;
pub fn tokens_to_operator_tree(tokens: Vec<Token>) -> Result<Node, Error> {
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<Box<dyn Operator>> = 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<Node>) -> Result<Node, Error> {
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<Node>, 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<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: &[Context], key: &str) -> Option<Value> {
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<Value, Error> {
let segments = ident.split("..").collect::<Vec<_>>();
if segments.len() != 2 {
Err(Error::InvalidRange(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::InvalidRange(ident.to_owned()))
}
Err(Error::EmptyExpression)
}
}
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
}

6
src/value/mod.rs Normal file
View File

@ -0,0 +1,6 @@
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
String(String),
Number(f64),
Boolean(bool),
}