2019-04-07 06:10:36 +00:00
|
|
|
#[cfg(feature = "regex_support")]
|
|
|
|
use regex::Regex;
|
|
|
|
|
2019-08-29 07:02:05 +00:00
|
|
|
use crate::{
|
|
|
|
value::{FloatType, IntType},
|
2019-08-29 08:10:54 +00:00
|
|
|
EvalexprError, Function, Value, ValueType,
|
2019-08-29 07:02:05 +00:00
|
|
|
};
|
2023-06-24 01:44:40 +00:00
|
|
|
use std::{
|
|
|
|
collections::HashSet,
|
|
|
|
ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr},
|
|
|
|
};
|
2019-03-19 18:08:23 +00:00
|
|
|
|
2021-05-30 06:52:28 +00:00
|
|
|
macro_rules! simple_math {
|
|
|
|
($func:ident) => {
|
|
|
|
Some(Function::new(|argument| {
|
|
|
|
let num = argument.as_number()?;
|
|
|
|
Ok(Value::Float(num.$func()))
|
|
|
|
}))
|
|
|
|
};
|
2021-06-30 20:11:58 +00:00
|
|
|
($func:ident, 2) => {
|
|
|
|
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.$func(b)))
|
|
|
|
}))
|
|
|
|
};
|
2021-05-30 06:52:28 +00:00
|
|
|
}
|
|
|
|
|
2022-09-14 18:36:36 +00:00
|
|
|
fn float_is(func: fn(FloatType) -> bool) -> Option<Function> {
|
2022-03-23 17:09:23 +00:00
|
|
|
Some(Function::new(move |argument| {
|
2022-03-23 15:33:53 +00:00
|
|
|
Ok(func(argument.as_number()?).into())
|
2022-03-23 17:09:23 +00:00
|
|
|
}))
|
2022-03-23 12:04:09 +00:00
|
|
|
}
|
|
|
|
|
2021-07-30 14:06:23 +00:00
|
|
|
macro_rules! int_function {
|
|
|
|
($func:ident) => {
|
|
|
|
Some(Function::new(|argument| {
|
|
|
|
let int = argument.as_int()?;
|
|
|
|
Ok(Value::Int(int.$func()))
|
|
|
|
}))
|
|
|
|
};
|
|
|
|
($func:ident, 2) => {
|
|
|
|
Some(Function::new(|argument| {
|
|
|
|
let tuple = argument.as_fixed_len_tuple(2)?;
|
|
|
|
let (a, b) = (tuple[0].as_int()?, tuple[1].as_int()?);
|
|
|
|
Ok(Value::Int(a.$func(b)))
|
|
|
|
}))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-03-19 18:08:23 +00:00
|
|
|
pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|
|
|
match identifier {
|
2021-05-30 06:52:28 +00:00
|
|
|
// Log
|
2021-05-30 23:04:33 +00:00
|
|
|
"math::ln" => simple_math!(ln),
|
2021-06-30 20:11:58 +00:00
|
|
|
"math::log" => simple_math!(log, 2),
|
2021-05-30 23:04:33 +00:00
|
|
|
"math::log2" => simple_math!(log2),
|
|
|
|
"math::log10" => simple_math!(log10),
|
2021-06-30 20:11:58 +00:00
|
|
|
// Exp
|
|
|
|
"math::exp" => simple_math!(exp),
|
|
|
|
"math::exp2" => simple_math!(exp2),
|
|
|
|
// Pow
|
|
|
|
"math::pow" => simple_math!(powf, 2),
|
2021-05-30 06:52:28 +00:00
|
|
|
// Cos
|
2021-05-30 23:04:33 +00:00
|
|
|
"math::cos" => simple_math!(cos),
|
|
|
|
"math::acos" => simple_math!(acos),
|
|
|
|
"math::cosh" => simple_math!(cosh),
|
|
|
|
"math::acosh" => simple_math!(acosh),
|
2021-05-30 06:52:28 +00:00
|
|
|
// Sin
|
2021-05-30 23:04:33 +00:00
|
|
|
"math::sin" => simple_math!(sin),
|
|
|
|
"math::asin" => simple_math!(asin),
|
|
|
|
"math::sinh" => simple_math!(sinh),
|
|
|
|
"math::asinh" => simple_math!(asinh),
|
2021-05-30 06:52:28 +00:00
|
|
|
// Tan
|
2021-05-30 23:04:33 +00:00
|
|
|
"math::tan" => simple_math!(tan),
|
|
|
|
"math::atan" => simple_math!(atan),
|
|
|
|
"math::tanh" => simple_math!(tanh),
|
|
|
|
"math::atanh" => simple_math!(atanh),
|
2021-06-30 20:11:58 +00:00
|
|
|
"math::atan2" => simple_math!(atan2, 2),
|
2021-05-30 06:52:28 +00:00
|
|
|
// Root
|
2021-05-30 23:04:33 +00:00
|
|
|
"math::sqrt" => simple_math!(sqrt),
|
|
|
|
"math::cbrt" => simple_math!(cbrt),
|
2021-06-30 20:11:58 +00:00
|
|
|
// Hypotenuse
|
|
|
|
"math::hypot" => simple_math!(hypot, 2),
|
2023-05-27 08:04:56 +00:00
|
|
|
// Rounding
|
2021-05-30 06:52:28 +00:00
|
|
|
"floor" => simple_math!(floor),
|
|
|
|
"round" => simple_math!(round),
|
|
|
|
"ceil" => simple_math!(ceil),
|
2022-03-30 12:44:19 +00:00
|
|
|
// Float special values
|
2022-09-14 18:36:36 +00:00
|
|
|
"math::is_nan" => float_is(FloatType::is_nan),
|
|
|
|
"math::is_finite" => float_is(FloatType::is_finite),
|
|
|
|
"math::is_infinite" => float_is(FloatType::is_infinite),
|
|
|
|
"math::is_normal" => float_is(FloatType::is_normal),
|
2023-05-21 07:12:12 +00:00
|
|
|
// Absolute
|
2023-05-27 08:04:56 +00:00
|
|
|
"math::abs" => Some(Function::new(|argument| match argument {
|
|
|
|
Value::Float(num) => Ok(Value::Float(num.abs())),
|
|
|
|
Value::Int(num) => Ok(Value::Int(num.abs())),
|
|
|
|
_ => Err(EvalexprError::expected_number(argument.clone())),
|
2023-05-21 07:12:12 +00:00
|
|
|
})),
|
2021-05-30 06:52:28 +00:00
|
|
|
// Other
|
2022-03-23 17:09:23 +00:00
|
|
|
"typeof" => Some(Function::new(move |argument| {
|
2022-03-23 15:33:53 +00:00
|
|
|
Ok(match argument {
|
|
|
|
Value::String(_) => "string",
|
|
|
|
Value::Float(_) => "float",
|
|
|
|
Value::Int(_) => "int",
|
|
|
|
Value::Boolean(_) => "boolean",
|
|
|
|
Value::Tuple(_) => "tuple",
|
|
|
|
Value::Empty => "empty",
|
2023-06-22 05:07:17 +00:00
|
|
|
Value::Map(_) => "map",
|
2022-03-23 17:09:23 +00:00
|
|
|
}
|
|
|
|
.into())
|
|
|
|
})),
|
2021-05-28 11:12:26 +00:00
|
|
|
"min" => Some(Function::new(|argument| {
|
2019-08-29 05:56:49 +00:00
|
|
|
let arguments = argument.as_tuple()?;
|
2019-05-04 11:54:19 +00:00
|
|
|
let mut min_int = IntType::max_value();
|
2022-09-14 18:36:36 +00:00
|
|
|
let mut min_float: FloatType = 1.0 / 0.0;
|
2019-05-04 11:54:19 +00:00
|
|
|
debug_assert!(min_float.is_infinite());
|
2019-03-19 18:08:23 +00:00
|
|
|
|
2019-05-04 11:54:19 +00:00
|
|
|
for argument in arguments {
|
|
|
|
if let Value::Float(float) = argument {
|
2019-08-29 05:56:49 +00:00
|
|
|
min_float = min_float.min(float);
|
2019-05-04 11:54:19 +00:00
|
|
|
} else if let Value::Int(int) = argument {
|
2019-08-29 05:56:49 +00:00
|
|
|
min_int = min_int.min(int);
|
2019-03-19 18:08:23 +00:00
|
|
|
} else {
|
2021-05-28 06:07:26 +00:00
|
|
|
return Err(EvalexprError::expected_number(argument));
|
2019-03-19 18:08:23 +00:00
|
|
|
}
|
2019-05-04 11:54:19 +00:00
|
|
|
}
|
2019-03-19 18:08:23 +00:00
|
|
|
|
2019-05-04 11:54:19 +00:00
|
|
|
if (min_int as FloatType) < min_float {
|
|
|
|
Ok(Value::Int(min_int))
|
|
|
|
} else {
|
|
|
|
Ok(Value::Float(min_float))
|
|
|
|
}
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
|
|
|
"max" => Some(Function::new(|argument| {
|
2019-08-29 05:56:49 +00:00
|
|
|
let arguments = argument.as_tuple()?;
|
2019-05-04 11:54:19 +00:00
|
|
|
let mut max_int = IntType::min_value();
|
2022-09-14 18:36:36 +00:00
|
|
|
let mut max_float: FloatType = -1.0 / 0.0;
|
2019-05-04 11:54:19 +00:00
|
|
|
debug_assert!(max_float.is_infinite());
|
2019-03-19 18:08:23 +00:00
|
|
|
|
2019-05-04 11:54:19 +00:00
|
|
|
for argument in arguments {
|
|
|
|
if let Value::Float(float) = argument {
|
2019-08-29 05:56:49 +00:00
|
|
|
max_float = max_float.max(float);
|
2019-05-04 11:54:19 +00:00
|
|
|
} else if let Value::Int(int) = argument {
|
2019-08-29 05:56:49 +00:00
|
|
|
max_int = max_int.max(int);
|
2019-03-19 18:08:23 +00:00
|
|
|
} else {
|
2021-05-28 06:07:26 +00:00
|
|
|
return Err(EvalexprError::expected_number(argument));
|
2019-03-19 18:08:23 +00:00
|
|
|
}
|
2019-05-04 11:54:19 +00:00
|
|
|
}
|
2019-04-07 06:10:36 +00:00
|
|
|
|
2019-05-04 11:54:19 +00:00
|
|
|
if (max_int as FloatType) > max_float {
|
|
|
|
Ok(Value::Int(max_int))
|
|
|
|
} else {
|
|
|
|
Ok(Value::Float(max_float))
|
|
|
|
}
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
2022-03-14 13:59:48 +00:00
|
|
|
"if" => Some(Function::new(|argument| {
|
2022-03-14 14:58:42 +00:00
|
|
|
let mut arguments = argument.as_fixed_len_tuple(3)?;
|
2022-03-14 15:08:08 +00:00
|
|
|
let result_index = if arguments[0].as_boolean()? { 1 } else { 2 };
|
|
|
|
Ok(arguments.swap_remove(result_index))
|
2022-03-14 13:59:48 +00:00
|
|
|
})),
|
2023-05-10 17:31:33 +00:00
|
|
|
"contains" => Some(Function::new(move |argument| {
|
|
|
|
let arguments = argument.as_fixed_len_tuple(2)?;
|
|
|
|
if let (Value::Tuple(a), b) = (&arguments[0].clone(), &arguments[1].clone()) {
|
|
|
|
if let Value::String(_) | Value::Int(_) | Value::Float(_) | Value::Boolean(_) = b {
|
|
|
|
Ok(a.contains(b).into())
|
|
|
|
} else {
|
|
|
|
Err(EvalexprError::type_error(
|
|
|
|
b.clone(),
|
|
|
|
vec![
|
|
|
|
ValueType::String,
|
|
|
|
ValueType::Int,
|
|
|
|
ValueType::Float,
|
|
|
|
ValueType::Boolean,
|
|
|
|
],
|
|
|
|
))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(EvalexprError::expected_tuple(arguments[0].clone()))
|
|
|
|
}
|
|
|
|
})),
|
|
|
|
"contains_any" => Some(Function::new(move |argument| {
|
|
|
|
let arguments = argument.as_fixed_len_tuple(2)?;
|
2023-05-08 13:36:13 +00:00
|
|
|
if let (Value::Tuple(a), b) = (&arguments[0].clone(), &arguments[1].clone()) {
|
|
|
|
if let Value::Tuple(b) = b {
|
2023-05-10 17:31:33 +00:00
|
|
|
let mut contains = false;
|
|
|
|
for value in b {
|
|
|
|
if let Value::String(_)
|
|
|
|
| Value::Int(_)
|
|
|
|
| Value::Float(_)
|
|
|
|
| Value::Boolean(_) = value
|
|
|
|
{
|
|
|
|
if a.contains(value) {
|
|
|
|
contains = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(EvalexprError::type_error(
|
|
|
|
value.clone(),
|
|
|
|
vec![
|
|
|
|
ValueType::String,
|
|
|
|
ValueType::Int,
|
|
|
|
ValueType::Float,
|
|
|
|
ValueType::Boolean,
|
|
|
|
],
|
|
|
|
));
|
2023-05-08 13:36:13 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-10 17:31:33 +00:00
|
|
|
Ok(contains.into())
|
2023-05-08 13:36:13 +00:00
|
|
|
} else {
|
2023-05-10 17:31:33 +00:00
|
|
|
Err(EvalexprError::expected_tuple(b.clone()))
|
2023-05-08 13:36:13 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-05-10 17:31:33 +00:00
|
|
|
Err(EvalexprError::expected_tuple(arguments[0].clone()))
|
2023-05-08 13:36:13 +00:00
|
|
|
}
|
|
|
|
})),
|
2021-05-28 11:12:26 +00:00
|
|
|
"len" => Some(Function::new(|argument| {
|
2019-08-29 08:10:54 +00:00
|
|
|
if let Ok(subject) = argument.as_string() {
|
2022-09-14 18:36:36 +00:00
|
|
|
Ok(Value::from(subject.len() as IntType))
|
2019-08-29 08:10:54 +00:00
|
|
|
} else if let Ok(subject) = argument.as_tuple() {
|
2022-09-14 18:36:36 +00:00
|
|
|
Ok(Value::from(subject.len() as IntType))
|
2019-08-29 08:10:54 +00:00
|
|
|
} else {
|
|
|
|
Err(EvalexprError::type_error(
|
|
|
|
argument.clone(),
|
|
|
|
vec![ValueType::String, ValueType::Tuple],
|
|
|
|
))
|
|
|
|
}
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
2021-05-30 06:52:28 +00:00
|
|
|
// String functions
|
2019-04-07 06:10:36 +00:00
|
|
|
#[cfg(feature = "regex_support")]
|
2021-05-28 11:12:26 +00:00
|
|
|
"str::regex_matches" => Some(Function::new(|argument| {
|
2019-08-29 05:56:49 +00:00
|
|
|
let arguments = argument.as_tuple()?;
|
2019-05-04 11:43:29 +00:00
|
|
|
|
2019-08-29 05:56:49 +00:00
|
|
|
let subject = arguments[0].as_string()?;
|
|
|
|
let re_str = arguments[1].as_string()?;
|
|
|
|
match Regex::new(&re_str) {
|
|
|
|
Ok(re) => Ok(Value::Boolean(re.is_match(&subject))),
|
2019-05-04 11:54:19 +00:00
|
|
|
Err(err) => Err(EvalexprError::invalid_regex(
|
|
|
|
re_str.to_string(),
|
|
|
|
format!("{}", err),
|
|
|
|
)),
|
|
|
|
}
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
2019-04-07 06:10:36 +00:00
|
|
|
#[cfg(feature = "regex_support")]
|
2021-05-28 11:12:26 +00:00
|
|
|
"str::regex_replace" => Some(Function::new(|argument| {
|
2019-08-29 05:56:49 +00:00
|
|
|
let arguments = argument.as_tuple()?;
|
2019-05-04 11:43:29 +00:00
|
|
|
|
2019-08-29 05:56:49 +00:00
|
|
|
let subject = arguments[0].as_string()?;
|
|
|
|
let re_str = arguments[1].as_string()?;
|
|
|
|
let repl = arguments[2].as_string()?;
|
|
|
|
match Regex::new(&re_str) {
|
2019-08-29 07:02:05 +00:00
|
|
|
Ok(re) => Ok(Value::String(
|
|
|
|
re.replace_all(&subject, repl.as_str()).to_string(),
|
|
|
|
)),
|
2019-05-04 11:54:19 +00:00
|
|
|
Err(err) => Err(EvalexprError::invalid_regex(
|
|
|
|
re_str.to_string(),
|
|
|
|
format!("{}", err),
|
|
|
|
)),
|
|
|
|
}
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
|
|
|
"str::to_lowercase" => Some(Function::new(|argument| {
|
2019-08-29 05:56:49 +00:00
|
|
|
let subject = argument.as_string()?;
|
2019-05-04 11:54:19 +00:00
|
|
|
Ok(Value::from(subject.to_lowercase()))
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
|
|
|
"str::to_uppercase" => Some(Function::new(|argument| {
|
2019-08-29 05:56:49 +00:00
|
|
|
let subject = argument.as_string()?;
|
2019-05-04 11:54:19 +00:00
|
|
|
Ok(Value::from(subject.to_uppercase()))
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
|
|
|
"str::trim" => Some(Function::new(|argument| {
|
2019-08-29 05:56:49 +00:00
|
|
|
let subject = argument.as_string()?;
|
2019-05-04 11:54:19 +00:00
|
|
|
Ok(Value::from(subject.trim()))
|
2021-05-28 11:12:26 +00:00
|
|
|
})),
|
2021-05-30 06:52:28 +00:00
|
|
|
"str::from" => Some(Function::new(|argument| {
|
|
|
|
Ok(Value::String(argument.to_string()))
|
|
|
|
})),
|
2022-03-30 12:39:26 +00:00
|
|
|
#[cfg(feature = "rand")]
|
|
|
|
"random" => Some(Function::new(|argument| {
|
|
|
|
argument.as_empty()?;
|
|
|
|
Ok(Value::Float(rand::random()))
|
|
|
|
})),
|
2021-07-30 14:06:23 +00:00
|
|
|
// Bitwise operators
|
|
|
|
"bitand" => int_function!(bitand, 2),
|
|
|
|
"bitor" => int_function!(bitor, 2),
|
|
|
|
"bitxor" => int_function!(bitxor, 2),
|
|
|
|
"bitnot" => int_function!(not),
|
2022-03-06 18:17:37 +00:00
|
|
|
"shl" => int_function!(shl, 2),
|
|
|
|
"shr" => int_function!(shr, 2),
|
2019-03-19 18:08:23 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|