1use base64::Engine;
2use chrono::{TimeZone, Utc};
3use hashbrown::{DefaultHashBuilder, HashMap};
4use rand::Rng;
5use regress::{Range, Regex};
6use std::borrow::{Borrow, Cow};
7use std::collections::HashSet;
8use std::time::{SystemTime, UNIX_EPOCH};
9use uuid::Uuid;
10
11use crate::datetime::{format_custom_date, parse_custom_format, parse_timezone_offset};
12use crate::evaluator::RegexLiteral;
13use crate::parser::expressions::check_balanced_brackets;
14
15use bumpalo::collections::CollectIn;
16use bumpalo::collections::String as BumpString;
17use bumpalo::collections::Vec as BumpVec;
18use bumpalo::Bump;
19
20use crate::{Error, Result};
21
22use super::frame::Frame;
23use super::value::serialize::{DumpFormatter, PrettyFormatter, Serializer};
24use super::value::{ArrayFlags, Value};
25use super::Evaluator;
26
27macro_rules! min_args {
28 ($context:ident, $args:ident, $min:literal) => {
29 if $args.len() < $min {
30 return Err(Error::T0410ArgumentNotValid(
31 $context.char_index,
32 $min,
33 $context.name.to_string(),
34 ));
35 }
36 };
37}
38
39macro_rules! max_args {
40 ($context:ident, $args:ident, $max:literal) => {
41 if $args.len() > $max {
42 return Err(Error::T0410ArgumentNotValid(
43 $context.char_index,
44 $max,
45 $context.name.to_string(),
46 ));
47 }
48 };
49}
50
51macro_rules! bad_arg {
52 ($context:ident, $index:literal) => {
53 return Err(Error::T0410ArgumentNotValid(
54 $context.char_index,
55 $index,
56 $context.name.to_string(),
57 ))
58 };
59}
60
61macro_rules! assert_arg {
62 ($condition: expr, $context:ident, $index:literal) => {
63 if !($condition) {
64 bad_arg!($context, $index);
65 }
66 };
67}
68
69macro_rules! assert_array_of_type {
70 ($condition:expr, $context:ident, $index:literal, $t:literal) => {
71 if !($condition) {
72 return Err(Error::T0412ArgumentMustBeArrayOfType(
73 $context.char_index,
74 $index,
75 $context.name.to_string(),
76 $t.to_string(),
77 ));
78 };
79 };
80}
81
82#[derive(Clone)]
83pub struct FunctionContext<'a, 'e> {
84 pub name: &'a str,
85 pub char_index: usize,
86 pub input: &'a Value<'a>,
87 pub frame: Frame<'a>,
88 pub evaluator: &'e Evaluator<'a>,
89 pub arena: &'a Bump,
90}
91
92#[allow(clippy::needless_lifetimes)]
93impl<'a, 'e> FunctionContext<'a, 'e> {
94 pub fn evaluate_function(
95 &self,
96 proc: &'a Value<'a>,
97 args: &[&'a Value<'a>],
98 ) -> Result<&'a Value<'a>> {
99 self.evaluator
100 .apply_function(self.char_index, self.input, proc, args, &self.frame)
101 }
102
103 pub fn trampoline_evaluate_value(&self, value: &'a Value<'a>) -> Result<&'a Value<'a>> {
104 self.evaluator
105 .trampoline_evaluate_value(value, self.input, &self.frame)
106 }
107}
108
109pub fn fn_append_internal<'a>(values: &mut BumpVec<&'a Value<'a>>, value: &'a Value<'a>) {
114 if value.is_undefined() {
115 return;
116 }
117
118 match value {
119 Value::Array(a, _) => values.extend_from_slice(a),
120 Value::Range(_) => values.extend(value.members()),
121 _ => values.push(value),
122 }
123}
124
125pub fn fn_append<'a>(
126 context: FunctionContext<'a, '_>,
127 args: &[&'a Value<'a>],
128) -> Result<&'a Value<'a>> {
129 let arg1 = args.first().copied().unwrap_or_else(Value::undefined);
130 let arg2 = args.get(1).copied().unwrap_or_else(Value::undefined);
131
132 if arg1.is_undefined() {
133 return Ok(arg2);
134 }
135
136 if arg2.is_undefined() {
137 return Ok(arg1);
138 }
139
140 let arg1_len = if arg1.is_array() { arg1.len() } else { 1 };
141 let arg2_len = if arg2.is_array() { arg2.len() } else { 1 };
142
143 let result = Value::array_with_capacity(
144 context.arena,
145 arg1_len + arg2_len,
146 if arg1.is_array() {
147 arg1.get_flags()
148 } else {
149 ArrayFlags::SEQUENCE
150 },
151 );
152
153 if arg1.is_array() {
154 arg1.members().for_each(|m| result.push(m));
155 } else {
156 result.push(arg1);
157 }
158
159 if arg2.is_array() {
160 arg2.members().for_each(|m| result.push(m));
161 } else {
162 result.push(arg2)
163 }
164
165 Ok(result)
166}
167
168pub fn fn_boolean<'a>(
169 context: FunctionContext<'a, '_>,
170 args: &[&'a Value<'a>],
171) -> Result<&'a Value<'a>> {
172 max_args!(context, args, 1);
173
174 let arg = args.first().copied().unwrap_or_else(Value::undefined);
175 Ok(match arg {
176 Value::Undefined => Value::undefined(),
177 Value::Null => Value::bool(false),
178 Value::Bool(b) => Value::bool(*b),
179 Value::Number(n) => {
180 arg.is_valid_number()?;
181 Value::bool(*n != 0.0)
182 }
183 Value::String(ref str) => Value::bool(!str.is_empty()),
184 Value::Object(ref obj) => Value::bool(!obj.is_empty()),
185 Value::Array { .. } => match arg.len() {
186 0 => Value::bool(false),
187 1 => fn_boolean(context.clone(), &[arg.get_member(0)])?,
188 _ => {
189 for item in arg.members() {
190 if fn_boolean(context.clone(), &[item])?.as_bool() {
191 return Ok(Value::bool(true));
192 }
193 }
194 Value::bool(false)
195 }
196 },
197 Value::Regex(_) => Value::bool(true),
198 Value::Lambda { .. } | Value::NativeFn { .. } | Value::Transformer { .. } => {
199 Value::bool(false)
200 }
201 Value::Range(ref range) => Value::bool(!range.is_empty()),
202 })
203}
204
205pub fn fn_map<'a>(
206 context: FunctionContext<'a, '_>,
207 args: &[&'a Value<'a>],
208) -> Result<&'a Value<'a>> {
209 let arr = args.first().copied().unwrap_or_else(Value::undefined);
210 let func = args.get(1).copied().unwrap_or_else(Value::undefined);
211
212 if arr.is_undefined() {
213 return Ok(Value::undefined());
214 }
215
216 let arr = Value::wrap_in_array_if_needed(context.arena, arr, ArrayFlags::empty());
217
218 assert_arg!(func.is_function(), context, 2);
219
220 let result = Value::array(context.arena, ArrayFlags::SEQUENCE);
221
222 for (index, item) in arr.members().enumerate() {
223 let mut args = Vec::new();
224 let arity = func.arity();
225
226 args.push(item);
227 if arity >= 2 {
228 args.push(Value::number(context.arena, index as f64));
229 }
230 if arity >= 3 {
231 args.push(arr);
232 }
233
234 let mapped = context.trampoline_evaluate_value(context.evaluate_function(func, &args)?)?;
235
236 if !mapped.is_undefined() {
237 result.push(mapped);
238 }
239 }
240
241 Ok(result)
242}
243
244pub fn fn_filter<'a>(
245 context: FunctionContext<'a, '_>,
246 args: &[&'a Value<'a>],
247) -> Result<&'a Value<'a>> {
248 let arr = args.first().copied().unwrap_or_else(Value::undefined);
249 let func = args.get(1).copied().unwrap_or_else(Value::undefined);
250
251 if arr.is_undefined() {
252 return Ok(Value::undefined());
253 }
254
255 let arr = Value::wrap_in_array_if_needed(context.arena, arr, ArrayFlags::empty());
256
257 assert_arg!(func.is_function(), context, 2);
258
259 let result = Value::array(context.arena, ArrayFlags::SEQUENCE);
260
261 for (index, item) in arr.members().enumerate() {
262 let mut args = Vec::new();
263 let arity = func.arity();
264
265 args.push(item);
266 if arity >= 2 {
267 args.push(Value::number(context.arena, index as f64));
268 }
269 if arity >= 3 {
270 args.push(arr);
271 }
272
273 let include = context.evaluate_function(func, &args)?;
274
275 if include.is_truthy() {
276 result.push(item);
277 }
278 }
279
280 Ok(result)
281}
282
283pub fn fn_each<'a>(
284 context: FunctionContext<'a, '_>,
285 args: &[&'a Value<'a>],
286) -> Result<&'a Value<'a>> {
287 let (obj, func) = if args.len() == 1 {
288 let obj_arg = if context.input.is_array() && context.input.has_flags(ArrayFlags::WRAPPED) {
289 &context.input[0]
290 } else {
291 context.input
292 };
293
294 (obj_arg, args[0])
295 } else {
296 (args[0], args[1])
297 };
298
299 if obj.is_undefined() {
300 return Ok(Value::undefined());
301 }
302
303 assert_arg!(obj.is_object(), context, 1);
304 assert_arg!(func.is_function(), context, 2);
305
306 let result = Value::array(context.arena, ArrayFlags::SEQUENCE);
307
308 for (key, value) in obj.entries() {
309 let key = Value::string(context.arena, key);
310
311 let mapped = context.evaluate_function(func, &[value, key])?;
312 if !mapped.is_undefined() {
313 result.push(mapped);
314 }
315 }
316
317 Ok(result)
318}
319
320pub fn fn_keys<'a>(
321 context: FunctionContext<'a, '_>,
322 args: &[&'a Value<'a>],
323) -> Result<&'a Value<'a>> {
324 let obj = if args.is_empty() {
325 if context.input.is_array() && context.input.has_flags(ArrayFlags::WRAPPED) {
326 &context.input[0]
327 } else {
328 context.input
329 }
330 } else {
331 args[0]
332 };
333
334 if obj.is_undefined() {
335 return Ok(Value::undefined());
336 }
337
338 let mut keys = Vec::new();
339
340 if obj.is_array() && obj.members().all(|member| member.is_object()) {
341 for sub_object in obj.members() {
342 for (key, _) in sub_object.entries() {
343 if !keys.iter().any(|item| item == key) {
345 keys.push(key.to_string());
346 }
347 }
348 }
349 } else if obj.is_object() {
350 for (key, _) in obj.entries() {
351 keys.push(key.to_string());
352 }
353 }
354
355 let result = Value::array(context.arena, ArrayFlags::SEQUENCE);
356 for key in keys {
357 result.push(Value::string(context.arena, &key));
358 }
359
360 Ok(result)
361}
362
363pub fn fn_merge<'a>(
364 context: FunctionContext<'a, '_>,
365 args: &[&'a Value<'a>],
366) -> Result<&'a Value<'a>> {
367 let mut array_of_objects = if args.is_empty() {
368 if context.input.is_array() && context.input.has_flags(ArrayFlags::WRAPPED) {
369 &context.input[0]
370 } else {
371 context.input
372 }
373 } else {
374 args[0]
375 };
376
377 if array_of_objects.is_undefined() {
378 return Ok(Value::undefined());
379 }
380
381 if array_of_objects.is_object() {
382 array_of_objects =
383 Value::wrap_in_array(context.arena, array_of_objects, ArrayFlags::empty());
384 }
385
386 assert_arg!(
387 array_of_objects.is_array() && array_of_objects.members().all(|member| member.is_object()),
388 context,
389 1
390 );
391
392 let result = Value::object(context.arena);
393
394 for obj in array_of_objects.members() {
395 for (key, value) in obj.entries() {
396 result.insert(key, value);
397 }
398 }
399
400 Ok(result)
401}
402
403pub fn fn_string<'a>(
404 context: FunctionContext<'a, '_>,
405 args: &[&'a Value<'a>],
406) -> Result<&'a Value<'a>> {
407 max_args!(context, args, 2);
408
409 let input = if args.is_empty() {
410 if context.input.is_array() && context.input.has_flags(ArrayFlags::WRAPPED) {
411 &context.input[0]
412 } else {
413 context.input
414 }
415 } else {
416 args.first().copied().unwrap_or_else(Value::undefined)
417 };
418
419 if input.is_undefined() {
420 return Ok(Value::undefined());
421 }
422
423 let pretty = args.get(1).copied().unwrap_or_else(Value::undefined);
424 assert_arg!(pretty.is_undefined() || pretty.is_bool(), context, 2);
425
426 if input.is_string() {
427 Ok(input)
428 } else if input.is_function() {
429 Ok(Value::string(context.arena, ""))
430 } else if input.is_number() && !input.is_finite() {
431 Err(Error::D3001StringNotFinite(context.char_index))
432 } else if *pretty == true {
433 let serializer = Serializer::new(PrettyFormatter::default(), true);
434 let output = serializer.serialize(input)?;
435 Ok(Value::string(context.arena, &output))
436 } else {
437 let serializer = Serializer::new(DumpFormatter, true);
438 let output = serializer.serialize(input)?;
439 Ok(Value::string(context.arena, &output))
440 }
441}
442
443pub fn fn_substring_before<'a>(
444 context: FunctionContext<'a, '_>,
445 args: &[&'a Value<'a>],
446) -> Result<&'a Value<'a>> {
447 let string = args.first().copied().unwrap_or_else(Value::undefined);
448
449 let chars = args.get(1).copied().unwrap_or_else(Value::undefined);
450
451 if !string.is_string() {
452 return Ok(Value::undefined());
453 }
454
455 if !chars.is_string() {
456 return Err(Error::D3010EmptyPattern(context.char_index));
457 }
458
459 let string: &str = &string.as_str();
460 let chars: &str = &chars.as_str();
461
462 if let Some(index) = string.find(chars) {
463 Ok(Value::string(context.arena, &string[..index]))
464 } else {
465 Ok(Value::string(context.arena, string))
466 }
467}
468
469pub fn fn_substring_after<'a>(
470 context: FunctionContext<'a, '_>,
471 args: &[&'a Value<'a>],
472) -> Result<&'a Value<'a>> {
473 let string = args.first().copied().unwrap_or_else(Value::undefined);
474
475 let chars = args.get(1).copied().unwrap_or_else(Value::undefined);
476
477 if !string.is_string() {
478 return Ok(Value::undefined());
479 }
480
481 if !chars.is_string() {
482 return Err(Error::D3010EmptyPattern(context.char_index));
483 }
484
485 let string: &str = &string.as_str();
486 let chars: &str = &chars.as_str();
487
488 if let Some(index) = string.find(chars) {
489 let after_index = index + chars.len();
490 Ok(Value::string(context.arena, &string[after_index..]))
491 } else {
492 Ok(Value::string(context.arena, string))
494 }
495}
496
497pub fn fn_not<'a>(
498 _context: FunctionContext<'a, '_>,
499 args: &[&'a Value<'a>],
500) -> Result<&'a Value<'a>> {
501 let arg = args.first().copied().unwrap_or_else(Value::undefined);
502
503 Ok(if arg.is_undefined() {
504 Value::undefined()
505 } else {
506 Value::bool(!arg.is_truthy())
507 })
508}
509
510pub fn fn_lowercase<'a>(
511 context: FunctionContext<'a, '_>,
512 args: &[&'a Value<'a>],
513) -> Result<&'a Value<'a>> {
514 let arg = args.first().copied().unwrap_or_else(Value::undefined);
515
516 Ok(if !arg.is_string() {
517 Value::undefined()
518 } else {
519 Value::string(context.arena, &arg.as_str().to_lowercase())
520 })
521}
522
523pub fn fn_uppercase<'a>(
524 context: FunctionContext<'a, '_>,
525 args: &[&'a Value<'a>],
526) -> Result<&'a Value<'a>> {
527 let arg = args.first().copied().unwrap_or_else(Value::undefined);
528
529 if !arg.is_string() {
530 Ok(Value::undefined())
531 } else {
532 Ok(Value::string(context.arena, &arg.as_str().to_uppercase()))
533 }
534}
535
536pub fn fn_trim<'a>(
537 context: FunctionContext<'a, '_>,
538 args: &[&'a Value<'a>],
539) -> Result<&'a Value<'a>> {
540 let arg = args.first().copied().unwrap_or_else(Value::undefined);
541
542 if !arg.is_string() {
543 Ok(Value::undefined())
544 } else {
545 let orginal = arg.as_str();
546 let mut words = orginal.split_whitespace();
547 let trimmed = match words.next() {
548 None => String::new(),
549 Some(first_word) => {
550 let (lower, _) = words.size_hint();
552 let mut result = String::with_capacity(lower);
553 result.push_str(first_word);
554 for word in words {
555 result.push(' ');
556 result.push_str(word);
557 }
558 result
559 }
560 };
561 Ok(Value::string(context.arena, &trimmed))
562 }
563}
564
565pub fn fn_substring<'a>(
566 context: FunctionContext<'a, '_>,
567 args: &[&'a Value<'a>],
568) -> Result<&'a Value<'a>> {
569 let string = args.first().copied().unwrap_or_else(Value::undefined);
570 let start = args.get(1).copied().unwrap_or_else(Value::undefined);
571 let length = args.get(2).copied().unwrap_or_else(Value::undefined);
572
573 if string.is_undefined() {
574 return Ok(Value::undefined());
575 }
576
577 assert_arg!(string.is_string(), context, 1);
578 assert_arg!(start.is_number(), context, 2);
579
580 let string = string.as_str();
581
582 let len = string.chars().count() as isize;
587 let mut start = start.as_isize();
588
589 if len + start < 0 {
591 start = 0;
592 }
593
594 let start = if start < 0 { len + start } else { start };
596
597 if length.is_undefined() {
598 Ok(Value::string(context.arena, &string[start as usize..]))
599 } else {
600 assert_arg!(length.is_number(), context, 3);
601
602 let length = length.as_isize();
603 if length < 0 {
604 Ok(Value::string(context.arena, ""))
605 } else {
606 let end = if start >= 0 {
607 (start + length) as usize
608 } else {
609 (len + start + length) as usize
610 };
611
612 let substring = string
613 .chars()
614 .skip(start as usize)
615 .take(end - start as usize)
616 .collect::<String>();
617
618 Ok(Value::string(context.arena, &substring))
619 }
620 }
621}
622
623pub fn fn_contains<'a>(
624 context: FunctionContext<'a, '_>,
625 args: &[&'a Value<'a>],
626) -> Result<&'a Value<'a>> {
627 let str_value = args.first().copied().unwrap_or_else(Value::undefined);
628 let token_value = args.get(1).copied().unwrap_or_else(Value::undefined);
629
630 if str_value.is_undefined() {
631 return Ok(Value::undefined());
632 }
633
634 assert_arg!(str_value.is_string(), context, 1);
635
636 let str_value = str_value.as_str();
637
638 let contains_result = match token_value {
640 Value::Regex(ref regex_literal) => {
641 let regex = regex_literal.get_regex();
642 regex.find_iter(&str_value).next().is_some()
643 }
644 Value::String(_) => {
645 let token_value = token_value.as_str();
646 str_value.contains(&token_value.to_string())
647 }
648 _ => {
649 return Err(Error::T0410ArgumentNotValid(
650 context.char_index,
651 2,
652 context.name.to_string(),
653 ));
654 }
655 };
656
657 Ok(Value::bool(contains_result))
658}
659
660pub fn fn_replace<'a>(
661 context: FunctionContext<'a, '_>,
662 args: &[&'a Value<'a>],
663) -> Result<&'a Value<'a>> {
664 let str_value = args.first().copied().unwrap_or_else(Value::undefined);
665 let pattern_value = args.get(1).copied().unwrap_or_else(Value::undefined);
666 let replacement_value = args.get(2).copied().unwrap_or_else(Value::undefined);
667 let limit_value = args.get(3).copied().unwrap_or_else(Value::undefined);
668
669 if str_value.is_undefined() {
670 return Ok(Value::undefined());
671 }
672
673 if pattern_value.is_string() && pattern_value.as_str().is_empty() {
674 return Err(Error::D3010EmptyPattern(context.char_index));
675 }
676
677 assert_arg!(str_value.is_string(), context, 1);
678
679 let str_value = str_value.as_str();
680 let limit_value = if limit_value.is_undefined() {
681 None
682 } else {
683 assert_arg!(limit_value.is_number(), context, 4);
684 if limit_value.as_isize().is_negative() {
685 return Err(Error::D3011NegativeLimit(context.char_index));
686 }
687 Some(limit_value.as_isize() as usize)
688 };
689
690 let regex = match pattern_value {
692 Value::Regex(ref regex_literal) => regex_literal.get_regex(),
693 Value::String(ref pattern_str) => {
694 assert_arg!(replacement_value.is_string(), context, 3);
695 let replacement_str = replacement_value.as_str();
696
697 let replaced_string = if let Some(limit) = limit_value {
698 str_value.replacen(&pattern_str.to_string(), &replacement_str, limit)
699 } else {
700 str_value.replace(&pattern_str.to_string(), &replacement_str)
701 };
702
703 return Ok(Value::string(context.arena, &replaced_string));
704 }
705 _ => bad_arg!(context, 2),
706 };
707
708 let mut result = String::new();
709 let mut last_end = 0;
710
711 for (replacements, m) in regex.find_iter(&str_value).enumerate() {
712 if m.range().is_empty() {
713 return Err(Error::D1004ZeroLengthMatch(context.char_index));
714 }
715
716 if let Some(limit) = limit_value {
717 if replacements >= limit {
718 break;
719 }
720 }
721
722 result.push_str(&str_value[last_end..m.start()]);
723
724 let match_str = &str_value[m.start()..m.end()];
725
726 let replacement_text = match replacement_value {
728 Value::NativeFn { func, .. } => {
729 let match_list = evaluate_match(context.arena, regex, match_str, None);
730
731 let func_result = func(context.clone(), &[match_list])?;
732
733 if let Value::String(ref s) = func_result {
734 s.as_str().to_string()
735 } else {
736 return Err(Error::D3012InvalidReplacementType(context.char_index));
737 }
738 }
739
740 func @ Value::Lambda { .. } => {
741 let match_list = evaluate_match(context.arena, regex, match_str, None);
742
743 let args = &[match_list];
744
745 let func_result =
746 context.trampoline_evaluate_value(context.evaluate_function(func, args)?)?;
747
748 match func_result {
749 Value::String(ref s) => s.as_str().to_string(),
750 _ => return Err(Error::D3012InvalidReplacementType(context.char_index)),
751 }
752 }
753
754 Value::String(replacement_str) => {
755 evaluate_replacement_string(replacement_str.as_str(), &str_value, &m)
756 }
757
758 _ => bad_arg!(context, 3),
759 };
760
761 result.push_str(&replacement_text);
762 last_end = m.end();
763 }
764
765 result.push_str(&str_value[last_end..]);
766
767 Ok(Value::string(context.arena, &result))
768}
769
770fn evaluate_replacement_string(
783 replacement_str: &str,
784 str_value: &str,
785 m: ®ress::Match,
786) -> String {
787 #[derive(Debug)]
788 enum S {
789 Literal,
790 Dollar,
791 Group(u32),
792 End,
793 }
794
795 let mut state = S::Literal;
796 let mut acc = String::new();
797
798 let groups: Vec<Option<Range>> = m.groups().collect();
799 let mut chars = replacement_str.chars();
800
801 loop {
802 let c = chars.next();
803 match (&state, c) {
804 (S::Literal, Some('$')) => {
805 state = S::Dollar;
806 }
807 (S::Literal, Some(c)) => {
808 acc.push(c);
809 }
810 (S::Dollar, Some('$')) => {
811 acc.push('$');
812 state = S::Literal;
813 }
814
815 (S::Dollar, Some(c)) if c.is_numeric() => {
817 let digit = c
818 .to_digit(10)
819 .expect("numeric char failed to parse as digit");
820 state = S::Group(digit);
821 }
822
823 (S::Dollar, c) => {
826 acc.push('$');
827 c.inspect(|c| acc.push(*c));
828 state = S::Literal;
829 }
830
831 (S::Group(so_far), Some(c)) if c.is_numeric() => {
833 let digit = c
834 .to_digit(10)
835 .expect("numeric char failed to parse as digit");
836
837 let next = so_far * 10 + digit;
838 let groups_len = groups.len() as u32;
839
840 if next >= groups_len {
844 if let Some(match_range) = groups.get(*so_far as usize).and_then(|x| x.as_ref())
845 {
846 str_value
847 .get(match_range.start..match_range.end)
848 .inspect(|s| acc.push_str(s));
849 } else {
850 }
852
853 acc.push(c);
854
855 state = S::Literal
856 } else {
857 state = S::Group(next);
858 }
859 }
860
861 (S::Group(index), c) => {
863 if let Some(match_range) = groups.get(*index as usize).and_then(|x| x.as_ref()) {
864 str_value
865 .get(match_range.start..match_range.end)
866 .inspect(|s| acc.push_str(s));
867 } else {
868 }
870
871 if let Some(c) = c {
872 if c == '$' {
873 state = S::Dollar;
874 } else {
875 acc.push(c);
876 state = S::Literal;
877 }
878 } else {
879 state = S::End;
880 }
881 }
882 (S::Literal, None) => {
883 state = S::End;
884 }
885
886 (S::End, _) => {
887 break;
888 }
889 }
890 }
891 acc
892}
893
894pub fn fn_split<'a>(
895 context: FunctionContext<'a, '_>,
896 args: &[&'a Value<'a>],
897) -> Result<&'a Value<'a>> {
898 let str_value = args.first().copied().unwrap_or_else(Value::undefined);
899 let separator_value = args.get(1).copied().unwrap_or_else(Value::undefined);
900 let limit_value = args.get(2).copied().unwrap_or_else(Value::undefined);
901
902 if str_value.is_undefined() {
903 return Ok(Value::undefined());
904 }
905
906 assert_arg!(str_value.is_string(), context, 1);
907
908 let str_value = str_value.as_str();
909 let separator_is_regex = match separator_value {
910 Value::Regex(_) => true,
911 Value::String(_) => false,
912 _ => {
913 return Err(Error::T0410ArgumentNotValid(
914 context.char_index,
915 2,
916 context.name.to_string(),
917 ));
918 }
919 };
920
921 let limit = if limit_value.is_undefined() {
923 None
924 } else {
925 assert_arg!(limit_value.is_number(), context, 3);
926 if limit_value.as_f64() < 0.0 {
927 return Err(Error::D3020NegativeLimit(context.char_index));
928 }
929 Some(limit_value.as_f64() as usize)
930 };
931
932 let substrings: Vec<String> = if separator_is_regex {
933 let regex = match separator_value {
935 Value::Regex(ref regex_literal) => regex_literal.get_regex(),
936 _ => unreachable!(),
937 };
938
939 let mut results = Vec::new();
940 let mut last_end = 0;
941 let effective_limit = limit.unwrap_or(usize::MAX);
942
943 for m in regex.find_iter(&str_value) {
944 if results.len() >= effective_limit {
945 break;
946 }
947
948 if m.start() > last_end {
949 let substring = str_value[last_end..m.start()].to_string();
950 results.push(substring);
951 }
952
953 last_end = m.end();
954 }
955
956 if results.len() < effective_limit {
957 let remaining = str_value[last_end..].to_string();
958 results.push(remaining);
959 }
960 results
961 } else {
962 let separator_str = separator_value.as_str().to_string();
964 let separator_str = separator_str.as_str();
965 if separator_str.is_empty() {
966 if let Some(limit) = limit {
968 str_value
969 .chars()
970 .take(limit)
971 .map(|c| c.to_string())
972 .collect()
973 } else {
974 str_value.chars().map(|c| c.to_string()).collect()
975 }
976 } else if let Some(limit) = limit {
977 str_value
978 .split(separator_str)
979 .take(limit)
980 .map(|s| s.to_string())
981 .collect()
982 } else {
983 str_value
984 .split(separator_str)
985 .map(|s| s.to_string())
986 .collect()
987 }
988 };
989
990 let result = Value::array_with_capacity(context.arena, substrings.len(), ArrayFlags::empty());
991 for substring in &substrings {
992 result.push(Value::string(context.arena, substring));
993 }
994 Ok(result)
995}
996
997pub fn fn_abs<'a>(
998 context: FunctionContext<'a, '_>,
999 args: &[&'a Value<'a>],
1000) -> Result<&'a Value<'a>> {
1001 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1002
1003 if arg.is_undefined() {
1004 return Ok(Value::undefined());
1005 }
1006
1007 assert_arg!(arg.is_number(), context, 1);
1008
1009 Ok(Value::number(context.arena, arg.as_f64().abs()))
1010}
1011
1012pub fn fn_floor<'a>(
1013 context: FunctionContext<'a, '_>,
1014 args: &[&'a Value<'a>],
1015) -> Result<&'a Value<'a>> {
1016 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1017
1018 if arg.is_undefined() {
1019 return Ok(Value::undefined());
1020 }
1021
1022 assert_arg!(arg.is_number(), context, 1);
1023
1024 Ok(Value::number(context.arena, arg.as_f64().floor()))
1025}
1026
1027pub fn fn_ceil<'a>(
1028 context: FunctionContext<'a, '_>,
1029 args: &[&'a Value<'a>],
1030) -> Result<&'a Value<'a>> {
1031 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1032
1033 if arg.is_undefined() {
1034 return Ok(Value::undefined());
1035 }
1036
1037 assert_arg!(arg.is_number(), context, 1);
1038
1039 Ok(Value::number(context.arena, arg.as_f64().ceil()))
1040}
1041
1042pub fn fn_lookup_internal<'a>(
1043 context: FunctionContext<'a, '_>,
1044 input: &'a Value<'a>,
1045 key: &str,
1046) -> &'a Value<'a> {
1047 match input {
1048 Value::Array { .. } => {
1049 let result = Value::array(context.arena, ArrayFlags::SEQUENCE);
1050
1051 for input in input.members() {
1052 let res = fn_lookup_internal(context.clone(), input, key);
1053 match res {
1054 Value::Undefined => {}
1055 Value::Array { .. } => {
1056 res.members().for_each(|item| result.push(item));
1057 }
1058 _ => result.push(res),
1059 };
1060 }
1061
1062 result
1063 }
1064 Value::Object(..) => input.get_entry(key),
1065 _ => Value::undefined(),
1066 }
1067}
1068
1069pub fn fn_lookup<'a>(
1070 context: FunctionContext<'a, '_>,
1071 args: &[&'a Value<'a>],
1072) -> Result<&'a Value<'a>> {
1073 let input = args.first().copied().unwrap_or_else(Value::undefined);
1074 let key = args.get(1).copied().unwrap_or_else(Value::undefined);
1075 assert_arg!(key.is_string(), context, 2);
1076 Ok(fn_lookup_internal(context.clone(), input, &key.as_str()))
1077}
1078
1079pub fn fn_count<'a>(
1080 context: FunctionContext<'a, '_>,
1081 args: &[&'a Value<'a>],
1082) -> Result<&'a Value<'a>> {
1083 max_args!(context, args, 1);
1084
1085 let count = match args.first() {
1086 Some(Value::Array(a, _)) => a.len() as f64,
1087 Some(Value::Undefined) => 0.0,
1088 Some(_) => 1.0,
1089 None => 0.0,
1090 };
1091
1092 Ok(Value::number(context.arena, count))
1093}
1094
1095pub fn fn_max<'a>(
1096 context: FunctionContext<'a, '_>,
1097 args: &[&'a Value<'a>],
1098) -> Result<&'a Value<'a>> {
1099 max_args!(context, args, 1);
1100
1101 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1102
1103 if arg.is_undefined() || (arg.is_array() && arg.is_empty()) {
1105 return Ok(Value::undefined());
1106 }
1107
1108 let arr = Value::wrap_in_array_if_needed(context.arena, arg, ArrayFlags::empty());
1109
1110 let mut max = f64::MIN;
1111
1112 for member in arr.members() {
1113 assert_array_of_type!(member.is_number(), context, 1, "number");
1114 max = f64::max(max, member.as_f64());
1115 }
1116 Ok(Value::number(context.arena, max))
1117}
1118
1119pub fn fn_min<'a>(
1120 context: FunctionContext<'a, '_>,
1121 args: &[&'a Value<'a>],
1122) -> Result<&'a Value<'a>> {
1123 max_args!(context, args, 1);
1124
1125 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1126
1127 if arg.is_undefined() || (arg.is_array() && arg.is_empty()) {
1129 return Ok(Value::undefined());
1130 }
1131
1132 let arr = Value::wrap_in_array_if_needed(context.arena, arg, ArrayFlags::empty());
1133
1134 let mut min = f64::MAX;
1135
1136 for member in arr.members() {
1137 assert_array_of_type!(member.is_number(), context, 1, "number");
1138 min = f64::min(min, member.as_f64());
1139 }
1140 Ok(Value::number(context.arena, min))
1141}
1142
1143pub fn fn_sum<'a>(
1144 context: FunctionContext<'a, '_>,
1145 args: &[&'a Value<'a>],
1146) -> Result<&'a Value<'a>> {
1147 max_args!(context, args, 1);
1148
1149 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1150
1151 if arg.is_undefined() {
1153 return Ok(Value::undefined());
1154 }
1155
1156 let arr = Value::wrap_in_array_if_needed(context.arena, arg, ArrayFlags::empty());
1157
1158 let mut sum = 0.0;
1159
1160 for member in arr.members() {
1161 assert_array_of_type!(member.is_number(), context, 1, "number");
1162 sum += member.as_f64();
1163 }
1164 Ok(Value::number(context.arena, sum))
1165}
1166
1167pub fn fn_number<'a>(
1168 context: FunctionContext<'a, '_>,
1169 args: &[&'a Value<'a>],
1170) -> Result<&'a Value<'a>> {
1171 max_args!(context, args, 1);
1172
1173 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1174
1175 match arg {
1176 Value::Undefined => Ok(Value::undefined()),
1177 Value::Number(..) => Ok(arg),
1178 Value::Bool(true) => Ok(Value::number(context.arena, 1)),
1179 Value::Bool(false) => Ok(Value::number(context.arena, 0)),
1180 Value::String(s) => {
1181 let result: f64 = s
1182 .parse()
1183 .map_err(|_e| Error::D3030NonNumericCast(context.char_index, arg.to_string()))?;
1184
1185 if !result.is_nan() && !result.is_infinite() {
1186 Ok(Value::number(context.arena, result))
1187 } else {
1188 Ok(Value::undefined())
1189 }
1190 }
1191 _ => bad_arg!(context, 1),
1192 }
1193}
1194
1195pub fn fn_random<'a>(
1196 context: FunctionContext<'a, '_>,
1197 args: &[&'a Value<'a>],
1198) -> Result<&'a Value<'a>> {
1199 max_args!(context, args, 0);
1200
1201 let v: f32 = rand::thread_rng().gen();
1202 Ok(Value::number(context.arena, v))
1203}
1204
1205pub fn fn_now<'a>(
1206 context: FunctionContext<'a, '_>,
1207 args: &[&'a Value<'a>],
1208) -> Result<&'a Value<'a>> {
1209 max_args!(context, args, 2);
1210
1211 let now = Utc::now();
1212
1213 let (picture, timezone) = match args {
1214 [picture, timezone] => (picture.as_str(), timezone.as_str()),
1215 [picture] => (picture.as_str(), Cow::Borrowed("")),
1216 [] => (Cow::Borrowed(""), Cow::Borrowed("")),
1217 _ => return Ok(Value::string(context.arena, "")),
1218 };
1219
1220 if picture.is_empty() && timezone.is_empty() {
1221 return Ok(Value::string(
1222 context.arena,
1223 &now.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
1224 ));
1225 }
1226
1227 let adjusted_time = if !timezone.is_empty() {
1228 parse_timezone_offset(&timezone)
1229 .map(|offset| now.with_timezone(&offset))
1230 .ok_or_else(|| Error::T0410ArgumentNotValid(2, 1, context.name.to_string()))?
1231 } else {
1232 now.into()
1233 };
1234
1235 if !picture.is_empty() {
1237 let formatted_date = format_custom_date(&adjusted_time, &picture)?;
1239 return Ok(Value::string(context.arena, &formatted_date));
1240 }
1241
1242 Ok(Value::string(context.arena, ""))
1244}
1245
1246pub fn fn_exists<'a>(
1247 context: FunctionContext<'a, '_>,
1248 args: &[&'a Value<'a>],
1249) -> Result<&'a Value<'a>> {
1250 min_args!(context, args, 1);
1251 max_args!(context, args, 1);
1252
1253 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1254
1255 match arg {
1256 Value::Undefined => Ok(Value::bool(false)),
1257 _ => Ok(Value::bool(true)),
1258 }
1259}
1260
1261pub fn from_millis<'a>(
1262 context: FunctionContext<'a, '_>,
1263 args: &[&'a Value<'a>],
1264) -> Result<&'a Value<'a>> {
1265 let arr = args.first().copied().unwrap_or_else(Value::undefined);
1266
1267 if arr.is_undefined() {
1268 return Ok(Value::undefined());
1269 }
1270
1271 max_args!(context, args, 3);
1272 assert_arg!(args[0].is_number(), context, 1);
1273
1274 let millis = args[0].as_f64() as i64;
1275
1276 let Some(timestamp) = Utc.timestamp_millis_opt(millis).single() else {
1277 bad_arg!(context, 1);
1278 };
1279
1280 let (picture, timezone) = match args {
1281 [_, picture, timezone] if picture.is_undefined() => {
1282 assert_arg!(timezone.is_string(), context, 3);
1283 (Cow::Borrowed(""), timezone.as_str())
1284 }
1285 [_, picture, timezone] => {
1286 assert_arg!(picture.is_string(), context, 2);
1287 assert_arg!(timezone.is_string(), context, 3);
1288 (picture.as_str(), timezone.as_str())
1289 }
1290 [_, picture] => {
1291 assert_arg!(picture.is_string(), context, 2);
1292 (picture.as_str(), Cow::Borrowed(""))
1293 }
1294 _ => (Cow::Borrowed(""), Cow::Borrowed("")),
1295 };
1296
1297 if picture.is_empty() && timezone.is_empty() {
1299 return Ok(Value::string(
1300 context.arena,
1301 ×tamp.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
1302 ));
1303 }
1304
1305 if let Err(err) = check_balanced_brackets(&picture) {
1307 return Err(Error::D3135PictureStringNoClosingBracketError(err));
1308 }
1309
1310 let adjusted_time = if !timezone.is_empty() {
1311 parse_timezone_offset(&timezone)
1312 .map(|offset| timestamp.with_timezone(&offset))
1313 .ok_or_else(|| Error::T0410ArgumentNotValid(0, 1, context.name.to_string()))?
1314 } else {
1315 timestamp.into()
1316 };
1317
1318 if !picture.is_empty() {
1320 let formatted_result = format_custom_date(&adjusted_time, &picture)?;
1322
1323 return Ok(Value::string(context.arena, &formatted_result));
1324 }
1325
1326 Ok(Value::string(
1328 context.arena,
1329 &adjusted_time.to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
1330 ))
1331}
1332
1333pub fn fn_millis<'a>(
1334 context: FunctionContext<'a, '_>,
1335 args: &[&'a Value<'a>],
1336) -> Result<&'a Value<'a>> {
1337 max_args!(context, args, 0);
1338
1339 let timestamp = SystemTime::now()
1340 .duration_since(UNIX_EPOCH)
1341 .expect("Time went backwards");
1342
1343 Ok(Value::number_from_u128(
1344 context.arena,
1345 timestamp.as_millis(),
1346 )?)
1347}
1348
1349pub fn fn_uuid<'a>(
1350 context: FunctionContext<'a, '_>,
1351 args: &[&'a Value<'a>],
1352) -> Result<&'a Value<'a>> {
1353 max_args!(context, args, 0);
1354
1355 Ok(Value::string(
1356 context.arena,
1357 Uuid::new_v4().to_string().as_str(),
1358 ))
1359}
1360
1361pub fn to_millis<'a>(
1362 context: FunctionContext<'a, '_>,
1363 args: &[&'a Value<'a>],
1364) -> Result<&'a Value<'a>> {
1365 let arr: &Value<'a> = args.first().copied().unwrap_or_else(Value::undefined);
1366
1367 if arr.is_undefined() {
1368 return Ok(Value::undefined());
1369 }
1370
1371 max_args!(context, args, 2);
1372 assert_arg!(args[0].is_string(), context, 1);
1373
1374 let timestamp_str = args[0].as_str();
1376 if timestamp_str.is_empty() {
1377 return Ok(Value::undefined());
1378 }
1379
1380 let picture = match args {
1382 [_, picture] if picture.is_undefined() => Cow::Borrowed(""),
1383 [_, picture] => {
1384 assert_arg!(picture.is_string(), context, 2);
1385 picture.as_str()
1386 }
1387 _ => Cow::Borrowed(""),
1388 };
1389
1390 match parse_custom_format(×tamp_str, &picture) {
1392 Some(millis) => Ok(Value::number(context.arena, millis as f64)),
1393 None => Ok(Value::undefined()),
1394 }
1395}
1396
1397pub fn fn_zip<'a>(
1398 context: FunctionContext<'a, '_>,
1399 args: &[&'a Value<'a>],
1400) -> Result<&'a Value<'a>> {
1401 if args.iter().any(|arg| arg.is_null() || arg.is_undefined()) {
1403 return Ok(Value::array(context.arena, ArrayFlags::empty()));
1404 }
1405
1406 let arrays: Vec<&bumpalo::collections::Vec<'a, &'a Value<'a>>> = args
1407 .iter()
1408 .filter_map(|arg| match *arg {
1409 Value::Array(arr, _) => Some(arr),
1410 _ => None,
1411 })
1412 .collect();
1413
1414 if arrays.is_empty() {
1415 let result: bumpalo::collections::Vec<&Value<'a>> =
1416 args.iter().copied().collect_in(context.arena);
1417
1418 let outer_array =
1419 Value::array_from(context.arena, result, ArrayFlags::empty()) as &Value<'a>;
1420
1421 let outer_array_alloc: bumpalo::collections::Vec<&Value<'a>> =
1422 bumpalo::vec![in context.arena; outer_array];
1423
1424 return Ok(Value::array_from(
1425 context.arena,
1426 outer_array_alloc,
1427 ArrayFlags::empty(),
1428 ));
1429 }
1430
1431 let min_length = arrays.iter().map(|arr| arr.len()).min().unwrap_or(0);
1432 let mut iterators: Vec<_> = arrays
1433 .iter()
1434 .map(|arr| arr.iter().take(min_length))
1435 .collect();
1436
1437 let result: bumpalo::collections::Vec<&Value<'a>> = std::iter::repeat(())
1439 .take(min_length)
1440 .map(|_| {
1441 let zipped: bumpalo::collections::Vec<&Value<'a>> = iterators
1442 .iter_mut()
1443 .map(|it| *it.next().unwrap()) .collect_in(context.arena);
1445
1446 context
1448 .arena
1449 .alloc(Value::Array(zipped, ArrayFlags::empty())) as &Value<'a>
1450 })
1451 .collect_in(context.arena);
1452
1453 Ok(Value::array_from(
1455 context.arena,
1456 result,
1457 ArrayFlags::empty(),
1458 ))
1459}
1460
1461pub fn single<'a>(
1462 context: FunctionContext<'a, '_>,
1463 args: &[&'a Value<'a>],
1464) -> Result<&'a Value<'a>> {
1465 max_args!(context, args, 2);
1466
1467 let arr: &Value<'a> = args.first().copied().unwrap_or_else(Value::undefined);
1468 if arr.is_undefined() {
1469 return Ok(Value::undefined());
1470 }
1471
1472 let func = args
1473 .get(1)
1474 .filter(|f| f.is_function())
1475 .copied()
1476 .unwrap_or_else(|| {
1477 context
1479 .arena
1480 .alloc(Value::nativefn(context.arena, "default_true", 1, |_, _| {
1481 Ok(&Value::Bool(true))
1482 }))
1483 });
1484
1485 if !arr.is_array() {
1486 let res = context.evaluate_function(func, &[arr])?;
1487 return if res.as_bool() {
1488 Ok(arr)
1489 } else {
1490 Err(Error::D3139Error(
1491 "No value matched the predicate.".to_string(),
1492 ))
1493 };
1494 }
1495
1496 if let Value::Array(elements, _) = arr {
1497 let mut result: Option<&'a Value<'a>> = None;
1498
1499 for (index, entry) in elements.iter().enumerate() {
1500 let res = context.evaluate_function(
1501 func,
1502 &[entry, Value::number(context.arena, index as f64), arr],
1503 )?;
1504
1505 if res.as_bool() {
1506 if result.is_some() {
1507 return Err(Error::D3138Error(format!(
1508 "More than one value matched the predicate at index {}",
1509 index
1510 )));
1511 } else {
1512 result = Some(entry);
1513 }
1514 }
1515 }
1516
1517 result.ok_or_else(|| Error::D3139Error("No values matched the predicate.".to_string()))
1518 } else {
1519 Err(Error::T0410ArgumentNotValid(0, 2, context.name.to_string()))
1520 }
1521}
1522
1523pub fn fn_assert<'a>(
1524 context: FunctionContext<'a, '_>,
1525 args: &[&'a Value<'a>],
1526) -> Result<&'a Value<'a>> {
1527 let condition = args.first().copied().unwrap_or_else(Value::undefined);
1528 let message = args.get(1).copied().unwrap_or_else(Value::undefined);
1529
1530 assert_arg!(condition.is_bool(), context, 1);
1531
1532 if let Value::Bool(false) = condition {
1533 Err(Error::D3141Assert(if message.is_string() {
1534 message.as_str().to_string()
1535 } else {
1536 "$assert() statement failed".to_string()
1537 }))
1538 } else {
1539 Ok(Value::undefined())
1540 }
1541}
1542
1543pub fn fn_error<'a>(
1544 context: FunctionContext<'a, '_>,
1545 args: &[&'a Value<'a>],
1546) -> Result<&'a Value<'a>> {
1547 let message = args.first().copied().unwrap_or_else(Value::undefined);
1548
1549 assert_arg!(message.is_undefined() || message.is_string(), context, 1);
1550
1551 Err(Error::D3137Error(if message.is_string() {
1552 message.as_str().to_string()
1553 } else {
1554 "$error() function evaluated".to_string()
1555 }))
1556}
1557
1558pub fn fn_length<'a>(
1559 context: FunctionContext<'a, '_>,
1560 args: &[&'a Value<'a>],
1561) -> Result<&'a Value<'a>> {
1562 max_args!(context, args, 1);
1563
1564 let arg1 = args.first().copied().unwrap_or_else(Value::undefined);
1565
1566 if arg1.is_undefined() {
1567 return Ok(Value::undefined());
1568 }
1569
1570 assert_arg!(arg1.is_string(), context, 1);
1571
1572 Ok(Value::number(
1573 context.arena,
1574 arg1.as_str().chars().count() as f64,
1575 ))
1576}
1577
1578pub fn fn_sqrt<'a>(
1579 context: FunctionContext<'a, '_>,
1580 args: &[&'a Value<'a>],
1581) -> Result<&'a Value<'a>> {
1582 max_args!(context, args, 1);
1583 let arg1 = args.first().copied().unwrap_or_else(Value::undefined);
1584
1585 if arg1.is_undefined() {
1586 return Ok(Value::undefined());
1587 }
1588
1589 assert_arg!(arg1.is_number(), context, 1);
1590
1591 let n = arg1.as_f64();
1592 if n.is_sign_negative() {
1593 Err(Error::D3060SqrtNegative(context.char_index, n.to_string()))
1594 } else {
1595 Ok(Value::number(context.arena, n.sqrt()))
1596 }
1597}
1598
1599pub fn fn_power<'a>(
1600 context: FunctionContext<'a, '_>,
1601 args: &[&'a Value<'a>],
1602) -> Result<&'a Value<'a>> {
1603 max_args!(context, args, 2);
1604
1605 let number = args.first().copied().unwrap_or_else(Value::undefined);
1606 let exp = args.get(1).copied().unwrap_or_else(Value::undefined);
1607
1608 if number.is_undefined() {
1609 return Ok(Value::undefined());
1610 }
1611
1612 assert_arg!(number.is_number(), context, 1);
1613 assert_arg!(exp.is_number(), context, 2);
1614
1615 let result = number.as_f64().powf(exp.as_f64());
1616
1617 if !result.is_finite() {
1618 Err(Error::D3061PowUnrepresentable(
1619 context.char_index,
1620 number.to_string(),
1621 exp.to_string(),
1622 ))
1623 } else {
1624 Ok(Value::number(context.arena, result))
1625 }
1626}
1627
1628pub fn fn_reverse<'a>(
1629 context: FunctionContext<'a, '_>,
1630 args: &[&'a Value<'a>],
1631) -> Result<&'a Value<'a>> {
1632 max_args!(context, args, 1);
1633
1634 let arr = args.first().copied().unwrap_or_else(Value::undefined);
1635
1636 if arr.is_undefined() {
1637 return Ok(Value::undefined());
1638 }
1639
1640 assert_arg!(arr.is_array(), context, 1);
1641
1642 let result = Value::array_with_capacity(context.arena, arr.len(), ArrayFlags::empty());
1643 arr.members().rev().for_each(|member| result.push(member));
1644 Ok(result)
1645}
1646
1647#[allow(clippy::mutable_key_type)]
1648pub fn fn_distinct<'a>(
1649 context: FunctionContext<'a, '_>,
1650 args: &[&'a Value<'a>],
1651) -> Result<&'a Value<'a>> {
1652 max_args!(context, args, 1);
1653
1654 let arr = args.first().copied().unwrap_or_else(Value::undefined);
1655 if !arr.is_array() || arr.len() <= 1 {
1656 return Ok(arr);
1657 }
1658
1659 let result = Value::array_with_capacity(context.arena, arr.len(), ArrayFlags::empty());
1660 let mut set = HashSet::new();
1661 for member in arr.members() {
1662 if set.contains(member) {
1663 continue;
1664 }
1665 set.insert(member);
1666 result.push(member);
1667 }
1668
1669 Ok(result)
1670}
1671
1672pub fn fn_join<'a>(
1673 context: FunctionContext<'a, '_>,
1674 args: &[&'a Value<'a>],
1675) -> Result<&'a Value<'a>> {
1676 max_args!(context, args, 2);
1677 let strings = args.first().copied().unwrap_or_else(Value::undefined);
1678
1679 if strings.is_undefined() {
1680 return Ok(Value::undefined());
1681 }
1682
1683 if strings.is_string() {
1684 return Ok(strings);
1685 }
1686
1687 assert_array_of_type!(strings.is_array(), context, 1, "string");
1688
1689 let separator = args.get(1).copied().unwrap_or_else(Value::undefined);
1690 assert_arg!(
1691 separator.is_undefined() || separator.is_string(),
1692 context,
1693 2
1694 );
1695
1696 let separator = if separator.is_string() {
1697 separator.as_str()
1698 } else {
1699 "".into()
1700 };
1701
1702 let mut result = String::with_capacity(1024);
1703 for (index, member) in strings.members().enumerate() {
1704 assert_array_of_type!(member.is_string(), context, 1, "string");
1705 result.push_str(member.as_str().borrow());
1706 if index != strings.len() - 1 {
1707 result.push_str(&separator);
1708 }
1709 }
1710
1711 Ok(Value::string(context.arena, &result))
1712}
1713
1714pub fn fn_sort<'a, 'e>(
1715 context: FunctionContext<'a, 'e>,
1716 args: &[&'a Value<'a>],
1717) -> Result<&'a Value<'a>> {
1718 max_args!(context, args, 2);
1719
1720 let arr = args.first().copied().unwrap_or_else(Value::undefined);
1721
1722 if arr.is_undefined() {
1723 return Ok(Value::undefined());
1724 }
1725
1726 if !arr.is_array() || arr.len() <= 1 {
1727 return Ok(Value::wrap_in_array_if_needed(
1728 context.arena,
1729 arr,
1730 ArrayFlags::empty(),
1731 ));
1732 }
1733
1734 let unsorted = arr.members().collect::<Vec<&'a Value<'a>>>();
1738 let sorted = if args.get(1).is_none() {
1739 merge_sort(
1740 unsorted,
1741 &|a: &'a Value<'a>, b: &'a Value<'a>| match (a, b) {
1742 (Value::Number(a), Value::Number(b)) => Ok(a > b),
1743 (Value::String(a), Value::String(b)) => Ok(a > b),
1744 _ => Err(Error::D3070InvalidDefaultSort(context.char_index)),
1745 },
1746 )?
1747 } else {
1748 let comparator = args.get(1).copied().unwrap_or_else(Value::undefined);
1749 assert_arg!(comparator.is_function(), context, 2);
1750 merge_sort(unsorted, &|a: &'a Value<'a>, b: &'a Value<'a>| {
1751 let result = context.evaluate_function(comparator, &[a, b])?;
1752 Ok(result.is_truthy())
1753 })?
1754 };
1755
1756 let result = Value::array_with_capacity(context.arena, sorted.len(), arr.get_flags());
1757 sorted.iter().for_each(|member| result.push(member));
1758
1759 Ok(result)
1760}
1761
1762pub fn merge_sort<'a, F>(items: Vec<&'a Value<'a>>, comp: &F) -> Result<Vec<&'a Value<'a>>>
1763where
1764 F: Fn(&'a Value<'a>, &'a Value<'a>) -> Result<bool>,
1765{
1766 fn merge_iter<'a, F>(
1767 result: &mut Vec<&'a Value<'a>>,
1768 left: &[&'a Value<'a>],
1769 right: &[&'a Value<'a>],
1770 comp: &F,
1771 ) -> Result<()>
1772 where
1773 F: Fn(&'a Value<'a>, &'a Value<'a>) -> Result<bool>,
1774 {
1775 if left.is_empty() {
1776 result.extend(right);
1777 Ok(())
1778 } else if right.is_empty() {
1779 result.extend(left);
1780 Ok(())
1781 } else if comp(left[0], right[0])? {
1782 result.push(right[0]);
1783 merge_iter(result, left, &right[1..], comp)
1784 } else {
1785 result.push(left[0]);
1786 merge_iter(result, &left[1..], right, comp)
1787 }
1788 }
1789
1790 fn merge<'a, F>(
1791 left: &[&'a Value<'a>],
1792 right: &[&'a Value<'a>],
1793 comp: &F,
1794 ) -> Result<Vec<&'a Value<'a>>>
1795 where
1796 F: Fn(&'a Value<'a>, &'a Value<'a>) -> Result<bool>,
1797 {
1798 let mut merged = Vec::with_capacity(left.len() + right.len());
1799 merge_iter(&mut merged, left, right, comp)?;
1800 Ok(merged)
1801 }
1802
1803 if items.len() <= 1 {
1804 return Ok(items);
1805 }
1806 let middle = (items.len() as f64 / 2.0).floor() as usize;
1807 let (left, right) = items.split_at(middle);
1808 let left = merge_sort(left.to_vec(), comp)?;
1809 let right = merge_sort(right.to_vec(), comp)?;
1810 merge(&left, &right, comp)
1811}
1812
1813pub fn fn_base64_encode<'a>(
1814 context: FunctionContext<'a, '_>,
1815 args: &[&'a Value<'a>],
1816) -> Result<&'a Value<'a>> {
1817 max_args!(context, args, 1);
1818 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1819 if arg.is_undefined() {
1820 return Ok(Value::undefined());
1821 }
1822 assert_arg!(arg.is_string(), context, 1);
1823
1824 let base64 = base64::engine::general_purpose::STANDARD;
1825
1826 let encoded = base64.encode(arg.as_str().as_bytes());
1827
1828 Ok(Value::string(context.arena, &encoded))
1829}
1830
1831pub fn fn_base64_decode<'a>(
1832 context: FunctionContext<'a, '_>,
1833 args: &[&'a Value<'a>],
1834) -> Result<&'a Value<'a>> {
1835 max_args!(context, args, 1);
1836 let arg = args.first().copied().unwrap_or_else(Value::undefined);
1837 if arg.is_undefined() {
1838 return Ok(Value::undefined());
1839 }
1840 assert_arg!(arg.is_string(), context, 1);
1841
1842 let base64 = base64::engine::general_purpose::STANDARD;
1843
1844 let decoded = base64.decode(arg.as_str().as_bytes());
1845 let data = decoded.map_err(|e| Error::D3137Error(e.to_string()))?;
1846 let decoded = String::from_utf8(data).map_err(|e| Error::D3137Error(e.to_string()))?;
1847
1848 Ok(Value::string(context.arena, &decoded))
1849}
1850
1851pub fn fn_round<'a>(
1852 context: FunctionContext<'a, '_>,
1853 args: &[&'a Value<'a>],
1854) -> Result<&'a Value<'a>> {
1855 max_args!(context, args, 2);
1856 let number = &args[0];
1857 if number.is_undefined() {
1858 return Ok(Value::undefined());
1859 }
1860 assert_arg!(number.is_number(), context, 1);
1861
1862 let precision = if let Some(precision) = args.get(1) {
1863 assert_arg!(precision.is_integer(), context, 2);
1864 precision.as_isize()
1865 } else {
1866 0
1867 };
1868
1869 let num = multiply_by_pow10(number.as_f64(), precision)?;
1870 let num = num.round_ties_even();
1871 let num = multiply_by_pow10(num, -precision)?;
1872
1873 Ok(Value::number(context.arena, num))
1874}
1875
1876fn is_array_of_strings(value: &Value) -> bool {
1877 if let Value::Array(elements, _) = value {
1878 elements.iter().all(|v| v.is_string())
1879 } else {
1880 false
1881 }
1882}
1883
1884pub fn fn_reduce<'a>(
1885 context: FunctionContext<'a, '_>,
1886 args: &[&'a Value<'a>],
1887) -> Result<&'a Value<'a>> {
1888 max_args!(context, args, 3);
1889
1890 if args.len() < 2 {
1891 return Err(Error::T0410ArgumentNotValid(0, 2, context.name.to_string()));
1892 }
1893
1894 let original_value = args[0];
1895 let func = args[1];
1896 let init = args.get(2).copied();
1897
1898 if func.is_function() && func.arity() < 2 {
1899 return Err(Error::D3050SecondArguement(context.name.to_string()));
1900 }
1901
1902 if !original_value.is_array() {
1903 if original_value.is_number() {
1904 return Ok(original_value);
1905 }
1906
1907 if original_value.is_string() {
1908 return Ok(original_value);
1909 }
1910
1911 return Ok(Value::undefined());
1912 }
1913
1914 let (elements, _extra_field) = match original_value {
1915 Value::Array(elems, extra) => (elems, extra),
1916 _ => return Err(Error::D3050SecondArguement(context.name.to_string())),
1917 };
1918
1919 if elements.is_empty() {
1920 return Ok(init.unwrap_or_else(|| Value::undefined()));
1921 }
1922
1923 if !func.is_function() {
1924 return Err(Error::T0410ArgumentNotValid(1, 1, context.name.to_string()));
1925 }
1926
1927 let mut accumulator = init.unwrap_or_else(|| elements[0]);
1928
1929 let has_init_value = init.is_some();
1930 let is_non_single_array_of_strings = is_array_of_strings(original_value) && elements.len() > 1;
1931
1932 let start_index = if has_init_value || is_non_single_array_of_strings {
1933 0
1934 } else {
1935 1
1936 };
1937
1938 for (index, value) in elements[start_index..].iter().enumerate() {
1939 let index_value = Value::number(context.arena, index as f64);
1940
1941 let result =
1942 context.evaluate_function(func, &[accumulator, value, index_value, original_value]);
1943
1944 match result {
1945 Ok(new_accumulator) => {
1946 accumulator = context.trampoline_evaluate_value(new_accumulator)?;
1948 }
1949 Err(_) => {
1950 return Err(Error::T0410ArgumentNotValid(1, 1, context.name.to_string()));
1951 }
1952 }
1953 }
1954
1955 Ok(accumulator)
1956}
1957
1958fn multiply_by_pow10(num: f64, pow: isize) -> Result<f64> {
1961 let num_str = format!("{}e{}", num, pow);
1962 num_str
1963 .parse::<f64>()
1964 .map_err(|e| Error::D3137Error(e.to_string()))
1965}
1966
1967pub fn fn_pad<'a>(
1968 context: FunctionContext<'a, '_>,
1969 args: &[&'a Value<'a>],
1970) -> Result<&'a Value<'a>> {
1971 let str_value = args.first().copied().unwrap_or_else(Value::undefined);
1972 if !str_value.is_string() {
1973 return Ok(Value::undefined());
1974 }
1975
1976 let width_value = args.get(1).copied().unwrap_or_else(Value::undefined);
1977 if !width_value.is_number() {
1978 return Ok(Value::undefined());
1979 }
1980
1981 let str_to_pad = str_value.as_str(); let width_i64 = width_value.as_f64().round() as i64;
1984 let width = width_i64.unsigned_abs() as usize;
1985 let is_right_padding = width_i64 > 0; let pad_char = args
1988 .get(2)
1989 .map(|v| v.as_str())
1990 .filter(|c| !c.is_empty())
1991 .unwrap_or(Cow::Borrowed(" "));
1992
1993 let pad_length = width.saturating_sub(str_to_pad.chars().count());
1994
1995 if pad_length == 0 {
1997 return Ok(Value::string(context.arena, &str_to_pad));
1998 }
1999
2000 let padding = pad_char
2001 .chars()
2002 .cycle()
2003 .take(pad_length)
2004 .collect::<String>();
2005
2006 let result = if is_right_padding {
2008 format!("{}{}", str_to_pad, padding)
2009 } else {
2010 format!("{}{}", padding, str_to_pad)
2011 };
2012
2013 Ok(Value::string(context.arena, &result))
2014}
2015
2016pub fn fn_match<'a>(
2017 context: FunctionContext<'a, '_>,
2018 args: &[&'a Value<'a>],
2019) -> Result<&'a Value<'a>> {
2020 let value_to_validate = match args.first().copied() {
2021 Some(val) if !val.is_undefined() => val,
2022 _ => return Ok(Value::undefined()),
2023 };
2024 assert_arg!(value_to_validate.is_string(), context, 1);
2025
2026 let pattern_value = match args.get(1).copied() {
2027 Some(val) => val,
2028 _ => return Err(Error::D3010EmptyPattern(context.char_index)),
2029 };
2030
2031 let regex_literal = match pattern_value {
2032 Value::Regex(ref regex_literal) => regex_literal,
2033 Value::String(ref s) => {
2034 let regex = RegexLiteral::new(s.as_str(), false, false)
2035 .map_err(|_| Error::D3010EmptyPattern(context.char_index))?;
2036 &*context.arena.alloc(regex)
2037 }
2038 _ => return Err(Error::D3010EmptyPattern(context.char_index)),
2039 };
2040
2041 let limit = args.get(2).and_then(|val| {
2042 if val.is_number() {
2043 Some(val.as_f64() as usize)
2044 } else {
2045 None
2046 }
2047 });
2048
2049 Ok(evaluate_match(
2050 context.arena,
2051 regex_literal.get_regex(),
2052 &value_to_validate.as_str(),
2053 limit,
2054 ))
2055}
2056
2057fn evaluate_match<'a>(
2079 arena: &'a Bump,
2080 regex: &Regex,
2081 input_str: &str,
2082 limit: Option<usize>,
2083) -> &'a Value<'a> {
2084 let limit = limit.unwrap_or(usize::MAX);
2085
2086 let key_match = BumpString::from_str_in("match", arena);
2087 let key_index = BumpString::from_str_in("index", arena);
2088 let key_groups = BumpString::from_str_in("groups", arena);
2089
2090 let mut matches: bumpalo::collections::Vec<&Value<'a>> =
2091 bumpalo::collections::Vec::new_in(arena);
2092
2093 for (i, m) in regex.find_iter(input_str).enumerate() {
2094 if i >= limit {
2095 break;
2096 }
2097
2098 let matched_text = &input_str[m.start()..m.end()];
2099 let match_str = arena.alloc(Value::string(arena, matched_text));
2100
2101 let index_val = arena.alloc(Value::number(arena, i as f64));
2102
2103 let capture_groups = m
2105 .groups()
2106 .filter_map(|group| group.map(|range| &input_str[range.start..range.end]))
2107 .map(|s| BumpString::from_str_in(s, arena))
2108 .map(|s| &*arena.alloc(Value::String(s)))
2109 .skip(1);
2111
2112 let group_vec = BumpVec::from_iter_in(capture_groups, arena);
2113
2114 let groups_val = arena.alloc(Value::Array(group_vec, ArrayFlags::empty()));
2115
2116 let mut match_obj: HashMap<BumpString, &Value<'a>, DefaultHashBuilder, &Bump> =
2117 HashMap::with_capacity_and_hasher_in(3, DefaultHashBuilder::default(), arena);
2118 match_obj.insert(key_match.clone(), match_str);
2119 match_obj.insert(key_index.clone(), index_val);
2120 match_obj.insert(key_groups.clone(), groups_val);
2121
2122 matches.push(arena.alloc(Value::Object(match_obj)));
2123 }
2124
2125 arena.alloc(Value::Array(matches, ArrayFlags::empty()))
2126}