1#[cfg(feature = "regex_support")]
2use regex::Regex;
3
4use crate::{
5 value::{FloatType, IntType},
6 EvalexprError, Function, Value, ValueType,
7};
8use std::{
9 collections::HashSet,
10 ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr},
11};
12
13macro_rules! simple_math {
14 ($func:ident) => {
15 Some(Function::new(|argument| {
16 let num = argument.as_number()?;
17 Ok(Value::Float(num.$func()))
18 }))
19 };
20 ($func:ident, 2) => {
21 Some(Function::new(|argument| {
22 let tuple = argument.as_fixed_len_tuple(2)?;
23 let (a, b) = (tuple[0].as_number()?, tuple[1].as_number()?);
24 Ok(Value::Float(a.$func(b)))
25 }))
26 };
27}
28
29fn float_is(func: fn(FloatType) -> bool) -> Option<Function> {
30 Some(Function::new(move |argument| {
31 Ok(func(argument.as_number()?).into())
32 }))
33}
34
35macro_rules! int_function {
36 ($func:ident) => {
37 Some(Function::new(|argument| {
38 let int = argument.as_int()?;
39 Ok(Value::Int(int.$func()))
40 }))
41 };
42 ($func:ident, 2) => {
43 Some(Function::new(|argument| {
44 let tuple = argument.as_fixed_len_tuple(2)?;
45 let (a, b) = (tuple[0].as_int()?, tuple[1].as_int()?);
46 Ok(Value::Int(a.$func(b)))
47 }))
48 };
49}
50
51pub fn builtin_function(identifier: &str) -> Option<Function> {
52 match identifier {
53 "math::ln" => simple_math!(ln),
55 "math::log" => simple_math!(log, 2),
56 "math::log2" => simple_math!(log2),
57 "math::log10" => simple_math!(log10),
58 "math::exp" => simple_math!(exp),
60 "math::exp2" => simple_math!(exp2),
61 "math::pow" => simple_math!(powf, 2),
63 "math::cos" => simple_math!(cos),
65 "math::acos" => simple_math!(acos),
66 "math::cosh" => simple_math!(cosh),
67 "math::acosh" => simple_math!(acosh),
68 "math::sin" => simple_math!(sin),
70 "math::asin" => simple_math!(asin),
71 "math::sinh" => simple_math!(sinh),
72 "math::asinh" => simple_math!(asinh),
73 "math::tan" => simple_math!(tan),
75 "math::atan" => simple_math!(atan),
76 "math::tanh" => simple_math!(tanh),
77 "math::atanh" => simple_math!(atanh),
78 "math::atan2" => simple_math!(atan2, 2),
79 "math::sqrt" => simple_math!(sqrt),
81 "math::cbrt" => simple_math!(cbrt),
82 "math::hypot" => simple_math!(hypot, 2),
84 "floor" => simple_math!(floor),
86 "round" => simple_math!(round),
87 "ceil" => simple_math!(ceil),
88 "math::is_nan" => float_is(FloatType::is_nan),
90 "math::is_finite" => float_is(FloatType::is_finite),
91 "math::is_infinite" => float_is(FloatType::is_infinite),
92 "math::is_normal" => float_is(FloatType::is_normal),
93 "math::abs" => Some(Function::new(|argument| match argument {
95 Value::Float(num) => Ok(Value::Float(num.abs())),
96 Value::Int(num) => Ok(Value::Int(num.abs())),
97 _ => Err(EvalexprError::expected_number(argument.clone())),
98 })),
99 "typeof" => Some(Function::new(move |argument| {
101 Ok(match argument {
102 Value::String(_) => "string",
103 Value::Float(_) => "float",
104 Value::Int(_) => "int",
105 Value::Boolean(_) => "boolean",
106 Value::Tuple(_) => "tuple",
107 Value::Empty => "empty",
108 Value::Map(_) => "map",
109 }
110 .into())
111 })),
112 "min" => Some(Function::new(|argument| {
113 let arguments = argument.as_tuple()?;
114 let mut min_int = IntType::max_value();
115 let mut min_float: FloatType = 1.0 / 0.0;
116 debug_assert!(min_float.is_infinite());
117
118 for argument in arguments {
119 if let Value::Float(float) = argument {
120 min_float = min_float.min(float);
121 } else if let Value::Int(int) = argument {
122 min_int = min_int.min(int);
123 } else {
124 return Err(EvalexprError::expected_number(argument));
125 }
126 }
127
128 if (min_int as FloatType) < min_float {
129 Ok(Value::Int(min_int))
130 } else {
131 Ok(Value::Float(min_float))
132 }
133 })),
134 "max" => Some(Function::new(|argument| {
135 let arguments = argument.as_tuple()?;
136 let mut max_int = IntType::min_value();
137 let mut max_float: FloatType = -1.0 / 0.0;
138 debug_assert!(max_float.is_infinite());
139
140 for argument in arguments {
141 if let Value::Float(float) = argument {
142 max_float = max_float.max(float);
143 } else if let Value::Int(int) = argument {
144 max_int = max_int.max(int);
145 } else {
146 return Err(EvalexprError::expected_number(argument));
147 }
148 }
149
150 if (max_int as FloatType) > max_float {
151 Ok(Value::Int(max_int))
152 } else {
153 Ok(Value::Float(max_float))
154 }
155 })),
156 "if" => Some(Function::new(|argument| {
157 let mut arguments = argument.as_fixed_len_tuple(3)?;
158 let result_index = if arguments[0].as_boolean()? { 1 } else { 2 };
159 Ok(arguments.swap_remove(result_index))
160 })),
161 "contains" => Some(Function::new(move |argument| {
162 let arguments = argument.as_fixed_len_tuple(2)?;
163 if let (Value::Tuple(a), b) = (&arguments[0].clone(), &arguments[1].clone()) {
164 if let Value::String(_) | Value::Int(_) | Value::Float(_) | Value::Boolean(_) = b {
165 Ok(a.contains(b).into())
166 } else {
167 Err(EvalexprError::type_error(
168 b.clone(),
169 vec![
170 ValueType::String,
171 ValueType::Int,
172 ValueType::Float,
173 ValueType::Boolean,
174 ],
175 ))
176 }
177 } else {
178 Err(EvalexprError::expected_tuple(arguments[0].clone()))
179 }
180 })),
181 "contains_any" => Some(Function::new(move |argument| {
182 let arguments = argument.as_fixed_len_tuple(2)?;
183 if let (Value::Tuple(a), b) = (&arguments[0].clone(), &arguments[1].clone()) {
184 if let Value::Tuple(b) = b {
185 let mut contains = false;
186 for value in b {
187 if let Value::String(_)
188 | Value::Int(_)
189 | Value::Float(_)
190 | Value::Boolean(_) = value
191 {
192 if a.contains(value) {
193 contains = true;
194 }
195 } else {
196 return Err(EvalexprError::type_error(
197 value.clone(),
198 vec![
199 ValueType::String,
200 ValueType::Int,
201 ValueType::Float,
202 ValueType::Boolean,
203 ],
204 ));
205 }
206 }
207 Ok(contains.into())
208 } else {
209 Err(EvalexprError::expected_tuple(b.clone()))
210 }
211 } else {
212 Err(EvalexprError::expected_tuple(arguments[0].clone()))
213 }
214 })),
215 "len" => Some(Function::new(|argument| {
216 if let Ok(subject) = argument.as_string() {
217 Ok(Value::from(subject.len() as IntType))
218 } else if let Ok(subject) = argument.as_tuple() {
219 Ok(Value::from(subject.len() as IntType))
220 } else {
221 Err(EvalexprError::type_error(
222 argument.clone(),
223 vec![ValueType::String, ValueType::Tuple],
224 ))
225 }
226 })),
227 #[cfg(feature = "regex_support")]
229 "str::regex_matches" => Some(Function::new(|argument| {
230 let arguments = argument.as_tuple()?;
231
232 let subject = arguments[0].as_string()?;
233 let re_str = arguments[1].as_string()?;
234 match Regex::new(&re_str) {
235 Ok(re) => Ok(Value::Boolean(re.is_match(&subject))),
236 Err(err) => Err(EvalexprError::invalid_regex(
237 re_str.to_string(),
238 format!("{}", err),
239 )),
240 }
241 })),
242 #[cfg(feature = "regex_support")]
243 "str::regex_replace" => Some(Function::new(|argument| {
244 let arguments = argument.as_tuple()?;
245
246 let subject = arguments[0].as_string()?;
247 let re_str = arguments[1].as_string()?;
248 let repl = arguments[2].as_string()?;
249 match Regex::new(&re_str) {
250 Ok(re) => Ok(Value::String(
251 re.replace_all(&subject, repl.as_str()).to_string(),
252 )),
253 Err(err) => Err(EvalexprError::invalid_regex(
254 re_str.to_string(),
255 format!("{}", err),
256 )),
257 }
258 })),
259 "str::to_lowercase" => Some(Function::new(|argument| {
260 let subject = argument.as_string()?;
261 Ok(Value::from(subject.to_lowercase()))
262 })),
263 "str::to_uppercase" => Some(Function::new(|argument| {
264 let subject = argument.as_string()?;
265 Ok(Value::from(subject.to_uppercase()))
266 })),
267 "str::trim" => Some(Function::new(|argument| {
268 let subject = argument.as_string()?;
269 Ok(Value::from(subject.trim()))
270 })),
271 "str::from" => Some(Function::new(|argument| {
272 Ok(Value::String(argument.to_string()))
273 })),
274 #[cfg(feature = "rand")]
275 "random" => Some(Function::new(|argument| {
276 argument.as_empty()?;
277 Ok(Value::Float(rand::random()))
278 })),
279 "bitand" => int_function!(bitand, 2),
281 "bitor" => int_function!(bitor, 2),
282 "bitxor" => int_function!(bitxor, 2),
283 "bitnot" => int_function!(not),
284 "shl" => int_function!(shl, 2),
285 "shr" => int_function!(shr, 2),
286 _ => None,
287 }
288}