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(
1528 Rc::clone(&bindings),
1529 local_bindings,
1530 ));
1531
1532 let return_value = evaluate_ast(
1533 body,
1534 Rc::clone(&heap),
1535 new_env,
1536 call_depth + 1,
1537 lambda_source.clone(),
1538 )
1539 .map_err(|error| anyhow!("in {}: {}", self.get_name(), error));
1540
1541 #[cfg(not(target_arch = "wasm32"))]
1542 FUNCTION_CALLS.lock().unwrap().push(FunctionCallStats {
1543 name: self.get_name(),
1544 start,
1545 end: std::time::Instant::now(),
1546 start_var_env: Some(start_var_env),
1547 end_var_env: Some(end_var_env),
1548 });
1549
1550 return_value
1551 }
1552 FunctionDef::BuiltIn(built_in) => {
1553 let return_value = built_in
1554 .call(args, heap, bindings, call_depth + 1, source)
1555 .map_err(|error| anyhow!("in {}: {}", self.get_name(), error));
1556
1557 #[cfg(not(target_arch = "wasm32"))]
1558 FUNCTION_CALLS.lock().unwrap().push(FunctionCallStats {
1559 name: self.get_name(),
1560 start,
1561 end: std::time::Instant::now(),
1562 start_var_env: None,
1563 end_var_env: None,
1564 });
1565
1566 return_value
1567 }
1568 }
1569 }
1570}
1571
1572pub fn is_built_in_function(ident: &str) -> bool {
1573 BuiltInFunction::from_ident(ident).is_some()
1574}
1575
1576pub fn get_built_in_function_def_by_ident(ident: &str) -> Option<FunctionDef> {
1577 BuiltInFunction::from_ident(ident).map(FunctionDef::BuiltIn)
1578}
1579
1580pub fn get_built_in_function_idents() -> Vec<&'static str> {
1581 BuiltInFunction::all_names()
1582}
1583
1584pub fn get_function_def(value: &Value, heap: &Heap) -> Option<FunctionDef> {
1585 match value {
1586 Value::Lambda(pointer) => Some(FunctionDef::Lambda(
1587 pointer.reify(heap).as_lambda().ok()?.clone(),
1588 )),
1589 Value::BuiltIn(built_in) => Some(FunctionDef::BuiltIn(*built_in)),
1590 _ => None,
1591 }
1592}
1593
1594#[cfg(test)]
1595mod tests {
1596 use super::*;
1597 use crate::environment::Environment;
1598 use std::cell::RefCell;
1599 use std::rc::Rc;
1600
1601 #[test]
1602 fn test_range_function() {
1603 let heap = Rc::new(RefCell::new(Heap::new()));
1605 let bindings = Rc::new(Environment::new());
1606 let range_fn = BuiltInFunction::Range;
1607
1608 let args = vec![Value::Number(4.0)];
1610 let result = range_fn
1611 .call(args, heap.clone(), bindings.clone(), 0, "")
1612 .unwrap();
1613
1614 let heap_borrow = heap.borrow();
1615 let list = result.as_list(&heap_borrow).unwrap();
1616 assert_eq!(list.len(), 4);
1617 assert_eq!(list[0], Value::Number(0.0));
1618 assert_eq!(list[3], Value::Number(3.0));
1619 }
1620
1621 #[test]
1622 fn test_range_function_two_args() {
1623 let heap = Rc::new(RefCell::new(Heap::new()));
1625 let bindings = Rc::new(Environment::new());
1626 let range_fn = BuiltInFunction::Range;
1627
1628 let args = vec![Value::Number(4.0), Value::Number(10.0)];
1630 let result = range_fn
1631 .call(args, heap.clone(), bindings.clone(), 0, "")
1632 .unwrap();
1633
1634 let heap_borrow = heap.borrow();
1635 let list = result.as_list(&heap_borrow).unwrap();
1636 assert_eq!(list.len(), 6);
1637 assert_eq!(list[0], Value::Number(4.0));
1638 assert_eq!(list[5], Value::Number(9.0));
1639 }
1640
1641 #[test]
1642 fn test_round_function_single_arg() {
1643 let heap = Rc::new(RefCell::new(Heap::new()));
1644 let bindings = Rc::new(Environment::new());
1645 let round_fn = BuiltInFunction::Round;
1646
1647 let test_cases = vec![
1649 (42.4, 42.0),
1650 (42.5, 43.0),
1651 (42.6, 43.0),
1652 (-42.4, -42.0),
1653 (-42.5, -43.0),
1654 (-42.6, -43.0),
1655 (0.0, 0.0),
1656 (1.999, 2.0),
1657 (-1.999, -2.0),
1658 ];
1659
1660 for (input, expected) in test_cases {
1661 let args = vec![Value::Number(input)];
1662 let result = round_fn
1663 .call(args, heap.clone(), bindings.clone(), 0, "")
1664 .unwrap();
1665 assert_eq!(
1666 result,
1667 Value::Number(expected),
1668 "round({}) should be {}",
1669 input,
1670 expected
1671 );
1672 }
1673 }
1674
1675 #[test]
1676 fn test_round_function_with_decimal_places() {
1677 let heap = Rc::new(RefCell::new(Heap::new()));
1678 let bindings = Rc::new(Environment::new());
1679 let round_fn = BuiltInFunction::Round;
1680
1681 let test_cases = vec![
1683 (42.4543, 0.0, 42.0),
1684 (42.4543, 1.0, 42.5),
1685 (42.4543, 2.0, 42.45),
1686 (42.4543, 3.0, 42.454),
1687 (42.4543, 4.0, 42.4543),
1688 (4.14159, 4.0, 4.1416),
1689 (0.005, 2.0, 0.01),
1690 (0.995, 2.0, 1.0),
1691 (9.995, 2.0, 9.99),
1694 (-9.995, 2.0, -9.99),
1695 ];
1696
1697 for (input, places, expected) in test_cases {
1698 let args = vec![Value::Number(input), Value::Number(places)];
1699 let result = round_fn
1700 .call(args, heap.clone(), bindings.clone(), 0, "")
1701 .unwrap();
1702
1703 if let Value::Number(result_num) = result {
1705 assert!(
1706 (result_num - expected).abs() < 1e-10,
1707 "round({}, {}) = {} should be close to {}",
1708 input,
1709 places,
1710 result_num,
1711 expected
1712 );
1713 } else {
1714 panic!("Expected number result");
1715 }
1716 }
1717 }
1718
1719 #[test]
1720 fn test_round_function_negative_decimal_places() {
1721 let heap = Rc::new(RefCell::new(Heap::new()));
1722 let bindings = Rc::new(Environment::new());
1723 let round_fn = BuiltInFunction::Round;
1724
1725 let test_cases = vec![
1727 (1234.567, -1.0, 1230.0),
1728 (1234.567, -2.0, 1200.0),
1729 (1234.567, -3.0, 1000.0),
1730 (1234.567, -4.0, 0.0),
1731 (5678.9, -1.0, 5680.0),
1732 (5678.9, -2.0, 5700.0),
1733 (5678.9, -3.0, 6000.0),
1734 (-1234.567, -1.0, -1230.0),
1735 (-1234.567, -2.0, -1200.0),
1736 (1500.0, -3.0, 2000.0),
1737 (-1500.0, -3.0, -2000.0),
1738 ];
1739
1740 for (input, places, expected) in test_cases {
1741 let args = vec![Value::Number(input), Value::Number(places)];
1742 let result = round_fn
1743 .call(args, heap.clone(), bindings.clone(), 0, "")
1744 .unwrap();
1745 assert_eq!(
1746 result,
1747 Value::Number(expected),
1748 "round({}, {}) should be {}",
1749 input,
1750 places,
1751 expected
1752 );
1753 }
1754 }
1755
1756 #[test]
1757 fn test_round_function_edge_cases() {
1758 let heap = Rc::new(RefCell::new(Heap::new()));
1759 let bindings = Rc::new(Environment::new());
1760 let round_fn = BuiltInFunction::Round;
1761
1762 let test_cases = vec![
1764 (f64::INFINITY, 0.0, f64::INFINITY),
1765 (f64::NEG_INFINITY, 0.0, f64::NEG_INFINITY),
1766 (0.0, 5.0, 0.0),
1767 (-0.0, 5.0, -0.0),
1768 (1e-10, 5.0, 0.0),
1769 (1e-10, 15.0, 1e-10),
1770 ];
1771
1772 for (input, places, expected) in test_cases {
1773 let args = vec![Value::Number(input), Value::Number(places)];
1774 let result = round_fn
1775 .call(args, heap.clone(), bindings.clone(), 0, "")
1776 .unwrap();
1777
1778 if let Value::Number(result_num) = result {
1779 if expected.is_infinite() {
1780 assert!(
1781 result_num.is_infinite()
1782 && result_num.is_sign_positive() == expected.is_sign_positive(),
1783 "round({}, {}) should be {}",
1784 input,
1785 places,
1786 expected
1787 );
1788 } else if expected == 0.0 || expected == -0.0 {
1789 assert!(
1790 result_num.abs() < 1e-10,
1791 "round({}, {}) = {} should be close to 0",
1792 input,
1793 places,
1794 result_num
1795 );
1796 } else {
1797 assert!(
1798 (result_num - expected).abs() < 1e-15,
1799 "round({}, {}) = {} should be close to {}",
1800 input,
1801 places,
1802 result_num,
1803 expected
1804 );
1805 }
1806 } else {
1807 panic!("Expected number result");
1808 }
1809 }
1810 }
1811
1812 #[test]
1813 fn test_random_function_deterministic() {
1814 let heap = Rc::new(RefCell::new(Heap::new()));
1815 let bindings = Rc::new(Environment::new());
1816 let random_fn = BuiltInFunction::Random;
1817
1818 let seed = 42.0;
1820 let args1 = vec![Value::Number(seed)];
1821 let result1 = random_fn
1822 .call(args1, heap.clone(), bindings.clone(), 0, "")
1823 .unwrap();
1824
1825 let args2 = vec![Value::Number(seed)];
1826 let result2 = random_fn
1827 .call(args2, heap.clone(), bindings.clone(), 0, "")
1828 .unwrap();
1829
1830 assert_eq!(result1, result2, "Same seed should produce same result");
1831 }
1832
1833 #[test]
1834 fn test_random_function_different_seeds() {
1835 let heap = Rc::new(RefCell::new(Heap::new()));
1836 let bindings = Rc::new(Environment::new());
1837 let random_fn = BuiltInFunction::Random;
1838
1839 let args1 = vec![Value::Number(42.0)];
1841 let result1 = random_fn
1842 .call(args1, heap.clone(), bindings.clone(), 0, "")
1843 .unwrap();
1844
1845 let args2 = vec![Value::Number(100.0)];
1846 let result2 = random_fn
1847 .call(args2, heap.clone(), bindings.clone(), 0, "")
1848 .unwrap();
1849
1850 assert_ne!(
1851 result1, result2,
1852 "Different seeds should produce different results"
1853 );
1854 }
1855
1856 #[test]
1857 fn test_random_function_range() {
1858 let heap = Rc::new(RefCell::new(Heap::new()));
1859 let bindings = Rc::new(Environment::new());
1860 let random_fn = BuiltInFunction::Random;
1861
1862 for seed in [0.0, 1.0, 42.0, 100.0, 999.0, 12345.0] {
1864 let args = vec![Value::Number(seed)];
1865 let result = random_fn
1866 .call(args, heap.clone(), bindings.clone(), 0, "")
1867 .unwrap();
1868
1869 if let Value::Number(num) = result {
1870 assert!(
1871 num >= 0.0 && num < 1.0,
1872 "Random value {} should be in range [0, 1)",
1873 num
1874 );
1875 } else {
1876 panic!("Expected number result");
1877 }
1878 }
1879 }
1880
1881 #[test]
1882 fn test_random_function_negative_seed() {
1883 let heap = Rc::new(RefCell::new(Heap::new()));
1884 let bindings = Rc::new(Environment::new());
1885 let random_fn = BuiltInFunction::Random;
1886
1887 let args = vec![Value::Number(-42.0)];
1889 let result = random_fn
1890 .call(args, heap.clone(), bindings.clone(), 0, "")
1891 .unwrap();
1892
1893 if let Value::Number(num) = result {
1894 assert!(
1895 num >= 0.0 && num < 1.0,
1896 "Random value {} should be in range [0, 1)",
1897 num
1898 );
1899 } else {
1900 panic!("Expected number result");
1901 }
1902 }
1903
1904 #[test]
1905 fn test_map_with_index() {
1906 use crate::values::LambdaDef;
1907
1908 let heap = Rc::new(RefCell::new(Heap::new()));
1909 let bindings = Rc::new(Environment::new());
1910
1911 let list = heap.borrow_mut().insert_list(vec![
1913 Value::Number(10.0),
1914 Value::Number(20.0),
1915 Value::Number(30.0),
1916 ]);
1917
1918 let lambda = LambdaDef {
1920 name: None,
1921 args: vec![
1922 crate::values::LambdaArg::Required("x".to_string()),
1923 crate::values::LambdaArg::Required("i".to_string()),
1924 ],
1925 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
1926 op: crate::ast::BinaryOp::Add,
1927 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
1928 "x".to_string(),
1929 ))),
1930 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
1931 "i".to_string(),
1932 ))),
1933 }),
1934 scope: HashMap::new(),
1935 source: Rc::from(""),
1936 };
1937 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1938
1939 let result = BuiltInFunction::Map
1941 .call(
1942 vec![list, lambda_value],
1943 heap.clone(),
1944 bindings.clone(),
1945 0,
1946 "",
1947 )
1948 .unwrap();
1949
1950 let heap_borrow = heap.borrow();
1952 let result_list = result.as_list(&heap_borrow).unwrap();
1953 assert_eq!(result_list.len(), 3);
1954 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)); }
1958
1959 #[test]
1960 fn test_filter_with_index() {
1961 use crate::values::LambdaDef;
1962
1963 let heap = Rc::new(RefCell::new(Heap::new()));
1964 let bindings = Rc::new(Environment::new());
1965
1966 let list = heap.borrow_mut().insert_list(vec![
1968 Value::Number(10.0),
1969 Value::Number(20.0),
1970 Value::Number(30.0),
1971 Value::Number(40.0),
1972 ]);
1973
1974 let lambda = LambdaDef {
1976 name: None,
1977 args: vec![
1978 crate::values::LambdaArg::Required("x".to_string()),
1979 crate::values::LambdaArg::Required("i".to_string()),
1980 ],
1981 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
1982 op: crate::ast::BinaryOp::Greater,
1983 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
1984 "i".to_string(),
1985 ))),
1986 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Number(1.0))),
1987 }),
1988 scope: HashMap::new(),
1989 source: Rc::from(""),
1990 };
1991 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1992
1993 let result = BuiltInFunction::Filter
1995 .call(
1996 vec![list, lambda_value],
1997 heap.clone(),
1998 bindings.clone(),
1999 0,
2000 "",
2001 )
2002 .unwrap();
2003
2004 let heap_borrow = heap.borrow();
2006 let result_list = result.as_list(&heap_borrow).unwrap();
2007 assert_eq!(result_list.len(), 2);
2008 assert_eq!(result_list[0], Value::Number(30.0));
2009 assert_eq!(result_list[1], Value::Number(40.0));
2010 }
2011
2012 #[test]
2013 fn test_reduce_with_index() {
2014 use crate::values::LambdaDef;
2015
2016 let heap = Rc::new(RefCell::new(Heap::new()));
2017 let bindings = Rc::new(Environment::new());
2018
2019 let list = heap.borrow_mut().insert_list(vec![
2021 Value::Number(10.0),
2022 Value::Number(20.0),
2023 Value::Number(30.0),
2024 ]);
2025
2026 let lambda = LambdaDef {
2028 name: None,
2029 args: vec![
2030 crate::values::LambdaArg::Required("acc".to_string()),
2031 crate::values::LambdaArg::Required("x".to_string()),
2032 crate::values::LambdaArg::Required("i".to_string()),
2033 ],
2034 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
2035 op: crate::ast::BinaryOp::Add,
2036 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
2037 op: crate::ast::BinaryOp::Add,
2038 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2039 "acc".to_string(),
2040 ))),
2041 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2042 "x".to_string(),
2043 ))),
2044 })),
2045 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2046 "i".to_string(),
2047 ))),
2048 }),
2049 scope: HashMap::new(),
2050 source: Rc::from(""),
2051 };
2052 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
2053
2054 let result = BuiltInFunction::Reduce
2056 .call(
2057 vec![list, lambda_value, Value::Number(0.0)],
2058 heap.clone(),
2059 bindings.clone(),
2060 0,
2061 "",
2062 )
2063 .unwrap();
2064
2065 assert_eq!(result, Value::Number(63.0));
2067 }
2068
2069 #[test]
2070 fn test_map_backward_compatible() {
2071 use crate::values::LambdaDef;
2072
2073 let heap = Rc::new(RefCell::new(Heap::new()));
2074 let bindings = Rc::new(Environment::new());
2075
2076 let list = heap.borrow_mut().insert_list(vec![
2078 Value::Number(10.0),
2079 Value::Number(20.0),
2080 Value::Number(30.0),
2081 ]);
2082
2083 let lambda = LambdaDef {
2085 name: None,
2086 args: vec![crate::values::LambdaArg::Required("x".to_string())],
2087 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
2088 op: crate::ast::BinaryOp::Multiply,
2089 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2090 "x".to_string(),
2091 ))),
2092 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Number(2.0))),
2093 }),
2094 scope: HashMap::new(),
2095 source: Rc::from(""),
2096 };
2097 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
2098
2099 let result = BuiltInFunction::Map
2101 .call(
2102 vec![list, lambda_value],
2103 heap.clone(),
2104 bindings.clone(),
2105 0,
2106 "",
2107 )
2108 .unwrap();
2109
2110 let heap_borrow = heap.borrow();
2112 let result_list = result.as_list(&heap_borrow).unwrap();
2113 assert_eq!(result_list.len(), 3);
2114 assert_eq!(result_list[0], Value::Number(20.0));
2115 assert_eq!(result_list[1], Value::Number(40.0));
2116 assert_eq!(result_list[2], Value::Number(60.0));
2117 }
2118
2119 #[test]
2120 fn test_convert_length() {
2121 let heap = Rc::new(RefCell::new(Heap::new()));
2122 let bindings = Rc::new(Environment::new());
2123 let convert_fn = BuiltInFunction::Convert;
2124
2125 let from_unit = heap.borrow_mut().insert_string("km".to_string());
2127 let to_unit = heap.borrow_mut().insert_string("m".to_string());
2128 let args = vec![Value::Number(1.0), from_unit, to_unit];
2129 let result = convert_fn
2130 .call(args, heap.clone(), bindings.clone(), 0, "")
2131 .unwrap();
2132 assert_eq!(result, Value::Number(1000.0));
2133
2134 let from_unit = heap.borrow_mut().insert_string("miles".to_string());
2136 let to_unit = heap.borrow_mut().insert_string("km".to_string());
2137 let args = vec![Value::Number(1.0), from_unit, to_unit];
2138 let result = convert_fn
2139 .call(args, heap.clone(), bindings.clone(), 0, "")
2140 .unwrap();
2141 if let Value::Number(n) = result {
2142 assert!((n - 1.609344).abs() < 1e-6);
2143 } else {
2144 panic!("Expected number");
2145 }
2146 }
2147
2148 #[test]
2149 fn test_convert_temperature() {
2150 let heap = Rc::new(RefCell::new(Heap::new()));
2151 let bindings = Rc::new(Environment::new());
2152 let convert_fn = BuiltInFunction::Convert;
2153
2154 let from_unit = heap.borrow_mut().insert_string("celsius".to_string());
2156 let to_unit = heap.borrow_mut().insert_string("fahrenheit".to_string());
2157 let args = vec![Value::Number(0.0), from_unit, to_unit];
2158 let result = convert_fn
2159 .call(args, heap.clone(), bindings.clone(), 0, "")
2160 .unwrap();
2161 if let Value::Number(n) = result {
2162 assert!((n - 32.0).abs() < 1e-10);
2163 }
2164
2165 let from_unit = heap.borrow_mut().insert_string("celsius".to_string());
2167 let to_unit = heap.borrow_mut().insert_string("fahrenheit".to_string());
2168 let args = vec![Value::Number(100.0), from_unit, to_unit];
2169 let result = convert_fn
2170 .call(args, heap.clone(), bindings.clone(), 0, "")
2171 .unwrap();
2172 if let Value::Number(n) = result {
2173 assert!((n - 212.0).abs() < 1e-10);
2174 }
2175 }
2176
2177 #[test]
2178 fn test_convert_mass() {
2179 let heap = Rc::new(RefCell::new(Heap::new()));
2180 let bindings = Rc::new(Environment::new());
2181 let convert_fn = BuiltInFunction::Convert;
2182
2183 let from_unit = heap.borrow_mut().insert_string("kg".to_string());
2185 let to_unit = heap.borrow_mut().insert_string("lbs".to_string());
2186 let args = vec![Value::Number(1.0), from_unit, to_unit];
2187 let result = convert_fn
2188 .call(args, heap.clone(), bindings.clone(), 0, "")
2189 .unwrap();
2190 if let Value::Number(n) = result {
2191 assert!((n - 2.20462).abs() < 0.001);
2192 }
2193 }
2194
2195 #[test]
2196 fn test_convert_information_storage() {
2197 let heap = Rc::new(RefCell::new(Heap::new()));
2198 let bindings = Rc::new(Environment::new());
2199 let convert_fn = BuiltInFunction::Convert;
2200
2201 let from_unit = heap.borrow_mut().insert_string("kibibytes".to_string());
2203 let to_unit = heap.borrow_mut().insert_string("bytes".to_string());
2204 let args = vec![Value::Number(1.0), from_unit, to_unit];
2205 let result = convert_fn
2206 .call(args, heap.clone(), bindings.clone(), 0, "")
2207 .unwrap();
2208 assert_eq!(result, Value::Number(1024.0));
2209 }
2210
2211 #[test]
2212 fn test_convert_same_unit() {
2213 let heap = Rc::new(RefCell::new(Heap::new()));
2214 let bindings = Rc::new(Environment::new());
2215 let convert_fn = BuiltInFunction::Convert;
2216
2217 let from_unit = heap.borrow_mut().insert_string("meters".to_string());
2219 let to_unit = heap.borrow_mut().insert_string("m".to_string());
2220 let args = vec![Value::Number(42.0), from_unit, to_unit];
2221 let result = convert_fn
2222 .call(args, heap.clone(), bindings.clone(), 0, "")
2223 .unwrap();
2224 assert_eq!(result, Value::Number(42.0));
2225 }
2226
2227 #[test]
2228 fn test_convert_incompatible_units() {
2229 let heap = Rc::new(RefCell::new(Heap::new()));
2230 let bindings = Rc::new(Environment::new());
2231 let convert_fn = BuiltInFunction::Convert;
2232
2233 let from_unit = heap.borrow_mut().insert_string("kg".to_string());
2235 let to_unit = heap.borrow_mut().insert_string("meters".to_string());
2236 let args = vec![Value::Number(1.0), from_unit, to_unit];
2237 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0, "");
2238 assert!(result.is_err());
2239 assert!(result.unwrap_err().to_string().contains("Cannot convert"));
2240 }
2241
2242 #[test]
2243 fn test_convert_unknown_unit() {
2244 let heap = Rc::new(RefCell::new(Heap::new()));
2245 let bindings = Rc::new(Environment::new());
2246 let convert_fn = BuiltInFunction::Convert;
2247
2248 let from_unit = heap.borrow_mut().insert_string("foobar".to_string());
2250 let to_unit = heap.borrow_mut().insert_string("meters".to_string());
2251 let args = vec![Value::Number(1.0), from_unit, to_unit];
2252 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0, "");
2253 assert!(result.is_err());
2254 assert!(result.unwrap_err().to_string().contains("Unknown unit"));
2255 }
2256
2257 #[test]
2258 fn test_convert_case_insensitive() {
2259 let heap = Rc::new(RefCell::new(Heap::new()));
2260 let bindings = Rc::new(Environment::new());
2261 let convert_fn = BuiltInFunction::Convert;
2262
2263 let from_unit = heap.borrow_mut().insert_string("KM".to_string());
2265 let to_unit = heap.borrow_mut().insert_string("M".to_string());
2266 let args = vec![Value::Number(1.0), from_unit, to_unit];
2267 let result = convert_fn
2268 .call(args, heap.clone(), bindings.clone(), 0, "")
2269 .unwrap();
2270 assert_eq!(result, Value::Number(1000.0));
2271 }
2272}