diff --git a/README.md b/README.md index 5dd5cbe..6669e13 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ use evalexpr::error::expect_number; let mut configuration = HashMapConfiguration::new(); configuration.insert_variable("five", 5); configuration.insert_variable("twelve", 12); -configuration.insert_function("f", Function::new(1 /* argument amount */, Box::new(|arguments| { +configuration.insert_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| { if let Value::Int(int) = arguments[0] { Ok(Value::Int(int / 2)) } else if let Value::Float(float) = arguments[0] { @@ -54,7 +54,7 @@ configuration.insert_function("f", Function::new(1 /* argument amount */, Box::n Err(Error::expected_number(arguments[0].clone())) } }))); -configuration.insert_function("avg", Function::new(2 /* argument amount */, Box::new(|arguments| { +configuration.insert_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| { expect_number(&arguments[0])?; expect_number(&arguments[1])?; @@ -115,6 +115,18 @@ Supported unary operators: | - | 110 | Negation | | ! | 110 | Logical not | +#### The Aggregation Operator + +The aggregation operator aggregates two values into a tuple. +If one of the values is a tuple already, the resulting tuple will be flattened. +Example: + +```rust +use evalexpr::*; + +assert_eq!(eval("1, 2, 3"), Ok(Value::from(vec![Value::from(1), Value::from(2), Value::from(3)]))); +``` + ### Values Operators take values as arguments and produce values as results. @@ -157,7 +169,7 @@ This crate also allows to define arbitrary functions to be used in parsed expres A function is defined as a `Function` instance. It contains two properties, the `argument_amount` and the `function`. The `function` is a boxed `Fn(&[Value]) -> Result`. -The `argument_amount` determines the length of the slice that is passed to `function`. +The `argument_amount` determines the length of the slice that is passed to `function` if it is `Some(_)`, otherwise the function is defined to take an arbitrary amount of arguments. It is verified on execution by the crate and does not need to be verified by the `function`. Be aware that functions need to verify the types of values that are passed to them. diff --git a/src/function/mod.rs b/src/function/mod.rs index ee282e9..d449d0b 100644 --- a/src/function/mod.rs +++ b/src/function/mod.rs @@ -2,13 +2,13 @@ use error::{self, Error}; use value::Value; pub struct Function { - argument_amount: usize, + argument_amount: Option, function: Box Result>, } impl Function { pub fn new( - argument_amount: usize, + argument_amount: Option, function: Box Result>, ) -> Self { Self { @@ -18,7 +18,10 @@ impl Function { } pub fn call(&self, arguments: &[Value]) -> Result { - error::expect_function_argument_amount(arguments.len(), self.argument_amount)?; + if let Some(argument_amount) = self.argument_amount { + error::expect_function_argument_amount(arguments.len(), argument_amount)?; + } + (self.function)(arguments) } } diff --git a/src/lib.rs b/src/lib.rs index a908064..0dc7c0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ //! let mut configuration = HashMapConfiguration::new(); //! configuration.insert_variable("five", 5); //! configuration.insert_variable("twelve", 12); -//! configuration.insert_function("f", Function::new(1 /* argument amount */, Box::new(|arguments| { +//! configuration.insert_function("f", Function::new(Some(1) /* argument amount */, Box::new(|arguments| { //! if let Value::Int(int) = arguments[0] { //! Ok(Value::Int(int / 2)) //! } else if let Value::Float(float) = arguments[0] { @@ -43,7 +43,7 @@ //! Err(Error::expected_number(arguments[0].clone())) //! } //! }))); -//! configuration.insert_function("avg", Function::new(2 /* argument amount */, Box::new(|arguments| { +//! configuration.insert_function("avg", Function::new(Some(2) /* argument amount */, Box::new(|arguments| { //! expect_number(&arguments[0])?; //! expect_number(&arguments[1])?; //! @@ -158,7 +158,7 @@ //! A function is defined as a `Function` instance. //! It contains two properties, the `argument_amount` and the `function`. //! The `function` is a boxed `Fn(&[Value]) -> Result`. -//! The `argument_amount` determines the length of the slice that is passed to `function`. +//! The `argument_amount` determines the length of the slice that is passed to `function` if it is `Some(_)`, otherwise the function is defined to take an arbitrary amount of arguments. //! It is verified on execution by the crate and does not need to be verified by the `function`. //! //! Be aware that functions need to verify the types of values that are passed to them. @@ -365,7 +365,7 @@ mod test { configuration.insert_function( "sub2".to_string(), Function::new( - 1, + Some(1), Box::new(|arguments| { if let Value::Int(int) = arguments[0] { Ok(Value::Int(int - 2)) @@ -407,7 +407,7 @@ mod test { configuration.insert_function( "sub2", Function::new( - 1, + Some(1), Box::new(|arguments| { if let Value::Int(int) = arguments[0] { Ok(Value::Int(int - 2)) @@ -422,7 +422,7 @@ mod test { configuration.insert_function( "avg", Function::new( - 2, + Some(2), Box::new(|arguments| { expect_number(&arguments[0])?; expect_number(&arguments[1])?; @@ -440,7 +440,7 @@ mod test { configuration.insert_function( "muladd", Function::new( - 3, + Some(3), Box::new(|arguments| { expect_number(&arguments[0])?; expect_number(&arguments[1])?;