mech 0.3.3

Mech is a programming language for building reactive systems like robots, games, and animations.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
#![allow(warnings)]
extern crate mech_syntax;
extern crate mech_core;
extern crate nalgebra as na;
use std::cell::RefCell;
use std::rc::Rc;
use mech_core::matrix::Matrix;
use mech_syntax::*;
use mech_core::*;
use mech_interpreter::*;
use indexmap::set::IndexSet;

/// Compare interpreter output to expected value
macro_rules! test_interpreter {
  ($func:ident, $input:tt, $expected:expr) => (
    #[test]
    fn $func() {
      let s = $input;
      match parser::parse(&s) {
          Ok(tree) => { 
            let mut intrp = Interpreter::new(0);
            let result = intrp.interpret(&tree).unwrap();
            assert_eq!(result, $expected);
          },
          Err(err) => {panic!("{:?}", err);}
      }   
    }
  )
}

/////////////////////////////////////////////////////////////////////////////////

test_interpreter!(interpret_literal_integer, "123", Value::F64(Ref::new(123.0)));
test_interpreter!(interpret_literal_sci, "1.23e2", Value::F64(Ref::new(123.0)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_formula_literal_suffix, "100u8", Value::U8(Ref::new(100)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_literal_bin, "0b10101", Value::I64(Ref::new(0b10101)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_literal_hex, "0x123abc", Value::I64(Ref::new(0x123abc)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_literal_oct, "0o1234", Value::I64(Ref::new(0o1234)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_literal_dec, "0d1234", Value::I64(Ref::new(1234)));
test_interpreter!(interpret_literal_float, "1.23", Value::F64(Ref::new(1.23)));
test_interpreter!(interpret_literal_string, r#""Hello""#, Value::String(Ref::new("Hello".to_string())));
test_interpreter!(interpret_literal_string_empty, r#""""#, Value::String(Ref::new("".to_string())));
test_interpreter!(interpret_literal_string_multiline, r#""Hello 
 World""#, Value::String(Ref::new("Hello \n World".to_string())));
test_interpreter!(interpret_literal_true, "true", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_literal_true2, "✓ ", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_literal_false2, "✗ ", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_literal_false, "false", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_literal_atom, ":A", Value::Atom(Ref::new(MechAtom::new(55450514845822917))));
test_interpreter!(interpret_literal_empty, "_", Value::Empty);

test_interpreter!(
  interpret_fsm_counter_accepts_typed_input,
  "#Counter(n<u64>) => <u64>\n  ├ :Count(n<u64>)\n  └ :Done(n<u64>).\n\n#Counter(n<u64>) -> :Count(n)\n  :Count(n)\n    ├ n > 0u64 -> :Count(n - 1u64)\n    └ n == 0u64 -> :Done(0u64)\n  :Done(n) => n.\n\n#Counter(5u64)",
  Value::U64(Ref::new(0))
);

test_interpreter!(
  interpret_fsm_fibonacci_accepts_typed_input,
  "#Fibonacci(n<u64>) => <u64>\n  ├ :Compute(n<u64>, a<u64>, b<u64>)\n  └ :Done(n<u64>).\n\n#Fibonacci(n<u64>) -> :Compute(n, 0u64, 1u64)\n  :Compute(n, a, b)\n    ├ n > 0u64 -> :Compute(n - 1u64, b, a + b)\n    └ n == 0u64 -> :Done(a)\n  :Done(n) => n.\n\n#Fibonacci(10u64)",
  Value::U64(Ref::new(55))
);

#[test]
fn interpret_fsm_fails_when_transition_targets_undefined_state() {
  let s = "#Door(n<u64>) => <u64>\n  ├ :Closed(n<u64>)\n  └ :Open(n<u64>).\n\n#Door(n<u64>) -> :Closed(n)\n  :Closed(n) -> :Locked(n)\n  :Open(n) => n.\n\n#Door(1u64)";
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  assert!(intrp.interpret(&tree).is_err());
}

test_interpreter!(
  interpret_fsm_accepts_when_all_states_are_implemented,
  "#Door(n<u64>) => <u64>\n  ├ :Closed(n<u64>)\n  ├ :Open(n<u64>)\n  └ :Locked(n<u64>).\n\n#Door(n<u64>) -> :Closed(n)\n  :Closed(n) -> :Locked(n)\n  :Locked(n) -> :Open(n)\n  :Open(n) => n.\n\n#Door(1u64)",
  Value::U64(Ref::new(1))
);
test_interpreter!(interpret_variable_define_empty, "em := _", Value::Empty);
#[cfg(feature = "u8")]
test_interpreter!(interpret_variable_define_kind_literal, "x := <u8>;", Value::Kind(ValueKind::U8));
#[test]
fn interpret_variable_define_undefined_kind_literal_error() {
  let s = "x := <foo>;";
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  assert!(intrp.interpret(&tree).is_err());
}
test_interpreter!(interpret_variable_define_typed_empty, "emp<_> := _", Value::Empty);
#[cfg(feature = "u64")]
test_interpreter!(
  interpret_variable_define_typed_option_some,
  "x<u64?> := 123u64",
  Value::U64(Ref::new(123))
);
#[cfg(feature = "u64")]
test_interpreter!(
  interpret_variable_define_typed_option_none,
  "x<u64?> := _",
  Value::Empty
);
#[cfg(feature = "u64")]
test_interpreter!(
  interpret_option_match_scalar_some,
  "x<u64?> := 4u64; x? | x > 3u64 => x | * => 0u64.",
  Value::U64(Ref::new(4))
);
#[cfg(feature = "u64")]
test_interpreter!(
  interpret_option_match_literal_pattern_matches_inner_value,
  "foo<u64?> := 0\n\nfoo?\n  | 0 => 9\n  | * => 10.",
  Value::F64(Ref::new(9.0))
);
#[cfg(feature = "u64")]
test_interpreter!(
  interpret_option_match_tuple_destructure,
  "x<u64?> := 2u64; y<u64?> := _; (x2,y2) := (x,y)? | (x,y) => (x,y) | * => (0u64,0u64).; x2 + y2",
  Value::U64(Ref::new(0))
);
test_interpreter!(
  interpret_match_allows_unreachable_wildcard_with_different_kind,
  "foo<f64?> := 1234\n\nbar := foo?\n  | x => \"One Two Three\"\n  | * => 12.\n\nbar + \"\"",
  Value::String(Ref::new("One Two Three".to_string()))
);

#[test]
fn interpret_option_match_requires_wildcard_arm() {
  let s = "foo<u64?> := 1234\n\nbar := foo?\n  | 0 => 9.\n\nbar";
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  assert!(intrp.interpret(&tree).is_err());
}

#[test]
fn interpret_enum_match_reports_missing_variants_color() {
  let s = r#"
<color> := :red | :green | :blue
my-color<color> := :red
string-color := my-color?
  | :red   => "red"
  | :green => "green".
"#;
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  let err = intrp.interpret(&tree).unwrap_err();
  let msg = format!("{:?}", err);
  assert!(msg.contains("MatchNonExhaustive"));
  assert!(msg.contains(":blue"));
  assert!(msg.contains("wildcard"));
}

#[test]
fn interpret_enum_match_reports_missing_variants_generalized() {
  let s = r#"
<door> := :open | :closed | :locked
state<door> := :open
label := state?
  | :open   => "open"
  | :closed => "closed".
"#;
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  let err = intrp.interpret(&tree).unwrap_err();
  let msg = format!("{:?}", err);
  assert!(msg.contains("MatchNonExhaustive"));
  assert!(msg.contains(":locked"));
  assert!(msg.contains("wildcard"));
}

#[cfg(feature = "u64")]
test_interpreter!(
  interpret_match_array_pattern_head,
  "xs := [10u64 20u64 30u64]; y := xs? | [x ...] => x | * => 0u64.; y + 0u64",
  Value::U64(Ref::new(10))
);

#[cfg(feature = "u64")]
test_interpreter!(
  interpret_match_array_pattern_last,
  "xs := [10u64 20u64 30u64]; y := xs? | [... x] => x | * => 0u64.; y + 0u64",
  Value::U64(Ref::new(30))
);


#[cfg(feature = "u64")]
test_interpreter!(
  interpret_match_array_pattern_rest_binding,
  "xs := [10u64 20u64 30u64 40u64]; y := xs? | [a, b | rest] => rest? | [r ...] => r | * => 0u64. | * => 0u64.; y + 0u64",
  Value::U64(Ref::new(30))
);

#[cfg(feature = "u64")]
test_interpreter!(
  interpret_match_array_pattern_rest_binding_returns_matrix,
  "xs := [10u64 20u64 30u64 40u64]; y := xs? | [a, b | rest] => rest | * => [0u64].; z := y? | [h ... t] => h + t | * => 0u64.; z + 0u64",
  Value::U64(Ref::new(70))
);

#[cfg(feature = "u64")]
test_interpreter!(
  interpret_match_tuple_pattern_with_guards,
  "foo := (1u64, 2u64, 3u64)\n\nmax<u64> := foo?\n  | (a, b, c), a > b && a > c => a\n  | (a, b, c), b > a && b > c => b\n  | (a, b, c), c > a && c > b => c\n  | * => 0u64.\n\nmax + 0u64",
  Value::U64(Ref::new(3))
);

test_interpreter!(interpret_option_match_tuple_struct_pattern, "state := (:Done, 9u64); y := state? | :Done(x) => x | * => 0u64.; y + 0u64", Value::U64(Ref::new(9)));
#[test]
fn interpret_tagged_union_match_requires_exhaustive_arms() {
  let s = r#"
<result> := :ok<u64> | :err<string>
<option> := :some<result> | :none
x<option> := :some(:ok(42u64))
result := x?
  | :some(:ok(n)) => n.
"#;
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  assert!(intrp.interpret(&tree).is_err());
}
test_interpreter!(
  interpret_function_shorthand_match_arm_broadcasts_over_matrix_input,
  "add-one(x<f64>) => <f64>\n  | x + 1.\n\nadd-one([1 2 3])",
  Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 4.0], 1, 3))
);
test_interpreter!(interpret_function_array_pattern_arms, "head(xs<[u64]:1,3>) => <u64>\n  | [x ...] => x\n  | * => 0u64.\nhead([10u64 20u64 30u64]) + 0u64", Value::U64(Ref::new(10)));
test_interpreter!(interpret_fsm_array_pattern_state_arguments, "#VecFsm(n<u64>) => <u64>\n  ├ :Scan(xs<[u64]:1,3>)\n  └ :Done(out<u64>).\n\n#VecFsm(n<u64>) -> :Scan([1u64 2u64 3u64])\n  :Scan([x ... y]) -> :Done(x + y)\n  :Done(out) => out.\n\n#VecFsm(0u64)", Value::U64(Ref::new(4)));
test_interpreter!(interpret_fsm_accepts_unsized_vector_input, "#Echo(xs<[u64]>) => <u64>\n  ├ :Start(xs<[u64]>)\n  └ :Done(out<u64>).\n\n#Echo(xs<[u64]>) -> :Start(xs)\n  :Start([x ...]) -> :Done(x)\n  :Done(out) => out.\n\n#Echo([5u64 3u64 8u64 1u64])", Value::U64(Ref::new(5)));
test_interpreter!(interpret_fsm_array_spread_reconstruction_keeps_scalar_guards, "#Demo(arr<[u64]>) => <u64>\n  ├ :Pass(arr<[u64]>)\n  └ :Done(out<u64>).\n\n#Demo(arr<[u64]>) -> :Pass(arr)\n  :Pass([a, b | tail])\n    ├ a > b -> :Pass([a | tail])\n    └ * -> :Done(0u64)\n  :Pass([x ...]) -> :Done(x)\n  :Done(out) => out.\n\n#Demo([5u64 3u64 8u64 1u64])", Value::U64(Ref::new(0)));
test_interpreter!(interpret_fsm_bubble_sort_returns_typed_u64_matrix, "#bubble-sort(arr<[u64]>) => <[u64]>\n  ├ :Start(arr<[u64]>)\n  ├ :Pass(arr<[u64]>, acc<[u64]>, swaps<u64>)\n  ├ :Next(arr<[u64]>, swaps<u64>)\n  ├ :Reverse(arr<[u64]>, acc<[u64]>, swaps<u64>)\n  └ :Done(arr<[u64]>).\n\n#bubble-sort(arr) -> :Start(arr)\n  :Start(arr) -> :Pass(arr, [], 0u64)\n  :Pass([a, b | tail], acc, swaps)\n    ├ a > b -> :Pass([a | tail], [b | acc], swaps + 1u64)\n    └ *     -> :Pass([b | tail], [a | acc], swaps)\n  :Pass([x], acc, swaps) -> :Next([x | acc], swaps)\n  :Pass([], acc, swaps)  -> :Next(acc, swaps)\n  :Next(arr, swaps) -> :Reverse(arr, [], swaps)\n  :Reverse([x | tail], acc, swaps) -> :Reverse(tail, [x | acc], swaps)\n  :Reverse([], acc, 0u64)     -> :Done(acc)\n  :Reverse([], acc, swaps) -> :Pass(acc, [], 0u64)\n  :Done(arr) => arr.\n\n#bubble-sort([5u64 3u64 8u64 1u64])", Value::MatrixU64(Matrix::from_vec(vec![1, 3, 5, 8], 1, 4)));
test_interpreter!(interpret_fsm_bubble_sort_assigns_matrix_value, "#bubble-sort(arr<[u64]>) => <[u64]>
  ├ :Start(arr<[u64]>)
  ├ :Pass(arr<[u64]>, acc<[u64]>, swaps<u64>)
  ├ :Next(arr<[u64]>, swaps<u64>)
  ├ :Reverse(arr<[u64]>, acc<[u64]>, swaps<u64>)
  └ :Done(arr<[u64]>).

#bubble-sort(arr) → :Start(arr)
  :Start(arr) → :Pass(arr, [], 0u64)
  :Pass([a, b | tail], acc, swaps)
    ├ a > b → :Pass([a | tail], [b | acc], swaps + 1u64)
    └ *     → :Pass([b | tail], [a | acc], swaps)
  :Pass([x], acc, swaps) → :Next([x | acc], swaps)
  :Pass([], acc, swaps)  → :Next(acc, swaps)
  :Next(arr, swaps) → :Reverse(arr, [], swaps)
  :Reverse([x | tail], acc, swaps) → :Reverse(tail, [x | acc], swaps)
  :Reverse([], acc, 0u64)     → :Done(acc)
  :Reverse([], acc, swaps) → :Pass(acc, [], 0u64)
  :Done(arr) ⇒ arr.

x := [5u64 3u64 8u64 1u64]
y := #bubble-sort(x)", Value::MatrixU64(Matrix::from_vec(vec![1, 3, 5, 8], 1, 4)));
#[test]
fn interpret_variable_define_typed_set_from_range_matrix() {
  let s = "input<{f64}> := 1..=5";
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  let result = intrp.interpret(&tree).unwrap();
  match result {
    Value::Set(mset) => {
      let mset = mset.borrow();
      assert_eq!(mset.set.len(), 5);
      for value in [1.0, 2.0, 3.0, 4.0, 5.0] {
        assert!(mset.set.contains(&Value::F64(Ref::new(value))));
      }
    }
    _ => panic!("Expected set output"),
  }
}
#[test]
fn interpret_variable_define_typed_set_from_matrix() {
  let s = "input<{f64}> := [1 2; 3 4; 5 6]";
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  let result = intrp.interpret(&tree).unwrap();
  match result {
    Value::Set(mset) => {
      let mset = mset.borrow();
      assert_eq!(mset.set.len(), 6);
      for value in [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] {
        assert!(mset.set.contains(&Value::F64(Ref::new(value))));
      }
    }
    _ => panic!("Expected set output"),
  }
}
test_interpreter!(interpret_literal_complex, "5+4i", Value::C64(Ref::new(C64::new(5.0, 4.0))));
test_interpreter!(interpret_literal_complex2, "5-4i", Value::C64(Ref::new(C64::new(5.0, -4.0))));
test_interpreter!(interpret_literal_complex3, "5-4j", Value::C64(Ref::new(C64::new(5.0, -4.0))));
test_interpreter!(interpret_literal_rational, "1/2", Value::R64(Ref::new(R64::new(1, 2))));

test_interpreter!(interpret_comment, "123 -- comment", Value::F64(Ref::new(123.0)));
test_interpreter!(interpret_comment2, "123 // comment", Value::F64(Ref::new(123.0)));

test_interpreter!(interpret_formula_math_add, "2 + 2", Value::F64(Ref::new(4.0)));
test_interpreter!(interpret_formula_math_sub, "2 - 2", Value::F64(Ref::new(0.0)));
test_interpreter!(interpret_formula_math_mul, "2 * 2", Value::F64(Ref::new(4.0)));
test_interpreter!(interpret_formula_math_div, "2 / 2", Value::F64(Ref::new(1.0)));
test_interpreter!(interpret_formula_precedence_mul_before_compare, "1 * 2 > 1 * 1", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_precedence_add_before_compare, "1 + 2 > 1", Value::Bool(Ref::new(true)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_formula_math_pow, "2<u8> ^ 2<u8>", Value::U8(Ref::new(4)));
test_interpreter!(interpret_formula_math_pow_f64, "2.0 ^ 2.0", Value::F64(Ref::new(4.0)));
test_interpreter!(interpret_formulat_math_add_rational, "1/10 + 2/10 + 3/10", Value::R64(Ref::new(R64::new(6, 10))));
test_interpreter!(interpret_formulat_math_sub_rational, "1/10 - 2/10 - 3/10", Value::R64(Ref::new(R64::new(-4, 10))));
test_interpreter!(interpret_formula_math_mul_rational, "1/10 * 2/10 * 3/10", Value::R64(Ref::new(R64::new(3, 500))));
test_interpreter!(interpret_formula_math_div_rational, "1/10 / 2/10 / 3/10", Value::R64(Ref::new(R64::new(5, 3))));
test_interpreter!(interpret_formula_math_add_complex, "1+2i + 3+4i", Value::C64(Ref::new(C64::new(4.0, 6.0))));
test_interpreter!(interpret_formula_math_add_complex_real_rhs, "4i + 1", Value::C64(Ref::new(C64::new(1.0, 4.0))));
test_interpreter!(interpret_formula_math_add_complex_real_lhs, "1 + 4i", Value::C64(Ref::new(C64::new(1.0, 4.0))));
test_interpreter!(interpret_variable_define_complex_real_sum, "y := 4i + 1", Value::C64(Ref::new(C64::new(1.0, 4.0))));
test_interpreter!(interpret_variable_add_complex_real, "z := 4i; z + 1", Value::C64(Ref::new(C64::new(1.0, 4.0))));
test_interpreter!(interpret_formula_math_sub_complex, "1+2i - 3+4i", Value::C64(Ref::new(C64::new(-2.0, -2.0))));
test_interpreter!(interpret_formula_math_mul_complex, "1+2i * 3+4i", Value::C64(Ref::new(C64::new(-5.0, 10.0))));
test_interpreter!(interpret_formula_math_div_complex, "1+2i / 3+4i", Value::C64(Ref::new(C64::new(0.44, 0.08))));

test_interpreter!(interpret_matrix_rational, "[1/2 3/4]", Value::MatrixR64(Matrix::from_vec(vec![R64::new(1, 2), R64::new(3, 4)], 1, 2)));
test_interpreter!(interpret_matrix_complex, "[1+2i 3+4i]", Value::MatrixC64(Matrix::from_vec(vec![C64::new(1.0, 2.0), C64::new(3.0, 4.0)], 1, 2)));
test_interpreter!(interpret_matrix_add_rational, "[1/2 3/4] + [1/4 1/2]", Value::MatrixR64(Matrix::from_vec(vec![R64::new(3, 4), R64::new(5, 4)], 1, 2)));
test_interpreter!(interpret_matrix_add_complex, "[1+2i 3+4i] + [5+6i 7+8i]", Value::MatrixC64(Matrix::from_vec(vec![C64::new(6.0, 8.0), C64::new(10.0, 12.0)], 1, 2)));
test_interpreter!(interpret_matrix_sub_rational, "[1/2 3/4] - [1/4 1/2]", Value::MatrixR64(Matrix::from_vec(vec![R64::new(1, 4), R64::new(1, 4)], 1, 2)));
test_interpreter!(interpret_matrix_sub_complex, "[1+2i 3+4i] - [5+6i 7+8i]", Value::MatrixC64(Matrix::from_vec(vec![C64::new(-4.0, -4.0), C64::new(-4.0, -4.0)], 1, 2)));
test_interpreter!(interpret_matrix_mul_rational, "[1/2 3/4] * [1/4 1/2]", Value::MatrixR64(Matrix::from_vec(vec![R64::new(1, 8), R64::new(3, 8)], 1, 2)));
test_interpreter!(interpret_matrix_mul_complex, "[1+2i 3+4i] * [5+6i 7+8i]", Value::MatrixC64(Matrix::from_vec(vec![C64::new(-7.0, 16.0), C64::new(-11.0, 52.0)], 1, 2)));
test_interpreter!(interpret_matrix_div_rational, "[1/2 3/4] / [1/4 1/2]", Value::MatrixR64(Matrix::from_vec(vec![R64::new(2, 1), R64::new(3, 2)], 1, 2)));
test_interpreter!(interpret_matrix_div_complex, "[1+2i 3+4i] / [5+6i 7+8i]", Value::MatrixC64(Matrix::from_vec(vec![C64::new(0.2786885245901639, 0.06557377049180328), C64::new(0.4690265486725664, 0.035398230088495575)], 1, 2)));

test_interpreter!(interpret_matrix_eq_rational, "[1/2 3/4] == [1/2 3/4]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_eq_complex, "[1+2i 3+4i] == [1+2i 3+4i]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_neq_rational, "[1/2 3/4] != [1/2 3/5]", Value::MatrixBool(Matrix::from_vec(vec![false, true], 1, 2)));
test_interpreter!(interpret_matrix_neq_complex, "[1+2i 3+4i] != [1+2i 3+5i]", Value::MatrixBool(Matrix::from_vec(vec![false, true], 1, 2)));
test_interpreter!(interpret_matrix_gt_rational, "[1/2 3/4] > [1/4 1/2]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_gt_complex, "[1+2i 3+4i] > [1+1i 3+3i]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_gte_rational, "[1/2 3/4] >= [1/2 3/4]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_gte_complex, "[1+2i 3+4i] >= [1+2i 3+4i]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_lt_rational, "[1/2 3/4] < [3/4 1/2]", Value::MatrixBool(Matrix::from_vec(vec![true, false], 1, 2)));
test_interpreter!(interpret_matrix_lt_complex, "[1+2i 3+4i] < [2+3i 4+5i]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_lte_rational, "[1/2 3/4] <= [1/2 3/4]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_lte_complex, "[1+2i 3+4i] <= [1+2i 3+4i]", Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_matrix_assignment_copy_index, "a := [1 2 3; 4 5 6; 7 8 9]; b := a; b[2,3]", Value::F64(Ref::new(6.0)));
test_interpreter!(interpret_matrix_assignment_copy_eq, "a := [1 2 3; 4 5 6; 7 8 9]; b := a; b == a", Value::MatrixBool(Matrix::from_vec(vec![true, true, true, true, true, true, true, true, true], 3, 3)));
test_interpreter!(
  interpret_table_wildcard_access_returns_matrix,
  "b := |a<f64> b<f64>| 1 2 | 3 4|; b<[*]>",
  Value::MatrixValue(Matrix::from_vec(
    vec![
      Value::F64(Ref::new(1.0)),
      Value::F64(Ref::new(3.0)),
      Value::F64(Ref::new(2.0)),
      Value::F64(Ref::new(4.0)),
    ],
    2,
    2
  ))
);
#[cfg(feature = "u64")]
test_interpreter!(interpret_kind_annotation, "1<u64>", Value::U64(Ref::new(1)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_kind_annotation_math, "1<u64> + 1<u64>", Value::U64(Ref::new(2)));
#[cfg(feature = "f64")]
test_interpreter!(
  interpret_nested_kind_matrix_literal,
  "<<[f64]:3>>",
  Value::Kind(ValueKind::Kind(Box::new(ValueKind::Matrix(Box::new(ValueKind::F64), vec![3]))))
);

// New tests overflow - unsigned
// test_interpreter!(interpret_kind_math_overflow_u64, "18446744073709551615<u64> + 1<u64>", Value::U64(Ref::new(0)));
// test_interpreter!(interpret_kind_math_overflow_u128, "340282366920938463463374607431768211455<u128> + 1<u128>", Value::U128(Ref::new(0)));


// New tests overflow - unsigned
// test_interpreter!(interpret_kind_math_overflow_u64, "18446744073709551615<u64> + 1<u64>", Value::U64(Ref::new(0)));
// test_interpreter!(interpret_kind_math_overflow_u128, "340282366920938463463374607431768211455<u128> + 1<u128>", Value::U128(Ref::new(0)));

// New test overflow - signed
// test_interpreter!(interpret_kind_math_overflow_i128, "170141183460469231731687303715884105727<i128> + 1<i128>", Value::I128(Ref::new(-170141183460469231731687303715884105728)));

// New test overflow - float
// test_interpreter!(interpret_kind_math_overflow_f32,"1.0<f32> + 1.0<f32>",Value::F32(Ref::new(3.402823e+38)));
// test_interpreter!(interpret_kind_math_overflow_f64,"1.0<f64> + 1.0<f64>",Value::F64(Ref::new(1.7976931348623157e+308)));

// New tests underflow - unsigned
//test_interpreter!(interpret_kind_math_underflow_u64, "0<u64> - 1<u64>", Value::U64(Ref::new(18446744073709551615)));

// New tests nominal with type def - unsigned
//u8
#[cfg(feature = "u8")]
test_interpreter!(interpret_formula_math_add_u8, "2<u8> + 2<u8>", Value::U8(Ref::new(4)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_formula_math_sub_u8, "2<u8> - 2<u8>", Value::U8(Ref::new(0)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_formula_math_div_u8, "2<u8> / 2<u8>", Value::U8(Ref::new(1)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_formula_math_mul_u8, "2<u8> * 2<u8>", Value::U8(Ref::new(4)));
// u16
#[cfg(feature = "u16")]
test_interpreter!(interpret_formula_math_add_u16, "2<u16> + 2<u16>", Value::U16(Ref::new(4)));
#[cfg(feature = "u16")]
test_interpreter!(interpret_formula_math_sub_u16, "2<u16> - 2<u16>", Value::U16(Ref::new(0)));
#[cfg(feature = "u16")]
test_interpreter!(interpret_formula_math_div_u16, "2<u16> / 2<u16>", Value::U16(Ref::new(1)));
#[cfg(feature = "u16")]
test_interpreter!(interpret_formula_math_mul_u16, "2<u16> * 2<u16>", Value::U16(Ref::new(4)));
// u32
#[cfg(feature = "u32")]
test_interpreter!(interpret_formula_math_add_u32, "2<u32> + 2<u32>", Value::U32(Ref::new(4)));
#[cfg(feature = "u32")]
test_interpreter!(interpret_formula_math_sub_u32, "2<u32> - 2<u32>", Value::U32(Ref::new(0)));
#[cfg(feature = "u32")]
test_interpreter!(interpret_formula_math_div_u32, "2<u32> / 2<u32>", Value::U32(Ref::new(1)));
#[cfg(feature = "u32")]
test_interpreter!(interpret_formula_math_mul_u32, "2<u32> * 2<u32>", Value::U32(Ref::new(4)));
// u64
#[cfg(feature = "u64")]
test_interpreter!(interpret_formula_math_add_u64, "2<u64> + 2<u64>", Value::U64(Ref::new(4)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_formula_math_sub_u64, "2<u64> - 2<u64>", Value::U64(Ref::new(0)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_formula_math_sub_u64_with_default_literal_rhs, "2<u64> - 1", Value::U64(Ref::new(1)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_formula_math_div_u64, "2<u64> / 2<u64>", Value::U64(Ref::new(1)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_formula_math_mul_u64, "2<u64> * 2<u64>", Value::U64(Ref::new(4)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_formula_compare_gt_u64_with_default_literal_rhs, "2<u64> > 1", Value::Bool(Ref::new(true)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_formula_compare_gt_u64_with_default_literal_lhs, "2 > 1<u64>", Value::Bool(Ref::new(true)));
// u128
#[cfg(feature = "u128")]
test_interpreter!(interpret_formula_math_add_u128, "2<u128> + 2<u128>", Value::U128(Ref::new(4)));
#[cfg(feature = "u128")]
test_interpreter!(interpret_formula_math_sub_u128, "2<u128> - 2<u128>", Value::U128(Ref::new(0)));
#[cfg(feature = "u128")]
test_interpreter!(interpret_formula_math_div_u128, "2<u128> / 2<u128>", Value::U128(Ref::new(1)));
#[cfg(feature = "u128")]
test_interpreter!(interpret_formula_math_mul_u128, "2<u128> * 2<u128>", Value::U128(Ref::new(4)));

// New tests nominal with type def - signed
//i8
#[cfg(feature = "i8")]
test_interpreter!(interpret_formula_math_add_i8, "2<i8> + 2<i8>", Value::I8(Ref::new(4)));
#[cfg(feature = "i8")]
test_interpreter!(interpret_formula_math_sub_i8, "2<i8> - 2<i8>", Value::I8(Ref::new(0)));
#[cfg(feature = "i8")]
test_interpreter!(interpret_formula_math_div_i8, "2<i8> / 2<i8>", Value::I8(Ref::new(1)));
#[cfg(feature = "i8")]
test_interpreter!(interpret_formula_math_mul_i8, "2<i8> * 2<i8>", Value::I8(Ref::new(4)));
// i16
#[cfg(feature = "i16")]
test_interpreter!(interpret_formula_math_add_i16, "2<i16> + 2<i16>", Value::I16(Ref::new(4)));
#[cfg(feature = "i16")]
test_interpreter!(interpret_formula_math_sub_i16, "2<i16> - 2<i16>", Value::I16(Ref::new(0)));
#[cfg(feature = "i16")]
test_interpreter!(interpret_formula_math_div_i16, "2<i16> / 2<i16>", Value::I16(Ref::new(1)));
#[cfg(feature = "i16")]
test_interpreter!(interpret_formula_math_mul_i16, "2<i16> * 2<i16>", Value::I16(Ref::new(4)));
// i32
#[cfg(feature = "i32")]
test_interpreter!(interpret_formula_math_add_i32, "2<i32> + 2<i32>", Value::I32(Ref::new(4)));
#[cfg(feature = "i32")]
test_interpreter!(interpret_formula_math_sub_i32, "2<i32> - 2<i32>", Value::I32(Ref::new(0)));
#[cfg(feature = "i32")]
test_interpreter!(interpret_formula_math_div_i32, "2<i32> / 2<i32>", Value::I32(Ref::new(1)));
#[cfg(feature = "i32")]
test_interpreter!(interpret_formula_math_mul_i32, "2<i32> * 2<i32>", Value::I32(Ref::new(4)));
// i64
#[cfg(feature = "i64")]
test_interpreter!(interpret_formula_math_add_i64, "2<i64> + 2<i64>", Value::I64(Ref::new(4)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_formula_math_sub_i64, "2<i64> - 2<i64>", Value::I64(Ref::new(0)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_formula_math_div_i64, "2<i64> / 2<i64>", Value::I64(Ref::new(1)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_formula_math_mul_i64, "2<i64> * 2<i64>", Value::I64(Ref::new(4)));
// i128
#[cfg(feature = "i128")]
test_interpreter!(interpret_formula_math_add_i128, "2<i128> + 2<i128>", Value::I128(Ref::new(4)));
#[cfg(feature = "i128")]
test_interpreter!(interpret_formula_math_sub_i128, "2<i128> - 2<i128>", Value::I128(Ref::new(0)));
#[cfg(feature = "i128")]
test_interpreter!(interpret_formula_math_div_i128, "2<i128> / 2<i128>", Value::I128(Ref::new(1)));
#[cfg(feature = "i128")]
test_interpreter!(interpret_formula_math_mul_i128, "2<i128> * 2<i128>", Value::I128(Ref::new(4)));

// New tests for nominal with type def - floats
// f32
#[cfg(feature = "f32")]
test_interpreter!(interpret_formula_math_add_f32, "2.0<f32> + 2.0<f32>", Value::F32(Ref::new(4.0)));
#[cfg(feature = "f32")]
test_interpreter!(interpret_formula_math_sub_f32, "2.0<f32> - 2.0<f32>", Value::F32(Ref::new(0.0)));
#[cfg(feature = "f32")]
test_interpreter!(interpret_formula_math_div_f32, "2.0<f32> / 2.0<f32>", Value::F32(Ref::new(1.0)));
#[cfg(feature = "f32")]
test_interpreter!(interpret_formula_math_mul_f32, "2.0<f32> * 2.0<f32>", Value::F32(Ref::new(4.0)));
//f64
test_interpreter!(interpret_formula_math_add_f64, "2.0<f64> + 2.0<f64>", Value::F64(Ref::new(4.0)));
test_interpreter!(interpret_formula_math_sub_f64, "2.0<f64> - 2.0<f64>", Value::F64(Ref::new(0.0)));
test_interpreter!(interpret_formula_math_div_f64, "2.0<f64> / 2.0<f64>", Value::F64(Ref::new(1.0)));
test_interpreter!(interpret_formula_math_mul_f64, "2.0<f64> * 2.0<f64>", Value::F64(Ref::new(4.0)));

#[cfg(feature = "u16")]
test_interpreter!(interpret_kind_math_no_overflow, "255<u16> + 1<u16>", Value::U16(Ref::new(256)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_kind_matrix_row3, "[1<u8> 2<u8> 3<u8>]", Value::MatrixU8(Matrix::from_vec(vec![1, 2, 3], 1, 3)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_kind_lhs_define, "x<u64> := 1", Value::U64(Ref::new(1)));
#[cfg(all(feature = "u64", feature = "i8"))]
test_interpreter!(interpret_kind_convert_twice, "x<u64> := 1; y<i8> := x", Value::I8(Ref::new(1)));
#[cfg(feature = "f32")]
test_interpreter!(interpret_kind_convert_float, "x<f32> := 123;", Value::F32(Ref::new(123.0)));
test_interpreter!(interpret_kind_convert_rational, "x<r64> := 1 / 2; y<f64> := x", Value::F64(Ref::new(0.5)));
test_interpreter!(interpret_kind_convert_rational2, "x<f64> := 1/2; y<r64> := x", Value::R64(Ref::new(R64::new(1, 2))));
test_interpreter!(interpret_kind_convert_mat_to_any, "x := [2 3 4]; y<[*]> := x", Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 4.0], 1, 3)));

test_interpreter!(interpret_kind_define, "<foo> := <f64>; x<foo> := 123", Value::F64(Ref::new(123.0)));
test_interpreter!(interpret_formula_math_neg, "-1", Value::F64(Ref::new(-1.0)));
test_interpreter!(interpret_formula_math_multiple_terms, "1 + 2 + 3", Value::F64(Ref::new(6.0)));
test_interpreter!(interpret_formula_comparison_bool, "true == false", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_formula_comparison_bool2, "true == true", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_comparison_eq, "10 == 11", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_formula_comparison_string_eq, r#"["a" "b"] == ["a" "b"]"#, Value::MatrixBool(Matrix::from_vec(vec![true, true], 1, 2)));
test_interpreter!(interpret_formula_comparison_string_neq, r#"["a" "b"] != ["a" "c"]"#, Value::MatrixBool(Matrix::from_vec(vec![false, true], 1, 2)));
test_interpreter!(interpret_formula_comparison_neq, "10 != 11", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_comparison_neq_bool, "false != true", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_comparison_gt, "10 > 11", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_formula_comparison_lt, "10 < 11", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_comparison_gte, "10 >= 10", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_comparison_lte, "10 <= 10", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_comparison_gt_vec, "[1 8; 10 5] > [7 2; 4 11]", Value::MatrixBool(Matrix::from_vec(vec![false, true, true, false], 2, 2)));
test_interpreter!(interpret_formula_comparison_lt_vec, "[1 8 10 5] < [7 2 4 11]", Value::MatrixBool(Matrix::from_vec(vec![true, false, false, true], 1, 4)));
test_interpreter!(interpret_formula_unicode, "😃:=1;🤦🏼‍♂️:=2;y̆és:=🤦🏼‍♂️ + 😃", Value::F64(Ref::new(3.0)));
test_interpreter!(interpret_formula_logic_and, "true && true", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_logic_and_vec, "[true false] && [false false]", Value::MatrixBool(Matrix::from_vec(vec![false, false], 1, 2)));
test_interpreter!(interpret_formula_logic_and2, "true && false", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_formula_logic_or_vec, "[true false true] || [false false true]", Value::MatrixBool(Matrix::from_vec(vec![true, false, true], 1, 3)));
test_interpreter!(interpret_formula_logic_or, "true || false", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_logic_or2, "false || false", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_formula_logic_xor_vec, "[true false false true] ⊕ [true true false true]", Value::MatrixBool(Matrix::from_vec(vec![false, true, false, false], 1, 4)));
test_interpreter!(interpret_formula_logic_not, "!false", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_formula_logic_not_vec, "![false true false]", Value::MatrixBool(Matrix::from_vec(vec![true, false, true], 1, 3)));
test_interpreter!(interpret_formula_logic_not_vec1, "![false]", Value::MatrixBool(Matrix::from_vec(vec![true], 1, 1)));

test_interpreter!(interpret_statement_variable_define, "x := 123", Value::F64(Ref::new(123.0)));

test_interpreter!(interpret_reference_bool, "x := false; y := true; x && y", Value::Bool(Ref::new(false)));
test_interpreter!(interpret_reference_bool2, "x := false; x && true", Value::Bool(Ref::new(false)));

test_interpreter!(interpret_variable_recall, "a := 1; b := 2; a", Value::MutableReference(Ref::new(Value::F64(Ref::new(1.0)))));

test_interpreter!(interpret_matrix_range_exclusive, "1..4", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0], 1, 3)));
test_interpreter!(interpret_matrix_range_exclusive_step, "1..4..13", Value::MatrixF64(Matrix::from_vec(vec![1.0, 5.0, 9.0], 1, 3)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_matrix_range_exclusive_u8, "1<u8>..4<u8>", Value::MatrixU8(Matrix::from_vec(vec![1, 2, 3], 1, 3)));
test_interpreter!(interpret_matrix_range_inclusive, "1..=4", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0], 1, 4)));
test_interpreter!(interpret_matrix_range_inclusive_step, "1..4..=13", Value::MatrixF64(Matrix::from_vec(vec![1.0, 5.0, 9.0, 13.0], 1, 4)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_matrix_range_inclusive_u8, "1<u8>..=4<u8>", Value::MatrixU8(Matrix::from_vec(vec![1, 2, 3, 4], 1, 4)));
test_interpreter!(interpret_matrix_empty, "[]", Value::MatrixValue(Matrix::from_vec(vec![], 0, 0)));
test_interpreter!(interpret_matrix_row3, "[1 2 3]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0], 1, 3)));
test_interpreter!(interpret_matrix_mat1, "[123]", Value::MatrixF64(Matrix::from_vec(vec![123.0], 1, 1)));
test_interpreter!(interpret_matrix_row3_float, "[1.2 2.3 3.4]", Value::MatrixF64(Matrix::from_vec(vec![1.2, 2.3, 3.4], 1, 3)));
test_interpreter!(interpret_matrix_mat2, "[1 2; 3 4]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 2.0, 4.0], 2, 2)));
test_interpreter!(interpret_matrix_transpose, "[1 2; 3 4]'", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0], 2, 2)));
#[cfg(feature = "u8")]
test_interpreter!(interpret_matrix_transpose_u8, "[1<u8> 2<u8> 3<u8>]'", Value::MatrixU8(Matrix::from_vec(vec![1u8, 2, 3], 3, 1)));
test_interpreter!(interpret_matrix_transpose_float, "[1.0 2.0 3.0; 4.0 5.0 6.0]'", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0], 3, 2)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_matrix_transpose_vector, "x := | x<i64> | 1 | 3 | 5 |; x.x'", Value::MatrixI64(Matrix::from_vec(vec![1i64, 3, 5], 1, 3)));
test_interpreter!(interpret_matrix_add_v2s, "[1;2] + 3", Value::MatrixF64(Matrix::from_vec(vec![4.0, 5.0], 2, 1)));

test_interpreter!(interpret_matrix_mat2_f64, "[1.1 2.2; 3.3 4.4]", Value::MatrixF64(Matrix::from_vec(vec![1.1, 3.3, 2.2, 4.4], 2, 2)));
test_interpreter!(interpret_matrix_negate, "-[1 2; 3 4]", Value::MatrixF64(Matrix::from_vec(vec![-1.0, -3.0, -2.0, -4.0], 2, 2)));
test_interpreter!(interpret_matrix_negate_float, "-[1.0 2.0; 3.0 4.0]", Value::MatrixF64(Matrix::from_vec(vec![-1.0, -3.0, -2.0, -4.0], 2, 2)));
test_interpreter!(interpret_matrix_negate_mat1, "-[1]", Value::MatrixF64(Matrix::from_vec(vec![-1.0], 1, 1)));

test_interpreter!(interpret_matrix_row3_add, "[1 2 3] + [4 5 6]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 7.0, 9.0], 1, 3)));
test_interpreter!(interpret_matrix_row3_mul_scalar, "[1 2 3] * 3", Value::MatrixF64(Matrix::from_vec(vec![3.0, 6.0, 9.0], 1, 3)));
test_interpreter!(interpret_matrix_row3_mul_scalar2, "3 * [1 2 3]", Value::MatrixF64(Matrix::from_vec(vec![3.0, 6.0, 9.0], 1, 3)));
test_interpreter!(interpret_matrix_row3_add_float, "[1.0 2.0 3.0] + [4.0 5.0 6.0]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 7.0, 9.0], 1, 3)));
test_interpreter!(interpret_matrix_row3_sub, "[1 2 3] - [4 5 6]", Value::MatrixF64(Matrix::from_vec(vec![-3.0, -3.0, -3.0], 1, 3)));
test_interpreter!(interpret_matrix_row3_sub_float, "[1.0 2.0 3.0] - [4.0 5.0 6.0]", Value::MatrixF64(Matrix::from_vec(vec![-3.0, -3.0, -3.0], 1, 3)));
test_interpreter!(interpret_matrix_row3_add_ref, "a := [1 2 3]; b := [4 5 6]; c := a + b", Value::MatrixF64(Matrix::from_vec(vec![5.0, 7.0, 9.0], 1, 3)));
test_interpreter!(interpret_matrix_dynamic_add, "[1 2 3 4; 5 6 7 8] + [1 2 3 4; 5 6 7 8]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 10.0, 4.0, 12.0, 6.0, 14.0, 8.0, 16.0], 2, 4)));
test_interpreter!(interpret_matrix_dynamic_div, "[2 4 6 8] / [2 2 2 2]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0], 1, 4)));
test_interpreter!(interpret_matrix_gt, "x := [66.0 2.0 3.0; 66.0 5.0 66.0]; y := [1.0 2.0 3.0; 4.0 5.0 6.0]; x > y", Value::MatrixBool(Matrix::from_vec(vec![true, true, false, false, false, true], 2, 3)));
test_interpreter!(interpret_matrix_lt, "x := [66.0 2.0 3.0; 66.0 4.0 66.0]; y := [1.0 2.0 3.0; 4.0 5.0 6.0]; x < y", Value::MatrixBool(Matrix::from_vec(vec![false, false, false, true, false, false], 2, 3)));
test_interpreter!(interpret_matrix_lt_int, "x := [66 2 3; 66 4 66]; y := [1 2 3; 4 5 6]; x < y", Value::MatrixBool(Matrix::from_vec(vec![false, false, false, true, false, false], 2, 3)));
test_interpreter!(interpret_matrix_add_m2v2, "[1 1; 2 2] + [1;2]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 4.0, 2.0, 4.0], 2, 2)));
test_interpreter!(interpret_matrix_add_v2m2, "[1;2] + [1 1; 2 2]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 4.0, 2.0, 4.0], 2, 2)));
test_interpreter!(interpret_matrix_add_r2m2, "[1 2] + [1 1; 1 1]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 2.0, 3.0, 3.0], 2, 2)));
test_interpreter!(interpret_matrix_add_m2r2, "[1 1; 1 1] + [1 2]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 2.0, 3.0, 3.0], 2, 2)));

test_interpreter!(interpret_matrix_dot, "[1 2 3] · [4 5 6]", Value::F64(Ref::new(32.0)));
test_interpreter!(interpret_matrix_matmul_mat1, "[2] ** [10]", Value::MatrixF64(Matrix::from_vec(vec![20.0], 1, 1)));
test_interpreter!(interpret_matrix_matmul_mat2_ref, "a := [1 2; 3 4]; b := [4 5; 6 7]; c := a ** b", Value::MatrixF64(Matrix::from_vec(vec![16.0, 36.0, 19.0, 43.0], 2, 2)));
test_interpreter!(interpret_matrixmatmul_mat2x3_ref, "a := [1.0 2.0 3.0; 4.0 5.0 6.0]; b := [4.0 5.0; 6.0 7.0; 8.0 9.0]; c := a ** b", Value::MatrixF64(Matrix::from_vec(vec![40.0, 94.0, 46.0, 109.0], 2, 2)));
test_interpreter!(interpret_matrixmatmul_r3m3, "a := [1.0 2.0 3.0]; b := [4.0 5.0 6.0; 7.0 8.0 9.0; 10 11 12]; c := a ** b", Value::MatrixF64(Matrix::from_vec(vec![48.0, 54.0, 60.0], 1, 3)));
test_interpreter!(interpret_matrixmatmul_m3v3, "b := [4.0 5.0 6.0; 7.0 8.0 9.0; 10 11 12]; a := [1.0 2.0 3.0]'; c := b ** a", Value::MatrixF64(Matrix::from_vec(vec![32.0, 50.0, 68.0], 3, 1)));
test_interpreter!(interpret_matrix_string, r#"["Hello" "World"]"#, Value::MatrixString(Matrix::from_vec(vec!["Hello".to_string(), "World".to_string()], 1, 2)));
test_interpreter!(interpret_matrix_string_access, r#"x:=["Hello" "World"];x[2]"#, Value::String(Ref::new("World".to_string())));
test_interpreter!(interpret_matrix_string_assign, r#"~x:=["Hello" "World"];x[1]="Foo";[x[1] x[2]]"#, Value::MatrixString(Matrix::from_vec(vec!["Foo".to_string(), "World".to_string()], 1, 2)));
test_interpreter!(interpret_matrix_string_assign_logical, r#"~x := ["Hello", "World", "!"]; x[[true false true]] = "Foo";"#, Value::MatrixString(Matrix::from_vec(vec!["Foo".to_string(), "World".to_string(), "Foo".to_string()], 1, 3)));
test_interpreter!(interpret_table_string_access, r#"x:=|x<string> y<string> | "a" "b" | "c" "d" |; x.y"#, Value::MatrixString(Matrix::from_vec(vec!["b".to_string(), "d".to_string()], 2, 1)));
test_interpreter!(interpret_matrix_define_ref, r#"x:=123;y<[f64]:1,4>:=x;"#, Value::MatrixF64(Matrix::from_vec(vec![123.0; 4], 1, 4)));
#[cfg(all(feature = "f64", feature = "u8"))]
test_interpreter!(interpret_matrix_define_convert, r#"y<[f64]:1,3> := 123<u8>;"#, Value::MatrixF64(Matrix::from_vec(vec![123.0; 3], 1, 3)));
#[cfg(all(feature = "u64", feature = "u8"))]
test_interpreter!(interpret_matrix_define_convert_matrix, r#"x := [1 2 3];y<[u64]> := x;z<[u8]> := y;"#, Value::MatrixU8(Matrix::from_vec(vec![1u8, 2, 3], 1, 3)));

// 2x2 Nominal Operations 
test_interpreter!(interpret_matrix_add_2x2, "[1 2; 3 4] + [5 6; 7 8]", Value::MatrixF64(Matrix::from_vec(vec![6.0, 10.0, 8.0, 12.0], 2, 2)));
test_interpreter!(interpret_matrix_sub_2x2, "[1 2; 3 4] - [5 6; 7 8]", Value::MatrixF64(Matrix::from_vec(vec![-4.0, -4.0, -4.0, -4.0], 2, 2)));
test_interpreter!(interpret_matrix_mul_2x2, "[1 2; 3 4] * [5 6; 7 8]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 21.0, 12.0, 32.0], 2, 2)));
test_interpreter!(interpret_matrix_div_2x2, "[20 30; 40 50] / [2 3; 4 5]", Value::MatrixF64(Matrix::from_vec(vec![10.0, 10.0, 10.0, 10.0], 2, 2)));

// 3x3 Nominal Operations
test_interpreter!(interpret_matrix_add_3x3, "[1 2 3; 4 5 6; 7 8 9] + [9 8 7; 6 5 4; 3 2 1]", Value::MatrixF64(Matrix::from_vec(vec![10.0; 9], 3, 3)));
test_interpreter!(interpret_matrix_mul_3x3, "[1 2 3; 4 5 6; 7 8 9] * [9 8 7; 6 5 4; 3 2 1]", Value::MatrixF64(Matrix::from_vec(vec![9.0, 24.0, 21.0, 16.0, 25.0, 16.0, 21.0, 24.0, 9.0], 3, 3)));
test_interpreter!(interpret_matrix_div_3x3, "[10 20 30; 40 50 60; 70 80 90] / [10 10 10; 10 10 10; 10 10 10]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0], 3, 3)));


// 4x4 Nominal Operations
test_interpreter!(interpret_matrix_add_4x4, 
          "[1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16] + [17 18 19 20; 21 22 23 24; 25 26 27 28; 29 30 31 32]", 
          Value::MatrixF64(Matrix::from_vec(vec![18.0, 26.0, 34.0, 42.0, 
                              20.0, 28.0, 36.0, 44.0, 
                              22.0, 30.0, 38.0, 46.0, 
                              24.0, 32.0, 40.0, 48.0], 4, 4)));

test_interpreter!(interpret_matrix_sub_4x4, 
          "[1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16] - [17 18 19 20; 21 22 23 24; 25 26 27 28; 29 30 31 32]", 
          Value::MatrixF64(Matrix::from_vec(vec![-16.0, -16.0, -16.0, -16.0, 
                              -16.0, -16.0, -16.0, -16.0, 
                              -16.0, -16.0, -16.0, -16.0, 
                              -16.0, -16.0, -16.0, -16.0], 4, 4)));

test_interpreter!(interpret_matrix_mul_4x4, 
          "[1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16] * [17 18 19 20; 21 22 23 24; 25 26 27 28; 29 30 31 32]", 
          Value::MatrixF64(Matrix::from_vec(vec![17.0, 105.0, 225.0, 377.0, 
                              36.0, 132.0, 260.0, 420.0, 
                              57.0, 161.0, 297.0, 465.0, 
                              80.0, 192.0, 336.0, 512.0], 4, 4)));

test_interpreter!(interpret_matrix_div_4x4, 
          "[2 3 4 5; 6 7 8 9; 10 11 12 13; 14 15 16 17] / [2 2 2 2; 3 3 3 3; 4 4 4 4; 5 5 5 5]", 
          Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 2.5, 2.8, 
                              1.5, 2.3333333333333335, 2.75, 3.0, 
                              2.0, 2.6666666666666665, 3.0, 3.2, 
                              2.5, 3.0, 3.25, 3.4], 4, 4)));

// 2x3 Nominal Operations
test_interpreter!(interpret_matrix_sub_2x3, "[1 2 3; 4 5 6] - [7 8 9; 10 11 12]", 
          Value::MatrixF64(Matrix::from_vec(vec![-6.0, -6.0, -6.0, 
                              -6.0, -6.0, -6.0], 2, 3)));

// 3x2 Nominal Operations
test_interpreter!(interpret_matrix_sub_3x2, "[1 2; 3 4; 5 6] - [7 8; 9 10; 11 12]", 
          Value::MatrixF64(Matrix::from_vec(vec![-6.0, -6.0, 
                              -6.0, -6.0, 
                              -6.0, -6.0], 3, 2)));

// u8 2x2 Underflow/Overflow
/*test_interpreter!(interpret_matrix_underflow_2x2_u8_sub,
  "[1 2; 3 4] - [5 6; 7 8]",
  Ref::new(Matrix2::from_vec(vec![254u8, 255u8, 253u8, 254u8])).to_value() 
);*/
/*test_interpreter!(interpret_matrix_overflow_2x2_u8_add,
  "[250 251; 252 253] + [10 11; 12 13]",
  Ref::new(Matrix2::from_vec(vec![4u8, 6u8, 8u8, 10u8])).to_value() 
);*/

// u8 3x3 Underflow/Overflow
/*test_interpreter!(interpret_matrix_underflow_3x3_u8_sub,
  "[1 2 3; 4 5 6; 7 8 9] - [10 11 12; 13 14 15; 16 17 18]",
  Ref::new(Matrix3::from_vec(vec![251u8, 252u8, 253u8, 254u8, 255u8, 255u8, 253u8, 254u8, 255u8])).to_value()
);*/
/*test_interpreter!(interpret_matrix_overflow_3x3_u8_add,
  "[250 251 252; 253 254 255; 0 1 2] + [10 11 12; 13 14 15; 16 17 18]",
  Ref::new(Matrix3::from_vec(vec![4u8, 6u8, 8u8, 10u8, 11u8, 12u8, 16u8, 18u8, 20u8])).to_value()
);*/

test_interpreter!(interpret_tuple, "(1,true)", Value::Tuple(Ref::new(MechTuple::from_vec(vec![Value::F64(Ref::new(1.0)), Value::Bool(Ref::new(true))]))));
test_interpreter!(interpret_tuple_nested, r#"(1,("Hello",false))"#, Value::Tuple(Ref::new(MechTuple::from_vec(vec![Value::F64(Ref::new(1.0)), Value::Tuple(Ref::new(MechTuple::from_vec(vec![Value::String(Ref::new("Hello".to_string())), Value::Bool(Ref::new(false))])))]))));
test_interpreter!(interpret_tuple_access, r#"q := (10, "b", true); r := (q.3, q.2, q.1)"#, Value::Tuple(Ref::new(MechTuple::from_vec(vec![Value::Bool(Ref::new(true)), Value::String(Ref::new("b".to_string())), Value::F64(Ref::new(10.0))]))));
test_interpreter!(interpret_tuple_destructure, r#"a := (10, 11, 12); (x,y,z) := a; x + y + z"#, Value::F64(Ref::new(33.0)));
test_interpreter!(interpret_tuple_assign, r#"~t := (1,2); t.1 = 10; t.1 + t.2"#, Value::F64(Ref::new(12.0)));

test_interpreter!(interpret_slice, "a := [1,2,3]; a[2]", Value::F64(Ref::new(2.0)));
test_interpreter!(interpret_slice_v, "a := [1,2,3]'; a[2]", Value::F64(Ref::new(2.0)));
test_interpreter!(interpret_slice_2d, "a := [1,2;3,4]; a[1,2]", Value::F64(Ref::new(2.0)));
test_interpreter!(interpret_slice_f64, "a := [1.0,2.0,3.0]; a[2]", Value::F64(Ref::new(2.0)));
test_interpreter!(interpret_slice_2d_f64, "a := [1,2;3,4]; a[2,1]", Value::F64(Ref::new(3.0)));
test_interpreter!(interpret_slice_range_2d, "x := [1 2 3; 4 5 6; 7 8 9]; x[2..=3, 2..=3]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 8.0, 6.0, 9.0], 2, 2)));
test_interpreter!(interpret_slice_sclar_range, "ix := [true false true]'; x := [1 2 3; 4 5 6; 7 8 9]; x[2,ix]", Value::MatrixF64(Matrix::from_vec(vec![4.0, 6.0], 1, 2)));
test_interpreter!(interpret_slice_range_scalar, "ix := [true false true]'; x := [1 2 3; 4 5 6; 7 8 9]; x[ix,2]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 8.0], 2, 1)));
test_interpreter!(interpret_slice_all, "x := [1 2; 4 5]; x[:]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 2.0, 5.0], 4, 1)));
test_interpreter!(interpret_slice_all_2d, "x := [1 2; 4 5]; x[:,2]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 5.0], 2, 1)));
test_interpreter!(interpret_slice_all_2d_row, "x := [1 2; 4 5]; x[2,:]", Value::MatrixF64(Matrix::from_vec(vec![4.0, 5.0], 1, 2)));
test_interpreter!(interpret_slice_all_2d_row2, "x := [1 2 3 4 5; 6 7 8 9 10]; x[1,:]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0], 1, 5)));
test_interpreter!(interpret_slice_all_range, "x := [1 2 3 4; 5 6 7 8]; x[:,1..=2]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 5.0, 2.0, 6.0], 2, 2)));
test_interpreter!(interpret_slice_range_all, "x := [1 2 3; 4 5 6; 7 8 9]; x[1..=2,:]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0], 2, 3)));
test_interpreter!(interpret_slice_range_dupe, "x := [1 2 3; 4 5 6; 7 8 9]; x[[1 1],:]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 2.0, 3.0, 3.0], 2, 3)));
test_interpreter!(interpret_slice_all_reshape, "x := [1 2 3; 4 5 6; 7 8 9]; y := x[:,[1,1]]; y[:]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 7.0, 1.0, 4.0, 7.0], 6, 1)));
test_interpreter!(interpret_slice_ix_ref, "x := [94 53 13]; y := [3 3]; x[y]", Value::MatrixF64(Matrix::from_vec(vec![13.0, 13.0], 2, 1)));
test_interpreter!(interpret_slice_ix_ref2, "x := [94 53 13]; y := [3; 3]; x[y]", Value::MatrixF64(Matrix::from_vec(vec![13.0, 13.0], 2, 1)));
test_interpreter!(interpret_slice_ix_ref3, "x := [94 53 13]; y := 3; x[y]", Value::F64(Ref::new(13.0)));
test_interpreter!(interpret_slice_logical_ix, "x := [94 53 13]; ix := [false true true]; x[ix]", Value::MatrixF64(Matrix::from_vec(vec![53.0, 13.0], 2, 1)));
test_interpreter!(interpret_slice_row, "x := [94 53 13; 4 5 6; 7 8 9]; x[2,1..3]", Value::MatrixF64(Matrix::from_vec(vec![4.0, 5.0], 1, 2)));
test_interpreter!(interpret_slice_col, "x := [94 53 13; 4 5 6; 7 8 9]; x[1..3,2]", Value::MatrixF64(Matrix::from_vec(vec![53.0, 5.0], 2, 1)));
test_interpreter!(interpret_slice_dynamic, "x := 1..10; y := x'; ix := 1..5; y[ix]'", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0], 1, 4)));
test_interpreter!(interpret_slice_all_bool, "ix := [false, false, true]'; x := [1 2 3; 4 5 6; 7 8 9]; x[:,ix]", Value::MatrixF64(Matrix::from_vec(vec![3.0, 6.0, 9.0], 3, 1)));
test_interpreter!(interpret_slice_ix_bool, "ix := [false, false, true]; x := [1 2 3; 4 5 6; 7 8 9]; x[[1,2,3,3],ix]", Value::MatrixF64(Matrix::from_vec(vec![3.0, 6.0, 9.0, 9.0], 4, 1)));
test_interpreter!(interpret_slice_bool_bool, "ix := [true, false, true]; x := [1 2 3; 4 5 6;7 8 9]; x[ix,ix]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 7.0, 3.0, 9.0], 2, 2)));
test_interpreter!(interpret_slice_ix_bool_v, "ix1 := [false, false, true]; ix2 := [1,2,3,3]; x := [1 2 3; 4 5 6; 7 8 9]; x[ix1',ix2']", Value::MatrixF64(Matrix::from_vec(vec![7.0, 8.0, 9.0, 9.0], 1, 4)));


test_interpreter!(interpret_swizzle_record, "x := {x: 1, y: 2, z: 3}; x.y,z,z", Value::Tuple(Ref::new(MechTuple::from_vec(vec![Value::F64(Ref::new(2.0)),Value::F64(Ref::new(3.0)),Value::F64(Ref::new(3.0))]))));
//test_interpreter!(interpret_swizzle_table, "x := | x<i64> y<u8>| 1 2 | 4 5 |; x.x,x,y", Value::Tuple(MechTuple::from_vec(vec![Matrix::Vector2(Ref::new(Vector2::from_vec(vec![Value::I64(Ref::new(1)),Value::I64(Ref::new(4))]))).to_value(),Matrix::Vector2(Ref::new(Vector2::from_vec(vec![Value::I64(Ref::new(1)),Value::I64(Ref::new(4))]))).to_value(),Matrix::Vector2(Ref::new(Vector2::from_vec(vec![Value::U8(Ref::new(2)),Value::U8(Ref::new(5))]))).to_value()])));

test_interpreter!(interpret_dot_record, "x := {x: 1, y: 2, z: 3}; x.x", Value::F64(Ref::new(1.0)));

test_interpreter!(interpret_dot_int_matrix, "x := [1,2,3]; x.1", Value::F64(Ref::new(1.0)));
#[cfg(all(feature = "i64", feature = "u8"))]
test_interpreter!(interpret_dot_index_table, "x :=  | x<i64> y<u8>| 1 2 | 4 5|; x.x", Value::MatrixI64(Matrix::from_vec(vec![1, 4], 2, 1)));
#[cfg(all(feature = "i64", feature = "u8"))]
test_interpreter!(interpret_dot_index_table2, "x := | x<i64> y<u8>| 1 2 | 4 5|; x.y", Value::MatrixU8(Matrix::from_vec(vec![2, 5], 2, 1)));
#[cfg(feature = "i64")]
test_interpreter!(interpret_dot_index_table3, "x := | x<i64> y<bool>| 1 true | 4 false | 3 true|; x.y", Value::MatrixBool(Matrix::from_vec(vec![true, false, true], 3, 1)));
#[cfg(all(feature = "i64", feature = "u8"))]
test_interpreter!(interpret_dot_index_table4, "x := | x<i64> y<u8>| 1 2| 3 4| 5 6| 7 8 |; x.x", Value::MatrixI64(Matrix::from_vec(vec![1, 3, 5, 7], 4, 1)));
#[cfg(all(feature = "i64", feature = "i8"))]
test_interpreter!(interpret_dot_index_table5, "x := | x<i64> y<i8>| 1 2| 3 4| 5 6| 7 8 |; x.y", Value::MatrixI8(Matrix::from_vec(vec![2, 4, 6, 8], 4, 1)));
#[cfg(all(feature = "u32", feature = "f32", feature = "i8"))]
test_interpreter!(interpret_dot_index_table6, "x := | x<u32> y<f32> z<i8>|1 2 3|4 5 6|; x.y", Value::MatrixF32(Matrix::from_vec(vec![2.0, 5.0], 2, 1)));

test_interpreter!(interpret_set_empty,"{_}", Value::Set(Ref::new(MechSet::from_vec(vec![]))));
test_interpreter!(interpret_set_empty2,"{}", Value::Set(Ref::new(MechSet::from_vec(vec![]))));
test_interpreter!(interpret_set, "{1,2,3}", Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(1.0)), Value::F64(Ref::new(2.0)), Value::F64(Ref::new(3.0))]))));
test_interpreter!(interpret_record,r#"{a: 1, b: "Hello"}"#, Value::Record(Ref::new(MechRecord::from_vec(vec![((55170961230981453,"a".to_string()),Value::F64(Ref::new(1.0))),((44311847522083591,"b".to_string()),Value::String(Ref::new("Hello".to_string())))]))));
test_interpreter!(interpret_define_custom_record, r#"<point2>:=<{a<f64>,b<f64>}>; p<point2>:={a:1.0,b:2.0}"#, Value::Record(Ref::new(MechRecord::from_vec(vec![((55170961230981453,"a".to_string()),Value::F64(Ref::new(1.0))),((44311847522083591,"b".to_string()),Value::F64(Ref::new(2.0)))]))));
test_interpreter!(interpret_record_field_access,r#"a := {x: 1,  y: 2}; a.y"#, Value::F64(Ref::new(2.0)));
test_interpreter!(interpret_map, r#"{"a": 1, "b": 2}"#, Value::Map(Ref::new(MechMap::from_vec(vec![(Value::String(Ref::new("a".to_string())),Value::F64(Ref::new(1.0))), (Value::String(Ref::new("b".to_string())),Value::F64(Ref::new(2.0)))]))));
test_interpreter!(interpret_map_access, r#"m := {"a": 10, "b": 20}; m{"b"}"#, Value::F64(Ref::new(20.0)));
test_interpreter!(interpret_map_assign, r#"~m := {"a": 10, "b": 20}; m{"b"} = 42; m{"b"}"#, Value::F64(Ref::new(42.0)));
test_interpreter!(interpret_map_assign2, r#"~m := {"a": 10, "b": 20}; m{"c"} = 42; m{"c"}"#, Value::F64(Ref::new(42.0)));
test_interpreter!(interpret_set_rational, r#"{1/2, 3/4}"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::R64(Ref::new(R64::new(1, 2))), Value::R64(Ref::new(R64::new(3, 4)))]))));

test_interpreter!(interpret_function_define,r#"foo(x<f64>) = z<f64> :=
z := 10 + x.
foo(10)"#, Value::F64(Ref::new(20.0)));
test_interpreter!(interpret_function_define_2_args,r#"foo(x<f64>, y<f64>) = z<f64> :=
z := x + y.
foo(10,20)"#, Value::F64(Ref::new(30.0)));
test_interpreter!(interpret_function_define_statements,r#"foo(x<f64>, y<f64>) = z<f64> :=
    a := 1 + x
    b := y + 1
    z := a + b.
foo(10,20)"#, Value::F64(Ref::new(32.0)));
test_interpreter!(interpret_function_define_nested_call,r#"bar(x<f64>) = z<f64> :=
z := 10 + x.
foo(x<f64>) = z<f64> :=
z := bar(x).
foo(10)"#, Value::F64(Ref::new(20.0)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_function_recursive_max,r#"max(x<u64>, y<u64>) => <u64>
  ├ (0, y) => y
  ├ (x, 0) => x
  └ (x, y) => max(x - 1<u64>, y - 1<u64>) + 1<u64>.
max(4<u64>, 7<u64>)"#, Value::U64(Ref::new(7)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_function_recursive_is_zero,r#"is-zero(x<u64>) => <bool>
  ├ 0 => true
  └ * => false.
is-zero(0<u64>)"#, Value::Bool(Ref::new(true)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_function_recursive_factorial_tree,r#"factorial(x<u64>) => <u64>
  ├ 0 => 1
  └ n => n * factorial(n - 1<u64>).
factorial(5<u64>)"#, Value::U64(Ref::new(120)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_function_recursive_factorial_bar,r#"factorial(x<u64>) => <u64>
  | 0 => 1
  | n => n * factorial(n - 1<u64>).
factorial(6<u64>)"#, Value::U64(Ref::new(720)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_function_recursive_fib,r#"fib(x<u64>) => <u64>
  ├ 0 => 0
  ├ 1 => 1
  └ n => fib(n - 1<u64>) + fib(n - 2<u64>).
fib(10<u64>)"#, Value::U64(Ref::new(55)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_function_recursive_power,r#"power(x<u64>, y<u64>) => <u64>
  ├ (*, 0) => 1
  └ (x, y) => x * power(x, y - 1<u64>).
power(2<u64>, 10<u64>)"#, Value::U64(Ref::new(1024)));
test_interpreter!(interpret_function_call_native_vector, "math/sin([1.570796327 1.570796327])", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0], 1, 2)));
test_interpreter!(interpret_function_call_native, r#"math/sin(1.5707963267948966)"#, Value::F64(Ref::new(1.0)));
test_interpreter!(interpret_function_call_native_cos, r#"math/cos(0.0)"#, Value::F64(Ref::new(1.0)));
test_interpreter!(interpret_function_call_native_vector2, "math/cos([0.0 0.0])", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0], 1, 2)));
test_interpreter!(interpret_user_function_scalar_auto_broadcast, r#"add-one(x<f64>) => <f64>
  | * => x + 1.
add-one([1 2 3])"#, Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 4.0], 1, 3)));

test_interpreter!(interpret_set_value,"~x := 1.23; x = 4.56;", Value::F64(Ref::new(4.56)));
test_interpreter!(interpret_set_value_row_vector,"~x := [6,2]; x[1] = 4;", Value::MatrixF64(Matrix::from_vec(vec![4.0, 2.0], 1, 2)));
test_interpreter!(interpret_set_value_col_vector,"~x := [false false true true]'; x[1] = true; x[1]", Value::Bool(Ref::new(true)));
test_interpreter!(interpret_set_value_scalar_scalar,"~x := [1 2; 3 4]; x[2,2] = 42; x[2,2];", Value::F64(Ref::new(42.0)));
test_interpreter!(interpret_set_value_all,"~x := [1 2; 3 4]; x[:] = 42; x[1] + x[2] + x[3] + x[4]; ", Value::F64(Ref::new(168.0)));
test_interpreter!(interpret_set_value_all_scalar,"~x := [1 2; 3 4]; x[:,1] = 42; x[1] + x[2] + x[3] + x[4]", Value::F64(Ref::new(90.0)));
test_interpreter!(interpret_set_value_scalar_all,"~x := [1 2; 3 4]; x[1,:] = 42; x[1] + x[3];", Value::F64(Ref::new(84.0)));
test_interpreter!(interpret_set_value_slice,"~x := [1 2 3 4]; x[[1 3]] = 42; x[1] + x[2] + x[3] + x[4];", Value::F64(Ref::new(90.0)));
test_interpreter!(interpret_set_value_scalar_slice,"~x := [1 2 3; 4 5 6; 7 8 9]; x[1,[1,3]] = 42; x[1] + x[7];", Value::F64(Ref::new(84.0)));
test_interpreter!(interpret_set_value_slice_slice,"~x := [1 2 3; 5 6 7; 9 10 11]; x[1..3,1..3] = 42; x[1] + x[2] + x[4] + x[5]", Value::F64(Ref::new(168.0)));
test_interpreter!(interpret_set_value_all_slice,"~x := [1 2 3; 5 6 7]; x[:,1..3] = 42; x[1] + x[2] + x[3] + x[4] + x[5] + x[6]", Value::F64(Ref::new(178.0)));
test_interpreter!(interpret_set_value_all_slice_vec,"~x := [1;6]; x = [4;5]; x[1] + x[2];", Value::F64(Ref::new(9.0)));
test_interpreter!(interpret_set_value_slice_all,"~x := [1 2 3; 5 6 7]'; x[1..3,:] = 42; x[1] + x[2] + x[3] + x[4] + x[5] + x[6]", Value::F64(Ref::new(178.0)));
test_interpreter!(interpret_set_value_slice_vec,"~x := [1 2 3 4]; x[1..=3] = [10 20 30]; x[1] + x[2] + x[3] + x[4]", Value::F64(Ref::new(64.0)));

test_interpreter!(interpret_set_record_field,"~x := {a: 1, b: true}; x.a = 2; x.a;", Value::F64(Ref::new(2.0)));
test_interpreter!(interpret_set_record_field2,"~x := {a: 1, b: true}; x.b = false; x.b;", Value::Bool(Ref::new(false)));
#[cfg(feature = "u64")]
test_interpreter!(interpret_set_record_field3,"~x := {a: 1<u64>, b: true}; x.a = 2<u64>; x.a;", Value::U64(Ref::new(2)));

test_interpreter!(interpret_set_table_col,"~x := | x<f64> y<f64> | 1 2 | 3 4 |; x.x = [42;46]; y := x.x; y[1] + y[2]", Value::F64(Ref::new(88.0)));
test_interpreter!(interpret_set_table_col2,"~x := | x<f64> y<f64> | 1 2 | 3 4 | 5 6 | 7 8 |; x.x = [42;46;47;48]; y := x.x; y[1] + y[2] + y[3] + y[4];", Value::F64(Ref::new(183.0)));
test_interpreter!(interpret_set_table_col_string,r#"~x := | x<string> | "a" | "b" |; x.x = ["c";"d"]; x.x"#, Value::MatrixString(Matrix::from_vec(vec!["c".to_string(), "d".to_string()], 2, 1)));

test_interpreter!(interpret_set_logical,"~x := [1 2 3]; ix := [true false true]; x[ix] = 4; x[1] + x[2] + x[3];", Value::F64(Ref::new(10.0)));
test_interpreter!(interpret_set_logical2,"~x := [1 2 3 4]; ix := [true false true true]; x[ix] = 5; x[1] + x[2] + x[3] + x[4];", Value::F64(Ref::new(17.0)));
test_interpreter!(interpret_set_logical_scalar,"~x := [1 2 3]; x[4 > 3] = 5; x[1] + x[2] + x[3]", Value::F64(Ref::new(15.0)));

test_interpreter!(interpret_set_logical_vector_scalar_bool,"~x := [1 2; 4 5]; x[[true false], 2] = 42; x[1] + x[2] + x[3] + x[4];", Value::F64(Ref::new(52.0)));
test_interpreter!(interpret_set_logical_scalar_vector_bool,"~x := [1 2; 4 5]; x[2,[false true]] = 42; x[1] + x[2] + x[3] + x[4]", Value::F64(Ref::new(49.0)));
test_interpreter!(interpret_set_logical_vector_vector_bool,"~x := [1 2; 4 5]; x[[true false],[false true]] = 42;", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 42.0, 5.0], 2, 2)));

test_interpreter!(interpret_set_logical_all_vector_bool,"~x := [1 2; 4 5]; x[:,[1 2]] = 42; x[1] + x[2] + x[3] + x[4]", Value::F64(Ref::new(168.0)));

test_interpreter!(interpret_horzcat,"x := [1 2]; y := [x 3]; y[1] + y[2] + y[3]", Value::F64(Ref::new(6.0)));
test_interpreter!(interpret_horzcat_r2m1,"x := [1 2]; z := [3]; y := [x z]; y[1] + y[2] + y[3]", Value::F64(Ref::new(6.0)));
test_interpreter!(interpret_horzcat_m1r2,"x := [1 2]; z := [3]; y := [z x]; y[1] + y[2] + y[3]", Value::F64(Ref::new(6.0)));
test_interpreter!(interpret_horzcat_sr2,"x := [1 2]; y := [3 x]; y[1] + y[2] + y[3]", Value::F64(Ref::new(6.0)));

test_interpreter!(interpret_horzcat_r2s,"x := [1 2]; y := [x 3];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0], 1, 3)));
test_interpreter!(interpret_horzcat_m1,"x := [1]; y := [x]", Value::MatrixF64(Matrix::from_vec(vec![1.0], 1, 1)));
test_interpreter!(interpret_horzcat_r2,"x := [1 2]; y := [x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0], 1, 2)));

test_interpreter!(interpret_horzcat_sm1,"x := [2]; y := [1 x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0], 1, 2)));
test_interpreter!(interpret_horzcat_m1s,"x := [2]; y := [x 1]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 1.0], 1, 2)));
test_interpreter!(interpret_horzcat_m1m1,"x := [2]; y := [x x]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 2.0], 1, 2)));

test_interpreter!(interpret_horzcat_sr3,"x := [1 2 3]; y := [1 x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_r3s,"x := [1 2 3]; y := [x 1]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0], 1, 4)));
test_interpreter!(interpret_horzcat_r2r2,"x := [1 2]; y := [x x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 1.0, 2.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1r3,"x := [1 2 3]; z := [1]; y := [z x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_r3m1,"x := [1 2 3]; z := [1]; y := [x z]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0], 1, 4)));

test_interpreter!(interpret_horzcat_ssm1,"x := [3]; y := [1 2 x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0], 1, 3)));
test_interpreter!(interpret_horzcat_sm1s,"x := [3]; y := [1 x 2]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 2.0], 1, 3)));
test_interpreter!(interpret_horzcat_m1ss,"x := [3]; y := [x 1 2]", Value::MatrixF64(Matrix::from_vec(vec![3.0, 1.0, 2.0], 1, 3)));
test_interpreter!(interpret_horzcat_m1m1m1,"x := [3]; y := [x x x]", Value::MatrixF64(Matrix::from_vec(vec![3.0, 3.0, 3.0], 1, 3)));
test_interpreter!(interpret_horzcat_sm1m1,"x := [3]; z:= [2]; y := [1 z x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0], 1, 3)));
test_interpreter!(interpret_horzcat_m1sm1,"x := [3]; z:= [2]; y := [z 1 x]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 1.0, 3.0], 1, 3)));
test_interpreter!(interpret_horzcat_m1m1s,"x := [3]; z:= [2]; y := [z x 1]", Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 1.0], 1, 3)));

test_interpreter!(interpret_horzcat_m1m1r2,"x := [1]; y:= [2 3]; z := [x x y];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1r2m1,"x := [1]; y:= [2 3]; z := [x y x];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0], 1, 4)));
test_interpreter!(interpret_horzcat_r2m1m1,"x := [1]; y:= [2 3]; z := [y x x];", Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 1.0, 1.0], 1, 4)));

test_interpreter!(interpret_horzcat_ssr2,"y:= [2 3]; z := [1 1 y];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_sr2s,"y:= [2 3]; z := [1 y 1];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0], 1, 4)));
test_interpreter!(interpret_horzcat_r2ss,"y:= [2 3]; z := [y 1 1];", Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 1.0, 1.0], 1, 4)));

test_interpreter!(interpret_horzcat_sm1r2,"x := [1]; y:= [2 3]; z := [1 x y];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1sr2, "x := [1]; y:= [2 3]; z := [x 1 y];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_sr2m1, "x := [1]; y:= [2 3]; z := [1 y x];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1r2s, "x := [1]; y:= [2 3]; z := [x y 1];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0], 1, 4)));
test_interpreter!(interpret_horzcat_r2sm1, "x := [1]; y:= [2 3]; z := [y 1 x];", Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 1.0, 1.0], 1, 4)));
test_interpreter!(interpret_horzcat_r2m1s, "x := [1]; y:= [2 3]; z := [y x 1];", Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, 1.0, 1.0], 1, 4)));

test_interpreter!(interpret_horzcat_sssm1, "x := [4]; y := [1 2 3 x];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1sss, "x := [4]; y := [x 1 2 3];", Value::MatrixF64(Matrix::from_vec(vec![4.0, 1.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_sm1ss, "x := [4]; y := [1 x 2 3];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 2.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_ssm1s, "x := [4]; y := [1 2 x 3];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 4.0, 3.0], 1, 4)));
test_interpreter!(interpret_horzcat_sm1sm1, "x := [4]; z := [5]; y := [1 x 2 z];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 2.0, 5.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1ssm1, "x := [4]; z := [5]; y := [x 1 2 z];", Value::MatrixF64(Matrix::from_vec(vec![4.0, 1.0, 2.0, 5.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1sm1s, "x := [4]; z := [5]; y := [x 1 z 2];", Value::MatrixF64(Matrix::from_vec(vec![4.0, 1.0, 5.0, 2.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1m1sm1, "x := [4]; z := [5]; w := [6]; y := [x z 1 w];", Value::MatrixF64(Matrix::from_vec(vec![4.0, 5.0, 1.0, 6.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1m1m1s, "x := [4]; z := [5]; w := [6]; y := [x z w 1];", Value::MatrixF64(Matrix::from_vec(vec![4.0, 5.0, 6.0, 1.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1sm1m1, "x := [4]; z := [5]; w := [6]; y := [x 1 z w];", Value::MatrixF64(Matrix::from_vec(vec![4.0, 1.0, 5.0, 6.0], 1, 4)));
test_interpreter!(interpret_horzcat_sm1m1m1, "x := [4]; z := [5]; w := [6]; y := [1 x z w];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 5.0, 6.0], 1, 4)));
test_interpreter!(interpret_horzcat_m1m1m1m1, "x := [4]; z := [5]; w := [6]; v := [7]; y := [x z w v];", Value::MatrixF64(Matrix::from_vec(vec![4.0, 5.0, 6.0, 7.0], 1, 4)));

test_interpreter!(interpret_horzcat_m2m2m2, "x := [1 2]; y := [x x x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 1.0, 2.0, 1.0, 2.0], 1, 6)));

test_interpreter!(interpret_horzcat_rd2, "x := [1 2 3 4 5]; y := [x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0], 1, 5)));
test_interpreter!(interpret_horzcat_rd4, "a := [1];b := [2 3];c := [4 5 6];d := [7 8 9 10];z := [a b c d];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0], 1, 10)));
test_interpreter!(interpret_horzcat_rd3, "a := [1 1]; z := [a a a];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 1.0, 1.0, 1.0, 1.0], 1, 6)));
test_interpreter!(interpret_horzcat_rdn, "a := [1 2 3]; z := [0 0 0 0 0 a];", Value::MatrixF64(Matrix::from_vec(vec![0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0], 1, 8)));

test_interpreter!(interpret_horzcat_m2m2, "a := [1 2; 3 4]; z := [a a];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 2.0, 4.0, 1.0, 3.0, 2.0, 4.0], 2, 4)));

test_interpreter!(interpret_horzcat_m2x3v2, "x := [1 2 3; 4 5 6]; z := [7 8]'; a := [x z];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0, 7.0, 8.0], 2, 4)));
test_interpreter!(interpret_horzcat_v2m2x3, "x := [1 2 3; 4 5 6]; z := [7 8]'; a := [z x];", Value::MatrixF64(Matrix::from_vec(vec![7.0, 8.0, 1.0, 4.0, 2.0, 5.0, 3.0, 6.0], 2, 4)));

test_interpreter!(interpret_horzcat_v2v2, "x := [1;2]; y := [x x];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 1.0, 2.0], 2, 2)));
test_interpreter!(interpret_horzcat_v3v3, "x := [1;2;3]; y := [x x];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0, 2.0, 3.0], 3, 2)));
test_interpreter!(interpret_horzcat_v4v4, "x := [1;2;3;4]; y := [x x];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0, 4.0], 4, 2)));
test_interpreter!(interpret_horzcat_vdvd, "x := [1;2;3;4;5]; y := [x x];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 1.0, 2.0, 3.0, 4.0, 5.0], 5, 2)));

test_interpreter!(interpret_horzcat_v2m2, "x := [1 2; 3 4]; y := [1; 2]; z := [y x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 1.0, 3.0, 2.0, 4.0], 2, 3)));
test_interpreter!(interpret_horzcat_m2v2, "x := [1 2; 3 4]; y := [1; 2]; z := [x y]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 2.0, 4.0, 1.0, 2.0], 2, 3)));


test_interpreter!(interpret_horzcat_m3x2v3, "x := [1 2; 3 4; 5 6]; y := [1; 2; 3]; z := [x y]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 5.0, 2.0, 4.0, 6.0, 1.0, 2.0, 3.0], 3, 3)));
test_interpreter!(interpret_horzcat_v3m3x2, "x := [1 2; 3 4; 5 6]; y := [1; 2; 3]; z := [y x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 1.0, 3.0, 5.0, 2.0, 4.0, 6.0], 3, 3)));

test_interpreter!(interpret_horzcat_mdv4, "x := [1 2; 3 4; 5 6; 7 8]; y := [1; 2; 3; 4]; z := [x y]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 5.0, 7.0, 2.0, 4.0, 6.0, 8.0, 1.0, 2.0, 3.0, 4.0], 4, 3)));
test_interpreter!(interpret_horzcat_v4md, "x := [1 2; 3 4; 5 6; 7 8]; y := [1; 2; 3; 4]; z := [y x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 1.0, 3.0, 5.0, 7.0, 2.0, 4.0, 6.0, 8.0], 4, 3)));

test_interpreter!(interpret_horzcat_mdvd, "x := [1 2; 3 4; 5 6; 7 8; 9 10]; y := [1; 2; 3; 4; 5]; z := [x y]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 5.0, 7.0, 9.0, 2.0, 4.0, 6.0, 8.0, 10.0, 1.0, 2.0, 3.0, 4.0, 5.0], 5, 3)));
test_interpreter!(interpret_horzcat_vdmd, "x := [1 2; 3 4; 5 6; 7 8; 9 10]; y := [1; 2; 3; 4; 5]; z := [y x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 1.0, 3.0, 5.0, 7.0, 9.0, 2.0, 4.0, 6.0, 8.0, 10.0], 5, 3)));

test_interpreter!(interpret_horzcat_m2, "x := [1 2; 3 4]; z := [x]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 2.0, 4.0], 2, 2)));

test_interpreter!(interpret_horzcat_m3v3, "x := [1 2 3; 4 5 6; 7 8 9]; y := [1;2;3]; z := [x y]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 4.0, 7.0, 2.0, 5.0, 8.0, 3.0, 6.0, 9.0, 1.0, 2.0, 3.0], 3, 4)));

test_interpreter!(interpret_horzcat_v2v2v2v2, "x := [1; 2;]; z := [x x x x] ", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0], 2, 4)));
test_interpreter!(interpret_horzcat_v2v2v2v2v2, "x := [1; 2;]; z := [x x x x x] ", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0, 1.0, 2.0], 2, 5)));
test_interpreter!(interpret_vertcat_vd2, "x := [1;2;3;4]; z := [5]; y := [x;z]", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0], 5, 1)));
test_interpreter!(interpret_vertcat_vd3, "x := [1;2;3]; z := [5]; y := [z;z;x]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 5.0, 1.0, 2.0, 3.0], 5, 1)));
test_interpreter!(interpret_vertcat_m1m1m1m1, "x := [5]; y := [x;x;x;x]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 5.0, 5.0, 5.0], 4, 1)));
test_interpreter!(interpret_vertcat_vd4, "x := [5]; z := [1;2]; y := [x;x;x;z]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 5.0, 5.0, 1.0, 2.0], 5, 1)));

test_interpreter!(interpret_vertcat_vdn, "x := [5]; y := [x;x;x;x;x]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 5.0, 5.0, 5.0, 5.0], 5, 1)));
test_interpreter!(interpret_vertcat_r2m2, "x := [5 2;3 4]; y := [8 9];z := [y;x]", Value::MatrixF64(Matrix::from_vec(vec![8.0, 5.0, 3.0, 9.0, 2.0, 4.0], 3, 2)));
test_interpreter!(interpret_vertcat_m2r2, "x := [5 2;3 4]; y := [8 9];z := [x;y]", Value::MatrixF64(Matrix::from_vec(vec![5.0, 3.0, 8.0, 2.0, 4.0, 9.0], 3, 2)));

test_interpreter!(interpret_vertcat_r2m2x3, "x := [1 2 3; 4 5 6]; y := [7 8 9]; z := [y;x]", Value::MatrixF64(Matrix::from_vec(vec![7.0, 1.0, 4.0, 8.0, 2.0, 5.0, 9.0, 3.0, 6.0], 3, 3)));

test_interpreter!(interpret_stats_sum_rowm2, "x := [1 2; 4 5]; y := stats/sum/row(x);", Value::MatrixF64(Matrix::from_vec(vec![5.0, 7.0], 1, 2)));

test_interpreter!(interpret_add_assign, "~x := 10; x += 20", Value::F64(Ref::new(30.0)));
test_interpreter!(interpret_add_assign_formula, "ix := [1 1 2 3]; y := 5; ~x := [1 2 3 4]; x[ix] += y;", Value::MatrixF64(Matrix::from_vec(vec![11.0, 7.0, 8.0, 4.0], 1, 4)));
test_interpreter!(interpret_add_assign_formula_all_m2m2,"~x := [1 2; 3 4]; y := [1 1 1 1];z := [10 10; 20 20]; x[y,:] += z;", Value::MatrixF64(Matrix::from_vec(vec![61.0, 3.0, 62.0, 4.0], 2, 2)));
test_interpreter!(interpret_sub_assign_formula, "ix := [1 1 2 3]; y := 5; ~x := [1 2 3 4]; x[ix] -= y;", Value::MatrixF64(Matrix::from_vec(vec![-9.0, -3.0, -2.0, 4.0], 1, 4)));
test_interpreter!(interpret_mul_assign_formula, "ix := [1 1 2 3]; y := 5; ~x := [1 2 3 4]; x[ix] *= y;", Value::MatrixF64(Matrix::from_vec(vec![25.0, 10.0, 15.0, 4.0], 1, 4)));
test_interpreter!(interpret_add_assign_range, "~x := [1 2; 3 4]; x[1..3] += 1", Value::MatrixF64(Matrix::from_vec(vec![2.0, 4.0, 2.0, 4.0], 2, 2)));
test_interpreter!(interpret_div_assign_range_all, "~x := [1 2; 3 4; 5 6]; x[1..3,:] /= [1 2; 3 4];", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 5.0, 1.0, 1.0, 6.0], 3, 2)));
test_interpreter!(interpret_div_assign_range, "~x := [1 2 3 4]; x[1..3] /= 2;", Value::MatrixF64(Matrix::from_vec(vec![0.5, 1.0, 3.0, 4.0], 1, 4)));
test_interpreter!(interpret_add_assign_range_vec, "~x := [1 2 3 4]; x[1..3] += 2;", Value::MatrixF64(Matrix::from_vec(vec![3.0, 4.0, 3.0, 4.0], 1, 4)));

test_interpreter!(interpret_set_logical_ram2m2_bool,"~x := [1 2; 3 4]; y := [true false]; z := [10 20; 30 40]; x[y,:] = z;", Value::MatrixF64(Matrix::from_vec(vec![10.0, 3.0, 20.0, 4.0], 2, 2)));
test_interpreter!(interpret_set_logical_ram3m3_bool,"~x := [1 2 3; 4 5 6; 7 8 9]; y := [true false true]; z := [10 20 30; 40 50 60; 70 80 90]; x[y,:] = z;", Value::MatrixF64(Matrix::from_vec(vec![10.0, 4.0, 70.0, 20.0, 5.0, 80.0, 30.0, 6.0, 90.0], 3, 3)));
test_interpreter!(interpret_set_logical_ram4m4_bool,"~x := [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]; y := [true false true false]; z := [10 20 30 40; 50 60 70 80; 90 100 110 120; 130 140 150 160]; x[y,:] = z;", Value::MatrixF64(Matrix::from_vec(vec![10.0, 5.0, 90.0, 13.0, 20.0, 6.0, 100.0, 14.0, 30.0, 7.0, 110.0, 15.0, 40.0, 8.0, 120.0, 16.0], 4, 4)));

test_interpreter!(interpret_set_logical_ram2m2,"~x := [1 2; 3 4]; y := [2 1]; x[y,:] = x;", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 2.0, 2.0], 2, 2)));
test_interpreter!(interpret_set_logical_ram3m3,"~x := [1 2 3; 4 5 6; 7 8 9]; y := [2 1 3]; x[y,:] = x;", Value::MatrixF64(Matrix::from_vec(vec![1.0, 1.0, 7.0, 2.0, 2.0, 8.0, 3.0, 3.0, 9.0], 3, 3)));

test_interpreter!(interpret_modulus,"[1 2 3 4 5] % 5", Value::MatrixF64(Matrix::from_vec(vec![1.0, 2.0, 3.0, 4.0, 0.0], 1, 5)));

test_interpreter!(interpret_horzcat_rdn2, "y := [4 5 6]; [y y y * 2]", Value::MatrixF64(Matrix::from_vec(vec![4.0, 5.0, 6.0, 4.0, 5.0, 6.0, 8.0, 10.0, 12.0], 1, 9)));

#[cfg(feature = "u8")]
test_interpreter!(interpret_fancy_table, r#"x := |x<f64> y<u8>|
     |1      2    |
     |3      4    |
     |5      6    |
x.x"#, Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 5.0], 3, 1)));

test_interpreter!(interpret_fancy_matrix, r#"
x := ┏       ┓
     ┃ 1   2 ┃
     ┃ 3   4 ┃
     ┗       ┛"#, Value::MatrixF64(Matrix::from_vec(vec![1.0, 3.0, 2.0, 4.0], 2, 2)));

#[cfg(all(feature = "f32", feature = "u64"))]
test_interpreter!(interpret_fancy_table2, r#"
x:=╭────────┬────────╮
   │ x<u64> │ y<f32> │
   ├────────┼────────┤
   │   1    │   2    │
   ├────────┼────────┤
   │   3    │   4    │
   ╰────────┴────────╯
x.x"#, Value::MatrixU64(Matrix::from_vec(vec![1_u64, 3], 2, 1)));

#[cfg(all(feature = "f32", feature = "u64"))]
test_interpreter!(interpret_fancy_table3, r#"
x:=╭────────┬────────╮
   │ x<u64> │ y<f32> │
   │   1    │   2    │
   │   3    │   4    │
   ╰────────┴────────╯
x.x"#, Value::MatrixU64(Matrix::from_vec(vec![1_u64, 3], 2, 1)));

#[cfg(all(feature = "f32", feature = "u64"))]
test_interpreter!(interpret_fancy_table4, r#"
x:=╭────────┬────────╮
   │ x<u64> │ y<f32> │
   ├────────┼────────┤
   │        │        │
   │   1    │   2    │
   │        │        │
   │        │        │
   │   3    │   4    │
   │        │        │
   ╰────────┴────────╯
x.x"#, Value::MatrixU64(Matrix::from_vec(vec![1_u64, 3], 2, 1)));
#[cfg(feature = "f32")]
test_interpreter!(interpret_table_access_element, r#"a:=|x<f32>|1.2|1.3|; a.x[1]"#, Value::F32(Ref::new(1.2)));
#[cfg(all(feature = "f32", feature = "u8"))]
test_interpreter!(interpret_table_access_row, r#"x:=|a<f32> b<u8>|1.2 3 |1.3 4|; x[2]"#, Value::Record(Ref::new(MechRecord::new(vec![("a",Value::F32(Ref::new(1.3))),("b",Value::U8(Ref::new(4)))]))));
test_interpreter!(interpret_table_append_row, r#"~x:=|a<f64> b<f64>|1 2 |3 4|; x += {a<f64>: 5, b<f64>: 6}; x[3]"#, Value::Record(Ref::new(MechRecord::new(vec![("a",Value::F64(Ref::new(5.0))),("b",Value::F64(Ref::new(6.0)))]))));
test_interpreter!(interpret_table_append_row2, r#"~x:=|a<f64> b<f64>|1 2 |3 4|; x += {b<f64>: 6, a<f64>: 5}; x[3]"#, Value::Record(Ref::new(MechRecord::new(vec![("b",Value::F64(Ref::new(6.0))),("a",Value::F64(Ref::new(5.0)))]))));
#[cfg(all(feature = "u8", feature = "u64"))]
test_interpreter!(interpret_table_append_row3, r#"~x := |a<u64> b<u8>| 1 2 | 3 4 |; a:=13; b:=14; y := {c<bool>: false, a<u64>: a, b<u8>: b}; x += y; x[3]"#, Value::Record(Ref::new(MechRecord::new(vec![("a",Value::U64(Ref::new(13))),("b",Value::U8(Ref::new(14)))]))));
#[cfg(all(feature = "u8", feature = "u64"))]
test_interpreter!(interpret_table_append_table, r#"~x := |a<u64> b<u8>| 1 2 | 3 4 |;y := |a<u64> b<u8>| 5 6 | 7 8 |; x += y; x[4]"#, Value::Record(Ref::new(MechRecord::new(vec![("a",Value::U64(Ref::new(7))),("b",Value::U8(Ref::new(8)))]))));
#[cfg(all(feature = "u8", feature = "u64"))]
test_interpreter!(interpret_table_select_rows, r#"x := |a<u64> b<u8>| 1 2 | 3 4 | 5 6 |; x[[1,3]]"#, Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("a",Value::U64(Ref::new(1))),("b",Value::U8(Ref::new(2)))]),MechRecord::new(vec![("a",Value::U64(Ref::new(5))),("b",Value::U8(Ref::new(6)))]),]).expect("Failed to create MechTable"))));
#[cfg(feature = "u64")]
test_interpreter!(interpret_table_select_logical, r#"a := | x<u64>  y<bool> | 2 true  | 3 false | 4 false | 5 true |; a{a.y}"#, Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("x",Value::U64(Ref::new(2))),("y",Value::Bool(Ref::new(true)))]),MechRecord::new(vec![("x",Value::U64(Ref::new(5))),("y",Value::Bool(Ref::new(true)))]),]).expect("Failed to create MechTable"))));
#[cfg(feature = "u64")]
test_interpreter!(interpret_table_select_logical2, r#"a := | x<u64>  y<bool> | 2 true  | 3 false | 4 false | 5 true |; a{a.x > 3<u64>}"#, Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("x",Value::U64(Ref::new(4))),("y",Value::Bool(Ref::new(false)))]),MechRecord::new(vec![("x",Value::U64(Ref::new(5))),("y",Value::Bool(Ref::new(true)))]),]).expect("Failed to create MechTable"))));

test_interpreter!(interpret_table_from_matrix,r#"x := [1 2; 3 4]; a<|foo<f64>,bar<f64>|> := x"#,Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("foo", Value::F64(Ref::new(1.0))),("bar", Value::F64(Ref::new(2.0)))]),MechRecord::new(vec![("foo", Value::F64(Ref::new(3.0))),("bar", Value::F64(Ref::new(4.0)))]),]).expect("Failed to create MechTable"))));
test_interpreter!(interpret_table_from_matrix_infer_any_columns,r#"x := [1 2; 3 4]; c<|foo<*> bar<*>|:2> := x"#,Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("foo", Value::F64(Ref::new(1.0))),("bar", Value::F64(Ref::new(2.0)))]),MechRecord::new(vec![("foo", Value::F64(Ref::new(3.0))),("bar", Value::F64(Ref::new(4.0)))]),]).expect("Failed to create MechTable"))));
#[cfg(feature = "u64")]
test_interpreter!(interpret_table_from_matrix_infer_kinds_and_size,r#"x := [1 2; 3 4]; b<|foo,bar|:1> := x"#,Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("foo", Value::U64(Ref::new(1))),("bar", Value::U64(Ref::new(2)))]),]).expect("Failed to create MechTable"))));
test_interpreter!(interpret_table_from_matrix2,r#"x := ["true" "false"; "true" "false"]; a<|x<string> y<string>|> := x"#,Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("x", Value::String(Ref::new("true".to_string()))),("y", Value::String(Ref::new("false".to_string())))]),MechRecord::new(vec![("x", Value::String(Ref::new("true".to_string()))),("y", Value::String(Ref::new("false".to_string())))]),]).expect("Failed to create MechTable"))));
test_interpreter!(interpret_table_from_matrix3,r#"x:=[true false; true false]; a<|x<bool> y<bool>|> := x;"#,Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("x", Value::Bool(Ref::new(true))),("y", Value::Bool(Ref::new(false)))]),MechRecord::new(vec![("x", Value::Bool(Ref::new(true))),("y", Value::Bool(Ref::new(false)))]),]).expect("Failed to create MechTable"))));
#[cfg(all(feature = "i8", feature = "u8"))]
test_interpreter!(interpret_table_from_matrix4,r#"x:=[1 2; 3 4]; a<|x<u8> y<i8>|> := x;"#,Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("x", Value::U8(Ref::new(1))),("y", Value::I8(Ref::new(2)))]),MechRecord::new(vec![("x", Value::U8(Ref::new(3))),("y", Value::I8(Ref::new(4)))]),]).expect("Failed to create MechTable"))));

#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_inner_join_symbol, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := A ⋈ B; J.b[1]"#, Value::U64(Ref::new(200)));
#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_inner_join_word, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := table/join(A, B); J.b[2]"#, Value::U64(Ref::new(300)));

#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_left_outer_join_symbol, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := A ⟕ B; J.id[1]"#, Value::U64(Ref::new(1)));
#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_left_outer_join_word, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := table/left-outer-join(A, B); J.id[2]"#, Value::U64(Ref::new(2)));

#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_right_outer_join_symbol, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := A ⟖ B; J.id[3]"#, Value::U64(Ref::new(4)));
#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_right_outer_join_word, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := table/right-outer-join(A, B); J.id[3]"#, Value::U64(Ref::new(4)));

#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_full_outer_join_symbol, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := A ⟗ B; J.id[4]"#, Value::U64(Ref::new(4)));
#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_full_outer_join_word, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := table/full-outer-join(A, B); J.id[1]"#, Value::U64(Ref::new(1)));

#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_left_semi_join_symbol, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := A ⋉ B; J.a[2]"#, Value::U64(Ref::new(30)));
#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_left_semi_join_word, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := table/left-semi-join(A, B); J.id[1]"#, Value::U64(Ref::new(2)));

#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_left_anti_join_symbol, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := A ▷ B; J.id[1]"#, Value::U64(Ref::new(1)));
#[cfg(all(feature = "table", feature = "u64"))]
test_interpreter!(interpret_table_left_anti_join_word, r#"A := |id<u64> a<u64>| 1 10 | 2 20 | 3 30 |; B := |id<u64> b<u64>| 2 200 | 3 300 | 4 400 |; J := table/left-anti-join(A, B); J.a[1]"#, Value::U64(Ref::new(10)));

#[cfg(feature = "u64")]
test_interpreter!(interpret_matrix_reshape,r#"x:=[1 3; 2 4]; y<[u64]:4,1> := x"#, Value::MatrixU64(Matrix::from_vec(vec![1, 2, 3, 4], 4, 1)));

test_interpreter!(interpret_matrix_reshape2,r#"x:=[1 2 3 4]; y<[string]:2,2> := x"#, Value::MatrixString(Matrix::from_vec(vec![String::from("1"), String::from("2"), String::from("3"), String::from("4")], 2, 2)));  
test_interpreter!(interpret_matrix_convert_str,r#"x:=1..=4; out<[string]>:=x"#, Value::MatrixString(Matrix::from_vec(vec![String::from("1"), String::from("2"), String::from("3"), String::from("4")], 1, 4)));

test_interpreter!(interpret_matrix_build_rational,r#"x<[r64]:1,2> := 1/2"#, Value::MatrixR64(Matrix::from_vec(vec![R64::new(1,2), R64::new(1,2)], 1, 2)));

test_interpreter!(interpret_convert_rational_to_string,r#"x<string>:=1/2"#, Value::String(Ref::new(String::from("1/2"))));
test_interpreter!(interpret_convert_f64_to_string2,r#"x<string>:=123"#, Value::String(Ref::new(String::from("123"))));

test_interpreter!(interpret_convert_f64_to_rational_to_string,r#"x<string> := 0.5<r64>"#,Value::String(Ref::new(String::from("1/2"))));
test_interpreter!(interpret_convert_matrix_to_optional_unsized_matrix, r#"x<[u64]?> := [1u64 2u64 3u64]; x[1]"#, Value::U64(Ref::new(1u64)));
test_interpreter!(interpret_user_function_input_annotation_optional_promotion, r#"
x := [1u64 2u64 3u64]
head(x<[u64]?>) => <u64?>
  | [] => _
  | [h ...] => h
  | _ => _.
head(x)
"#, Value::U64(Ref::new(1u64)));

test_interpreter!(interpret_matrix_power_and_addition,"~μ := [1 2 3]; K := [0.1 0.2 0.3; 0.4 0.5 0.6; 0.7 0.8 0.9]; Ẑ := [0.01; 0.02; 0.03]; μ = μ + (K ** Ẑ)'", Value::MatrixF64(Matrix::from_vec(vec![1.014, 2.032, 3.05], 1, 3)));
test_interpreter!(interpret_assign_scalar_no_space, "~z:=10;z=20", Value::F64(Ref::new(20.0)));


test_interpreter!(interpret_paren_term_whitespace, "fahrenheit := ( 25 * 9 / 5 ) + 32", Value::F64(Ref::new(77.0)));

test_interpreter!(interpret_formulas_no_whitespace, "x:=10*[1,2,3]**[4,5,6]';", Value::MatrixF64(Matrix::from_vec(vec![320.0], 1, 1)));

test_interpreter!(interpret_matrix_negatives, r#"
A := [2.0, 1.0, -1.0
      -3.0, -1.0, 2.0
      -2.0, 1.0, 2.0]"#, Value::MatrixF64(Matrix::from_vec(vec![2.0, -3.0, -2.0, 1.0, -1.0, 1.0, -1.0, 2.0, 2.0], 3, 3)));

test_interpreter!(interpret_matrix_solve, r#"A := [2.0, 1.0, -1.0;-3.0, -1.0, 2.0;-2.0, 1.0, 2.0];b := [8.0, -11.0, -3.0]'; math/round(A \ b)"#, Value::MatrixF64(Matrix::from_vec(vec![2.0, 3.0, -1.0], 3, 1)));

// │ y │ true │ false │

test_interpreter!(table_column_inference, "| y | true | false |", Value::Table(Ref::new(MechTable::from_records(vec![MechRecord::new(vec![("y",Value::Bool(Ref::new(true)))]),MechRecord::new(vec![("y",Value::Bool(Ref::new(false)))]),]).expect("Failed to create MechTable"))));

test_interpreter!(interpret_set_union, r#"A := {1, 2, 3}; B := {2, 3, 4}; U := A ∪ B"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(1.0)), Value::F64(Ref::new(2.0)), Value::F64(Ref::new(3.0)), Value::F64(Ref::new(4.0))]))));
test_interpreter!(interpret_set_intersection, r#"A := {1, 2, 3}; B := {2, 3, 4}; U := A ∩ B"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(2.0)), Value::F64(Ref::new(3.0))]))));
test_interpreter!(interpret_set_difference, r#"A := {"a", "b", "c"}; B := {"b", "c", "d"}; U := A ∖ B"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::String(Ref::new("a".to_string()))]))));
test_interpreter!(interpret_set_subset, r#"A := {"b", "c"}; B := {"b", "c", "d"}; C := A ⊆ B"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_set_superset, r#"A := {"b", "c", "d"}; B := {"b", "c"}; C := A ⊇ B"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_set_membership, r#"A := {1, 2, 3}; B := 2 ∈ A;"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_set_not_membership, r#"A := {1, 2, 3}; B := 4 ∉ A;"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_set_strict_subset, r#"A := {1, 2}; B := {1, 2, 3}; C := A ⊂ B"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_set_strict_superset, r#"A := {1, 2, 3}; B := {1, 2}; C := A ⊃ B"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_set_strict_subset2, r#"A := {1, 2}; B := {1, 2}; C := A ⊊ B"#, Value::Bool(Ref::new(false)));
test_interpreter!(interpret_set_strict_superset2, r#"A := {1, 2}; B := {1, 2}; C := A ⊋ B"#, Value::Bool(Ref::new(false)));

test_interpreter!(interpret_set_union_empty, r#"A := {}; B := {1, 2}; U := A ∪ B"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(1.0)), Value::F64(Ref::new(2.0))]))));
test_interpreter!(interpret_set_intersection_empty, r#"A := {}; B := {1, 2, 3}; U := A ∩ B"#, Value::Set(Ref::new(MechSet::from_vec(vec![]))));
test_interpreter!(interpret_set_difference_empty, r#"A := {1, 2}; B := {1, 2}; U := A ∖ B"#, Value::Set(Ref::new(MechSet::from_vec(vec![]))));
test_interpreter!(interpret_set_union_duplicates, r#"A := {1, 1, 2}; B := {2, 2, 3}; U := A ∪ B"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(1.0)), Value::F64(Ref::new(2.0)), Value::F64(Ref::new(3.0))]))));
test_interpreter!(interpret_set_subset_empty_left, r#"A := {}; B := {1}; C := A ⊆ B"#, Value::Bool(Ref::new(true)));

test_interpreter!(interpret_compare_max_scalar, "compare/max(5,3)", Value::F64(Ref::new(5.0)));
test_interpreter!(interpret_compare_max_vector, "compare/max([3 4 5 6],4)", Value::MatrixF64(Matrix::from_vec(vec![4.0, 4.0, 5.0, 6.0], 1, 4)));
test_interpreter!(interpret_compare_max_vector_vector, "compare/max([3 4 5 6],[6 5 4 3])", Value::MatrixF64(Matrix::from_vec(vec![6.0, 5.0, 5.0, 6.0], 1, 4)));
test_interpreter!(interpret_compare_min_scalar, "compare/min(5,3)", Value::F64(Ref::new(3.0)));
test_interpreter!(interpret_compare_min_vector, "compare/min([3 4 5 6],4)", Value::MatrixF64(Matrix::from_vec(vec![3.0, 4.0, 4.0, 4.0], 1, 4)));
test_interpreter!(interpret_compare_min_vector_vector, "compare/min([3 4 5 6],[6 5 4 3])", Value::MatrixF64(Matrix::from_vec(vec![3.0, 4.0, 4.0, 3.0], 1, 4)));

test_interpreter!(interpret_set_comprehension, r#"{ x * x | x <- {1,2,3,4}, y := 2, (x % 2) == 0 }"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(4.0)), Value::F64(Ref::new(16.0))]))));
test_interpreter!(interpret_set_comprehension_variable, r#"qq := {1,2,3,4}; { x * x | x <- qq, y := 2, (x % 2) != 0 }"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(1.0)), Value::F64(Ref::new(9.0))]))));
test_interpreter!(interpret_set_comprehension_tuple, r#"qq := {(1,2),(3,4),(5,6),(7,8)}; { x * x | (x, *) <- qq }"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(1.0)), Value::F64(Ref::new(9.0)), Value::F64(Ref::new(25.0)), Value::F64(Ref::new(49.0))]))));
test_interpreter!(interpret_set_comprehension_fof, r#"pairs:= {(1,2), (1,3), (2,8), (3,5), (3,9)}; user := 1; {fof | ( u, f ) <- pairs, ( f, fof ) <- pairs, u ⩵ user}"#, Value::Set(Ref::new(MechSet::from_vec(vec![Value::F64(Ref::new(5.0)), Value::F64(Ref::new(9.0)), Value::F64(Ref::new(8.0))]))));

test_interpreter!(interpret_matrix_comprehension, r#"[ x * x | x <- [1 2 3 4], y := 2, (x % 2) == 0 ]"#, Value::MatrixF64(Matrix::from_vec(vec![4.0, 16.0], 1, 2)));
test_interpreter!(interpret_matrix_comprehension_variable, r#"qq := [1 2 3 4]; [ x * x | x <- qq, y := 2, (x % 2) != 0 ]"#, Value::MatrixF64(Matrix::from_vec(vec![1.0, 9.0], 1, 2)));

test_interpreter!(interpret_table_record_mutation, r#"~T:=|x<f64> y<bool>|1.2 true|1.3 false|;~r:=T[1];r.x=42;T.x[1]"#, Value::F64(Ref::new(42.0)));
//test_interpreter!("interpret_table_record_mutation_fail", r#"T := | x<f64>  y<bool> |  1.2     true   |  1.3     false  |;~r := T{1};r.x = 42;T.x[1]"#, Value::F64(Ref::new(1.2)));

test_interpreter!(interpret_define_custom_enum, r#"<color>:=:red|:green|:blue; x<color>:=:red;"#, Value::Atom(Ref::new(MechAtom::new(hash_str("red")))));
test_interpreter!(interpret_kind_membership_enum_payload, r#"
<color> := :red<u64> | :green<u64> | :blue
:red(300) ∈ <color>
"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_kind_not_membership_enum_payload, r#"
<color> := :red<u64> | :green<u64> | :blue
:red("300") ∉ <color>
"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_tagged_union_nested_match, r#"
<result> := :ok<u64> | :err<string>
<option> := :some<result> | :none
x<option> := :some(:ok(42u64))
result := x?
  | :some(:ok(n))  => n
  | :some(:err(e)) => 0u64
  | :none          => 0u64
  | *              => 0u64.
result + 0u64
"#, Value::U64(Ref::new(42u64)));
test_interpreter!(interpret_tagged_union_function_input_enum_kind, r#"
<result> := :ok<u64> | :err<string>
<option> := :some<result> | :none
x<option> := :some(:err("this sucks"))

unwrap(x<option>) => <u64>
  | :some(:ok(n))  => n
  | :some(:err(e)) => 0u64
  | :none          => 0u64.

unwrap(x)
"#, Value::U64(Ref::new(0u64)));
#[test]
fn interpret_tagged_union_function_match_requires_exhaustive_arms() {
  let s = r#"
<result> := :ok<u64> | :err<string>
<option> := :some<result> | :none
x<option> := :some(:err("this sucks"))

unwrap(x<option>) => <u64>
  | :some(:ok(n))  => n
  | :some(:err(e)) => 0u64.

unwrap(x)
"#;
  let tree = parser::parse(s).unwrap();
  let mut intrp = Interpreter::new(0);
  let err = intrp.interpret(&tree).unwrap_err();
  let msg = format!("{:?}", err);
  assert!(msg.contains("FunctionMatchNonExhaustive"));
  assert!(msg.contains(":none"));
  assert!(msg.contains("wildcard"));
}
test_interpreter!(interpret_string_concatenation, r#"x := "Hello, " + "world!""#, Value::String(Ref::new("Hello, world!".to_string())));
test_interpreter!(interpret_string_concatenation2, r#""a" + "b" + "c""#, Value::String(Ref::new("abc".to_string())));
test_interpreter!(interpret_string_concatenation_var, r#"greeting := "Hello"; name := "Alice"; message := greeting + ", " + name + "!""#, Value::String(Ref::new("Hello, Alice!".to_string())));
test_interpreter!(interpret_string_concatenation_matrix, r#"["a" "b"] + "c""#, Value::MatrixString(Matrix::from_vec(vec!["ac".to_string(), "bc".to_string()], 1, 2)));
test_interpreter!(interpret_string_concatenation_matrix2, r#"["a" "b"; "c" "d"] + ["1" "2"; "3" "4"]"#, Value::MatrixString(Matrix::from_vec(vec!["a1".to_string(), "c3".to_string(), "b2".to_string(), "d4".to_string()], 2, 2)));
test_interpreter!(interpret_string_concatenation_matrix3, r#"prefix := "Item"; letters := ["A" "B" "C"]; labels := prefix + letters"#, Value::MatrixString(Matrix::from_vec(vec!["ItemA".to_string(), "ItemB".to_string(), "ItemC".to_string()], 1, 3)));
test_interpreter!(interpret_string_raw_literal, r#""""C:\Users\Name\Documents""""#, Value::String(Ref::new(r"C:\Users\Name\Documents".to_string())));
test_interpreter!(interpret_string_raw_literal_multiline, r#""""This is a raw string literal.It can span multiple lines
and include "quotes" and \backslashes\ without needing escapes.""""#, Value::String(Ref::new(r#"This is a raw string literal.It can span multiple lines
and include "quotes" and \backslashes\ without needing escapes."#.to_string())));
test_interpreter!(interpret_atom_equality, r#"a := :status/active; b := :status/active; c := (a == b);"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_atom_inequality_false, r#"a := :status/active; b := :status/active; c := (a != b);"#, Value::Bool(Ref::new(false)));
test_interpreter!(interpret_atom_inequality, r#"a := :status/active; b := :status/inactive; c := (a != b);"#, Value::Bool(Ref::new(true)));
test_interpreter!(interpret_atom_equality_false, r#"a := :status/active; b := :status/inactive; c := (a == b);"#, Value::Bool(Ref::new(false)));

test_interpreter!(interpreter_mika_micromica, r#"╭⦿╯"#, Value::Atom(Ref::new(MechAtom::from_name("╭⦿╯"))));
test_interpreter!(interpreter_mika_micromica_gripper, r#"Ɔ∞⦿╯"#, Value::Atom(Ref::new(MechAtom::from_name("Ɔ∞⦿╯"))));
test_interpreter!(interpreter_mika_minimika, r#"(˙◯˙)"#, Value::Atom(Ref::new(MechAtom::from_name("(˙◯˙)"))));
test_interpreter!(interpreter_mika_micromica_mikasection, r#"╭⦿╯ ⸢Hello, I'm Mika!⸥"#, Value::Atom(Ref::new(MechAtom::from_name("╭⦿╯"))));