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_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, accepts_two)
1041 };
1042
1043 let mut mapped_list = vec![];
1044 for (idx, item) in list.iter().enumerate() {
1045 let func_def = get_function_def(func, &heap.borrow())
1046 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1047
1048 let args = if func_accepts_two_args {
1049 vec![*item, Value::Number(idx as f64)]
1050 } else {
1051 vec![*item]
1052 };
1053
1054 let result = func_def.call(
1055 Value::Null,
1056 args,
1057 Rc::clone(&heap),
1058 Rc::clone(&bindings),
1059 call_depth + 1,
1060 source,
1061 )?;
1062 mapped_list.push(result);
1063 }
1064
1065 Ok(heap.borrow_mut().insert_list(mapped_list))
1066 }
1067
1068 Self::Filter => {
1069 let func = &args[1];
1070 let (list, func_accepts_two_args) = {
1071 let borrowed_heap = &heap.borrow();
1072 let list = args[0].as_list(borrowed_heap)?.clone();
1073 let func_def = get_function_def(func, borrowed_heap)
1074 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1075
1076 let accepts_two = func_def.arity().can_accept(2);
1078
1079 (list, accepts_two)
1080 };
1081
1082 let mut filtered_list = vec![];
1083 for (idx, item) in list.iter().enumerate() {
1084 let func_def = get_function_def(func, &heap.borrow())
1085 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1086
1087 let args = if func_accepts_two_args {
1088 vec![*item, Value::Number(idx as f64)]
1089 } else {
1090 vec![*item]
1091 };
1092
1093 let result = func_def.call(
1094 Value::Null,
1095 args,
1096 Rc::clone(&heap),
1097 Rc::clone(&bindings),
1098 call_depth + 1,
1099 source,
1100 )?;
1101 if result.as_bool()? {
1102 filtered_list.push(*item);
1103 }
1104 }
1105
1106 Ok(heap.borrow_mut().insert_list(filtered_list))
1107 }
1108
1109 Self::Reduce => {
1110 let func = &args[1];
1111 let initial = args[2];
1112 let (list, func_accepts_three_args) = {
1113 let borrowed_heap = &heap.borrow();
1114 let list = args[0].as_list(borrowed_heap)?.clone();
1115 let func_def = get_function_def(func, borrowed_heap)
1116 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1117
1118 let accepts_three = func_def.arity().can_accept(3);
1120
1121 (list, accepts_three)
1122 };
1123
1124 let mut accumulator = initial;
1125 for (idx, item) in list.iter().enumerate() {
1126 let func_def = get_function_def(func, &heap.borrow())
1127 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1128
1129 let args = if func_accepts_three_args {
1130 vec![accumulator, *item, Value::Number(idx as f64)]
1131 } else {
1132 vec![accumulator, *item]
1133 };
1134
1135 accumulator = func_def.call(
1136 Value::Null,
1137 args,
1138 Rc::clone(&heap),
1139 Rc::clone(&bindings),
1140 call_depth + 1,
1141 source,
1142 )?;
1143 }
1144
1145 Ok(accumulator)
1146 }
1147
1148 Self::Every => {
1149 let func = &args[1];
1150 let (list, func_accepts_two_args) = {
1151 let borrowed_heap = &heap.borrow();
1152 let list = args[0].as_list(borrowed_heap)?.clone();
1153 let func_def = get_function_def(func, borrowed_heap)
1154 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1155
1156 let accepts_two = func_def.arity().can_accept(2);
1158
1159 (list, accepts_two)
1160 };
1161
1162 for (idx, item) in list.iter().enumerate() {
1163 let func_def = get_function_def(func, &heap.borrow())
1164 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1165
1166 let args = if func_accepts_two_args {
1167 vec![*item, Value::Number(idx as f64)]
1168 } else {
1169 vec![*item]
1170 };
1171
1172 let result = func_def.call(
1173 Value::Null,
1174 args,
1175 Rc::clone(&heap),
1176 Rc::clone(&bindings),
1177 call_depth + 1,
1178 source,
1179 )?;
1180 if !result.as_bool()? {
1181 return Ok(Value::Bool(false));
1182 }
1183 }
1184
1185 Ok(Value::Bool(true))
1186 }
1187
1188 Self::Some => {
1189 let func = &args[1];
1190 let (list, func_accepts_two_args) = {
1191 let borrowed_heap = &heap.borrow();
1192 let list = args[0].as_list(borrowed_heap)?.clone();
1193 let func_def = get_function_def(func, borrowed_heap)
1194 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1195
1196 let accepts_two = func_def.arity().can_accept(2);
1198
1199 (list, accepts_two)
1200 };
1201
1202 for (idx, item) in list.iter().enumerate() {
1203 let func_def = get_function_def(func, &heap.borrow())
1204 .ok_or_else(|| anyhow!("second argument must be a function"))?;
1205
1206 let args = if func_accepts_two_args {
1207 vec![*item, Value::Number(idx as f64)]
1208 } else {
1209 vec![*item]
1210 };
1211
1212 let result = func_def.call(
1213 Value::Null,
1214 args,
1215 Rc::clone(&heap),
1216 Rc::clone(&bindings),
1217 call_depth + 1,
1218 source,
1219 )?;
1220 if result.as_bool()? {
1221 return Ok(Value::Bool(true));
1222 }
1223 }
1224
1225 Ok(Value::Bool(false))
1226 }
1227
1228 Self::SortBy => {
1229 let func = &args[1];
1230 let mut list = {
1231 let borrowed_heap = &heap.borrow();
1232 args[0].as_list(borrowed_heap)?.clone()
1233 };
1234
1235 list.sort_by(|a, b| {
1236 let func_def_a = get_function_def(func, &heap.borrow());
1237 let func_def_b = get_function_def(func, &heap.borrow());
1238
1239 match (func_def_a, func_def_b) {
1240 (Some(fd_a), Some(fd_b)) => {
1241 let result_a = fd_a.call(
1242 Value::Null,
1243 vec![*a],
1244 Rc::clone(&heap),
1245 Rc::clone(&bindings),
1246 call_depth + 1,
1247 source,
1248 );
1249 let result_b = fd_b.call(
1250 Value::Null,
1251 vec![*b],
1252 Rc::clone(&heap),
1253 Rc::clone(&bindings),
1254 call_depth + 1,
1255 source,
1256 );
1257
1258 match (result_a, result_b) {
1259 (Ok(val_a), Ok(val_b)) => val_a
1260 .compare(&val_b, &heap.borrow())
1261 .unwrap_or(None)
1262 .unwrap_or(std::cmp::Ordering::Equal),
1263 _ => std::cmp::Ordering::Equal,
1264 }
1265 }
1266 _ => std::cmp::Ordering::Equal,
1267 }
1268 });
1269
1270 Ok(heap.borrow_mut().insert_list(list))
1271 }
1272 }
1273 }
1274
1275 pub fn all() -> Vec<Self> {
1276 vec![
1277 Self::Sqrt,
1278 Self::Sin,
1279 Self::Cos,
1280 Self::Tan,
1281 Self::Asin,
1282 Self::Acos,
1283 Self::Atan,
1284 Self::Log,
1285 Self::Log10,
1286 Self::Exp,
1287 Self::Abs,
1288 Self::Floor,
1289 Self::Ceil,
1290 Self::Round,
1291 Self::Trunc,
1292 Self::Random,
1293 Self::Min,
1294 Self::Max,
1295 Self::Avg,
1296 Self::Sum,
1297 Self::Prod,
1298 Self::Median,
1299 Self::Percentile,
1300 Self::Range,
1301 Self::Len,
1302 Self::Head,
1303 Self::Tail,
1304 Self::Slice,
1305 Self::Concat,
1306 Self::Dot,
1307 Self::Unique,
1308 Self::Sort,
1309 Self::SortBy,
1310 Self::Reverse,
1311 Self::Any,
1312 Self::All,
1313 Self::Map,
1314 Self::Reduce,
1315 Self::Filter,
1316 Self::Every,
1317 Self::Some,
1318 Self::Split,
1319 Self::Join,
1320 Self::Replace,
1321 Self::Trim,
1322 Self::Uppercase,
1323 Self::Lowercase,
1324 Self::ToString,
1325 Self::ToNumber,
1326 Self::ToBool,
1327 Self::Convert,
1328 Self::Includes,
1329 Self::Format,
1330 Self::Typeof,
1331 Self::Arity,
1332 Self::Keys,
1333 Self::Values,
1334 Self::Entries,
1335 #[cfg(not(target_arch = "wasm32"))]
1336 Self::Print,
1337 #[cfg(not(target_arch = "wasm32"))]
1338 Self::TimeNow,
1339 ]
1340 }
1341
1342 pub fn all_names() -> Vec<&'static str> {
1343 Self::all().iter().map(|f| f.name()).collect()
1344 }
1345}
1346
1347impl FunctionDef {
1348 pub fn get_name(&self) -> String {
1349 match self {
1350 FunctionDef::BuiltIn(built_in) => {
1351 format!("built-in function \"{}\"", built_in.name())
1352 }
1353 FunctionDef::Lambda(LambdaDef { name, .. }) => name
1354 .clone()
1355 .map_or(String::from("anonymous function"), |n| {
1356 format!("function \"{}\"", n)
1357 }),
1358 }
1359 }
1360
1361 pub fn arity(&self) -> FunctionArity {
1362 match self {
1363 FunctionDef::BuiltIn(built_in) => built_in.arity(),
1364 FunctionDef::Lambda(lambda_def) => lambda_def.get_arity(),
1365 }
1366 }
1367
1368 pub fn check_arity(&self, arg_count: usize) -> Result<()> {
1369 match self {
1370 FunctionDef::BuiltIn(built_in) => match built_in.arity() {
1371 FunctionArity::Exact(expected) => {
1372 if arg_count == expected {
1373 Ok(())
1374 } else {
1375 Err(anyhow!(
1376 "{} takes exactly {} arguments, but {} were given",
1377 self.get_name(),
1378 expected,
1379 arg_count
1380 ))
1381 }
1382 }
1383 FunctionArity::AtLeast(expected) => {
1384 if arg_count >= expected {
1385 Ok(())
1386 } else {
1387 Err(anyhow!(
1388 "{} takes at least {} arguments, but {} were given",
1389 self.get_name(),
1390 expected,
1391 arg_count
1392 ))
1393 }
1394 }
1395 FunctionArity::Between(min, max) => {
1396 if arg_count >= min && arg_count <= max {
1397 Ok(())
1398 } else {
1399 Err(anyhow!(
1400 "{} takes between {} and {} arguments, but {} were given",
1401 self.get_name(),
1402 min,
1403 max,
1404 arg_count
1405 ))
1406 }
1407 }
1408 },
1409 FunctionDef::Lambda(def) => {
1410 let arity = def.get_arity();
1411
1412 match arity {
1413 FunctionArity::Exact(expected) => {
1414 if arg_count == expected {
1415 Ok(())
1416 } else {
1417 Err(anyhow!(
1418 "{} takes exactly {} arguments, but {} were given",
1419 self.get_name(),
1420 expected,
1421 arg_count
1422 ))
1423 }
1424 }
1425 FunctionArity::AtLeast(expected) => {
1426 if arg_count >= expected {
1427 Ok(())
1428 } else {
1429 Err(anyhow!(
1430 "{} takes at least {} arguments, but {} were given",
1431 self.get_name(),
1432 expected,
1433 arg_count
1434 ))
1435 }
1436 }
1437 FunctionArity::Between(min, max) => {
1438 if arg_count >= min && arg_count <= max {
1439 Ok(())
1440 } else {
1441 Err(anyhow!(
1442 "{} takes between {} and {} arguments, but {} were given",
1443 self.get_name(),
1444 min,
1445 max,
1446 arg_count
1447 ))
1448 }
1449 }
1450 }
1451 }
1452 }
1453 }
1454
1455 pub fn call(
1456 &self,
1457 this_value: Value,
1458 args: Vec<Value>,
1459 heap: Rc<RefCell<Heap>>,
1460 bindings: Rc<RefCell<HashMap<String, Value>>>,
1461 call_depth: usize,
1462 source: &str,
1463 ) -> Result<Value> {
1464 #[cfg(not(target_arch = "wasm32"))]
1465 let start = std::time::Instant::now();
1466
1467 self.check_arity(args.len())?;
1468
1469 if call_depth > 1000 {
1470 return Err(anyhow!(
1471 "in {}: maximum call depth of 1000 exceeded",
1472 self.get_name()
1473 ));
1474 }
1475
1476 match self {
1477 FunctionDef::Lambda(LambdaDef {
1478 name,
1479 args: expected_args,
1480 body,
1481 scope,
1482 source: lambda_source,
1483 }) => {
1484 #[cfg(not(target_arch = "wasm32"))]
1485 let start_var_env = std::time::Instant::now();
1486
1487 let mut new_bindings = bindings.borrow().clone();
1489
1490 for (key, value) in scope {
1492 new_bindings.insert(key.clone(), *value);
1493 }
1494
1495 if let Some(fn_name) = name {
1497 new_bindings.insert(fn_name.clone(), this_value);
1498 }
1499
1500 if let Some(inputs) = new_bindings.get("inputs").copied() {
1502 new_bindings.insert(String::from("inputs"), inputs);
1503 }
1504
1505 for (idx, expected_arg) in expected_args.iter().enumerate() {
1507 match expected_arg {
1508 LambdaArg::Required(arg_name) => {
1509 new_bindings.insert(arg_name.clone(), args[idx]);
1510 }
1511 LambdaArg::Optional(arg_name) => {
1512 new_bindings.insert(
1513 arg_name.clone(),
1514 args.get(idx).copied().unwrap_or(Value::Null),
1515 );
1516 }
1517 LambdaArg::Rest(arg_name) => {
1518 new_bindings.insert(
1519 arg_name.clone(),
1520 heap.borrow_mut()
1521 .insert_list(args.iter().skip(idx).copied().collect()),
1522 );
1523 }
1524 }
1525 }
1526
1527 #[cfg(not(target_arch = "wasm32"))]
1528 let end_var_env = std::time::Instant::now();
1529
1530 let return_value = evaluate_ast(
1531 body,
1532 Rc::clone(&heap),
1533 Rc::new(RefCell::new(new_bindings)),
1534 call_depth + 1,
1535 lambda_source.clone(),
1536 )
1537 .map_err(|error| anyhow!("in {}: {}", self.get_name(), error));
1538
1539 #[cfg(not(target_arch = "wasm32"))]
1540 FUNCTION_CALLS.lock().unwrap().push(FunctionCallStats {
1541 name: self.get_name(),
1542 start,
1543 end: std::time::Instant::now(),
1544 start_var_env: Some(start_var_env),
1545 end_var_env: Some(end_var_env),
1546 });
1547
1548 return_value
1549 }
1550 FunctionDef::BuiltIn(built_in) => {
1551 let return_value = built_in
1552 .call(args, heap, bindings, call_depth + 1, source)
1553 .map_err(|error| anyhow!("in {}: {}", self.get_name(), error));
1554
1555 #[cfg(not(target_arch = "wasm32"))]
1556 FUNCTION_CALLS.lock().unwrap().push(FunctionCallStats {
1557 name: self.get_name(),
1558 start,
1559 end: std::time::Instant::now(),
1560 start_var_env: None,
1561 end_var_env: None,
1562 });
1563
1564 return_value
1565 }
1566 }
1567 }
1568}
1569
1570pub fn is_built_in_function(ident: &str) -> bool {
1571 BuiltInFunction::from_ident(ident).is_some()
1572}
1573
1574pub fn get_built_in_function_def_by_ident(ident: &str) -> Option<FunctionDef> {
1575 BuiltInFunction::from_ident(ident).map(FunctionDef::BuiltIn)
1576}
1577
1578pub fn get_built_in_function_idents() -> Vec<&'static str> {
1579 BuiltInFunction::all_names()
1580}
1581
1582pub fn get_function_def(value: &Value, heap: &Heap) -> Option<FunctionDef> {
1583 match value {
1584 Value::Lambda(pointer) => Some(FunctionDef::Lambda(
1585 pointer.reify(heap).as_lambda().ok()?.clone(),
1586 )),
1587 Value::BuiltIn(built_in) => Some(FunctionDef::BuiltIn(*built_in)),
1588 _ => None,
1589 }
1590}
1591
1592#[cfg(test)]
1593mod tests {
1594 use super::*;
1595 use std::cell::RefCell;
1596 use std::collections::HashMap;
1597 use std::rc::Rc;
1598
1599 #[test]
1600 fn test_range_function() {
1601 let heap = Rc::new(RefCell::new(Heap::new()));
1603 let bindings = Rc::new(RefCell::new(HashMap::new()));
1604 let range_fn = BuiltInFunction::Range;
1605
1606 let args = vec![Value::Number(4.0)];
1608 let result = range_fn
1609 .call(args, heap.clone(), bindings.clone(), 0, "")
1610 .unwrap();
1611
1612 let heap_borrow = heap.borrow();
1613 let list = result.as_list(&heap_borrow).unwrap();
1614 assert_eq!(list.len(), 4);
1615 assert_eq!(list[0], Value::Number(0.0));
1616 assert_eq!(list[3], Value::Number(3.0));
1617 }
1618
1619 #[test]
1620 fn test_range_function_two_args() {
1621 let heap = Rc::new(RefCell::new(Heap::new()));
1623 let bindings = Rc::new(RefCell::new(HashMap::new()));
1624 let range_fn = BuiltInFunction::Range;
1625
1626 let args = vec![Value::Number(4.0), Value::Number(10.0)];
1628 let result = range_fn
1629 .call(args, heap.clone(), bindings.clone(), 0, "")
1630 .unwrap();
1631
1632 let heap_borrow = heap.borrow();
1633 let list = result.as_list(&heap_borrow).unwrap();
1634 assert_eq!(list.len(), 6);
1635 assert_eq!(list[0], Value::Number(4.0));
1636 assert_eq!(list[5], Value::Number(9.0));
1637 }
1638
1639 #[test]
1640 fn test_round_function_single_arg() {
1641 let heap = Rc::new(RefCell::new(Heap::new()));
1642 let bindings = Rc::new(RefCell::new(HashMap::new()));
1643 let round_fn = BuiltInFunction::Round;
1644
1645 let test_cases = vec![
1647 (42.4, 42.0),
1648 (42.5, 43.0),
1649 (42.6, 43.0),
1650 (-42.4, -42.0),
1651 (-42.5, -43.0),
1652 (-42.6, -43.0),
1653 (0.0, 0.0),
1654 (1.999, 2.0),
1655 (-1.999, -2.0),
1656 ];
1657
1658 for (input, expected) in test_cases {
1659 let args = vec![Value::Number(input)];
1660 let result = round_fn
1661 .call(args, heap.clone(), bindings.clone(), 0, "")
1662 .unwrap();
1663 assert_eq!(
1664 result,
1665 Value::Number(expected),
1666 "round({}) should be {}",
1667 input,
1668 expected
1669 );
1670 }
1671 }
1672
1673 #[test]
1674 fn test_round_function_with_decimal_places() {
1675 let heap = Rc::new(RefCell::new(Heap::new()));
1676 let bindings = Rc::new(RefCell::new(HashMap::new()));
1677 let round_fn = BuiltInFunction::Round;
1678
1679 let test_cases = vec![
1681 (42.4543, 0.0, 42.0),
1682 (42.4543, 1.0, 42.5),
1683 (42.4543, 2.0, 42.45),
1684 (42.4543, 3.0, 42.454),
1685 (42.4543, 4.0, 42.4543),
1686 (4.14159, 4.0, 4.1416),
1687 (0.005, 2.0, 0.01),
1688 (0.995, 2.0, 1.0),
1689 (9.995, 2.0, 9.99),
1692 (-9.995, 2.0, -9.99),
1693 ];
1694
1695 for (input, places, expected) in test_cases {
1696 let args = vec![Value::Number(input), Value::Number(places)];
1697 let result = round_fn
1698 .call(args, heap.clone(), bindings.clone(), 0, "")
1699 .unwrap();
1700
1701 if let Value::Number(result_num) = result {
1703 assert!(
1704 (result_num - expected).abs() < 1e-10,
1705 "round({}, {}) = {} should be close to {}",
1706 input,
1707 places,
1708 result_num,
1709 expected
1710 );
1711 } else {
1712 panic!("Expected number result");
1713 }
1714 }
1715 }
1716
1717 #[test]
1718 fn test_round_function_negative_decimal_places() {
1719 let heap = Rc::new(RefCell::new(Heap::new()));
1720 let bindings = Rc::new(RefCell::new(HashMap::new()));
1721 let round_fn = BuiltInFunction::Round;
1722
1723 let test_cases = vec![
1725 (1234.567, -1.0, 1230.0),
1726 (1234.567, -2.0, 1200.0),
1727 (1234.567, -3.0, 1000.0),
1728 (1234.567, -4.0, 0.0),
1729 (5678.9, -1.0, 5680.0),
1730 (5678.9, -2.0, 5700.0),
1731 (5678.9, -3.0, 6000.0),
1732 (-1234.567, -1.0, -1230.0),
1733 (-1234.567, -2.0, -1200.0),
1734 (1500.0, -3.0, 2000.0),
1735 (-1500.0, -3.0, -2000.0),
1736 ];
1737
1738 for (input, places, expected) in test_cases {
1739 let args = vec![Value::Number(input), Value::Number(places)];
1740 let result = round_fn
1741 .call(args, heap.clone(), bindings.clone(), 0, "")
1742 .unwrap();
1743 assert_eq!(
1744 result,
1745 Value::Number(expected),
1746 "round({}, {}) should be {}",
1747 input,
1748 places,
1749 expected
1750 );
1751 }
1752 }
1753
1754 #[test]
1755 fn test_round_function_edge_cases() {
1756 let heap = Rc::new(RefCell::new(Heap::new()));
1757 let bindings = Rc::new(RefCell::new(HashMap::new()));
1758 let round_fn = BuiltInFunction::Round;
1759
1760 let test_cases = vec![
1762 (f64::INFINITY, 0.0, f64::INFINITY),
1763 (f64::NEG_INFINITY, 0.0, f64::NEG_INFINITY),
1764 (0.0, 5.0, 0.0),
1765 (-0.0, 5.0, -0.0),
1766 (1e-10, 5.0, 0.0),
1767 (1e-10, 15.0, 1e-10),
1768 ];
1769
1770 for (input, places, expected) in test_cases {
1771 let args = vec![Value::Number(input), Value::Number(places)];
1772 let result = round_fn
1773 .call(args, heap.clone(), bindings.clone(), 0, "")
1774 .unwrap();
1775
1776 if let Value::Number(result_num) = result {
1777 if expected.is_infinite() {
1778 assert!(
1779 result_num.is_infinite()
1780 && result_num.is_sign_positive() == expected.is_sign_positive(),
1781 "round({}, {}) should be {}",
1782 input,
1783 places,
1784 expected
1785 );
1786 } else if expected == 0.0 || expected == -0.0 {
1787 assert!(
1788 result_num.abs() < 1e-10,
1789 "round({}, {}) = {} should be close to 0",
1790 input,
1791 places,
1792 result_num
1793 );
1794 } else {
1795 assert!(
1796 (result_num - expected).abs() < 1e-15,
1797 "round({}, {}) = {} should be close to {}",
1798 input,
1799 places,
1800 result_num,
1801 expected
1802 );
1803 }
1804 } else {
1805 panic!("Expected number result");
1806 }
1807 }
1808 }
1809
1810 #[test]
1811 fn test_random_function_deterministic() {
1812 let heap = Rc::new(RefCell::new(Heap::new()));
1813 let bindings = Rc::new(RefCell::new(HashMap::new()));
1814 let random_fn = BuiltInFunction::Random;
1815
1816 let seed = 42.0;
1818 let args1 = vec![Value::Number(seed)];
1819 let result1 = random_fn
1820 .call(args1, heap.clone(), bindings.clone(), 0, "")
1821 .unwrap();
1822
1823 let args2 = vec![Value::Number(seed)];
1824 let result2 = random_fn
1825 .call(args2, heap.clone(), bindings.clone(), 0, "")
1826 .unwrap();
1827
1828 assert_eq!(result1, result2, "Same seed should produce same result");
1829 }
1830
1831 #[test]
1832 fn test_random_function_different_seeds() {
1833 let heap = Rc::new(RefCell::new(Heap::new()));
1834 let bindings = Rc::new(RefCell::new(HashMap::new()));
1835 let random_fn = BuiltInFunction::Random;
1836
1837 let args1 = vec![Value::Number(42.0)];
1839 let result1 = random_fn
1840 .call(args1, heap.clone(), bindings.clone(), 0, "")
1841 .unwrap();
1842
1843 let args2 = vec![Value::Number(100.0)];
1844 let result2 = random_fn
1845 .call(args2, heap.clone(), bindings.clone(), 0, "")
1846 .unwrap();
1847
1848 assert_ne!(result1, result2, "Different seeds should produce different results");
1849 }
1850
1851 #[test]
1852 fn test_random_function_range() {
1853 let heap = Rc::new(RefCell::new(Heap::new()));
1854 let bindings = Rc::new(RefCell::new(HashMap::new()));
1855 let random_fn = BuiltInFunction::Random;
1856
1857 for seed in [0.0, 1.0, 42.0, 100.0, 999.0, 12345.0] {
1859 let args = vec![Value::Number(seed)];
1860 let result = random_fn
1861 .call(args, heap.clone(), bindings.clone(), 0, "")
1862 .unwrap();
1863
1864 if let Value::Number(num) = result {
1865 assert!(num >= 0.0 && num < 1.0, "Random value {} should be in range [0, 1)", num);
1866 } else {
1867 panic!("Expected number result");
1868 }
1869 }
1870 }
1871
1872 #[test]
1873 fn test_random_function_negative_seed() {
1874 let heap = Rc::new(RefCell::new(Heap::new()));
1875 let bindings = Rc::new(RefCell::new(HashMap::new()));
1876 let random_fn = BuiltInFunction::Random;
1877
1878 let args = vec![Value::Number(-42.0)];
1880 let result = random_fn
1881 .call(args, heap.clone(), bindings.clone(), 0, "")
1882 .unwrap();
1883
1884 if let Value::Number(num) = result {
1885 assert!(num >= 0.0 && num < 1.0, "Random value {} should be in range [0, 1)", num);
1886 } else {
1887 panic!("Expected number result");
1888 }
1889 }
1890
1891 #[test]
1892 fn test_map_with_index() {
1893 use crate::values::LambdaDef;
1894
1895 let heap = Rc::new(RefCell::new(Heap::new()));
1896 let bindings = Rc::new(RefCell::new(HashMap::new()));
1897
1898 let list = heap.borrow_mut().insert_list(vec![
1900 Value::Number(10.0),
1901 Value::Number(20.0),
1902 Value::Number(30.0),
1903 ]);
1904
1905 let lambda = LambdaDef {
1907 name: None,
1908 args: vec![
1909 crate::values::LambdaArg::Required("x".to_string()),
1910 crate::values::LambdaArg::Required("i".to_string()),
1911 ],
1912 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
1913 op: crate::ast::BinaryOp::Add,
1914 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
1915 "x".to_string(),
1916 ))),
1917 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
1918 "i".to_string(),
1919 ))),
1920 }),
1921 scope: HashMap::new(),
1922 source: Rc::from(""),
1923 };
1924 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1925
1926 let result = BuiltInFunction::Map
1928 .call(
1929 vec![list, lambda_value],
1930 heap.clone(),
1931 bindings.clone(),
1932 0,
1933 "",
1934 )
1935 .unwrap();
1936
1937 let heap_borrow = heap.borrow();
1939 let result_list = result.as_list(&heap_borrow).unwrap();
1940 assert_eq!(result_list.len(), 3);
1941 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)); }
1945
1946 #[test]
1947 fn test_filter_with_index() {
1948 use crate::values::LambdaDef;
1949
1950 let heap = Rc::new(RefCell::new(Heap::new()));
1951 let bindings = Rc::new(RefCell::new(HashMap::new()));
1952
1953 let list = heap.borrow_mut().insert_list(vec![
1955 Value::Number(10.0),
1956 Value::Number(20.0),
1957 Value::Number(30.0),
1958 Value::Number(40.0),
1959 ]);
1960
1961 let lambda = LambdaDef {
1963 name: None,
1964 args: vec![
1965 crate::values::LambdaArg::Required("x".to_string()),
1966 crate::values::LambdaArg::Required("i".to_string()),
1967 ],
1968 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
1969 op: crate::ast::BinaryOp::Greater,
1970 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
1971 "i".to_string(),
1972 ))),
1973 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Number(1.0))),
1974 }),
1975 scope: HashMap::new(),
1976 source: Rc::from(""),
1977 };
1978 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
1979
1980 let result = BuiltInFunction::Filter
1982 .call(
1983 vec![list, lambda_value],
1984 heap.clone(),
1985 bindings.clone(),
1986 0,
1987 "",
1988 )
1989 .unwrap();
1990
1991 let heap_borrow = heap.borrow();
1993 let result_list = result.as_list(&heap_borrow).unwrap();
1994 assert_eq!(result_list.len(), 2);
1995 assert_eq!(result_list[0], Value::Number(30.0));
1996 assert_eq!(result_list[1], Value::Number(40.0));
1997 }
1998
1999 #[test]
2000 fn test_reduce_with_index() {
2001 use crate::values::LambdaDef;
2002
2003 let heap = Rc::new(RefCell::new(Heap::new()));
2004 let bindings = Rc::new(RefCell::new(HashMap::new()));
2005
2006 let list = heap.borrow_mut().insert_list(vec![
2008 Value::Number(10.0),
2009 Value::Number(20.0),
2010 Value::Number(30.0),
2011 ]);
2012
2013 let lambda = LambdaDef {
2015 name: None,
2016 args: vec![
2017 crate::values::LambdaArg::Required("acc".to_string()),
2018 crate::values::LambdaArg::Required("x".to_string()),
2019 crate::values::LambdaArg::Required("i".to_string()),
2020 ],
2021 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
2022 op: crate::ast::BinaryOp::Add,
2023 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
2024 op: crate::ast::BinaryOp::Add,
2025 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2026 "acc".to_string(),
2027 ))),
2028 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2029 "x".to_string(),
2030 ))),
2031 })),
2032 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2033 "i".to_string(),
2034 ))),
2035 }),
2036 scope: HashMap::new(),
2037 source: Rc::from(""),
2038 };
2039 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
2040
2041 let result = BuiltInFunction::Reduce
2043 .call(
2044 vec![list, lambda_value, Value::Number(0.0)],
2045 heap.clone(),
2046 bindings.clone(),
2047 0,
2048 "",
2049 )
2050 .unwrap();
2051
2052 assert_eq!(result, Value::Number(63.0));
2054 }
2055
2056 #[test]
2057 fn test_map_backward_compatible() {
2058 use crate::values::LambdaDef;
2059
2060 let heap = Rc::new(RefCell::new(Heap::new()));
2061 let bindings = Rc::new(RefCell::new(HashMap::new()));
2062
2063 let list = heap.borrow_mut().insert_list(vec![
2065 Value::Number(10.0),
2066 Value::Number(20.0),
2067 Value::Number(30.0),
2068 ]);
2069
2070 let lambda = LambdaDef {
2072 name: None,
2073 args: vec![crate::values::LambdaArg::Required("x".to_string())],
2074 body: crate::ast::Spanned::dummy(crate::ast::Expr::BinaryOp {
2075 op: crate::ast::BinaryOp::Multiply,
2076 left: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Identifier(
2077 "x".to_string(),
2078 ))),
2079 right: Box::new(crate::ast::Spanned::dummy(crate::ast::Expr::Number(2.0))),
2080 }),
2081 scope: HashMap::new(),
2082 source: Rc::from(""),
2083 };
2084 let lambda_value = heap.borrow_mut().insert_lambda(lambda);
2085
2086 let result = BuiltInFunction::Map
2088 .call(
2089 vec![list, lambda_value],
2090 heap.clone(),
2091 bindings.clone(),
2092 0,
2093 "",
2094 )
2095 .unwrap();
2096
2097 let heap_borrow = heap.borrow();
2099 let result_list = result.as_list(&heap_borrow).unwrap();
2100 assert_eq!(result_list.len(), 3);
2101 assert_eq!(result_list[0], Value::Number(20.0));
2102 assert_eq!(result_list[1], Value::Number(40.0));
2103 assert_eq!(result_list[2], Value::Number(60.0));
2104 }
2105
2106 #[test]
2107 fn test_convert_length() {
2108 let heap = Rc::new(RefCell::new(Heap::new()));
2109 let bindings = Rc::new(RefCell::new(HashMap::new()));
2110 let convert_fn = BuiltInFunction::Convert;
2111
2112 let from_unit = heap.borrow_mut().insert_string("km".to_string());
2114 let to_unit = heap.borrow_mut().insert_string("m".to_string());
2115 let args = vec![Value::Number(1.0), from_unit, to_unit];
2116 let result = convert_fn
2117 .call(args, heap.clone(), bindings.clone(), 0, "")
2118 .unwrap();
2119 assert_eq!(result, Value::Number(1000.0));
2120
2121 let from_unit = heap.borrow_mut().insert_string("miles".to_string());
2123 let to_unit = heap.borrow_mut().insert_string("km".to_string());
2124 let args = vec![Value::Number(1.0), from_unit, to_unit];
2125 let result = convert_fn
2126 .call(args, heap.clone(), bindings.clone(), 0, "")
2127 .unwrap();
2128 if let Value::Number(n) = result {
2129 assert!((n - 1.609344).abs() < 1e-6);
2130 } else {
2131 panic!("Expected number");
2132 }
2133 }
2134
2135 #[test]
2136 fn test_convert_temperature() {
2137 let heap = Rc::new(RefCell::new(Heap::new()));
2138 let bindings = Rc::new(RefCell::new(HashMap::new()));
2139 let convert_fn = BuiltInFunction::Convert;
2140
2141 let from_unit = heap.borrow_mut().insert_string("celsius".to_string());
2143 let to_unit = heap.borrow_mut().insert_string("fahrenheit".to_string());
2144 let args = vec![Value::Number(0.0), from_unit, to_unit];
2145 let result = convert_fn
2146 .call(args, heap.clone(), bindings.clone(), 0, "")
2147 .unwrap();
2148 if let Value::Number(n) = result {
2149 assert!((n - 32.0).abs() < 1e-10);
2150 }
2151
2152 let from_unit = heap.borrow_mut().insert_string("celsius".to_string());
2154 let to_unit = heap.borrow_mut().insert_string("fahrenheit".to_string());
2155 let args = vec![Value::Number(100.0), from_unit, to_unit];
2156 let result = convert_fn
2157 .call(args, heap.clone(), bindings.clone(), 0, "")
2158 .unwrap();
2159 if let Value::Number(n) = result {
2160 assert!((n - 212.0).abs() < 1e-10);
2161 }
2162 }
2163
2164 #[test]
2165 fn test_convert_mass() {
2166 let heap = Rc::new(RefCell::new(Heap::new()));
2167 let bindings = Rc::new(RefCell::new(HashMap::new()));
2168 let convert_fn = BuiltInFunction::Convert;
2169
2170 let from_unit = heap.borrow_mut().insert_string("kg".to_string());
2172 let to_unit = heap.borrow_mut().insert_string("lbs".to_string());
2173 let args = vec![Value::Number(1.0), from_unit, to_unit];
2174 let result = convert_fn
2175 .call(args, heap.clone(), bindings.clone(), 0, "")
2176 .unwrap();
2177 if let Value::Number(n) = result {
2178 assert!((n - 2.20462).abs() < 0.001);
2179 }
2180 }
2181
2182 #[test]
2183 fn test_convert_information_storage() {
2184 let heap = Rc::new(RefCell::new(Heap::new()));
2185 let bindings = Rc::new(RefCell::new(HashMap::new()));
2186 let convert_fn = BuiltInFunction::Convert;
2187
2188 let from_unit = heap.borrow_mut().insert_string("kibibytes".to_string());
2190 let to_unit = heap.borrow_mut().insert_string("bytes".to_string());
2191 let args = vec![Value::Number(1.0), from_unit, to_unit];
2192 let result = convert_fn
2193 .call(args, heap.clone(), bindings.clone(), 0, "")
2194 .unwrap();
2195 assert_eq!(result, Value::Number(1024.0));
2196 }
2197
2198 #[test]
2199 fn test_convert_same_unit() {
2200 let heap = Rc::new(RefCell::new(Heap::new()));
2201 let bindings = Rc::new(RefCell::new(HashMap::new()));
2202 let convert_fn = BuiltInFunction::Convert;
2203
2204 let from_unit = heap.borrow_mut().insert_string("meters".to_string());
2206 let to_unit = heap.borrow_mut().insert_string("m".to_string());
2207 let args = vec![Value::Number(42.0), from_unit, to_unit];
2208 let result = convert_fn
2209 .call(args, heap.clone(), bindings.clone(), 0, "")
2210 .unwrap();
2211 assert_eq!(result, Value::Number(42.0));
2212 }
2213
2214 #[test]
2215 fn test_convert_incompatible_units() {
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("kg".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("Cannot convert"));
2227 }
2228
2229 #[test]
2230 fn test_convert_unknown_unit() {
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("foobar".to_string());
2237 let to_unit = heap.borrow_mut().insert_string("meters".to_string());
2238 let args = vec![Value::Number(1.0), from_unit, to_unit];
2239 let result = convert_fn.call(args, heap.clone(), bindings.clone(), 0, "");
2240 assert!(result.is_err());
2241 assert!(result.unwrap_err().to_string().contains("Unknown unit"));
2242 }
2243
2244 #[test]
2245 fn test_convert_case_insensitive() {
2246 let heap = Rc::new(RefCell::new(Heap::new()));
2247 let bindings = Rc::new(RefCell::new(HashMap::new()));
2248 let convert_fn = BuiltInFunction::Convert;
2249
2250 let from_unit = heap.borrow_mut().insert_string("KM".to_string());
2252 let to_unit = heap.borrow_mut().insert_string("M".to_string());
2253 let args = vec![Value::Number(1.0), from_unit, to_unit];
2254 let result = convert_fn
2255 .call(args, heap.clone(), bindings.clone(), 0, "")
2256 .unwrap();
2257 assert_eq!(result, Value::Number(1000.0));
2258 }
2259}