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