1use std::cmp::Ordering;
27
28use crate::eval::{EvalError, Value};
29use crate::types::{CelType, FunctionDecl, OverloadDecl};
30
31pub fn math_extension() -> Vec<FunctionDecl> {
33 let mut funcs = Vec::new();
34
35 funcs.push(build_minmax_function("math.greatest", true));
37 funcs.push(build_minmax_function("math.least", false));
38
39 funcs.push(
41 FunctionDecl::new("math.ceil").with_overload(
42 OverloadDecl::function("math_ceil_double", vec![CelType::Double], CelType::Double)
43 .with_impl(|args| match &args[0] {
44 Value::Double(v) => Value::Double(v.ceil()),
45 _ => Value::error(EvalError::invalid_argument("expected double")),
46 }),
47 ),
48 );
49 funcs.push(
50 FunctionDecl::new("math.floor").with_overload(
51 OverloadDecl::function("math_floor_double", vec![CelType::Double], CelType::Double)
52 .with_impl(|args| match &args[0] {
53 Value::Double(v) => Value::Double(v.floor()),
54 _ => Value::error(EvalError::invalid_argument("expected double")),
55 }),
56 ),
57 );
58 funcs.push(
59 FunctionDecl::new("math.round").with_overload(
60 OverloadDecl::function("math_round_double", vec![CelType::Double], CelType::Double)
61 .with_impl(|args| match &args[0] {
62 Value::Double(v) => {
63 let rounded = if *v >= 0.0 {
65 (*v + 0.5).floor()
66 } else {
67 (*v - 0.5).ceil()
68 };
69 Value::Double(rounded)
70 }
71 _ => Value::error(EvalError::invalid_argument("expected double")),
72 }),
73 ),
74 );
75 funcs.push(
76 FunctionDecl::new("math.trunc").with_overload(
77 OverloadDecl::function("math_trunc_double", vec![CelType::Double], CelType::Double)
78 .with_impl(|args| match &args[0] {
79 Value::Double(v) => Value::Double(v.trunc()),
80 _ => Value::error(EvalError::invalid_argument("expected double")),
81 }),
82 ),
83 );
84
85 funcs.push(
87 FunctionDecl::new("math.abs")
88 .with_overload(
89 OverloadDecl::function("math_abs_int", vec![CelType::Int], CelType::Int).with_impl(
90 |args| match &args[0] {
91 Value::Int(v) => match v.checked_abs() {
92 Some(r) => Value::Int(r),
93 None => Value::error(EvalError::overflow("integer overflow in abs")),
94 },
95 _ => Value::error(EvalError::invalid_argument("expected int")),
96 },
97 ),
98 )
99 .with_overload(
100 OverloadDecl::function("math_abs_uint", vec![CelType::UInt], CelType::UInt)
101 .with_impl(|args| match &args[0] {
102 Value::UInt(v) => Value::UInt(*v),
103 _ => Value::error(EvalError::invalid_argument("expected uint")),
104 }),
105 )
106 .with_overload(
107 OverloadDecl::function("math_abs_double", vec![CelType::Double], CelType::Double)
108 .with_impl(|args| match &args[0] {
109 Value::Double(v) => Value::Double(v.abs()),
110 _ => Value::error(EvalError::invalid_argument("expected double")),
111 }),
112 ),
113 );
114
115 funcs.push(
117 FunctionDecl::new("math.sign")
118 .with_overload(
119 OverloadDecl::function("math_sign_int", vec![CelType::Int], CelType::Int)
120 .with_impl(|args| match &args[0] {
121 Value::Int(v) => Value::Int(v.signum()),
122 _ => Value::error(EvalError::invalid_argument("expected int")),
123 }),
124 )
125 .with_overload(
126 OverloadDecl::function("math_sign_uint", vec![CelType::UInt], CelType::UInt)
127 .with_impl(|args| match &args[0] {
128 Value::UInt(v) => Value::UInt(if *v == 0 { 0 } else { 1 }),
129 _ => Value::error(EvalError::invalid_argument("expected uint")),
130 }),
131 )
132 .with_overload(
133 OverloadDecl::function("math_sign_double", vec![CelType::Double], CelType::Double)
134 .with_impl(|args| match &args[0] {
135 Value::Double(v) => {
136 if v.is_nan() {
137 Value::Double(f64::NAN)
138 } else if *v > 0.0 {
139 Value::Double(1.0)
140 } else if *v < 0.0 {
141 Value::Double(-1.0)
142 } else {
143 Value::Double(0.0)
144 }
145 }
146 _ => Value::error(EvalError::invalid_argument("expected double")),
147 }),
148 ),
149 );
150
151 funcs.push(
153 FunctionDecl::new("math.isNaN").with_overload(
154 OverloadDecl::function("math_isnan_double", vec![CelType::Double], CelType::Bool)
155 .with_impl(|args| match &args[0] {
156 Value::Double(v) => Value::Bool(v.is_nan()),
157 _ => Value::error(EvalError::invalid_argument("expected double")),
158 }),
159 ),
160 );
161 funcs.push(
162 FunctionDecl::new("math.isInf").with_overload(
163 OverloadDecl::function("math_isinf_double", vec![CelType::Double], CelType::Bool)
164 .with_impl(|args| match &args[0] {
165 Value::Double(v) => Value::Bool(v.is_infinite()),
166 _ => Value::error(EvalError::invalid_argument("expected double")),
167 }),
168 ),
169 );
170 funcs.push(
171 FunctionDecl::new("math.isFinite").with_overload(
172 OverloadDecl::function("math_isfinite_double", vec![CelType::Double], CelType::Bool)
173 .with_impl(|args| match &args[0] {
174 Value::Double(v) => Value::Bool(v.is_finite()),
175 _ => Value::error(EvalError::invalid_argument("expected double")),
176 }),
177 ),
178 );
179
180 add_bit_operations(&mut funcs);
182
183 funcs
184}
185
186fn compare_numeric(a: &Value, b: &Value) -> Option<Ordering> {
189 match (a, b) {
190 (Value::Int(x), Value::Int(y)) => x.partial_cmp(y),
191 (Value::UInt(x), Value::UInt(y)) => x.partial_cmp(y),
192 (Value::Double(x), Value::Double(y)) => x.partial_cmp(y),
193 (Value::Int(x), Value::UInt(y)) => {
194 if *x < 0 {
195 Some(Ordering::Less)
196 } else {
197 (*x as u64).partial_cmp(y)
198 }
199 }
200 (Value::UInt(x), Value::Int(y)) => {
201 if *y < 0 {
202 Some(Ordering::Greater)
203 } else {
204 x.partial_cmp(&(*y as u64))
205 }
206 }
207 (Value::Int(x), Value::Double(y)) => (*x as f64).partial_cmp(y),
208 (Value::Double(x), Value::Int(y)) => x.partial_cmp(&(*y as f64)),
209 (Value::UInt(x), Value::Double(y)) => (*x as f64).partial_cmp(y),
210 (Value::Double(x), Value::UInt(y)) => x.partial_cmp(&(*y as f64)),
211 _ => None,
212 }
213}
214
215fn greatest_impl(args: &[Value]) -> Value {
218 let values: &[Value] = if args.len() == 1 {
220 if let Value::List(list) = &args[0] {
221 list
222 } else {
223 return args[0].clone();
225 }
226 } else {
227 args
228 };
229
230 if values.is_empty() {
231 return Value::error(EvalError::invalid_argument(
232 "math.greatest requires at least one argument",
233 ));
234 }
235
236 for v in values {
238 if let Value::Error(_) = v {
239 return v.clone();
240 }
241 }
242
243 let mut best = &values[0];
244 for v in &values[1..] {
245 match compare_numeric(v, best) {
246 Some(Ordering::Greater) => best = v,
247 None => {
248 if let Value::Double(d) = best {
250 if d.is_nan() {
251 best = v;
252 continue;
253 }
254 }
255 if let Value::Double(d) = v {
256 if d.is_nan() {
257 continue;
258 }
259 }
260 return Value::error(EvalError::invalid_argument(
261 "math.greatest: incomparable types",
262 ));
263 }
264 _ => {}
265 }
266 }
267 best.clone()
268}
269
270fn least_impl(args: &[Value]) -> Value {
273 let values: &[Value] = if args.len() == 1 {
275 if let Value::List(list) = &args[0] {
276 list
277 } else {
278 return args[0].clone();
280 }
281 } else {
282 args
283 };
284
285 if values.is_empty() {
286 return Value::error(EvalError::invalid_argument(
287 "math.least requires at least one argument",
288 ));
289 }
290
291 for v in values {
293 if let Value::Error(_) = v {
294 return v.clone();
295 }
296 }
297
298 let mut best = &values[0];
299 for v in &values[1..] {
300 match compare_numeric(v, best) {
301 Some(Ordering::Less) => best = v,
302 None => {
303 if let Value::Double(d) = best {
305 if d.is_nan() {
306 best = v;
307 continue;
308 }
309 }
310 if let Value::Double(d) = v {
311 if d.is_nan() {
312 continue;
313 }
314 }
315 return Value::error(EvalError::invalid_argument(
316 "math.least: incomparable types",
317 ));
318 }
319 _ => {}
320 }
321 }
322 best.clone()
323}
324
325fn build_minmax_function(name: &str, is_greatest: bool) -> FunctionDecl {
326 let base = name.replace('.', "_");
327 let mut decl = FunctionDecl::new(name);
328
329 let shared_impl: fn(&[Value]) -> Value = if is_greatest {
330 greatest_impl
331 } else {
332 least_impl
333 };
334
335 for (suffix, cel_type) in [
337 ("int", CelType::Int),
338 ("uint", CelType::UInt),
339 ("double", CelType::Double),
340 ] {
341 decl = decl.with_overload(
342 OverloadDecl::function(
343 format!("{}_{}", base, suffix),
344 vec![cel_type.clone()],
345 cel_type,
346 )
347 .with_impl(shared_impl),
348 );
349 }
350
351 for (suffix, cel_type) in [
353 ("int", CelType::Int),
354 ("uint", CelType::UInt),
355 ("double", CelType::Double),
356 ] {
357 decl = decl.with_overload(
358 OverloadDecl::function(
359 format!("{}_{}_{}", base, suffix, suffix),
360 vec![cel_type.clone(), cel_type.clone()],
361 cel_type,
362 )
363 .with_impl(shared_impl),
364 );
365 }
366
367 let types = [
369 ("int", CelType::Int),
370 ("uint", CelType::UInt),
371 ("double", CelType::Double),
372 ];
373 for (name1, type1) in &types {
374 for (name2, type2) in &types {
375 if name1 != name2 {
376 decl = decl.with_overload(
377 OverloadDecl::function(
378 format!("{}_{}_{}", base, name1, name2),
379 vec![type1.clone(), type2.clone()],
380 CelType::Dyn,
381 )
382 .with_impl(shared_impl),
383 );
384 }
385 }
386 }
387
388 for arity in 3..=6 {
390 for (suffix, cel_type) in [
392 ("int", CelType::Int),
393 ("uint", CelType::UInt),
394 ("double", CelType::Double),
395 ] {
396 decl = decl.with_overload(
397 OverloadDecl::function(
398 format!("{}_{}{}", base, suffix, arity),
399 vec![cel_type.clone(); arity],
400 cel_type,
401 )
402 .with_impl(shared_impl),
403 );
404 }
405 decl = decl.with_overload(
407 OverloadDecl::function(
408 format!("{}_dyn{}", base, arity),
409 vec![CelType::Dyn; arity],
410 CelType::Dyn,
411 )
412 .with_impl(shared_impl),
413 );
414 }
415
416 for (suffix, cel_type) in [
418 ("int", CelType::Int),
419 ("uint", CelType::UInt),
420 ("double", CelType::Double),
421 ] {
422 decl = decl.with_overload(
423 OverloadDecl::function(
424 format!("{}_list_{}", base, suffix),
425 vec![CelType::list(cel_type.clone())],
426 cel_type,
427 )
428 .with_impl(shared_impl),
429 );
430 }
431 decl = decl.with_overload(
432 OverloadDecl::function(
433 format!("{}_list_dyn", base),
434 vec![CelType::list(CelType::Dyn)],
435 CelType::Dyn,
436 )
437 .with_impl(shared_impl),
438 );
439
440 decl
441}
442
443fn add_bit_operations(funcs: &mut Vec<FunctionDecl>) {
444 funcs.push(
446 FunctionDecl::new("math.bitAnd")
447 .with_overload(
448 OverloadDecl::function(
449 "math_bitand_int_int",
450 vec![CelType::Int, CelType::Int],
451 CelType::Int,
452 )
453 .with_impl(|args| match (&args[0], &args[1]) {
454 (Value::Int(a), Value::Int(b)) => Value::Int(a & b),
455 _ => Value::error(EvalError::invalid_argument("expected int, int")),
456 }),
457 )
458 .with_overload(
459 OverloadDecl::function(
460 "math_bitand_uint_uint",
461 vec![CelType::UInt, CelType::UInt],
462 CelType::UInt,
463 )
464 .with_impl(|args| match (&args[0], &args[1]) {
465 (Value::UInt(a), Value::UInt(b)) => Value::UInt(a & b),
466 _ => Value::error(EvalError::invalid_argument("expected uint, uint")),
467 }),
468 ),
469 );
470
471 funcs.push(
473 FunctionDecl::new("math.bitOr")
474 .with_overload(
475 OverloadDecl::function(
476 "math_bitor_int_int",
477 vec![CelType::Int, CelType::Int],
478 CelType::Int,
479 )
480 .with_impl(|args| match (&args[0], &args[1]) {
481 (Value::Int(a), Value::Int(b)) => Value::Int(a | b),
482 _ => Value::error(EvalError::invalid_argument("expected int, int")),
483 }),
484 )
485 .with_overload(
486 OverloadDecl::function(
487 "math_bitor_uint_uint",
488 vec![CelType::UInt, CelType::UInt],
489 CelType::UInt,
490 )
491 .with_impl(|args| match (&args[0], &args[1]) {
492 (Value::UInt(a), Value::UInt(b)) => Value::UInt(a | b),
493 _ => Value::error(EvalError::invalid_argument("expected uint, uint")),
494 }),
495 ),
496 );
497
498 funcs.push(
500 FunctionDecl::new("math.bitXor")
501 .with_overload(
502 OverloadDecl::function(
503 "math_bitxor_int_int",
504 vec![CelType::Int, CelType::Int],
505 CelType::Int,
506 )
507 .with_impl(|args| match (&args[0], &args[1]) {
508 (Value::Int(a), Value::Int(b)) => Value::Int(a ^ b),
509 _ => Value::error(EvalError::invalid_argument("expected int, int")),
510 }),
511 )
512 .with_overload(
513 OverloadDecl::function(
514 "math_bitxor_uint_uint",
515 vec![CelType::UInt, CelType::UInt],
516 CelType::UInt,
517 )
518 .with_impl(|args| match (&args[0], &args[1]) {
519 (Value::UInt(a), Value::UInt(b)) => Value::UInt(a ^ b),
520 _ => Value::error(EvalError::invalid_argument("expected uint, uint")),
521 }),
522 ),
523 );
524
525 funcs.push(
527 FunctionDecl::new("math.bitNot")
528 .with_overload(
529 OverloadDecl::function("math_bitnot_int", vec![CelType::Int], CelType::Int)
530 .with_impl(|args| match &args[0] {
531 Value::Int(a) => Value::Int(!a),
532 _ => Value::error(EvalError::invalid_argument("expected int")),
533 }),
534 )
535 .with_overload(
536 OverloadDecl::function("math_bitnot_uint", vec![CelType::UInt], CelType::UInt)
537 .with_impl(|args| match &args[0] {
538 Value::UInt(a) => Value::UInt(!a),
539 _ => Value::error(EvalError::invalid_argument("expected uint")),
540 }),
541 ),
542 );
543
544 funcs.push(
546 FunctionDecl::new("math.bitShiftLeft")
547 .with_overload(
548 OverloadDecl::function(
549 "math_bitshiftleft_int_int",
550 vec![CelType::Int, CelType::Int],
551 CelType::Int,
552 )
553 .with_impl(|args| match (&args[0], &args[1]) {
554 (Value::Int(a), Value::Int(b)) => {
555 if *b < 0 {
556 return Value::error(EvalError::invalid_argument(
557 "math.bitShiftLeft: negative shift amount",
558 ));
559 }
560 if *b >= 64 {
561 return Value::Int(0);
562 }
563 Value::Int((*a as u64).wrapping_shl(*b as u32) as i64)
564 }
565 (Value::UInt(a), Value::Int(b)) => {
566 if *b < 0 {
567 return Value::error(EvalError::invalid_argument(
568 "math.bitShiftLeft: negative shift amount",
569 ));
570 }
571 if *b >= 64 {
572 return Value::UInt(0);
573 }
574 Value::UInt(a.wrapping_shl(*b as u32))
575 }
576 _ => Value::error(EvalError::invalid_argument("expected int/uint, int")),
577 }),
578 )
579 .with_overload(
580 OverloadDecl::function(
581 "math_bitshiftleft_uint_int",
582 vec![CelType::UInt, CelType::Int],
583 CelType::UInt,
584 )
585 .with_impl(|args| match (&args[0], &args[1]) {
586 (Value::UInt(a), Value::Int(b)) => {
587 if *b < 0 {
588 return Value::error(EvalError::invalid_argument(
589 "math.bitShiftLeft: negative shift amount",
590 ));
591 }
592 if *b >= 64 {
593 return Value::UInt(0);
594 }
595 Value::UInt(a.wrapping_shl(*b as u32))
596 }
597 _ => Value::error(EvalError::invalid_argument("expected uint, int")),
598 }),
599 ),
600 );
601
602 funcs.push(
604 FunctionDecl::new("math.bitShiftRight")
605 .with_overload(
606 OverloadDecl::function(
607 "math_bitshiftright_int_int",
608 vec![CelType::Int, CelType::Int],
609 CelType::Int,
610 )
611 .with_impl(|args| match (&args[0], &args[1]) {
612 (Value::Int(a), Value::Int(b)) => {
613 if *b < 0 {
614 return Value::error(EvalError::invalid_argument(
615 "math.bitShiftRight: negative shift amount",
616 ));
617 }
618 if *b >= 64 {
619 return Value::Int(0);
620 }
621 Value::Int((*a as u64).wrapping_shr(*b as u32) as i64)
623 }
624 (Value::UInt(a), Value::Int(b)) => {
625 if *b < 0 {
626 return Value::error(EvalError::invalid_argument(
627 "math.bitShiftRight: negative shift amount",
628 ));
629 }
630 if *b >= 64 {
631 return Value::UInt(0);
632 }
633 Value::UInt(a.wrapping_shr(*b as u32))
634 }
635 _ => Value::error(EvalError::invalid_argument("expected int/uint, int")),
636 }),
637 )
638 .with_overload(
639 OverloadDecl::function(
640 "math_bitshiftright_uint_int",
641 vec![CelType::UInt, CelType::Int],
642 CelType::UInt,
643 )
644 .with_impl(|args| match (&args[0], &args[1]) {
645 (Value::UInt(a), Value::Int(b)) => {
646 if *b < 0 {
647 return Value::error(EvalError::invalid_argument(
648 "math.bitShiftRight: negative shift amount",
649 ));
650 }
651 if *b >= 64 {
652 return Value::UInt(0);
653 }
654 Value::UInt(a.wrapping_shr(*b as u32))
655 }
656 _ => Value::error(EvalError::invalid_argument("expected uint, int")),
657 }),
658 ),
659 );
660}
661
662#[cfg(test)]
663mod tests {
664 use super::*;
665
666 #[test]
667 fn test_math_extension_has_functions() {
668 let funcs = math_extension();
669 assert!(funcs.len() >= 17);
672 }
673
674 #[test]
675 fn test_math_greatest_overloads() {
676 let funcs = math_extension();
677 let greatest = funcs.iter().find(|f| f.name == "math.greatest").unwrap();
678
679 assert!(greatest
681 .overloads
682 .iter()
683 .any(|o| o.id == "math_greatest_int" && o.params.len() == 1));
684 assert!(greatest
685 .overloads
686 .iter()
687 .any(|o| o.id == "math_greatest_double" && o.params.len() == 1));
688
689 assert!(greatest
691 .overloads
692 .iter()
693 .any(|o| o.id == "math_greatest_int_int" && o.params.len() == 2));
694
695 assert!(greatest
697 .overloads
698 .iter()
699 .any(|o| o.id == "math_greatest_int3" && o.params.len() == 3));
700
701 assert!(greatest
703 .overloads
704 .iter()
705 .any(|o| o.id == "math_greatest_list_int"));
706 }
707
708 #[test]
709 fn test_math_abs_overloads() {
710 let funcs = math_extension();
711 let abs = funcs.iter().find(|f| f.name == "math.abs").unwrap();
712 assert_eq!(abs.overloads.len(), 3); }
714
715 #[test]
716 fn test_bit_operations() {
717 let funcs = math_extension();
718
719 let bit_and = funcs.iter().find(|f| f.name == "math.bitAnd").unwrap();
720 assert_eq!(bit_and.overloads.len(), 2); let bit_not = funcs.iter().find(|f| f.name == "math.bitNot").unwrap();
723 assert_eq!(bit_not.overloads.len(), 2); }
725
726 #[test]
727 fn test_all_functions_are_standalone() {
728 let funcs = math_extension();
729 for func in &funcs {
730 for overload in &func.overloads {
731 assert!(
732 !overload.is_member,
733 "Expected {} to be standalone, but it's a member function",
734 overload.id
735 );
736 }
737 }
738 }
739
740 #[test]
741 fn test_ceil_impl() {
742 let result = (math_extension()
743 .iter()
744 .find(|f| f.name == "math.ceil")
745 .unwrap()
746 .overloads[0]
747 .implementation
748 .as_ref()
749 .unwrap())(&[Value::Double(1.5)]);
750 assert_eq!(result, Value::Double(2.0));
751 }
752
753 #[test]
754 fn test_floor_impl() {
755 let result = (math_extension()
756 .iter()
757 .find(|f| f.name == "math.floor")
758 .unwrap()
759 .overloads[0]
760 .implementation
761 .as_ref()
762 .unwrap())(&[Value::Double(1.5)]);
763 assert_eq!(result, Value::Double(1.0));
764 }
765
766 #[test]
767 fn test_round_half_away_from_zero() {
768 let round_fn = math_extension()
769 .iter()
770 .find(|f| f.name == "math.round")
771 .unwrap()
772 .overloads[0]
773 .implementation
774 .clone()
775 .unwrap();
776
777 assert_eq!(round_fn(&[Value::Double(2.5)]), Value::Double(3.0));
778 assert_eq!(round_fn(&[Value::Double(-2.5)]), Value::Double(-3.0));
779 assert_eq!(round_fn(&[Value::Double(1.4)]), Value::Double(1.0));
780 assert_eq!(round_fn(&[Value::Double(-1.4)]), Value::Double(-1.0));
781 }
782
783 #[test]
784 fn test_abs_overflow() {
785 let abs_fn = math_extension()
786 .iter()
787 .find(|f| f.name == "math.abs")
788 .unwrap()
789 .overloads
790 .iter()
791 .find(|o| o.id == "math_abs_int")
792 .unwrap()
793 .implementation
794 .clone()
795 .unwrap();
796
797 assert_eq!(abs_fn(&[Value::Int(-5)]), Value::Int(5));
799 assert!(matches!(abs_fn(&[Value::Int(i64::MIN)]), Value::Error(_)));
801 }
802
803 #[test]
804 fn test_greatest_basic() {
805 assert_eq!(
806 greatest_impl(&[Value::Int(1), Value::Int(3), Value::Int(2)]),
807 Value::Int(3)
808 );
809 assert_eq!(
810 greatest_impl(&[Value::Double(1.5), Value::Double(2.5)]),
811 Value::Double(2.5)
812 );
813 }
814
815 #[test]
816 fn test_least_basic() {
817 assert_eq!(
818 least_impl(&[Value::Int(1), Value::Int(3), Value::Int(2)]),
819 Value::Int(1)
820 );
821 assert_eq!(
822 least_impl(&[Value::UInt(5), Value::UInt(2)]),
823 Value::UInt(2)
824 );
825 }
826
827 #[test]
828 fn test_greatest_mixed_types() {
829 assert_eq!(
830 greatest_impl(&[Value::Int(1), Value::UInt(5)]),
831 Value::UInt(5)
832 );
833 assert_eq!(
834 greatest_impl(&[Value::Int(-1), Value::UInt(0)]),
835 Value::UInt(0)
836 );
837 }
838
839 #[test]
840 fn test_greatest_empty_list() {
841 use std::sync::Arc;
842 let empty: Arc<[Value]> = Arc::from(vec![]);
843 assert!(matches!(
844 greatest_impl(&[Value::List(empty)]),
845 Value::Error(_)
846 ));
847 }
848
849 #[test]
850 fn test_bitshift_negative() {
851 let shift_fn = math_extension()
852 .iter()
853 .find(|f| f.name == "math.bitShiftLeft")
854 .unwrap()
855 .overloads
856 .iter()
857 .find(|o| o.id == "math_bitshiftleft_int_int")
858 .unwrap()
859 .implementation
860 .clone()
861 .unwrap();
862
863 assert!(matches!(
864 shift_fn(&[Value::Int(1), Value::Int(-1)]),
865 Value::Error(_)
866 ));
867 }
868}