1use crate::{
2 expressions::evaluate_ast,
3 heap::{Heap, HeapPointer, IterablePointer},
4 units,
5 values::{FunctionArity, LambdaArg, LambdaDef, ReifiedValue, Value},
6};
7use anyhow::{Result, anyhow};
8use dyn_fmt::AsStrFormatExt;
9use std::{cell::RefCell, collections::HashMap, rc::Rc, sync::LazyLock};
10
11#[cfg(not(target_arch = "wasm32"))]
12use std::sync::Mutex;
13
14#[cfg(not(target_arch = "wasm32"))]
15use crate::stats::FunctionCallStats;
16
17#[cfg(not(target_arch = "wasm32"))]
18pub static FUNCTION_CALLS: LazyLock<Mutex<Vec<FunctionCallStats>>> =
19 LazyLock::new(|| Mutex::new(Vec::new()));
20
21pub static BUILTIN_FUNCTION_NAMES: LazyLock<Vec<&'static str>> =
23 LazyLock::new(BuiltInFunction::all_names);
24
25#[derive(
26 Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
27)]
28pub enum BuiltInFunction {
29 Sqrt,
31 Sin,
32 Cos,
33 Tan,
34 Asin,
35 Acos,
36 Atan,
37 Log,
38 Log10,
39 Exp,
40 Abs,
41 Floor,
42 Ceil,
43 Round,
44 Trunc,
45
46 Min,
48 Max,
49 Avg,
50 Sum,
51 Prod,
52 Median,
53 Percentile,
54
55 Range,
57 Len,
58 Head,
59 Tail,
60 Slice,
61 Concat,
62 Dot,
63 Unique,
64 Sort,
65 SortBy,
66 Reverse,
67 Any,
68 All,
69
70 Map,
72 Reduce,
73 Filter,
74 Every,
75 Some,
76
77 Split,
79 Join,
80 Replace,
81 Trim,
82 Uppercase,
83 Lowercase,
84 Includes,
85 Format,
86
87 Typeof,
89 Arity,
90
91 Keys,
93 Values,
94 Entries,
95
96 ToString,
98 ToNumber,
99 ToBool,
100 Convert,
101
102 #[cfg(not(target_arch = "wasm32"))]
104 Print,
105 #[cfg(not(target_arch = "wasm32"))]
106 TimeNow,
107}
108
109#[derive(Debug, Clone)]
110pub enum FunctionDef {
111 BuiltIn(BuiltInFunction),
112 Lambda(LambdaDef),
113}
114
115impl BuiltInFunction {
116 pub fn from_ident(ident: &str) -> Option<Self> {
117 match ident {
118 "sqrt" => Some(Self::Sqrt),
119 "sin" => Some(Self::Sin),
120 "cos" => Some(Self::Cos),
121 "tan" => Some(Self::Tan),
122 "asin" => Some(Self::Asin),
123 "acos" => Some(Self::Acos),
124 "atan" => Some(Self::Atan),
125 "log" => Some(Self::Log),
126 "log10" => Some(Self::Log10),
127 "exp" => Some(Self::Exp),
128 "abs" => Some(Self::Abs),
129 "floor" => Some(Self::Floor),
130 "ceil" => Some(Self::Ceil),
131 "round" => Some(Self::Round),
132 "trunc" => Some(Self::Trunc),
133 "min" => Some(Self::Min),
134 "max" => Some(Self::Max),
135 "avg" => Some(Self::Avg),
136 "sum" => Some(Self::Sum),
137 "prod" => Some(Self::Prod),
138 "median" => Some(Self::Median),
139 "percentile" => Some(Self::Percentile),
140 "range" => Some(Self::Range),
141 "any" => Some(Self::Any),
142 "all" => Some(Self::All),
143 "len" => Some(Self::Len),
144 "head" => Some(Self::Head),
145 "tail" => Some(Self::Tail),
146 "slice" => Some(Self::Slice),
147 "concat" => Some(Self::Concat),
148 "dot" => Some(Self::Dot),
149 "unique" => Some(Self::Unique),
150 "sort" => Some(Self::Sort),
151 "sort_by" => Some(Self::SortBy),
152 "reverse" => Some(Self::Reverse),
153 "map" => Some(Self::Map),
154 "reduce" => Some(Self::Reduce),
155 "filter" => Some(Self::Filter),
156 "every" => Some(Self::Every),
157 "some" => Some(Self::Some),
158 "split" => Some(Self::Split),
159 "join" => Some(Self::Join),
160 "replace" => Some(Self::Replace),
161 "trim" => Some(Self::Trim),
162 "uppercase" => Some(Self::Uppercase),
163 "lowercase" => Some(Self::Lowercase),
164 "to_string" => Some(Self::ToString),
165 "to_number" => Some(Self::ToNumber),
166 "to_bool" => Some(Self::ToBool),
167 "convert" => Some(Self::Convert),
168 "includes" => Some(Self::Includes),
169 "format" => Some(Self::Format),
170 "typeof" => Some(Self::Typeof),
171 "arity" => Some(Self::Arity),
172 "keys" => Some(Self::Keys),
173 "values" => Some(Self::Values),
174 "entries" => Some(Self::Entries),
175 #[cfg(not(target_arch = "wasm32"))]
176 "print" => Some(Self::Print),
177 #[cfg(not(target_arch = "wasm32"))]
178 "time_now" => Some(Self::TimeNow),
179 _ => None,
180 }
181 }
182
183 pub fn name(&self) -> &'static str {
184 match self {
185 Self::Sqrt => "sqrt",
186 Self::Sin => "sin",
187 Self::Cos => "cos",
188 Self::Tan => "tan",
189 Self::Asin => "asin",
190 Self::Acos => "acos",
191 Self::Atan => "atan",
192 Self::Log => "log",
193 Self::Log10 => "log10",
194 Self::Exp => "exp",
195 Self::Abs => "abs",
196 Self::Floor => "floor",
197 Self::Ceil => "ceil",
198 Self::Round => "round",
199 Self::Trunc => "trunc",
200 Self::Min => "min",
201 Self::Max => "max",
202 Self::Avg => "avg",
203 Self::Sum => "sum",
204 Self::Prod => "prod",
205 Self::Median => "median",
206 Self::Percentile => "percentile",
207 Self::Range => "range",
208 Self::Any => "any",
209 Self::All => "all",
210 Self::Len => "len",
211 Self::Head => "head",
212 Self::Tail => "tail",
213 Self::Slice => "slice",
214 Self::Concat => "concat",
215 Self::Dot => "dot",
216 Self::Unique => "unique",
217 Self::Sort => "sort",
218 Self::SortBy => "sort_by",
219 Self::Reverse => "reverse",
220 Self::Map => "map",
221 Self::Reduce => "reduce",
222 Self::Filter => "filter",
223 Self::Every => "every",
224 Self::Some => "some",
225 Self::Split => "split",
226 Self::Join => "join",
227 Self::Replace => "replace",
228 Self::Trim => "trim",
229 Self::Uppercase => "uppercase",
230 Self::Lowercase => "lowercase",
231 Self::Includes => "includes",
232 Self::Format => "format",
233 Self::Typeof => "typeof",
234 Self::Arity => "arity",
235 Self::Keys => "keys",
236 Self::Values => "values",
237 Self::Entries => "entries",
238 Self::ToString => "to_string",
239 Self::ToNumber => "to_number",
240 Self::ToBool => "to_bool",
241 Self::Convert => "convert",
242 #[cfg(not(target_arch = "wasm32"))]
243 Self::Print => "print",
244 #[cfg(not(target_arch = "wasm32"))]
245 Self::TimeNow => "time_now",
246 }
247 }
248
249 pub fn arity(&self) -> FunctionArity {
250 match self {
251 Self::Sqrt
253 | Self::Sin
254 | Self::Cos
255 | Self::Tan
256 | Self::Asin
257 | Self::Acos
258 | Self::Atan
259 | Self::Log
260 | Self::Log10
261 | Self::Exp
262 | Self::Abs
263 | Self::Floor
264 | Self::Ceil
265 | Self::Trunc => FunctionArity::Exact(1),
266
267 Self::Round => FunctionArity::Between(1, 2),
269
270 Self::Min | Self::Max | Self::Avg | Self::Sum | Self::Prod | Self::Median => {
272 FunctionArity::AtLeast(1)
273 }
274
275 Self::Range => FunctionArity::Between(1, 2),
277
278 Self::Len
280 | Self::Head
281 | Self::Tail
282 | Self::Unique
283 | Self::Sort
284 | Self::Reverse
285 | Self::Any
286 | Self::All => FunctionArity::Exact(1),
287 Self::Slice => FunctionArity::Exact(3),
288 Self::Concat => FunctionArity::AtLeast(2),
289 Self::Dot | Self::Percentile => FunctionArity::Exact(2),
290
291 Self::Map | Self::Filter | Self::Every | Self::Some | Self::SortBy => {
293 FunctionArity::Exact(2)
294 }
295 Self::Reduce => FunctionArity::Exact(3),
296
297 Self::Split | Self::Join | Self::Includes => FunctionArity::Exact(2),
299 Self::Replace => FunctionArity::Exact(3),
300 Self::Trim
301 | Self::Uppercase
302 | Self::Lowercase
303 | Self::ToString
304 | Self::ToNumber
305 | Self::ToBool => FunctionArity::Exact(1),
306 Self::Convert => FunctionArity::Exact(3),
307 Self::Format => FunctionArity::AtLeast(1),
308
309 Self::Typeof | Self::Arity => FunctionArity::Exact(1),
311
312 Self::Keys | Self::Values | Self::Entries => FunctionArity::Exact(1),
314
315 #[cfg(not(target_arch = "wasm32"))]
317 Self::Print => FunctionArity::AtLeast(1),
318 #[cfg(not(target_arch = "wasm32"))]
319 Self::TimeNow => FunctionArity::Exact(0),
320 }
321 }
322
323 pub fn call(
324 &self,
325 args: Vec<Value>,
326 heap: Rc<RefCell<Heap>>,
327 bindings: Rc<RefCell<HashMap<String, Value>>>,
328 call_depth: usize,
329 ) -> Result<Value> {
330 match self {
331 Self::Sqrt => Ok(Value::Number(args[0].as_number()?.sqrt())),
333 Self::Sin => Ok(Value::Number(args[0].as_number()?.sin())),
334 Self::Cos => Ok(Value::Number(args[0].as_number()?.cos())),
335 Self::Tan => Ok(Value::Number(args[0].as_number()?.tan())),
336 Self::Asin => Ok(Value::Number(args[0].as_number()?.asin())),
337 Self::Acos => Ok(Value::Number(args[0].as_number()?.acos())),
338 Self::Atan => Ok(Value::Number(args[0].as_number()?.atan())),
339 Self::Log => Ok(Value::Number(args[0].as_number()?.ln())),
340 Self::Log10 => Ok(Value::Number(args[0].as_number()?.log10())),
341 Self::Exp => Ok(Value::Number(args[0].as_number()?.exp())),
342 Self::Abs => Ok(Value::Number(args[0].as_number()?.abs())),
343 Self::Floor => Ok(Value::Number(args[0].as_number()?.floor())),
344 Self::Ceil => Ok(Value::Number(args[0].as_number()?.ceil())),
345 Self::Trunc => Ok(Value::Number(args[0].as_number()?.trunc())),
346
347 Self::Round => {
348 let num = args[0].as_number()?;
349 if args.len() == 1 {
350 Ok(Value::Number(num.round()))
351 } else {
352 let decimal_places = args[1].as_number()? as i32;
353 let multiplier = 10_f64.powi(decimal_places);
354 Ok(Value::Number((num * multiplier).round() / multiplier))
355 }
356 }
357
358 Self::Min => {
360 let nums = if args.len() == 1 {
361 match &args[0] {
363 Value::List(_) => {
364 let borrowed_heap = heap.borrow();
365 let list = args[0].as_list(&borrowed_heap)?;
366 list.iter()
367 .map(|a| a.as_number())
368 .collect::<Result<Vec<f64>>>()?
369 }
370 _ => vec![args[0].as_number()?],
371 }
372 } else {
373 args.iter()
374 .map(|a| a.as_number())
375 .collect::<Result<Vec<f64>>>()?
376 };
377
378 if nums.is_empty() {
379 return Err(anyhow!("min requires at least one number"));
380 }
381
382 Ok(Value::Number(
383 nums.iter().copied().fold(f64::INFINITY, f64::min),
384 ))
385 }
386
387 Self::Max => {
388 let nums = if args.len() == 1 {
389 match &args[0] {
391 Value::List(_) => {
392 let borrowed_heap = heap.borrow();
393 let list = args[0].as_list(&borrowed_heap)?;
394 list.iter()
395 .map(|a| a.as_number())
396 .collect::<Result<Vec<f64>>>()?
397 }
398 _ => vec![args[0].as_number()?],
399 }
400 } else {
401 args.iter()
402 .map(|a| a.as_number())
403 .collect::<Result<Vec<f64>>>()?
404 };
405
406 if nums.is_empty() {
407 return Err(anyhow!("max requires at least one number"));
408 }
409
410 Ok(Value::Number(
411 nums.iter().copied().fold(f64::NEG_INFINITY, f64::max),
412 ))
413 }
414
415 Self::Avg => {
416 let nums = if args.len() == 1 {
417 match &args[0] {
418 Value::List(_) => {
419 let borrowed_heap = heap.borrow();
420 let list = args[0].as_list(&borrowed_heap)?;
421 list.iter()
422 .map(|a| a.as_number())
423 .collect::<Result<Vec<f64>>>()?
424 }
425 _ => vec![args[0].as_number()?],
426 }
427 } else {
428 args.iter()
429 .map(|a| a.as_number())
430 .collect::<Result<Vec<f64>>>()?
431 };
432 if nums.is_empty() {
433 return Err(anyhow!("avg requires at least one number"));
434 }
435 Ok(Value::Number(nums.iter().sum::<f64>() / nums.len() as f64))
436 }
437
438 Self::Prod => {
439 let nums = if args.len() == 1 {
440 match &args[0] {
441 Value::List(_) => {
442 let borrowed_heap = heap.borrow();
443 let list = args[0].as_list(&borrowed_heap)?;
444 list.iter()
445 .map(|a| a.as_number())
446 .collect::<Result<Vec<f64>>>()?
447 }
448 _ => vec![args[0].as_number()?],
449 }
450 } else {
451 args.iter()
452 .map(|a| a.as_number())
453 .collect::<Result<Vec<f64>>>()?
454 };
455 if nums.is_empty() {
456 return Err(anyhow!("prod requires at least one number"));
457 }
458 Ok(Value::Number(nums.iter().product()))
459 }
460
461 Self::Range => {
462 let (start, end) = match args[..] {
463 [Value::Number(start)] => (0.0, start),
464 [Value::Number(start), Value::Number(end)] => (start, end),
465 _ => return Err(anyhow!("range requires 1 or 2 numbers")),
466 };
467
468 if start > end {
469 return Err(anyhow!(
470 "range requires start to be less than or equal to end"
471 ));
472 }
473
474 if !f64::is_finite(start) || !f64::is_finite(end) {
475 return Err(anyhow!("range requires finite numbers"));
476 }
477
478 let start_i64 = start as i64;
479 let end_i64 = end as i64;
480 let length = end_i64 - start_i64;
481
482 if length > u32::MAX as i64 {
483 return Err(anyhow!(
484 "list would be longer than the maximum length of {}",
485 u32::MAX
486 ));
487 }
488
489 let values = (start_i64..end_i64)
490 .map(|e| Value::Number(e as f64))
491 .collect();
492 let list = heap.borrow_mut().insert_list(values);
493
494 Ok(list)
495 }
496
497 Self::Sum => {
498 let nums = if args.len() == 1 {
499 match &args[0] {
500 Value::List(_) => {
501 let borrowed_heap = heap.borrow();
502 let list = args[0].as_list(&borrowed_heap)?;
503 list.iter()
504 .map(|a| a.as_number())
505 .collect::<Result<Vec<f64>>>()?
506 }
507 _ => vec![args[0].as_number()?],
508 }
509 } else {
510 args.iter()
511 .map(|a| a.as_number())
512 .collect::<Result<Vec<f64>>>()?
513 };
514 if nums.is_empty() {
515 return Err(anyhow!("sum requires at least one number"));
516 }
517 Ok(Value::Number(nums.iter().sum()))
518 }
519
520 Self::Median => {
522 let mut nums = if args.len() == 1 {
523 match &args[0] {
524 Value::List(_) => {
525 let borrowed_heap = heap.borrow();
526 let list = args[0].as_list(&borrowed_heap)?;
527 list.iter()
528 .map(|a| a.as_number())
529 .collect::<Result<Vec<f64>>>()?
530 }
531 _ => vec![args[0].as_number()?],
532 }
533 } else {
534 args.into_iter()
535 .map(|a| a.as_number())
536 .collect::<Result<Vec<f64>>>()?
537 };
538
539 if nums.is_empty() {
540 return Err(anyhow!("median requires at least one number"));
541 }
542
543 nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
544 let len = nums.len();
545 if len % 2 == 0 {
546 Ok(Value::Number((nums[len / 2 - 1] + nums[len / 2]) / 2.0))
547 } else {
548 Ok(Value::Number(nums[len / 2]))
549 }
550 }
551
552 Self::Percentile => {
553 let p = args[1].as_number()?;
554 let heap = &heap.borrow();
555 let list = args[0].as_list(heap)?;
556
557 if !(0.0..=100.0).contains(&p) {
558 return Err(anyhow!("percentile must be between 0 and 100"));
559 }
560
561 let mut nums = list
562 .iter()
563 .map(|a| a.as_number())
564 .collect::<Result<Vec<f64>>>()?;
565
566 nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
567 let index = (p / 100.0 * (nums.len() - 1) as f64).round() as usize;
568
569 Ok(Value::Number(nums[index]))
570 }
571
572 Self::Len => match &args[0] {
574 Value::List(l) => Ok(Value::Number(
575 l.reify(&heap.borrow()).as_list()?.len() as f64
576 )),
577 Value::String(s) => Ok(Value::Number(
578 s.reify(&heap.borrow()).as_string()?.len() as f64
579 )),
580 _ => Err(anyhow!("argument must be a list or string")),
581 },
582
583 Self::Head => match &args[0] {
584 Value::List(p) => Ok(p
585 .reify(&heap.borrow())
586 .as_list()?
587 .first()
588 .copied()
589 .unwrap_or(Value::Null)),
590 Value::String(p) => {
591 let val = {
592 p.reify(&heap.borrow())
593 .as_string()?
594 .get(0..1)
595 .unwrap_or("")
596 .to_string()
597 };
598
599 Ok(heap.borrow_mut().insert_string(val))
600 }
601 _ => Err(anyhow!("argument must be a list or string")),
602 },
603
604 Self::Tail => match &args[0] {
605 Value::List(p) => {
606 let val = {
607 p.reify(&heap.borrow())
608 .as_list()?
609 .get(1..)
610 .unwrap_or([].as_slice())
611 .to_vec()
612 };
613
614 Ok(heap.borrow_mut().insert_list(val))
615 }
616 Value::String(s) => {
617 let val = {
618 s.reify(&heap.borrow())
619 .as_string()?
620 .get(1..)
621 .unwrap_or("")
622 .to_string()
623 };
624
625 Ok(heap.borrow_mut().insert_string(val))
626 }
627 _ => Err(anyhow!("argument must be a list or string")),
628 },
629
630 Self::Slice => {
631 let start = args[1].as_number()? as usize;
632 let end = args[2].as_number()? as usize;
633
634 match args[0] {
635 Value::List(_) => {
636 let l = {
637 let borrowed_heap = &heap.borrow();
638 args[0].as_list(borrowed_heap)?.clone()
639 };
640
641 l.get(start..end)
642 .map_or(Err(anyhow!("index out of bounds")), |l| {
643 Ok(heap.borrow_mut().insert_list(l.to_vec()))
644 })
645 }
646 Value::String(_) => {
647 let s = {
648 let borrowed_heap = &heap.borrow();
649 args[0].as_string(borrowed_heap)?.to_string()
650 };
651
652 s.get(start..end)
653 .map_or(Err(anyhow!("index out of bounds")), |s| {
654 Ok(heap.borrow_mut().insert_string(s.to_string()))
655 })
656 }
657 _ => Err(anyhow!("argument must be a list or string")),
658 }
659 }
660
661 Self::Concat => {
662 let mut list = vec![];
663
664 for arg in args {
665 match arg {
666 Value::List(p) => list.extend(p.reify(&heap.borrow()).as_list()?.clone()),
667 Value::Spread(IterablePointer::List(p)) => {
668 list.extend(p.reify(&heap.borrow()).as_list()?.clone())
669 }
670 Value::Spread(IterablePointer::String(p)) => {
671 let string = {
672 let borrowed_heap = &heap.borrow();
673 p.reify(borrowed_heap).as_string()?.to_string()
674 };
675
676 list.extend(
677 string
678 .chars()
679 .map(|c| heap.borrow_mut().insert_string(c.to_string())),
680 );
681 }
682 _ => list.push(arg),
683 }
684 }
685
686 Ok(heap.borrow_mut().insert_list(list))
687 }
688
689 Self::Dot => {
690 let (a, b) = {
691 let borrowed_heap = &heap.borrow();
692 (
693 args[0].as_list(borrowed_heap)?.clone(),
694 args[1].as_list(borrowed_heap)?.clone(),
695 )
696 };
697
698 if a.len() != b.len() {
699 return Err(anyhow!(
700 "cannot calculate dot product of lists with different lengths"
701 ));
702 }
703
704 Ok(Value::Number(
705 a.iter()
706 .zip(b.iter())
707 .map(|(a, b)| {
708 let a_num = a.as_number()?;
709 let b_num = b.as_number()?;
710 Ok(a_num * b_num)
711 })
712 .collect::<Result<Vec<f64>>>()?
713 .iter()
714 .sum(),
715 ))
716 }
717
718 Self::Unique => {
719 let list = {
720 let borrowed_heap = &heap.borrow();
721 args[0].as_list(borrowed_heap)?.clone()
722 };
723 let mut unique_list = vec![];
724 let borrowed_heap = heap.borrow();
725
726 for item in list {
727 let mut is_duplicate = false;
728 for existing in &unique_list {
729 if item.equals(existing, &borrowed_heap)? {
730 is_duplicate = true;
731 break;
732 }
733 }
734 if !is_duplicate {
735 unique_list.push(item);
736 }
737 }
738
739 drop(borrowed_heap);
740 Ok(heap.borrow_mut().insert_list(unique_list))
741 }
742
743 Self::Sort => {
744 let mut list = {
745 let borrowed_heap = &heap.borrow();
746 args[0].as_list(borrowed_heap)?.clone()
747 };
748 let borrowed_heap = heap.borrow();
749 list.sort_by(|a, b| {
750 a.compare(b, &borrowed_heap)
751 .unwrap_or(None)
752 .unwrap_or(std::cmp::Ordering::Equal)
753 });
754 drop(borrowed_heap);
755 Ok(heap.borrow_mut().insert_list(list))
756 }
757
758 Self::Reverse => {
759 let mut list = { args[0].as_list(&heap.borrow())?.clone() };
760 list.reverse();
761 Ok(heap.borrow_mut().insert_list(list))
762 }
763
764 Self::Any => {
765 let list = args[0].as_list(&heap.borrow())?.clone();
766 Ok(Value::Bool(
767 list.iter().any(|v| v.as_bool().unwrap_or(false)),
768 ))
769 }
770
771 Self::All => {
772 let list = args[0].as_list(&heap.borrow())?.clone();
773 Ok(Value::Bool(
774 list.iter().all(|v| v.as_bool().unwrap_or(false)),
775 ))
776 }
777
778 Self::Split => {
780 let (s, delimeter) = {
781 let borrowed_heap = &heap.borrow();
782 (
783 args[0].as_string(borrowed_heap)?.to_string(),
784 args[1].as_string(borrowed_heap)?.to_string(),
785 )
786 };
787
788 let list = s
789 .split(&delimeter)
790 .map(|s| heap.borrow_mut().insert_string(s.to_string()))
791 .collect();
792
793 Ok(heap.borrow_mut().insert_list(list))
794 }
795
796 Self::Join => {
797 let joined_string = {
798 let borrowed_heap = &heap.borrow();
799 let delimeter = args[1].as_string(borrowed_heap)?;
800 let list = args[0].as_list(borrowed_heap)?;
801 list.iter()
802 .map(|v| v.stringify_internal(borrowed_heap))
803 .collect::<Vec<String>>()
804 .join(delimeter)
805 };
806
807 Ok(heap.borrow_mut().insert_string(joined_string))
808 }
809
810 Self::Replace => {
811 let string = {
812 let borrowed_heap = heap.borrow();
813 let old = args[1].as_string(&borrowed_heap)?.to_string();
814 let new = args[2].as_string(&borrowed_heap)?.to_string();
815 let s = args[0].as_string(&borrowed_heap)?.to_string();
816 s.replace(&old, &new)
817 };
818
819 Ok(heap.borrow_mut().insert_string(string))
820 }
821
822 Self::Trim => {
823 let string = {
824 let borrowed_heap = heap.borrow();
825 args[0].as_string(&borrowed_heap)?.trim().to_string()
826 };
827
828 Ok(heap.borrow_mut().insert_string(string))
829 }
830
831 Self::Uppercase => {
832 let string = args[0].as_string(&heap.borrow())?.to_uppercase();
833 Ok(heap.borrow_mut().insert_string(string))
834 }
835
836 Self::Lowercase => {
837 let string = args[0].as_string(&heap.borrow())?.to_lowercase();
838 Ok(heap.borrow_mut().insert_string(string))
839 }
840
841 Self::Includes => {
842 match &args[0].reify(&heap.borrow())? {
843 ReifiedValue::List(l, _) => {
845 let borrowed_heap = heap.borrow();
846 for item in (*l).iter() {
847 if item.equals(&args[1], &borrowed_heap)? {
848 return Ok(Value::Bool(true));
849 }
850 }
851 Ok(Value::Bool(false))
852 }
853 ReifiedValue::String(s, _) => {
855 let needle = {
856 let borrowed_heap = &heap.borrow();
857 args[1]
858 .as_string(borrowed_heap)
859 .map_err(|_| anyhow!("second argument must be a string"))?
860 .to_string()
861 };
862 Ok(Value::Bool(s.contains(&needle)))
863 }
864 _ => Err(anyhow!("first argument must be a list or string")),
865 }
866 }
867
868 Self::Format => {
869 let format_str = {
870 let borrowed_heap = &heap.borrow();
871 args[0]
872 .as_string(borrowed_heap)
873 .map_err(|_| anyhow!("first argument must be a string"))?
874 .to_string()
875 };
876
877 let format_args = {
878 let borrowed_heap = &heap.borrow();
879 &args[1..]
880 .iter()
881 .map(|v| v.stringify_internal(borrowed_heap))
882 .collect::<Vec<String>>()
883 };
884
885 Ok(heap
886 .borrow_mut()
887 .insert_string(format_str.format(format_args)))
888 }
889
890 Self::Typeof => Ok(heap
892 .borrow_mut()
893 .insert_string(args[0].get_type().to_string())),
894
895 Self::Arity => {
896 let arity = match args[0] {
897 Value::Lambda(p) => p.reify(&heap.borrow()).as_lambda()?.get_arity(),
898 Value::BuiltIn(built_in) => built_in.arity(),
899 _ => return Err(anyhow!("argument must be a function or built-in function")),
900 };
901
902 Ok(Value::Number(match arity {
903 FunctionArity::Exact(n) => n as f64,
904 FunctionArity::AtLeast(n) => n as f64,
905 FunctionArity::Between(min, _max) => min as f64,
906 }))
907 }
908
909 Self::Keys => {
911 let record = args[0].as_record(&heap.borrow())?.clone();
912 let keys = {
913 let key_strings = record.keys().cloned().collect::<Vec<String>>();
914 key_strings
915 .iter()
916 .map(|k| heap.borrow_mut().insert_string(k.to_string()))
917 .collect()
918 };
919
920 Ok(heap.borrow_mut().insert_list(keys))
921 }
922
923 Self::Values => {
924 let record = args[0].as_record(&heap.borrow())?.clone();
925 let values = record.values().cloned().collect();
926
927 Ok(heap.borrow_mut().insert_list(values))
928 }
929
930 Self::Entries => {
931 let record = args[0].as_record(&heap.borrow())?.clone();
932 let entries = record
933 .iter()
934 .map(|(k, v)| {
935 let entry = {
936 let mut borrowed_heap = heap.borrow_mut();
937 vec![borrowed_heap.insert_string(k.to_string()), *v]
938 };
939 heap.borrow_mut().insert_list(entry)
940 })
941 .collect();
942
943 Ok(heap.borrow_mut().insert_list(entries))
944 }
945
946 Self::ToString => match args[0] {
948 Value::String(_) => Ok(args[0]), _ => {
950 let string = args[0].stringify_internal(&heap.borrow());
951 Ok(heap.borrow_mut().insert_string(string))
952 }
953 },
954
955 Self::ToNumber => match args[0] {
956 Value::Number(_) => Ok(args[0]), Value::Bool(b) => Ok(Value::Number(if b { 1.0 } else { 0.0 })),
958 _ => Ok(Value::Number(args[0].as_string(&heap.borrow())?.parse()?)),
959 },
960
961 Self::ToBool => match args[0] {
962 Value::Bool(_) => Ok(args[0]), Value::Number(_) => Ok(Value::Bool(args[0].as_number()? != 0.0)),
964 _ => Err(anyhow!(
965 "expected a boolean or number, but got a {}",
966 args[0].get_type()
967 )),
968 },
969
970 Self::Convert => {
971 let value = args[0].as_number()?;
972 let from_unit = {
973 let borrowed_heap = &heap.borrow();
974 args[1].as_string(borrowed_heap)?.to_string()
975 };
976 let to_unit = {
977 let borrowed_heap = &heap.borrow();
978 args[2].as_string(borrowed_heap)?.to_string()
979 };
980
981 let result = units::convert(value, &from_unit, &to_unit)?;
982 Ok(Value::Number(result))
983 }
984
985 #[cfg(not(target_arch = "wasm32"))]
987 Self::Print => {
988 let borrowed_heap = &heap.borrow();
989
990 let output = if args.len() == 1 {
991 args[0].stringify_internal(borrowed_heap)
992 } else {
993 let format_str = args[0].as_string(borrowed_heap).map_err(|_| {
994 anyhow!("first argument must be a formatting string if multiple arguments are given")
995 })?;
996 let format_args = &args[1..]
997 .iter()
998 .map(|v| v.stringify_internal(borrowed_heap))
999 .collect::<Vec<String>>();
1000 format_str.format(format_args)
1001 };
1002
1003 eprintln!("{}", output);
1005
1006 Ok(Value::Null)
1007 }
1008
1009 #[cfg(not(target_arch = "wasm32"))]
1010 Self::TimeNow => Ok(Value::Number(
1011 std::time::SystemTime::now()
1012 .duration_since(std::time::UNIX_EPOCH)
1013 .unwrap()
1014 .as_secs_f64(),
1015 )),
1016
1017 Self::Map => {
1019 let func = &args[1];
1020 let (list, func_accepts_two_args) = {
1021 let borrowed_heap = &heap.borrow();
1022 let list = args[0].as_list(borrowed_heap)?.clone();
1023 let func_def = get_function_def(func, borrowed_heap)
1024 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1025
1026 let accepts_two = func_def.arity().can_accept(2);
1028
1029 (list, accepts_two)
1030 };
1031
1032 let mut mapped_list = vec![];
1033 for (idx, item) in list.iter().enumerate() {
1034 let func_def = get_function_def(func, &heap.borrow())
1035 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1036
1037 let args = if func_accepts_two_args {
1038 vec![*item, Value::Number(idx as f64)]
1039 } else {
1040 vec![*item]
1041 };
1042
1043 let result = func_def.call(
1044 Value::Null,
1045 args,
1046 Rc::clone(&heap),
1047 Rc::clone(&bindings),
1048 call_depth + 1,
1049 )?;
1050 mapped_list.push(result);
1051 }
1052
1053 Ok(heap.borrow_mut().insert_list(mapped_list))
1054 }
1055
1056 Self::Filter => {
1057 let func = &args[1];
1058 let (list, func_accepts_two_args) = {
1059 let borrowed_heap = &heap.borrow();
1060 let list = args[0].as_list(borrowed_heap)?.clone();
1061 let func_def = get_function_def(func, borrowed_heap)
1062 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1063
1064 let accepts_two = func_def.arity().can_accept(2);
1066
1067 (list, accepts_two)
1068 };
1069
1070 let mut filtered_list = vec![];
1071 for (idx, item) in list.iter().enumerate() {
1072 let func_def = get_function_def(func, &heap.borrow())
1073 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1074
1075 let args = if func_accepts_two_args {
1076 vec![*item, Value::Number(idx as f64)]
1077 } else {
1078 vec![*item]
1079 };
1080
1081 let result = func_def.call(
1082 Value::Null,
1083 args,
1084 Rc::clone(&heap),
1085 Rc::clone(&bindings),
1086 call_depth + 1,
1087 )?;
1088 if result.as_bool()? {
1089 filtered_list.push(*item);
1090 }
1091 }
1092
1093 Ok(heap.borrow_mut().insert_list(filtered_list))
1094 }
1095
1096 Self::Reduce => {
1097 let func = &args[1];
1098 let initial = args[2];
1099 let (list, func_accepts_three_args) = {
1100 let borrowed_heap = &heap.borrow();
1101 let list = args[0].as_list(borrowed_heap)?.clone();
1102 let func_def = get_function_def(func, borrowed_heap)
1103 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1104
1105 let accepts_three = func_def.arity().can_accept(3);
1107
1108 (list, accepts_three)
1109 };
1110
1111 let mut accumulator = initial;
1112 for (idx, item) in list.iter().enumerate() {
1113 let func_def = get_function_def(func, &heap.borrow())
1114 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1115
1116 let args = if func_accepts_three_args {
1117 vec![accumulator, *item, Value::Number(idx as f64)]
1118 } else {
1119 vec![accumulator, *item]
1120 };
1121
1122 accumulator = func_def.call(
1123 Value::Null,
1124 args,
1125 Rc::clone(&heap),
1126 Rc::clone(&bindings),
1127 call_depth + 1,
1128 )?;
1129 }
1130
1131 Ok(accumulator)
1132 }
1133
1134 Self::Every => {
1135 let func = &args[1];
1136 let (list, func_accepts_two_args) = {
1137 let borrowed_heap = &heap.borrow();
1138 let list = args[0].as_list(borrowed_heap)?.clone();
1139 let func_def = get_function_def(func, borrowed_heap)
1140 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1141
1142 let accepts_two = func_def.arity().can_accept(2);
1144
1145 (list, accepts_two)
1146 };
1147
1148 for (idx, item) in list.iter().enumerate() {
1149 let func_def = get_function_def(func, &heap.borrow())
1150 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1151
1152 let args = if func_accepts_two_args {
1153 vec![*item, Value::Number(idx as f64)]
1154 } else {
1155 vec![*item]
1156 };
1157
1158 let result = func_def.call(
1159 Value::Null,
1160 args,
1161 Rc::clone(&heap),
1162 Rc::clone(&bindings),
1163 call_depth + 1,
1164 )?;
1165 if !result.as_bool()? {
1166 return Ok(Value::Bool(false));
1167 }
1168 }
1169
1170 Ok(Value::Bool(true))
1171 }
1172
1173 Self::Some => {
1174 let func = &args[1];
1175 let (list, func_accepts_two_args) = {
1176 let borrowed_heap = &heap.borrow();
1177 let list = args[0].as_list(borrowed_heap)?.clone();
1178 let func_def = get_function_def(func, borrowed_heap)
1179 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1180
1181 let accepts_two = func_def.arity().can_accept(2);
1183
1184 (list, accepts_two)
1185 };
1186
1187 for (idx, item) in list.iter().enumerate() {
1188 let func_def = get_function_def(func, &heap.borrow())
1189 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1190
1191 let args = if func_accepts_two_args {
1192 vec![*item, Value::Number(idx as f64)]
1193 } else {
1194 vec![*item]
1195 };
1196
1197 let result = func_def.call(
1198 Value::Null,
1199 args,
1200 Rc::clone(&heap),
1201 Rc::clone(&bindings),
1202 call_depth + 1,
1203 )?;
1204 if result.as_bool()? {
1205 return Ok(Value::Bool(true));
1206 }
1207 }
1208
1209 Ok(Value::Bool(false))
1210 }
1211
1212 Self::SortBy => {
1213 let func = &args[1];
1214 let mut list = {
1215 let borrowed_heap = &heap.borrow();
1216 args[0].as_list(borrowed_heap)?.clone()
1217 };
1218
1219 list.sort_by(|a, b| {
1220 let func_def_a = get_function_def(func, &heap.borrow());
1221 let func_def_b = get_function_def(func, &heap.borrow());
1222
1223 match (func_def_a, func_def_b) {
1224 (Some(fd_a), Some(fd_b)) => {
1225 let result_a = fd_a.call(
1226 Value::Null,
1227 vec![*a],
1228 Rc::clone(&heap),
1229 Rc::clone(&bindings),
1230 call_depth + 1,
1231 );
1232 let result_b = fd_b.call(
1233 Value::Null,
1234 vec![*b],
1235 Rc::clone(&heap),
1236 Rc::clone(&bindings),
1237 call_depth + 1,
1238 );
1239
1240 match (result_a, result_b) {
1241 (Ok(val_a), Ok(val_b)) => val_a
1242 .compare(&val_b, &heap.borrow())
1243 .unwrap_or(None)
1244 .unwrap_or(std::cmp::Ordering::Equal),
1245 _ => std::cmp::Ordering::Equal,
1246 }
1247 }
1248 _ => std::cmp::Ordering::Equal,
1249 }
1250 });
1251
1252 Ok(heap.borrow_mut().insert_list(list))
1253 }
1254 }
1255 }
1256
1257 pub fn all() -> Vec<Self> {
1258 vec![
1259 Self::Sqrt,
1260 Self::Sin,
1261 Self::Cos,
1262 Self::Tan,
1263 Self::Asin,
1264 Self::Acos,
1265 Self::Atan,
1266 Self::Log,
1267 Self::Log10,
1268 Self::Exp,
1269 Self::Abs,
1270 Self::Floor,
1271 Self::Ceil,
1272 Self::Round,
1273 Self::Trunc,
1274 Self::Min,
1275 Self::Max,
1276 Self::Avg,
1277 Self::Sum,
1278 Self::Prod,
1279 Self::Median,
1280 Self::Percentile,
1281 Self::Range,
1282 Self::Len,
1283 Self::Head,
1284 Self::Tail,
1285 Self::Slice,
1286 Self::Concat,
1287 Self::Dot,
1288 Self::Unique,
1289 Self::Sort,
1290 Self::SortBy,
1291 Self::Reverse,
1292 Self::Any,
1293 Self::All,
1294 Self::Map,
1295 Self::Reduce,
1296 Self::Filter,
1297 Self::Every,
1298 Self::Some,
1299 Self::Split,
1300 Self::Join,
1301 Self::Replace,
1302 Self::Trim,
1303 Self::Uppercase,
1304 Self::Lowercase,
1305 Self::ToString,
1306 Self::ToNumber,
1307 Self::ToBool,
1308 Self::Convert,
1309 Self::Includes,
1310 Self::Format,
1311 Self::Typeof,
1312 Self::Arity,
1313 Self::Keys,
1314 Self::Values,
1315 Self::Entries,
1316 #[cfg(not(target_arch = "wasm32"))]
1317 Self::Print,
1318 #[cfg(not(target_arch = "wasm32"))]
1319 Self::TimeNow,
1320 ]
1321 }
1322
1323 pub fn all_names() -> Vec<&'static str> {
1324 Self::all().iter().map(|f| f.name()).collect()
1325 }
1326}
1327
1328impl FunctionDef {
1329 pub fn get_name(&self) -> String {
1330 match self {
1331 FunctionDef::BuiltIn(built_in) => {
1332 format!("built-in function \"{}\"", built_in.name())
1333 }
1334 FunctionDef::Lambda(LambdaDef { name, .. }) => name
1335 .clone()
1336 .map_or(String::from("anonymous function"), |n| {
1337 format!("function \"{}\"", n)
1338 }),
1339 }
1340 }
1341
1342 pub fn arity(&self) -> FunctionArity {
1343 match self {
1344 FunctionDef::BuiltIn(built_in) => built_in.arity(),
1345 FunctionDef::Lambda(lambda_def) => lambda_def.get_arity(),
1346 }
1347 }
1348
1349 pub fn check_arity(&self, arg_count: usize) -> Result<()> {
1350 match self {
1351 FunctionDef::BuiltIn(built_in) => match built_in.arity() {
1352 FunctionArity::Exact(expected) => {
1353 if arg_count == expected {
1354 Ok(())
1355 } else {
1356 Err(anyhow!(
1357 "{} takes exactly {} arguments, but {} were given",
1358 self.get_name(),
1359 expected,
1360 arg_count
1361 ))
1362 }
1363 }
1364 FunctionArity::AtLeast(expected) => {
1365 if arg_count >= expected {
1366 Ok(())
1367 } else {
1368 Err(anyhow!(
1369 "{} takes at least {} arguments, but {} were given",
1370 self.get_name(),
1371 expected,
1372 arg_count
1373 ))
1374 }
1375 }
1376 FunctionArity::Between(min, max) => {
1377 if arg_count >= min && arg_count <= max {
1378 Ok(())
1379 } else {
1380 Err(anyhow!(
1381 "{} takes between {} and {} arguments, but {} were given",
1382 self.get_name(),
1383 min,
1384 max,
1385 arg_count
1386 ))
1387 }
1388 }
1389 },
1390 FunctionDef::Lambda(def) => {
1391 let arity = def.get_arity();
1392
1393 match arity {
1394 FunctionArity::Exact(expected) => {
1395 if arg_count == expected {
1396 Ok(())
1397 } else {
1398 Err(anyhow!(
1399 "{} takes exactly {} arguments, but {} were given",
1400 self.get_name(),
1401 expected,
1402 arg_count
1403 ))
1404 }
1405 }
1406 FunctionArity::AtLeast(expected) => {
1407 if arg_count >= expected {
1408 Ok(())
1409 } else {
1410 Err(anyhow!(
1411 "{} takes at least {} arguments, but {} were given",
1412 self.get_name(),
1413 expected,
1414 arg_count
1415 ))
1416 }
1417 }
1418 FunctionArity::Between(min, max) => {
1419 if arg_count >= min && arg_count <= max {
1420 Ok(())
1421 } else {
1422 Err(anyhow!(
1423 "{} takes between {} and {} arguments, but {} were given",
1424 self.get_name(),
1425 min,
1426 max,
1427 arg_count
1428 ))
1429 }
1430 }
1431 }
1432 }
1433 }
1434 }
1435
1436 pub fn call(
1437 &self,
1438 this_value: Value,
1439 args: Vec<Value>,
1440 heap: Rc<RefCell<Heap>>,
1441 bindings: Rc<RefCell<HashMap<String, Value>>>,
1442 call_depth: usize,
1443 ) -> Result<Value> {
1444 #[cfg(not(target_arch = "wasm32"))]
1445 let start = std::time::Instant::now();
1446
1447 self.check_arity(args.len())?;
1448
1449 if call_depth > 1000 {
1450 return Err(anyhow!(
1451 "in {}: maximum call depth of 1000 exceeded",
1452 self.get_name()
1453 ));
1454 }
1455
1456 match self {
1457 FunctionDef::Lambda(LambdaDef {
1458 name,
1459 args: expected_args,
1460 body,
1461 scope,
1462 }) => {
1463 #[cfg(not(target_arch = "wasm32"))]
1464 let start_var_env = std::time::Instant::now();
1465
1466 let mut new_bindings = bindings.borrow().clone();
1468
1469 for (key, value) in scope {
1471 new_bindings.insert(key.clone(), *value);
1472 }
1473
1474 if let Some(fn_name) = name {
1476 new_bindings.insert(fn_name.clone(), this_value);
1477 }
1478
1479 if let Some(inputs) = new_bindings.get("inputs").copied() {
1481 new_bindings.insert(String::from("inputs"), inputs);
1482 }
1483
1484 for (idx, expected_arg) in expected_args.iter().enumerate() {
1486 match expected_arg {
1487 LambdaArg::Required(arg_name) => {
1488 new_bindings.insert(arg_name.clone(), args[idx]);
1489 }
1490 LambdaArg::Optional(arg_name) => {
1491 new_bindings.insert(
1492 arg_name.clone(),
1493 args.get(idx).copied().unwrap_or(Value::Null),
1494 );
1495 }
1496 LambdaArg::Rest(arg_name) => {
1497 new_bindings.insert(
1498 arg_name.clone(),
1499 heap.borrow_mut()
1500 .insert_list(args.iter().skip(idx).copied().collect()),
1501 );
1502 }
1503 }
1504 }
1505
1506 #[cfg(not(target_arch = "wasm32"))]
1507 let end_var_env = std::time::Instant::now();
1508
1509 let return_value = evaluate_ast(
1510 body,
1511 Rc::clone(&heap),
1512 Rc::new(RefCell::new(new_bindings)),
1513 call_depth + 1,
1514 )
1515 .map_err(|error| anyhow!("in {}: {}", self.get_name(), error));
1516
1517 #[cfg(not(target_arch = "wasm32"))]
1518 FUNCTION_CALLS.lock().unwrap().push(FunctionCallStats {
1519 name: self.get_name(),
1520 start,
1521 end: std::time::Instant::now(),
1522 start_var_env: Some(start_var_env),
1523 end_var_env: Some(end_var_env),
1524 });
1525
1526 return_value
1527 }
1528 FunctionDef::BuiltIn(built_in) => {
1529 let return_value = built_in
1530 .call(args, heap, bindings, call_depth + 1)
1531 .map_err(|error| anyhow!("in {}: {}", self.get_name(), error));
1532
1533 #[cfg(not(target_arch = "wasm32"))]
1534 FUNCTION_CALLS.lock().unwrap().push(FunctionCallStats {
1535 name: self.get_name(),
1536 start,
1537 end: std::time::Instant::now(),
1538 start_var_env: None,
1539 end_var_env: None,
1540 });
1541
1542 return_value
1543 }
1544 }
1545 }
1546}
1547
1548pub fn is_built_in_function(ident: &str) -> bool {
1549 BuiltInFunction::from_ident(ident).is_some()
1550}
1551
1552pub fn get_built_in_function_def_by_ident(ident: &str) -> Option<FunctionDef> {
1553 BuiltInFunction::from_ident(ident).map(FunctionDef::BuiltIn)
1554}
1555
1556pub fn get_built_in_function_idents() -> Vec<&'static str> {
1557 BuiltInFunction::all_names()
1558}
1559
1560pub fn get_function_def(value: &Value, heap: &Heap) -> Option<FunctionDef> {
1561 match value {
1562 Value::Lambda(pointer) => Some(FunctionDef::Lambda(
1563 pointer.reify(heap).as_lambda().ok()?.clone(),
1564 )),
1565 Value::BuiltIn(built_in) => Some(FunctionDef::BuiltIn(*built_in)),
1566 _ => None,
1567 }
1568}
1569
1570#[cfg(test)]
1571mod tests {
1572 use super::*;
1573 use std::cell::RefCell;
1574 use std::collections::HashMap;
1575 use std::rc::Rc;
1576
1577 #[test]
1578 fn test_range_function() {
1579 let heap = Rc::new(RefCell::new(Heap::new()));
1581 let bindings = Rc::new(RefCell::new(HashMap::new()));
1582 let range_fn = BuiltInFunction::Range;
1583
1584 let args = vec![Value::Number(4.0)];
1586 let result = range_fn
1587 .call(args, heap.clone(), bindings.clone(), 0)
1588 .unwrap();
1589
1590 let heap_borrow = heap.borrow();
1591 let list = result.as_list(&heap_borrow).unwrap();
1592 assert_eq!(list.len(), 4);
1593 assert_eq!(list[0], Value::Number(0.0));
1594 assert_eq!(list[3], Value::Number(3.0));
1595 }
1596
1597 #[test]
1598 fn test_range_function_two_args() {
1599 let heap = Rc::new(RefCell::new(Heap::new()));
1601 let bindings = Rc::new(RefCell::new(HashMap::new()));
1602 let range_fn = BuiltInFunction::Range;
1603
1604 let args = vec![Value::Number(4.0), Value::Number(10.0)];
1606 let result = range_fn
1607 .call(args, heap.clone(), bindings.clone(), 0)
1608 .unwrap();
1609
1610 let heap_borrow = heap.borrow();
1611 let list = result.as_list(&heap_borrow).unwrap();
1612 assert_eq!(list.len(), 6);
1613 assert_eq!(list[0], Value::Number(4.0));
1614 assert_eq!(list[5], Value::Number(9.0));
1615 }
1616
1617 #[test]
1618 fn test_round_function_single_arg() {
1619 let heap = Rc::new(RefCell::new(Heap::new()));
1620 let bindings = Rc::new(RefCell::new(HashMap::new()));
1621 let round_fn = BuiltInFunction::Round;
1622
1623 let test_cases = vec![
1625 (42.4, 42.0),
1626 (42.5, 43.0),
1627 (42.6, 43.0),
1628 (-42.4, -42.0),
1629 (-42.5, -43.0),
1630 (-42.6, -43.0),
1631 (0.0, 0.0),
1632 (1.999, 2.0),
1633 (-1.999, -2.0),
1634 ];
1635
1636 for (input, expected) in test_cases {
1637 let args = vec![Value::Number(input)];
1638 let result = round_fn
1639 .call(args, heap.clone(), bindings.clone(), 0)
1640 .unwrap();
1641 assert_eq!(
1642 result,
1643 Value::Number(expected),
1644 "round({}) should be {}",
1645 input,
1646 expected
1647 );
1648 }
1649 }
1650
1651 #[test]
1652 fn test_round_function_with_decimal_places() {
1653 let heap = Rc::new(RefCell::new(Heap::new()));
1654 let bindings = Rc::new(RefCell::new(HashMap::new()));
1655 let round_fn = BuiltInFunction::Round;
1656
1657 let test_cases = vec![
1659 (42.4543, 0.0, 42.0),
1660 (42.4543, 1.0, 42.5),
1661 (42.4543, 2.0, 42.45),
1662 (42.4543, 3.0, 42.454),
1663 (42.4543, 4.0, 42.4543),
1664 (4.14159, 4.0, 4.1416),
1665 (0.005, 2.0, 0.01),
1666 (0.995, 2.0, 1.0),
1667 (9.995, 2.0, 9.99),
1670 (-9.995, 2.0, -9.99),
1671 ];
1672
1673 for (input, places, expected) in test_cases {
1674 let args = vec![Value::Number(input), Value::Number(places)];
1675 let result = round_fn
1676 .call(args, heap.clone(), bindings.clone(), 0)
1677 .unwrap();
1678
1679 if let Value::Number(result_num) = result {
1681 assert!(
1682 (result_num - expected).abs() < 1e-10,
1683 "round({}, {}) = {} should be close to {}",
1684 input,
1685 places,
1686 result_num,
1687 expected
1688 );
1689 } else {
1690 panic!("Expected number result");
1691 }
1692 }
1693 }
1694
1695 #[test]
1696 fn test_round_function_negative_decimal_places() {
1697 let heap = Rc::new(RefCell::new(Heap::new()));
1698 let bindings = Rc::new(RefCell::new(HashMap::new()));
1699 let round_fn = BuiltInFunction::Round;
1700
1701 let test_cases = vec![
1703 (1234.567, -1.0, 1230.0),
1704 (1234.567, -2.0, 1200.0),
1705 (1234.567, -3.0, 1000.0),
1706 (1234.567, -4.0, 0.0),
1707 (5678.9, -1.0, 5680.0),
1708 (5678.9, -2.0, 5700.0),
1709 (5678.9, -3.0, 6000.0),
1710 (-1234.567, -1.0, -1230.0),
1711 (-1234.567, -2.0, -1200.0),
1712 (1500.0, -3.0, 2000.0),
1713 (-1500.0, -3.0, -2000.0),
1714 ];
1715
1716 for (input, places, expected) in test_cases {
1717 let args = vec![Value::Number(input), Value::Number(places)];
1718 let result = round_fn
1719 .call(args, heap.clone(), bindings.clone(), 0)
1720 .unwrap();
1721 assert_eq!(
1722 result,
1723 Value::Number(expected),
1724 "round({}, {}) should be {}",
1725 input,
1726 places,
1727 expected
1728 );
1729 }
1730 }
1731
1732 #[test]
1733 fn test_round_function_edge_cases() {
1734 let heap = Rc::new(RefCell::new(Heap::new()));
1735 let bindings = Rc::new(RefCell::new(HashMap::new()));
1736 let round_fn = BuiltInFunction::Round;
1737
1738 let test_cases = vec![
1740 (f64::INFINITY, 0.0, f64::INFINITY),
1741 (f64::NEG_INFINITY, 0.0, f64::NEG_INFINITY),
1742 (0.0, 5.0, 0.0),
1743 (-0.0, 5.0, -0.0),
1744 (1e-10, 5.0, 0.0),
1745 (1e-10, 15.0, 1e-10),
1746 ];
1747
1748 for (input, places, expected) in test_cases {
1749 let args = vec![Value::Number(input), Value::Number(places)];
1750 let result = round_fn
1751 .call(args, heap.clone(), bindings.clone(), 0)
1752 .unwrap();
1753
1754 if let Value::Number(result_num) = result {
1755 if expected.is_infinite() {
1756 assert!(
1757 result_num.is_infinite()
1758 && result_num.is_sign_positive() == expected.is_sign_positive(),
1759 "round({}, {}) should be {}",
1760 input,
1761 places,
1762 expected
1763 );
1764 } else if expected == 0.0 || expected == -0.0 {
1765 assert!(
1766 result_num.abs() < 1e-10,
1767 "round({}, {}) = {} should be close to 0",
1768 input,
1769 places,
1770 result_num
1771 );
1772 } else {
1773 assert!(
1774 (result_num - expected).abs() < 1e-15,
1775 "round({}, {}) = {} should be close to {}",
1776 input,
1777 places,
1778 result_num,
1779 expected
1780 );
1781 }
1782 } else {
1783 panic!("Expected number result");
1784 }
1785 }
1786 }
1787
1788 #[test]
1789 fn test_map_with_index() {
1790 use crate::ast::Expr;
1791 use crate::values::LambdaDef;
1792
1793 let heap = Rc::new(RefCell::new(Heap::new()));
1794 let bindings = Rc::new(RefCell::new(HashMap::new()));
1795
1796 let list = heap.borrow_mut().insert_list(vec![
1798 Value::Number(10.0),
1799 Value::Number(20.0),
1800 Value::Number(30.0),
1801 ]);
1802
1803 let lambda = LambdaDef {
1805 name: None,
1806 args: vec![
1807 crate::values::LambdaArg::Required("x".to_string()),
1808 crate::values::LambdaArg::Required("i".to_string()),
1809 ],
1810 body: Expr::BinaryOp {
1811 op: crate::ast::BinaryOp::Add,
1812 left: Box::new(Expr::Identifier("x".to_string())),
1813 right: Box::new(Expr::Identifier("i".to_string())),
1814 },
1815 scope: HashMap::new(),
1816 };
1817 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1818
1819 let result = BuiltInFunction::Map
1821 .call(
1822 vec![list, lambda_value],
1823 heap.clone(),
1824 bindings.clone(),
1825 0,
1826 )
1827 .unwrap();
1828
1829 let heap_borrow = heap.borrow();
1831 let result_list = result.as_list(&heap_borrow).unwrap();
1832 assert_eq!(result_list.len(), 3);
1833 assert_eq!(result_list[0], Value::Number(10.0)); assert_eq!(result_list[1], Value::Number(21.0)); assert_eq!(result_list[2], Value::Number(32.0)); }
1837
1838 #[test]
1839 fn test_filter_with_index() {
1840 use crate::ast::Expr;
1841 use crate::values::LambdaDef;
1842
1843 let heap = Rc::new(RefCell::new(Heap::new()));
1844 let bindings = Rc::new(RefCell::new(HashMap::new()));
1845
1846 let list = heap.borrow_mut().insert_list(vec![
1848 Value::Number(10.0),
1849 Value::Number(20.0),
1850 Value::Number(30.0),
1851 Value::Number(40.0),
1852 ]);
1853
1854 let lambda = LambdaDef {
1856 name: None,
1857 args: vec![
1858 crate::values::LambdaArg::Required("x".to_string()),
1859 crate::values::LambdaArg::Required("i".to_string()),
1860 ],
1861 body: Expr::BinaryOp {
1862 op: crate::ast::BinaryOp::Greater,
1863 left: Box::new(Expr::Identifier("i".to_string())),
1864 right: Box::new(Expr::Number(1.0)),
1865 },
1866 scope: HashMap::new(),
1867 };
1868 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1869
1870 let result = BuiltInFunction::Filter
1872 .call(
1873 vec![list, lambda_value],
1874 heap.clone(),
1875 bindings.clone(),
1876 0,
1877 )
1878 .unwrap();
1879
1880 let heap_borrow = heap.borrow();
1882 let result_list = result.as_list(&heap_borrow).unwrap();
1883 assert_eq!(result_list.len(), 2);
1884 assert_eq!(result_list[0], Value::Number(30.0));
1885 assert_eq!(result_list[1], Value::Number(40.0));
1886 }
1887
1888 #[test]
1889 fn test_reduce_with_index() {
1890 use crate::ast::Expr;
1891 use crate::values::LambdaDef;
1892
1893 let heap = Rc::new(RefCell::new(Heap::new()));
1894 let bindings = Rc::new(RefCell::new(HashMap::new()));
1895
1896 let list = heap.borrow_mut().insert_list(vec![
1898 Value::Number(10.0),
1899 Value::Number(20.0),
1900 Value::Number(30.0),
1901 ]);
1902
1903 let lambda = LambdaDef {
1905 name: None,
1906 args: vec![
1907 crate::values::LambdaArg::Required("acc".to_string()),
1908 crate::values::LambdaArg::Required("x".to_string()),
1909 crate::values::LambdaArg::Required("i".to_string()),
1910 ],
1911 body: Expr::BinaryOp {
1912 op: crate::ast::BinaryOp::Add,
1913 left: Box::new(Expr::BinaryOp {
1914 op: crate::ast::BinaryOp::Add,
1915 left: Box::new(Expr::Identifier("acc".to_string())),
1916 right: Box::new(Expr::Identifier("x".to_string())),
1917 }),
1918 right: Box::new(Expr::Identifier("i".to_string())),
1919 },
1920 scope: HashMap::new(),
1921 };
1922 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1923
1924 let result = BuiltInFunction::Reduce
1926 .call(
1927 vec![list, lambda_value, Value::Number(0.0)],
1928 heap.clone(),
1929 bindings.clone(),
1930 0,
1931 )
1932 .unwrap();
1933
1934 assert_eq!(result, Value::Number(63.0));
1936 }
1937
1938 #[test]
1939 fn test_map_backward_compatible() {
1940 use crate::ast::Expr;
1941 use crate::values::LambdaDef;
1942
1943 let heap = Rc::new(RefCell::new(Heap::new()));
1944 let bindings = Rc::new(RefCell::new(HashMap::new()));
1945
1946 let list = heap.borrow_mut().insert_list(vec![
1948 Value::Number(10.0),
1949 Value::Number(20.0),
1950 Value::Number(30.0),
1951 ]);
1952
1953 let lambda = LambdaDef {
1955 name: None,
1956 args: vec![crate::values::LambdaArg::Required("x".to_string())],
1957 body: Expr::BinaryOp {
1958 op: crate::ast::BinaryOp::Multiply,
1959 left: Box::new(Expr::Identifier("x".to_string())),
1960 right: Box::new(Expr::Number(2.0)),
1961 },
1962 scope: HashMap::new(),
1963 };
1964 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1965
1966 let result = BuiltInFunction::Map
1968 .call(
1969 vec![list, lambda_value],
1970 heap.clone(),
1971 bindings.clone(),
1972 0,
1973 )
1974 .unwrap();
1975
1976 let heap_borrow = heap.borrow();
1978 let result_list = result.as_list(&heap_borrow).unwrap();
1979 assert_eq!(result_list.len(), 3);
1980 assert_eq!(result_list[0], Value::Number(20.0));
1981 assert_eq!(result_list[1], Value::Number(40.0));
1982 assert_eq!(result_list[2], Value::Number(60.0));
1983 }
1984
1985 #[test]
1986 fn test_convert_length() {
1987 let heap = Rc::new(RefCell::new(Heap::new()));
1988 let bindings = Rc::new(RefCell::new(HashMap::new()));
1989 let convert_fn = BuiltInFunction::Convert;
1990
1991 let from_unit = heap.borrow_mut().insert_string("km".to_string());
1993 let to_unit = heap.borrow_mut().insert_string("m".to_string());
1994 let args = vec![Value::Number(1.0), from_unit, to_unit];
1995 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
1996 assert_eq!(result, Value::Number(1000.0));
1997
1998 let from_unit = heap.borrow_mut().insert_string("miles".to_string());
2000 let to_unit = heap.borrow_mut().insert_string("km".to_string());
2001 let args = vec![Value::Number(1.0), from_unit, to_unit];
2002 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
2003 if let Value::Number(n) = result {
2004 assert!((n - 1.609344).abs() < 1e-6);
2005 } else {
2006 panic!("Expected number");
2007 }
2008 }
2009
2010 #[test]
2011 fn test_convert_temperature() {
2012 let heap = Rc::new(RefCell::new(Heap::new()));
2013 let bindings = Rc::new(RefCell::new(HashMap::new()));
2014 let convert_fn = BuiltInFunction::Convert;
2015
2016 let from_unit = heap.borrow_mut().insert_string("celsius".to_string());
2018 let to_unit = heap.borrow_mut().insert_string("fahrenheit".to_string());
2019 let args = vec![Value::Number(0.0), from_unit, to_unit];
2020 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
2021 if let Value::Number(n) = result {
2022 assert!((n - 32.0).abs() < 1e-10);
2023 }
2024
2025 let from_unit = heap.borrow_mut().insert_string("celsius".to_string());
2027 let to_unit = heap.borrow_mut().insert_string("fahrenheit".to_string());
2028 let args = vec![Value::Number(100.0), from_unit, to_unit];
2029 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
2030 if let Value::Number(n) = result {
2031 assert!((n - 212.0).abs() < 1e-10);
2032 }
2033 }
2034
2035 #[test]
2036 fn test_convert_mass() {
2037 let heap = Rc::new(RefCell::new(Heap::new()));
2038 let bindings = Rc::new(RefCell::new(HashMap::new()));
2039 let convert_fn = BuiltInFunction::Convert;
2040
2041 let from_unit = heap.borrow_mut().insert_string("kg".to_string());
2043 let to_unit = heap.borrow_mut().insert_string("lbs".to_string());
2044 let args = vec![Value::Number(1.0), from_unit, to_unit];
2045 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
2046 if let Value::Number(n) = result {
2047 assert!((n - 2.20462).abs() < 0.001);
2048 }
2049 }
2050
2051 #[test]
2052 fn test_convert_information_storage() {
2053 let heap = Rc::new(RefCell::new(Heap::new()));
2054 let bindings = Rc::new(RefCell::new(HashMap::new()));
2055 let convert_fn = BuiltInFunction::Convert;
2056
2057 let from_unit = heap.borrow_mut().insert_string("kibibytes".to_string());
2059 let to_unit = heap.borrow_mut().insert_string("bytes".to_string());
2060 let args = vec![Value::Number(1.0), from_unit, to_unit];
2061 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
2062 assert_eq!(result, Value::Number(1024.0));
2063 }
2064
2065 #[test]
2066 fn test_convert_same_unit() {
2067 let heap = Rc::new(RefCell::new(Heap::new()));
2068 let bindings = Rc::new(RefCell::new(HashMap::new()));
2069 let convert_fn = BuiltInFunction::Convert;
2070
2071 let from_unit = heap.borrow_mut().insert_string("meters".to_string());
2073 let to_unit = heap.borrow_mut().insert_string("m".to_string());
2074 let args = vec![Value::Number(42.0), from_unit, to_unit];
2075 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
2076 assert_eq!(result, Value::Number(42.0));
2077 }
2078
2079 #[test]
2080 fn test_convert_incompatible_units() {
2081 let heap = Rc::new(RefCell::new(Heap::new()));
2082 let bindings = Rc::new(RefCell::new(HashMap::new()));
2083 let convert_fn = BuiltInFunction::Convert;
2084
2085 let from_unit = heap.borrow_mut().insert_string("kg".to_string());
2087 let to_unit = heap.borrow_mut().insert_string("meters".to_string());
2088 let args = vec![Value::Number(1.0), from_unit, to_unit];
2089 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0);
2090 assert!(result.is_err());
2091 assert!(result.unwrap_err().to_string().contains("Cannot convert"));
2092 }
2093
2094 #[test]
2095 fn test_convert_unknown_unit() {
2096 let heap = Rc::new(RefCell::new(Heap::new()));
2097 let bindings = Rc::new(RefCell::new(HashMap::new()));
2098 let convert_fn = BuiltInFunction::Convert;
2099
2100 let from_unit = heap.borrow_mut().insert_string("foobar".to_string());
2102 let to_unit = heap.borrow_mut().insert_string("meters".to_string());
2103 let args = vec![Value::Number(1.0), from_unit, to_unit];
2104 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0);
2105 assert!(result.is_err());
2106 assert!(result.unwrap_err().to_string().contains("Unknown unit"));
2107 }
2108
2109 #[test]
2110 fn test_convert_case_insensitive() {
2111 let heap = Rc::new(RefCell::new(Heap::new()));
2112 let bindings = Rc::new(RefCell::new(HashMap::new()));
2113 let convert_fn = BuiltInFunction::Convert;
2114
2115 let from_unit = heap.borrow_mut().insert_string("KM".to_string());
2117 let to_unit = heap.borrow_mut().insert_string("M".to_string());
2118 let args = vec![Value::Number(1.0), from_unit, to_unit];
2119 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0).unwrap();
2120 assert_eq!(result, Value::Number(1000.0));
2121 }
2122}