expressive/src/function/builtin.rs

207 lines
7.2 KiB
Rust
Raw Normal View History

#[cfg(feature = "regex_support")]
use regex::Regex;
2019-08-29 07:02:05 +00:00
use crate::{
value::{FloatType, IntType},
EvalexprError, Function, Value, ValueType,
2019-08-29 07:02:05 +00:00
};
2022-03-06 18:17:37 +00:00
use std::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr};
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
}
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)))
}))
};
}
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),
2021-05-30 06:52:28 +00:00
// Rounding
"floor" => simple_math!(floor),
"round" => simple_math!(round),
"ceil" => simple_math!(ceil),
// Other
"min" => Some(Function::new(|argument| {
let arguments = argument.as_tuple()?;
2019-05-04 11:54:19 +00:00
let mut min_int = IntType::max_value();
let mut min_float = 1.0f64 / 0.0f64;
debug_assert!(min_float.is_infinite());
2019-05-04 11:54:19 +00:00
for argument in arguments {
if let Value::Float(float) = argument {
min_float = min_float.min(float);
2019-05-04 11:54:19 +00:00
} else if let Value::Int(int) = argument {
min_int = min_int.min(int);
} else {
2021-05-28 06:07:26 +00:00
return Err(EvalexprError::expected_number(argument));
}
2019-05-04 11:54:19 +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))
}
})),
"max" => Some(Function::new(|argument| {
let arguments = argument.as_tuple()?;
2019-05-04 11:54:19 +00:00
let mut max_int = IntType::min_value();
let mut max_float = -1.0f64 / 0.0f64;
debug_assert!(max_float.is_infinite());
2019-05-04 11:54:19 +00:00
for argument in arguments {
if let Value::Float(float) = argument {
max_float = max_float.max(float);
2019-05-04 11:54:19 +00:00
} else if let Value::Int(int) = argument {
max_int = max_int.max(int);
} else {
2021-05-28 06:07:26 +00:00
return Err(EvalexprError::expected_number(argument));
}
2019-05-04 11:54:19 +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))
}
})),
"if" => Some(Function::new(|argument| {
if let [condition, if_true, if_false] = &argument.as_fixed_len_tuple(3)?[..] {
2022-03-14 14:07:38 +00:00
return Ok(if condition.as_boolean()? {
if_true
} else {
if_false
}
.clone());
}
Err(EvalexprError::type_error(
argument.clone(),
vec![ValueType::Boolean, ValueType::Empty, ValueType::Empty],
))
})),
"len" => Some(Function::new(|argument| {
if let Ok(subject) = argument.as_string() {
Ok(Value::from(subject.len() as i64))
} else if let Ok(subject) = argument.as_tuple() {
Ok(Value::from(subject.len() as i64))
} else {
Err(EvalexprError::type_error(
argument.clone(),
vec![ValueType::String, ValueType::Tuple],
))
}
})),
2021-05-30 06:52:28 +00:00
// String functions
#[cfg(feature = "regex_support")]
"str::regex_matches" => Some(Function::new(|argument| {
let arguments = argument.as_tuple()?;
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),
)),
}
})),
#[cfg(feature = "regex_support")]
"str::regex_replace" => Some(Function::new(|argument| {
let arguments = argument.as_tuple()?;
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),
)),
}
})),
"str::to_lowercase" => Some(Function::new(|argument| {
let subject = argument.as_string()?;
2019-05-04 11:54:19 +00:00
Ok(Value::from(subject.to_lowercase()))
})),
"str::to_uppercase" => Some(Function::new(|argument| {
let subject = argument.as_string()?;
2019-05-04 11:54:19 +00:00
Ok(Value::from(subject.to_uppercase()))
})),
"str::trim" => Some(Function::new(|argument| {
let subject = argument.as_string()?;
2019-05-04 11:54:19 +00:00
Ok(Value::from(subject.trim()))
})),
2021-05-30 06:52:28 +00:00
"str::from" => Some(Function::new(|argument| {
Ok(Value::String(argument.to_string()))
})),
// 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),
_ => None,
}
}