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