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