Merge pull request #79 from olback/common-math-functions

Add common math functions
This commit is contained in:
ISibboI 2021-06-02 16:43:23 +03:00 committed by GitHub
commit 7d2f2f86c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 158 additions and 23 deletions

View File

@ -321,15 +321,37 @@ For more information about user-defined functions, refer to the respective [sect
This crate offers a set of builtin functions.
| Identifier | Argument Amount | Argument Types | Description |
|------------|-----------------|----------------|-------------|
|----------------------|-----------------|------------------------|-------------|
| `min` | >= 1 | Numeric | Returns the minimum of the arguments |
| `max` | >= 1 | Numeric | Returns the maximum of the arguments |
| `len` | 1 | String/Tuple | Returns the character length of a string, or the amount of elements in a tuple (not recursively) |
| `floor` | 1 | Numeric | Returns the largest integer less than or equal to a number |
| `round` | 1 | Numeric | Returns the nearest integer to a number. Round half-way cases away from 0.0 |
| `ceil` | 1 | Numeric | Returns the smallest integer greater than or equal to a number |
| `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 |
| `math::log10` | 1 | Numeric | Returns the base 10 logarithm of the number |
| `math::cos` | 1 | Numeric | Computes the cosine of a number (in radians) |
| `math::acos` | 1 | Numeric | Computes the arccosine of a number. Return value is in radians in the range [0, pi] or NaN if the number is outside the range [-1, 1] |
| `math::cosh` | 1 | Numeric | Hyperbolic cosine function |
| `math::acosh` | 1 | Numeric | Inverse hyperbolic cosine function |
| `math::sin` | 1 | Numeric | Computes the sine of a number (in radians) |
| `math::asin` | 1 | Numeric | Computes the arcsine of a number. Return value is in radians in the range [-pi/2, pi/2] or NaN if the number is outside the range [-1, 1] |
| `math::sinh` | 1 | Numeric | Hyperbolic sine function |
| `math::asinh` | 1 | Numeric | Inverse hyperbolic sine function |
| `math::tan` | 1 | Numeric | Computes the tangent of a number (in radians) |
| `math::atan` | 1 | Numeric | Computes the arctangent of a number. Return value is in radians in the range [-pi/2, pi/2] |
| `math::tanh` | 1 | Numeric | Hyperbolic tangent function |
| `math::atanh` | 1 | Numeric | Inverse hyperbolic tangent function. |
| `math::sqrt` | 1 | Numeric | Returns the square root of a number. Returns NaN if a negative number |
| `math::cbrt` | 1 | Numeric | Returns the cube root of a number |
| `str::regex_matches` | 2 | String, String | Returns true if the first argument matches the regex in the second argument (Requires `regex_support` feature flag) |
| `str::regex_replace` | 3 | String, String, String | Returns the first argument with all matches of the regex in the second argument replaced by the third argument (Requires `regex_support` feature flag) |
| `str::to_lowercase` | 1 | String | Returns the lower-case version of the string |
| `str::to_uppercase` | 1 | String | Returns the upper-case version of the string |
| `str::trim` | 1 | String | Strips whitespace from the start and the end of the string |
| `str::from` | >= 0 | Any | Returns passed value as string |
The `min` and `max` functions can deal with a mixture of integer and floating point arguments.
If the maximum or minimum is an integer, then an integer is returned.

View File

@ -6,8 +6,49 @@ use crate::{
EvalexprError, Function, Value, ValueType,
};
macro_rules! simple_math {
($func:ident) => {
Some(Function::new(|argument| {
let num = argument.as_number()?;
Ok(Value::Float(num.$func()))
}))
};
}
pub fn builtin_function(identifier: &str) -> Option<Function> {
match identifier {
// Log
"math::ln" => simple_math!(ln),
"math::log" => Some(Function::new(|argument| {
let tuple = argument.as_fixed_len_tuple(2)?;
let (a, b) = (tuple[0].as_number()?, tuple[1].as_number()?);
Ok(Value::Float(a.log(b)))
})),
"math::log2" => simple_math!(log2),
"math::log10" => simple_math!(log10),
// Cos
"math::cos" => simple_math!(cos),
"math::acos" => simple_math!(acos),
"math::cosh" => simple_math!(cosh),
"math::acosh" => simple_math!(acosh),
// Sin
"math::sin" => simple_math!(sin),
"math::asin" => simple_math!(asin),
"math::sinh" => simple_math!(sinh),
"math::asinh" => simple_math!(asinh),
// Tan
"math::tan" => simple_math!(tan),
"math::atan" => simple_math!(atan),
"math::tanh" => simple_math!(tanh),
"math::atanh" => simple_math!(atanh),
// Root
"math::sqrt" => simple_math!(sqrt),
"math::cbrt" => simple_math!(cbrt),
// Rounding
"floor" => simple_math!(floor),
"round" => simple_math!(round),
"ceil" => simple_math!(ceil),
// Other
"min" => Some(Function::new(|argument| {
let arguments = argument.as_tuple()?;
let mut min_int = IntType::max_value();
@ -52,7 +93,6 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
Ok(Value::Float(max_float))
}
})),
"len" => Some(Function::new(|argument| {
if let Ok(subject) = argument.as_string() {
Ok(Value::from(subject.len() as i64))
@ -65,8 +105,7 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
))
}
})),
// string functions
// String functions
#[cfg(feature = "regex_support")]
"str::regex_matches" => Some(Function::new(|argument| {
let arguments = argument.as_tuple()?;
@ -110,6 +149,9 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
let subject = argument.as_string()?;
Ok(Value::from(subject.trim()))
})),
"str::from" => Some(Function::new(|argument| {
Ok(Value::String(argument.to_string()))
})),
_ => None,
}
}

View File

@ -308,15 +308,37 @@
//! This crate offers a set of builtin functions.
//!
//! | Identifier | Argument Amount | Argument Types | Description |
//! |------------|-----------------|----------------|-------------|
//! |----------------------|-----------------|------------------------|-------------|
//! | `min` | >= 1 | Numeric | Returns the minimum of the arguments |
//! | `max` | >= 1 | Numeric | Returns the maximum of the arguments |
//! | `len` | 1 | String/Tuple | Returns the character length of a string, or the amount of elements in a tuple (not recursively) |
//! | `floor` | 1 | Numeric | Returns the largest integer less than or equal to a number |
//! | `round` | 1 | Numeric | Returns the nearest integer to a number. Round half-way cases away from 0.0 |
//! | `ceil` | 1 | Numeric | Returns the smallest integer greater than or equal to a number |
//! | `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 |
//! | `math::log10` | 1 | Numeric | Returns the base 10 logarithm of the number |
//! | `math::cos` | 1 | Numeric | Computes the cosine of a number (in radians) |
//! | `math::acos` | 1 | Numeric | Computes the arccosine of a number. Return value is in radians in the range [0, pi] or NaN if the number is outside the range [-1, 1] |
//! | `math::cosh` | 1 | Numeric | Hyperbolic cosine function |
//! | `math::acosh` | 1 | Numeric | Inverse hyperbolic cosine function |
//! | `math::sin` | 1 | Numeric | Computes the sine of a number (in radians) |
//! | `math::asin` | 1 | Numeric | Computes the arcsine of a number. Return value is in radians in the range [-pi/2, pi/2] or NaN if the number is outside the range [-1, 1] |
//! | `math::sinh` | 1 | Numeric | Hyperbolic sine function |
//! | `math::asinh` | 1 | Numeric | Inverse hyperbolic sine function |
//! | `math::tan` | 1 | Numeric | Computes the tangent of a number (in radians) |
//! | `math::atan` | 1 | Numeric | Computes the arctangent of a number. Return value is in radians in the range [-pi/2, pi/2] |
//! | `math::tanh` | 1 | Numeric | Hyperbolic tangent function |
//! | `math::atanh` | 1 | Numeric | Inverse hyperbolic tangent function. |
//! | `math::sqrt` | 1 | Numeric | Returns the square root of a number. Returns NaN if a negative number |
//! | `math::cbrt` | 1 | Numeric | Returns the cube root of a number |
//! | `str::regex_matches` | 2 | String, String | Returns true if the first argument matches the regex in the second argument (Requires `regex_support` feature flag) |
//! | `str::regex_replace` | 3 | String, String, String | Returns the first argument with all matches of the regex in the second argument replaced by the third argument (Requires `regex_support` feature flag) |
//! | `str::to_lowercase` | 1 | String | Returns the lower-case version of the string |
//! | `str::to_uppercase` | 1 | String | Returns the upper-case version of the string |
//! | `str::trim` | 1 | String | Strips whitespace from the start and the end of the string |
//! | `str::from` | >= 0 | Any | Returns passed value as string |
//!
//! The `min` and `max` functions can deal with a mixture of integer and floating point arguments.
//! If the maximum or minimum is an integer, then an integer is returned.

View File

@ -271,10 +271,44 @@ fn test_n_ary_functions() {
#[test]
fn test_builtin_functions() {
// Log
assert_eq!(eval("math::ln(2.718281828459045)"), Ok(Value::Float(1.0)));
assert_eq!(eval("math::log(9, 9)"), Ok(Value::Float(1.0)));
assert_eq!(eval("math::log2(2)"), Ok(Value::Float(1.0)));
assert_eq!(eval("math::log10(10)"), Ok(Value::Float(1.0)));
// Cos
assert_eq!(eval("math::cos(0)"), Ok(Value::Float(1.0)));
assert_eq!(eval("math::acos(1)"), Ok(Value::Float(0.0)));
assert_eq!(eval("math::cosh(0)"), Ok(Value::Float(1.0)));
assert_eq!(eval("math::acosh(1)"), Ok(Value::Float(0.0)));
// Sin
assert_eq!(eval("math::sin(0)"), Ok(Value::Float(0.0)));
assert_eq!(eval("math::asin(0)"), Ok(Value::Float(0.0)));
assert_eq!(eval("math::sinh(0)"), Ok(Value::Float(0.0)));
assert_eq!(eval("math::asinh(0)"), Ok(Value::Float(0.0)));
// Tan
assert_eq!(eval("math::tan(0)"), Ok(Value::Float(0.0)));
assert_eq!(eval("math::atan(0)"), Ok(Value::Float(0.0)));
assert_eq!(eval("math::tanh(0)"), Ok(Value::Float(0.0)));
assert_eq!(eval("math::atanh(0)"), Ok(Value::Float(0.0)));
// Root
assert_eq!(eval("math::sqrt(25)"), Ok(Value::Float(5.0)));
assert_eq!(eval("math::cbrt(8)"), Ok(Value::Float(2.0)));
// Rounding
assert_eq!(eval("floor(1.1)"), Ok(Value::Float(1.0)));
assert_eq!(eval("floor(1.9)"), Ok(Value::Float(1.0)));
assert_eq!(eval("round(1.1)"), Ok(Value::Float(1.0)));
assert_eq!(eval("round(1.5)"), Ok(Value::Float(2.0)));
assert_eq!(eval("round(2.5)"), Ok(Value::Float(3.0)));
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)));
// Other
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)));
assert_eq!(eval("len(\"a\", \"b\")"), Ok(Value::Int(2)));
// String
assert_eq!(
eval("str::to_lowercase(\"FOOBAR\")"),
Ok(Value::from("foobar"))
@ -287,6 +321,21 @@ fn test_builtin_functions() {
eval("str::trim(\" foo bar \")"),
Ok(Value::from("foo bar"))
);
assert_eq!(
eval("str::from(\"a\")"),
Ok(Value::String(String::from("\"a\"")))
);
assert_eq!(eval("str::from(1.0)"), Ok(Value::String(String::from("1"))));
assert_eq!(eval("str::from(1)"), Ok(Value::String(String::from("1"))));
assert_eq!(
eval("str::from(true)"),
Ok(Value::String(String::from("true")))
);
assert_eq!(
eval("str::from(1, 2, 3)"),
Ok(Value::String(String::from("(1, 2, 3)")))
);
assert_eq!(eval("str::from()"), Ok(Value::String(String::from("()"))));
}
#[test]