1use crate::error::set_runtime_error;
23use crate::stack::{
24 Stack, drop_stack_value, get_stack_base, heap_value_mut, peek_heap_mut_second, pop, pop_sv,
25 push, stack_value_size,
26};
27use crate::value::{Value, VariantData};
28use std::sync::Arc;
29
30#[inline]
32fn stack_depth(stack: Stack) -> usize {
33 if stack.is_null() {
34 return 0;
35 }
36 let base = get_stack_base();
37 if base.is_null() {
38 return 0;
39 }
40 (stack as usize - base as usize) / stack_value_size()
41}
42
43unsafe fn drain_stack_to_base(mut stack: Stack, base: Stack) {
48 unsafe {
49 while stack > base {
50 let (rest, sv) = pop_sv(stack);
51 drop_stack_value(sv);
52 stack = rest;
53 }
54 }
55}
56
57unsafe fn call_with_value(base: Stack, value: Value, callable: &Value) -> Stack {
62 unsafe {
63 let stack = push(base, value);
64 crate::quotations::invoke_callable(stack, callable)
65 }
66}
67
68#[unsafe(no_mangle)]
78pub unsafe extern "C" fn patch_seq_list_map(stack: Stack) -> Stack {
79 unsafe {
80 let (stack, callable) = pop(stack);
82
83 match &callable {
85 Value::Quotation { .. } | Value::Closure { .. } => {}
86 _ => panic!(
87 "list-map: expected Quotation or Closure, got {:?}",
88 callable
89 ),
90 }
91
92 let (stack, list_val) = pop(stack);
94
95 let variant_data = match list_val {
96 Value::Variant(v) => v,
97 _ => panic!("list-map: expected Variant (list), got {:?}", list_val),
98 };
99
100 let mut results = Vec::with_capacity(variant_data.fields.len());
102
103 for field in variant_data.fields.iter() {
104 let temp_base = crate::stack::alloc_stack();
106 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
107
108 if temp_stack <= temp_base {
110 panic!("list-map: quotation consumed element without producing result");
111 }
112 let (remaining, result) = pop(temp_stack);
113 results.push(result);
114
115 if remaining > temp_base {
117 drain_stack_to_base(remaining, temp_base);
118 }
119 }
120
121 let new_variant = Value::Variant(Arc::new(VariantData::new(
123 variant_data.tag.clone(),
124 results,
125 )));
126
127 push(stack, new_variant)
128 }
129}
130
131#[unsafe(no_mangle)]
141pub unsafe extern "C" fn patch_seq_list_filter(stack: Stack) -> Stack {
142 unsafe {
143 let (stack, callable) = pop(stack);
145
146 match &callable {
148 Value::Quotation { .. } | Value::Closure { .. } => {}
149 _ => panic!(
150 "list-filter: expected Quotation or Closure, got {:?}",
151 callable
152 ),
153 }
154
155 let (stack, list_val) = pop(stack);
157
158 let variant_data = match list_val {
159 Value::Variant(v) => v,
160 _ => panic!("list-filter: expected Variant (list), got {:?}", list_val),
161 };
162
163 let mut results = Vec::new();
165
166 for field in variant_data.fields.iter() {
167 let temp_base = crate::stack::alloc_stack();
169 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
170
171 if temp_stack <= temp_base {
173 panic!("list-filter: quotation consumed element without producing result");
174 }
175 let (remaining, result) = pop(temp_stack);
176
177 let keep = match result {
178 Value::Bool(b) => b,
179 _ => panic!("list-filter: quotation must return Bool, got {:?}", result),
180 };
181
182 if keep {
183 results.push(field.clone());
184 }
185
186 if remaining > temp_base {
188 drain_stack_to_base(remaining, temp_base);
189 }
190 }
191
192 let new_variant = Value::Variant(Arc::new(VariantData::new(
194 variant_data.tag.clone(),
195 results,
196 )));
197
198 push(stack, new_variant)
199 }
200}
201
202#[unsafe(no_mangle)]
212pub unsafe extern "C" fn patch_seq_list_fold(stack: Stack) -> Stack {
213 unsafe {
214 let (stack, callable) = pop(stack);
216
217 match &callable {
219 Value::Quotation { .. } | Value::Closure { .. } => {}
220 _ => panic!(
221 "list-fold: expected Quotation or Closure, got {:?}",
222 callable
223 ),
224 }
225
226 let (stack, init) = pop(stack);
228
229 let (stack, list_val) = pop(stack);
231
232 let variant_data = match list_val {
233 Value::Variant(v) => v,
234 _ => panic!("list-fold: expected Variant (list), got {:?}", list_val),
235 };
236
237 let mut acc = init;
239
240 for field in variant_data.fields.iter() {
241 let temp_base = crate::stack::alloc_stack();
243 let temp_stack = push(temp_base, acc);
244 let temp_stack = push(temp_stack, field.clone());
245
246 let temp_stack = match &callable {
247 Value::Quotation { wrapper, .. } => {
248 let fn_ref: unsafe extern "C" fn(Stack) -> Stack =
249 std::mem::transmute(*wrapper);
250 fn_ref(temp_stack)
251 }
252 Value::Closure { fn_ptr, env } => {
253 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
254 std::mem::transmute(*fn_ptr);
255 fn_ref(temp_stack, env.as_ptr(), env.len())
256 }
257 _ => unreachable!(),
258 };
259
260 if temp_stack <= temp_base {
262 panic!("list-fold: quotation consumed inputs without producing result");
263 }
264 let (remaining, new_acc) = pop(temp_stack);
265 acc = new_acc;
266
267 if remaining > temp_base {
269 drain_stack_to_base(remaining, temp_base);
270 }
271 }
272
273 push(stack, acc)
274 }
275}
276
277#[unsafe(no_mangle)]
287pub unsafe extern "C" fn patch_seq_list_each(stack: Stack) -> Stack {
288 unsafe {
289 let (stack, callable) = pop(stack);
291
292 match &callable {
294 Value::Quotation { .. } | Value::Closure { .. } => {}
295 _ => panic!(
296 "list-each: expected Quotation or Closure, got {:?}",
297 callable
298 ),
299 }
300
301 let (stack, list_val) = pop(stack);
303
304 let variant_data = match list_val {
305 Value::Variant(v) => v,
306 _ => panic!("list-each: expected Variant (list), got {:?}", list_val),
307 };
308
309 for field in variant_data.fields.iter() {
311 let temp_base = crate::stack::alloc_stack();
312 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
313 if temp_stack > temp_base {
315 drain_stack_to_base(temp_stack, temp_base);
316 }
317 }
318
319 stack
320 }
321}
322
323#[unsafe(no_mangle)]
333pub unsafe extern "C" fn patch_seq_list_length(stack: Stack) -> Stack {
334 unsafe { crate::variant_ops::patch_seq_variant_field_count(stack) }
335}
336
337#[unsafe(no_mangle)]
346pub unsafe extern "C" fn patch_seq_list_empty(stack: Stack) -> Stack {
347 unsafe {
348 let (stack, list_val) = pop(stack);
349
350 let is_empty = match list_val {
351 Value::Variant(v) => v.fields.is_empty(),
352 _ => panic!("list-empty?: expected Variant (list), got {:?}", list_val),
353 };
354
355 push(stack, Value::Bool(is_empty))
356 }
357}
358
359#[unsafe(no_mangle)]
368pub unsafe extern "C" fn patch_seq_list_make(stack: Stack) -> Stack {
369 unsafe {
370 let list = Value::Variant(Arc::new(VariantData::new(
371 crate::seqstring::global_string("List".to_string()),
372 vec![],
373 )));
374 push(stack, list)
375 }
376}
377
378#[unsafe(no_mangle)]
389pub unsafe extern "C" fn patch_seq_list_push(stack: Stack) -> Stack {
390 unsafe {
391 if let Some(Value::Variant(variant_arc)) = peek_heap_mut_second(stack)
395 && let Some(data) = Arc::get_mut(variant_arc)
396 {
397 let (stack, value) = pop(stack);
402 data.fields.push(value);
403 return stack; }
405
406 let (stack, value) = pop(stack);
408 let (stack, list_val) = pop(stack);
409 let variant_arc = match list_val {
410 Value::Variant(v) => v,
411 _ => panic!("list.push: expected Variant (list), got {:?}", list_val),
412 };
413 push_to_variant(stack, variant_arc, value)
414 }
415}
416
417unsafe fn push_to_variant(stack: Stack, mut variant_arc: Arc<VariantData>, value: Value) -> Stack {
419 unsafe {
420 if let Some(data) = Arc::get_mut(&mut variant_arc) {
421 data.fields.push(value);
423 push(stack, Value::Variant(variant_arc))
424 } else {
425 let mut new_fields = Vec::with_capacity(variant_arc.fields.len() + 1);
427 new_fields.extend(variant_arc.fields.iter().cloned());
428 new_fields.push(value);
429 let new_list = Value::Variant(Arc::new(VariantData::new(
430 variant_arc.tag.clone(),
431 new_fields,
432 )));
433 push(stack, new_list)
434 }
435 }
436}
437
438#[unsafe(no_mangle)]
453pub unsafe extern "C" fn patch_seq_list_get(stack: Stack) -> Stack {
454 unsafe {
455 if stack_depth(stack) < 2 {
457 set_runtime_error("list.get: stack underflow (need 2 values)");
458 return stack;
459 }
460 let (stack, index_val) = pop(stack);
461 let (stack, list_val) = pop(stack);
462
463 let index = match index_val {
464 Value::Int(i) => i,
465 _ => {
466 set_runtime_error(format!(
467 "list.get: expected Int (index), got {:?}",
468 index_val
469 ));
470 let stack = push(stack, Value::Int(0));
471 return push(stack, Value::Bool(false));
472 }
473 };
474
475 let variant_data = match list_val {
476 Value::Variant(v) => v,
477 _ => {
478 set_runtime_error(format!(
479 "list.get: expected Variant (list), got {:?}",
480 list_val
481 ));
482 let stack = push(stack, Value::Int(0));
483 return push(stack, Value::Bool(false));
484 }
485 };
486
487 if index < 0 || index as usize >= variant_data.fields.len() {
488 let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false))
491 } else {
492 let value = variant_data.fields[index as usize].clone();
493 let stack = push(stack, value);
494 push(stack, Value::Bool(true))
495 }
496 }
497}
498
499#[unsafe(no_mangle)]
519pub unsafe extern "C" fn patch_seq_list_set(stack: Stack) -> Stack {
520 unsafe {
521 if stack_depth(stack) < 3 {
523 set_runtime_error("list.set: stack underflow (need 3 values)");
524 return stack;
525 }
526
527 if let Some(Value::Variant(variant_arc)) = heap_value_mut(stack.sub(3))
532 && let Some(data) = Arc::get_mut(variant_arc)
533 {
534 let index_sv = *stack.sub(2);
537 if crate::tagged_stack::is_tagged_int(index_sv) {
538 let index = crate::tagged_stack::untag_int(index_sv);
539 if index >= 0 && (index as usize) < data.fields.len() {
540 let (stack, value) = pop(stack);
544 let (stack, _index) = pop(stack);
545 data.fields[index as usize] = value;
546 return push(stack, Value::Bool(true));
547 }
548 let (stack, _value) = pop(stack);
550 let (stack, _index) = pop(stack);
551 return push(stack, Value::Bool(false));
552 }
553 }
554
555 let (stack, value) = pop(stack);
557 let (stack, index_val) = pop(stack);
558 let (stack, list_val) = pop(stack);
559
560 let index = match index_val {
561 Value::Int(i) => i,
562 _ => {
563 set_runtime_error(format!(
564 "list.set: expected Int (index), got {:?}",
565 index_val
566 ));
567 let stack = push(stack, list_val);
568 return push(stack, Value::Bool(false));
569 }
570 };
571
572 let mut arc = match list_val {
573 Value::Variant(v) => v,
574 other => {
575 set_runtime_error(format!(
576 "list.set: expected Variant (list), got {:?}",
577 other
578 ));
579 let stack = push(stack, other);
580 return push(stack, Value::Bool(false));
581 }
582 };
583
584 if index < 0 || index as usize >= arc.fields.len() {
585 let stack = push(stack, Value::Variant(arc));
586 push(stack, Value::Bool(false))
587 } else if let Some(data) = Arc::get_mut(&mut arc) {
588 data.fields[index as usize] = value;
589 let stack = push(stack, Value::Variant(arc));
590 push(stack, Value::Bool(true))
591 } else {
592 let mut new_fields: Vec<Value> = arc.fields.to_vec();
593 new_fields[index as usize] = value;
594 let new_list = Value::Variant(Arc::new(VariantData::new(arc.tag.clone(), new_fields)));
595 let stack = push(stack, new_list);
596 push(stack, Value::Bool(true))
597 }
598 }
599}
600
601#[unsafe(no_mangle)]
610pub unsafe extern "C" fn patch_seq_list_reverse(stack: Stack) -> Stack {
611 unsafe {
612 let (stack, list_val) = pop(stack);
613
614 let variant_data = match list_val {
615 Value::Variant(v) => v,
616 _ => panic!("list.reverse: expected Variant (list), got {:?}", list_val),
617 };
618
619 let mut reversed: Vec<Value> = variant_data.fields.to_vec();
620 reversed.reverse();
621
622 let new_variant = Value::Variant(Arc::new(VariantData::new(
623 variant_data.tag.clone(),
624 reversed,
625 )));
626
627 push(stack, new_variant)
628 }
629}
630
631pub use patch_seq_list_each as list_each;
633pub use patch_seq_list_empty as list_empty;
634pub use patch_seq_list_filter as list_filter;
635pub use patch_seq_list_fold as list_fold;
636pub use patch_seq_list_get as list_get;
637pub use patch_seq_list_length as list_length;
638pub use patch_seq_list_make as list_make;
639pub use patch_seq_list_map as list_map;
640pub use patch_seq_list_push as list_push;
641pub use patch_seq_list_reverse as list_reverse;
642pub use patch_seq_list_set as list_set;
643
644#[cfg(test)]
645mod tests {
646 use super::*;
647 use crate::seqstring::global_string;
648
649 unsafe extern "C" fn double_quot(stack: Stack) -> Stack {
651 unsafe {
652 let (stack, val) = pop(stack);
653 match val {
654 Value::Int(n) => push(stack, Value::Int(n * 2)),
655 _ => panic!("Expected Int"),
656 }
657 }
658 }
659
660 unsafe extern "C" fn is_positive_quot(stack: Stack) -> Stack {
662 unsafe {
663 let (stack, val) = pop(stack);
664 match val {
665 Value::Int(n) => push(stack, Value::Bool(n > 0)),
666 _ => panic!("Expected Int"),
667 }
668 }
669 }
670
671 unsafe extern "C" fn add_quot(stack: Stack) -> Stack {
673 unsafe {
674 let (stack, b) = pop(stack);
675 let (stack, a) = pop(stack);
676 match (a, b) {
677 (Value::Int(x), Value::Int(y)) => push(stack, Value::Int(x + y)),
678 _ => panic!("Expected two Ints"),
679 }
680 }
681 }
682
683 #[test]
684 fn test_list_map_double() {
685 unsafe {
686 let list = Value::Variant(Arc::new(VariantData::new(
688 global_string("List".to_string()),
689 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
690 )));
691
692 let stack = crate::stack::alloc_test_stack();
693 let stack = push(stack, list);
694 let fn_ptr = double_quot as *const () as usize;
695 let stack = push(
696 stack,
697 Value::Quotation {
698 wrapper: fn_ptr,
699 impl_: fn_ptr,
700 },
701 );
702 let stack = list_map(stack);
703
704 let (_stack, result) = pop(stack);
705 match result {
706 Value::Variant(v) => {
707 assert_eq!(v.fields.len(), 3);
708 assert_eq!(v.fields[0], Value::Int(2));
709 assert_eq!(v.fields[1], Value::Int(4));
710 assert_eq!(v.fields[2], Value::Int(6));
711 }
712 _ => panic!("Expected Variant"),
713 }
714 }
715 }
716
717 #[test]
718 fn test_list_filter_positive() {
719 unsafe {
720 let list = Value::Variant(Arc::new(VariantData::new(
722 global_string("List".to_string()),
723 vec![
724 Value::Int(-1),
725 Value::Int(2),
726 Value::Int(-3),
727 Value::Int(4),
728 Value::Int(0),
729 ],
730 )));
731
732 let stack = crate::stack::alloc_test_stack();
733 let stack = push(stack, list);
734 let fn_ptr = is_positive_quot as *const () as usize;
735 let stack = push(
736 stack,
737 Value::Quotation {
738 wrapper: fn_ptr,
739 impl_: fn_ptr,
740 },
741 );
742 let stack = list_filter(stack);
743
744 let (_stack, result) = pop(stack);
745 match result {
746 Value::Variant(v) => {
747 assert_eq!(v.fields.len(), 2);
748 assert_eq!(v.fields[0], Value::Int(2));
749 assert_eq!(v.fields[1], Value::Int(4));
750 }
751 _ => panic!("Expected Variant"),
752 }
753 }
754 }
755
756 #[test]
757 fn test_list_fold_sum() {
758 unsafe {
759 let list = Value::Variant(Arc::new(VariantData::new(
761 global_string("List".to_string()),
762 vec![
763 Value::Int(1),
764 Value::Int(2),
765 Value::Int(3),
766 Value::Int(4),
767 Value::Int(5),
768 ],
769 )));
770
771 let stack = crate::stack::alloc_test_stack();
772 let stack = push(stack, list);
773 let stack = push(stack, Value::Int(0)); let fn_ptr = add_quot as *const () as usize;
775 let stack = push(
776 stack,
777 Value::Quotation {
778 wrapper: fn_ptr,
779 impl_: fn_ptr,
780 },
781 );
782 let stack = list_fold(stack);
783
784 let (_stack, result) = pop(stack);
785 assert_eq!(result, Value::Int(15)); }
787 }
788
789 #[test]
790 fn test_list_fold_empty() {
791 unsafe {
792 let list = Value::Variant(Arc::new(VariantData::new(
794 global_string("List".to_string()),
795 vec![],
796 )));
797
798 let stack = crate::stack::alloc_test_stack();
799 let stack = push(stack, list);
800 let stack = push(stack, Value::Int(42)); let fn_ptr = add_quot as *const () as usize;
802 let stack = push(
803 stack,
804 Value::Quotation {
805 wrapper: fn_ptr,
806 impl_: fn_ptr,
807 },
808 );
809 let stack = list_fold(stack);
810
811 let (_stack, result) = pop(stack);
812 assert_eq!(result, Value::Int(42)); }
814 }
815
816 #[test]
817 fn test_list_length() {
818 unsafe {
819 let list = Value::Variant(Arc::new(VariantData::new(
820 global_string("List".to_string()),
821 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
822 )));
823
824 let stack = crate::stack::alloc_test_stack();
825 let stack = push(stack, list);
826 let stack = list_length(stack);
827
828 let (_stack, result) = pop(stack);
829 assert_eq!(result, Value::Int(3));
830 }
831 }
832
833 #[test]
834 fn test_list_empty_true() {
835 unsafe {
836 let list = Value::Variant(Arc::new(VariantData::new(
837 global_string("List".to_string()),
838 vec![],
839 )));
840
841 let stack = crate::stack::alloc_test_stack();
842 let stack = push(stack, list);
843 let stack = list_empty(stack);
844
845 let (_stack, result) = pop(stack);
846 assert_eq!(result, Value::Bool(true));
847 }
848 }
849
850 #[test]
851 fn test_list_empty_false() {
852 unsafe {
853 let list = Value::Variant(Arc::new(VariantData::new(
854 global_string("List".to_string()),
855 vec![Value::Int(1)],
856 )));
857
858 let stack = crate::stack::alloc_test_stack();
859 let stack = push(stack, list);
860 let stack = list_empty(stack);
861
862 let (_stack, result) = pop(stack);
863 assert_eq!(result, Value::Bool(false));
864 }
865 }
866
867 #[test]
868 fn test_list_map_empty() {
869 unsafe {
870 let list = Value::Variant(Arc::new(VariantData::new(
871 global_string("List".to_string()),
872 vec![],
873 )));
874
875 let stack = crate::stack::alloc_test_stack();
876 let stack = push(stack, list);
877 let fn_ptr = double_quot as *const () as usize;
878 let stack = push(
879 stack,
880 Value::Quotation {
881 wrapper: fn_ptr,
882 impl_: fn_ptr,
883 },
884 );
885 let stack = list_map(stack);
886
887 let (_stack, result) = pop(stack);
888 match result {
889 Value::Variant(v) => {
890 assert_eq!(v.fields.len(), 0);
891 }
892 _ => panic!("Expected Variant"),
893 }
894 }
895 }
896
897 #[test]
898 fn test_list_map_preserves_tag() {
899 unsafe {
900 let list = Value::Variant(Arc::new(VariantData::new(
902 global_string("CustomTag".to_string()),
903 vec![Value::Int(1), Value::Int(2)],
904 )));
905
906 let stack = crate::stack::alloc_test_stack();
907 let stack = push(stack, list);
908 let fn_ptr = double_quot as *const () as usize;
909 let stack = push(
910 stack,
911 Value::Quotation {
912 wrapper: fn_ptr,
913 impl_: fn_ptr,
914 },
915 );
916 let stack = list_map(stack);
917
918 let (_stack, result) = pop(stack);
919 match result {
920 Value::Variant(v) => {
921 assert_eq!(v.tag.as_str(), "CustomTag"); assert_eq!(v.fields[0], Value::Int(2));
923 assert_eq!(v.fields[1], Value::Int(4));
924 }
925 _ => panic!("Expected Variant"),
926 }
927 }
928 }
929
930 unsafe extern "C" fn add_captured_closure(
933 stack: Stack,
934 env: *const Value,
935 _env_len: usize,
936 ) -> Stack {
937 unsafe {
938 let (stack, val) = pop(stack);
939 let captured = &*env; match (val, captured) {
941 (Value::Int(n), Value::Int(c)) => push(stack, Value::Int(n + c)),
942 _ => panic!("Expected Int"),
943 }
944 }
945 }
946
947 #[test]
948 fn test_list_map_with_closure() {
949 unsafe {
950 let list = Value::Variant(Arc::new(VariantData::new(
952 global_string("List".to_string()),
953 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
954 )));
955
956 let env: std::sync::Arc<[Value]> =
958 std::sync::Arc::from(vec![Value::Int(10)].into_boxed_slice());
959 let closure = Value::Closure {
960 fn_ptr: add_captured_closure as *const () as usize,
961 env,
962 };
963
964 let stack = crate::stack::alloc_test_stack();
965 let stack = push(stack, list);
966 let stack = push(stack, closure);
967 let stack = list_map(stack);
968
969 let (_stack, result) = pop(stack);
970 match result {
971 Value::Variant(v) => {
972 assert_eq!(v.fields.len(), 3);
973 assert_eq!(v.fields[0], Value::Int(11)); assert_eq!(v.fields[1], Value::Int(12)); assert_eq!(v.fields[2], Value::Int(13)); }
977 _ => panic!("Expected Variant"),
978 }
979 }
980 }
981
982 #[test]
983 fn test_list_get_type_error_index() {
984 unsafe {
985 crate::error::clear_runtime_error();
986
987 let list = Value::Variant(Arc::new(VariantData::new(
988 global_string("List".to_string()),
989 vec![Value::Int(1), Value::Int(2)],
990 )));
991
992 let stack = crate::stack::alloc_test_stack();
993 let stack = push(stack, list);
994 let stack = push(stack, Value::Bool(true)); let stack = list_get(stack);
996
997 assert!(crate::error::has_runtime_error());
999 let error = crate::error::take_runtime_error().unwrap();
1000 assert!(error.contains("expected Int"));
1001
1002 let (stack, success) = pop(stack);
1004 assert_eq!(success, Value::Bool(false));
1005 let (_stack, value) = pop(stack);
1006 assert_eq!(value, Value::Int(0));
1007 }
1008 }
1009
1010 #[test]
1011 fn test_list_get_type_error_list() {
1012 unsafe {
1013 crate::error::clear_runtime_error();
1014
1015 let stack = crate::stack::alloc_test_stack();
1016 let stack = push(stack, Value::Int(42)); let stack = push(stack, Value::Int(0)); let stack = list_get(stack);
1019
1020 assert!(crate::error::has_runtime_error());
1022 let error = crate::error::take_runtime_error().unwrap();
1023 assert!(error.contains("expected Variant"));
1024
1025 let (stack, success) = pop(stack);
1027 assert_eq!(success, Value::Bool(false));
1028 let (_stack, value) = pop(stack);
1029 assert_eq!(value, Value::Int(0));
1030 }
1031 }
1032
1033 #[test]
1034 fn test_list_set_type_error_index() {
1035 unsafe {
1036 crate::error::clear_runtime_error();
1037
1038 let list = Value::Variant(Arc::new(VariantData::new(
1039 global_string("List".to_string()),
1040 vec![Value::Int(1), Value::Int(2)],
1041 )));
1042
1043 let stack = crate::stack::alloc_test_stack();
1044 let stack = push(stack, list);
1045 let stack = push(stack, Value::Bool(true)); let stack = push(stack, Value::Int(99)); let stack = list_set(stack);
1048
1049 assert!(crate::error::has_runtime_error());
1051 let error = crate::error::take_runtime_error().unwrap();
1052 assert!(error.contains("expected Int"));
1053
1054 let (stack, success) = pop(stack);
1056 assert_eq!(success, Value::Bool(false));
1057 let (_stack, returned_list) = pop(stack);
1058 assert!(matches!(returned_list, Value::Variant(_)));
1059 }
1060 }
1061
1062 #[test]
1063 fn test_list_set_type_error_list() {
1064 unsafe {
1065 crate::error::clear_runtime_error();
1066
1067 let stack = crate::stack::alloc_test_stack();
1068 let stack = push(stack, Value::Int(42)); let stack = push(stack, Value::Int(0)); let stack = push(stack, Value::Int(99)); let stack = list_set(stack);
1072
1073 assert!(crate::error::has_runtime_error());
1075 let error = crate::error::take_runtime_error().unwrap();
1076 assert!(error.contains("expected Variant"));
1077
1078 let (stack, success) = pop(stack);
1080 assert_eq!(success, Value::Bool(false));
1081 let (_stack, returned) = pop(stack);
1082 assert_eq!(returned, Value::Int(42)); }
1084 }
1085
1086 #[test]
1091 fn test_list_reverse_empty() {
1092 unsafe {
1093 let stack = crate::stack::alloc_test_stack();
1094 let empty_list = Value::Variant(Arc::new(VariantData::new(
1096 crate::seqstring::global_string("List".to_string()),
1097 vec![],
1098 )));
1099 let stack = push(stack, empty_list);
1100 let stack = list_reverse(stack);
1101
1102 let (_stack, result) = pop(stack);
1103 match result {
1104 Value::Variant(v) => {
1105 assert_eq!(v.fields.len(), 0);
1106 assert_eq!(v.tag.as_str(), "List");
1107 }
1108 _ => panic!("Expected Variant"),
1109 }
1110 }
1111 }
1112
1113 #[test]
1114 fn test_list_reverse_single() {
1115 unsafe {
1116 let stack = crate::stack::alloc_test_stack();
1117 let list = Value::Variant(Arc::new(VariantData::new(
1118 crate::seqstring::global_string("List".to_string()),
1119 vec![Value::Int(42)],
1120 )));
1121 let stack = push(stack, list);
1122 let stack = list_reverse(stack);
1123
1124 let (_stack, result) = pop(stack);
1125 match result {
1126 Value::Variant(v) => {
1127 assert_eq!(v.fields.len(), 1);
1128 assert_eq!(v.fields[0], Value::Int(42));
1129 }
1130 _ => panic!("Expected Variant"),
1131 }
1132 }
1133 }
1134
1135 #[test]
1136 fn test_list_reverse_multiple() {
1137 unsafe {
1138 let stack = crate::stack::alloc_test_stack();
1139 let list = Value::Variant(Arc::new(VariantData::new(
1140 crate::seqstring::global_string("List".to_string()),
1141 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
1142 )));
1143 let stack = push(stack, list);
1144 let stack = list_reverse(stack);
1145
1146 let (_stack, result) = pop(stack);
1147 match result {
1148 Value::Variant(v) => {
1149 assert_eq!(v.fields.len(), 3);
1150 assert_eq!(v.fields[0], Value::Int(3));
1151 assert_eq!(v.fields[1], Value::Int(2));
1152 assert_eq!(v.fields[2], Value::Int(1));
1153 assert_eq!(v.tag.as_str(), "List"); }
1155 _ => panic!("Expected Variant"),
1156 }
1157 }
1158 }
1159}