From 8eedf720e72212162be11326cce234ecec3083bc Mon Sep 17 00:00:00 2001 From: Ophir LOJKINE Date: Wed, 23 Mar 2022 16:33:53 +0100 Subject: [PATCH] Implement changes requested in PR https://github.com/ISibboI/evalexpr/pull/101#issuecomment-1076466426 --- README.md | 9 +++++---- src/function/builtin.rs | 28 +++++++++++++++++----------- src/lib.rs | 9 +++++---- tests/integration.rs | 30 +++++++++++++++++++----------- 4 files changed, 46 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index a432317..e4c535b 100644 --- a/README.md +++ b/README.md @@ -345,10 +345,11 @@ This crate offers a set of builtin functions. | `round` | 1 | Numeric | Returns the nearest integer to a number. Rounds half-way cases away from 0.0 | | `ceil` | 1 | Numeric | Returns the smallest integer greater than or equal to a number | | `if` | 3 | Boolean, Any, Any | If the first argument is true, returns the second argument, otherwise, returns the third | -| `is_nan` | 1 | Numeric | Returns true if the argument is the floating-point value NaN, false otherwise | -| `is_finite` | 1 | Numeric | Returns true if the argument is a finite floating-point number, false otherwise | -| `is_infinite` | 1 | Numeric | Returns true if the argument is an infinite floating-point number, false otherwise | -| `is_normal` | 1 | Numeric | Returns true if the argument is a floating-point number that is neither zero, infinite, [subnormal](https://en.wikipedia.org/wiki/Subnormal_number), or NaN, false otherwise | +| `typeof` | 1 | Any | returns "string", "float", "int", "boolean", "tuple", or "empty" depending on the type of the argument | +| `math::is_nan` | 1 | Numeric | Returns true if the argument is the floating-point value NaN, false if it is another floating-point value, and throws an error if it is not a number | +| `math::is_finite` | 1 | Numeric | Returns true if the argument is a finite floating-point number, false otherwise | +| `math::is_infinite` | 1 | Numeric | Returns true if the argument is an infinite floating-point number, false otherwise | +| `math::is_normal` | 1 | Numeric | Returns true if the argument is a floating-point number that is neither zero, infinite, [subnormal](https://en.wikipedia.org/wiki/Subnormal_number), or NaN, false otherwise | | `math::ln` | 1 | Numeric | Returns the natural logarithm of the number | | `math::log` | 2 | Numeric, Numeric | Returns the logarithm of the number with respect to an arbitrary base | | `math::log2` | 1 | Numeric | Returns the base 2 logarithm of the number | diff --git a/src/function/builtin.rs b/src/function/builtin.rs index 95aca35..a0600f2 100644 --- a/src/function/builtin.rs +++ b/src/function/builtin.rs @@ -24,13 +24,9 @@ macro_rules! simple_math { } fn float_is(func: fn(f64) -> bool) -> Option { - Some(Function::new(move |argument| { - if let Ok(num) = argument.as_float() { - Ok(func(num).into()) - } else { - Ok(false.into()) - } - })) + Some(Function::new(move |argument| + Ok(func(argument.as_number()?).into()) + )) } macro_rules! int_function { @@ -86,11 +82,21 @@ pub fn builtin_function(identifier: &str) -> Option { "floor" => simple_math!(floor), "round" => simple_math!(round), "ceil" => simple_math!(ceil), - "is_nan" => float_is(f64::is_nan), - "is_finite" => float_is(f64::is_finite), - "is_infinite" => float_is(f64::is_infinite), - "is_normal" => float_is(f64::is_normal), + "math::is_nan" => float_is(f64::is_nan), + "math::is_finite" => float_is(f64::is_finite), + "math::is_infinite" => float_is(f64::is_infinite), + "math::is_normal" => float_is(f64::is_normal), // Other + "typeof" => Some(Function::new(move |argument| + Ok(match argument { + Value::String(_) => "string", + Value::Float(_) => "float", + Value::Int(_) => "int", + Value::Boolean(_) => "boolean", + Value::Tuple(_) => "tuple", + Value::Empty => "empty", + }.into()) + )), "min" => Some(Function::new(|argument| { let arguments = argument.as_tuple()?; let mut min_int = IntType::max_value(); diff --git a/src/lib.rs b/src/lib.rs index 0391408..823ed8c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -328,10 +328,11 @@ //! | `round` | 1 | Numeric | Returns the nearest integer to a number. Rounds half-way cases away from 0.0 | //! | `ceil` | 1 | Numeric | Returns the smallest integer greater than or equal to a number | //! | `if` | 3 | Boolean, Any, Any | If the first argument is true, returns the second argument, otherwise, returns the third | -//! | `is_nan` | 1 | Numeric | Returns true if the argument is the floating-point value NaN, false otherwise | -//! | `is_finite` | 1 | Numeric | Returns true if the argument is a finite floating-point number, false otherwise | -//! | `is_infinite` | 1 | Numeric | Returns true if the argument is an infinite floating-point number, false otherwise | -//! | `is_normal` | 1 | Numeric | Returns true if the argument is a floating-point number that is neither zero, infinite, [subnormal](https://en.wikipedia.org/wiki/Subnormal_number), or NaN, false otherwise | +//! | `typeof` | 1 | Any | returns "string", "float", "int", "boolean", "tuple", or "empty" depending on the type of the argument | +//! | `math::is_nan` | 1 | Numeric | Returns true if the argument is the floating-point value NaN, false if it is another floating-point value, and throws an error if it is not a number | +//! | `math::is_finite` | 1 | Numeric | Returns true if the argument is a finite floating-point number, false otherwise | +//! | `math::is_infinite` | 1 | Numeric | Returns true if the argument is an infinite floating-point number, false otherwise | +//! | `math::is_normal` | 1 | Numeric | Returns true if the argument is a floating-point number that is neither zero, infinite, [subnormal](https://en.wikipedia.org/wiki/Subnormal_number), or NaN, false otherwise | //! | `math::ln` | 1 | Numeric | Returns the natural logarithm of the number | //! | `math::log` | 2 | Numeric, Numeric | Returns the logarithm of the number with respect to an arbitrary base | //! | `math::log2` | 1 | Numeric | Returns the base 2 logarithm of the number | diff --git a/tests/integration.rs b/tests/integration.rs index 81b5128..17e72e6 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -362,17 +362,22 @@ fn test_builtin_functions() { assert_eq!(eval("round(1.9)"), Ok(Value::Float(2.0))); assert_eq!(eval("ceil(1.1)"), Ok(Value::Float(2.0))); assert_eq!(eval("ceil(1.9)"), Ok(Value::Float(2.0))); - assert_eq!(eval("is_nan(\"xxx\")"), Ok(Value::Boolean(false))); - assert_eq!(eval("is_nan(1.0/0.0)"), Ok(Value::Boolean(false))); - assert_eq!(eval("is_nan(0.0/0.0)"), Ok(Value::Boolean(true))); - assert_eq!(eval("is_finite(1.0/0.0)"), Ok(Value::Boolean(false))); - assert_eq!(eval("is_finite(0.0/0.0)"), Ok(Value::Boolean(false))); - assert_eq!(eval("is_finite(0.0)"), Ok(Value::Boolean(true))); - assert_eq!(eval("is_infinite(0.0/0.0)"), Ok(Value::Boolean(false))); - assert_eq!(eval("is_infinite(1.0/0.0)"), Ok(Value::Boolean(true))); - assert_eq!(eval("is_normal(1.0/0.0)"), Ok(Value::Boolean(false))); - assert_eq!(eval("is_normal(0)"), Ok(Value::Boolean(false))); + assert_eq!(eval("math::is_nan(1.0/0.0)"), Ok(Value::Boolean(false))); + assert_eq!(eval("math::is_nan(0.0/0.0)"), Ok(Value::Boolean(true))); + assert_eq!(eval("math::is_finite(1.0/0.0)"), Ok(Value::Boolean(false))); + assert_eq!(eval("math::is_finite(0.0/0.0)"), Ok(Value::Boolean(false))); + assert_eq!(eval("math::is_finite(0.0)"), Ok(Value::Boolean(true))); + assert_eq!(eval("math::is_infinite(0.0/0.0)"), Ok(Value::Boolean(false))); + assert_eq!(eval("math::is_infinite(1.0/0.0)"), Ok(Value::Boolean(true))); + assert_eq!(eval("math::is_normal(1.0/0.0)"), Ok(Value::Boolean(false))); + assert_eq!(eval("math::is_normal(0)"), Ok(Value::Boolean(false))); // Other + assert_eq!(eval("typeof(4.0, 3)"), Ok(Value::String("tuple".into()))); + assert_eq!(eval("typeof(4.0)"), Ok(Value::String("float".into()))); + assert_eq!(eval("typeof(4)"), Ok(Value::String("int".into()))); + assert_eq!(eval("typeof(\"\")"), Ok(Value::String("string".into()))); + assert_eq!(eval("typeof(true)"), Ok(Value::String("boolean".into()))); + assert_eq!(eval("typeof()"), Ok(Value::String("empty".into()))); assert_eq!(eval("min(4.0, 3)"), Ok(Value::Int(3))); assert_eq!(eval("max(4.0, 3)"), Ok(Value::Float(4.0))); assert_eq!(eval("len(\"foobar\")"), Ok(Value::Int(6))); @@ -440,10 +445,13 @@ fn test_errors() { eval("true-"), Err(EvalexprError::WrongOperatorArgumentAmount { actual: 1, - expected: 2 + expected: 2, }) ); assert_eq!(eval("!(()true)"), Err(EvalexprError::AppendedToLeafNode)); + assert_eq!(eval("math::is_nan(\"xxx\")"), Err(EvalexprError::ExpectedNumber { + actual: Value::String("xxx".to_string()) + })); } #[test]