1use crate::error::set_runtime_error;
23use crate::stack::{Stack, drop_stack_value, get_stack_base, pop, pop_sv, push, stack_value_size};
24use crate::value::{Value, VariantData};
25use std::sync::Arc;
26
27#[inline]
29fn stack_depth(stack: Stack) -> usize {
30 if stack.is_null() {
31 return 0;
32 }
33 let base = get_stack_base();
34 if base.is_null() {
35 return 0;
36 }
37 (stack as usize - base as usize) / stack_value_size()
38}
39
40unsafe fn drain_stack_to_base(mut stack: Stack, base: Stack) {
45 unsafe {
46 while stack > base {
47 let (rest, sv) = pop_sv(stack);
48 drop_stack_value(sv);
49 stack = rest;
50 }
51 }
52}
53
54unsafe fn call_with_value(base: Stack, value: Value, callable: &Value) -> Stack {
59 unsafe {
60 let stack = push(base, value);
61
62 match callable {
63 Value::Quotation { wrapper, .. } => {
64 let fn_ref: unsafe extern "C" fn(Stack) -> Stack = std::mem::transmute(*wrapper);
65 fn_ref(stack)
66 }
67 Value::Closure { fn_ptr, env } => {
68 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
69 std::mem::transmute(*fn_ptr);
70 fn_ref(stack, env.as_ptr(), env.len())
71 }
72 _ => panic!("list operation: expected Quotation or Closure"),
73 }
74 }
75}
76
77#[unsafe(no_mangle)]
87pub unsafe extern "C" fn patch_seq_list_map(stack: Stack) -> Stack {
88 unsafe {
89 let (stack, callable) = pop(stack);
91
92 match &callable {
94 Value::Quotation { .. } | Value::Closure { .. } => {}
95 _ => panic!(
96 "list-map: expected Quotation or Closure, got {:?}",
97 callable
98 ),
99 }
100
101 let (stack, list_val) = pop(stack);
103
104 let variant_data = match list_val {
105 Value::Variant(v) => v,
106 _ => panic!("list-map: expected Variant (list), got {:?}", list_val),
107 };
108
109 let mut results = Vec::with_capacity(variant_data.fields.len());
111
112 for field in variant_data.fields.iter() {
113 let temp_base = crate::stack::alloc_stack();
115 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
116
117 if temp_stack <= temp_base {
119 panic!("list-map: quotation consumed element without producing result");
120 }
121 let (remaining, result) = pop(temp_stack);
122 results.push(result);
123
124 if remaining > temp_base {
126 drain_stack_to_base(remaining, temp_base);
127 }
128 }
129
130 let new_variant = Value::Variant(Arc::new(VariantData::new(
132 variant_data.tag.clone(),
133 results,
134 )));
135
136 push(stack, new_variant)
137 }
138}
139
140#[unsafe(no_mangle)]
150pub unsafe extern "C" fn patch_seq_list_filter(stack: Stack) -> Stack {
151 unsafe {
152 let (stack, callable) = pop(stack);
154
155 match &callable {
157 Value::Quotation { .. } | Value::Closure { .. } => {}
158 _ => panic!(
159 "list-filter: expected Quotation or Closure, got {:?}",
160 callable
161 ),
162 }
163
164 let (stack, list_val) = pop(stack);
166
167 let variant_data = match list_val {
168 Value::Variant(v) => v,
169 _ => panic!("list-filter: expected Variant (list), got {:?}", list_val),
170 };
171
172 let mut results = Vec::new();
174
175 for field in variant_data.fields.iter() {
176 let temp_base = crate::stack::alloc_stack();
178 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
179
180 if temp_stack <= temp_base {
182 panic!("list-filter: quotation consumed element without producing result");
183 }
184 let (remaining, result) = pop(temp_stack);
185
186 let keep = match result {
187 Value::Bool(b) => b,
188 _ => panic!("list-filter: quotation must return Bool, got {:?}", result),
189 };
190
191 if keep {
192 results.push(field.clone());
193 }
194
195 if remaining > temp_base {
197 drain_stack_to_base(remaining, temp_base);
198 }
199 }
200
201 let new_variant = Value::Variant(Arc::new(VariantData::new(
203 variant_data.tag.clone(),
204 results,
205 )));
206
207 push(stack, new_variant)
208 }
209}
210
211#[unsafe(no_mangle)]
221pub unsafe extern "C" fn patch_seq_list_fold(stack: Stack) -> Stack {
222 unsafe {
223 let (stack, callable) = pop(stack);
225
226 match &callable {
228 Value::Quotation { .. } | Value::Closure { .. } => {}
229 _ => panic!(
230 "list-fold: expected Quotation or Closure, got {:?}",
231 callable
232 ),
233 }
234
235 let (stack, init) = pop(stack);
237
238 let (stack, list_val) = pop(stack);
240
241 let variant_data = match list_val {
242 Value::Variant(v) => v,
243 _ => panic!("list-fold: expected Variant (list), got {:?}", list_val),
244 };
245
246 let mut acc = init;
248
249 for field in variant_data.fields.iter() {
250 let temp_base = crate::stack::alloc_stack();
252 let temp_stack = push(temp_base, acc);
253 let temp_stack = push(temp_stack, field.clone());
254
255 let temp_stack = match &callable {
256 Value::Quotation { wrapper, .. } => {
257 let fn_ref: unsafe extern "C" fn(Stack) -> Stack =
258 std::mem::transmute(*wrapper);
259 fn_ref(temp_stack)
260 }
261 Value::Closure { fn_ptr, env } => {
262 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
263 std::mem::transmute(*fn_ptr);
264 fn_ref(temp_stack, env.as_ptr(), env.len())
265 }
266 _ => unreachable!(),
267 };
268
269 if temp_stack <= temp_base {
271 panic!("list-fold: quotation consumed inputs without producing result");
272 }
273 let (remaining, new_acc) = pop(temp_stack);
274 acc = new_acc;
275
276 if remaining > temp_base {
278 drain_stack_to_base(remaining, temp_base);
279 }
280 }
281
282 push(stack, acc)
283 }
284}
285
286#[unsafe(no_mangle)]
296pub unsafe extern "C" fn patch_seq_list_each(stack: Stack) -> Stack {
297 unsafe {
298 let (stack, callable) = pop(stack);
300
301 match &callable {
303 Value::Quotation { .. } | Value::Closure { .. } => {}
304 _ => panic!(
305 "list-each: expected Quotation or Closure, got {:?}",
306 callable
307 ),
308 }
309
310 let (stack, list_val) = pop(stack);
312
313 let variant_data = match list_val {
314 Value::Variant(v) => v,
315 _ => panic!("list-each: expected Variant (list), got {:?}", list_val),
316 };
317
318 for field in variant_data.fields.iter() {
320 let temp_base = crate::stack::alloc_stack();
321 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
322 if temp_stack > temp_base {
324 drain_stack_to_base(temp_stack, temp_base);
325 }
326 }
327
328 stack
329 }
330}
331
332#[unsafe(no_mangle)]
342pub unsafe extern "C" fn patch_seq_list_length(stack: Stack) -> Stack {
343 unsafe { crate::variant_ops::patch_seq_variant_field_count(stack) }
344}
345
346#[unsafe(no_mangle)]
355pub unsafe extern "C" fn patch_seq_list_empty(stack: Stack) -> Stack {
356 unsafe {
357 let (stack, list_val) = pop(stack);
358
359 let is_empty = match list_val {
360 Value::Variant(v) => v.fields.is_empty(),
361 _ => panic!("list-empty?: expected Variant (list), got {:?}", list_val),
362 };
363
364 push(stack, Value::Bool(is_empty))
365 }
366}
367
368#[unsafe(no_mangle)]
377pub unsafe extern "C" fn patch_seq_list_make(stack: Stack) -> Stack {
378 unsafe {
379 let list = Value::Variant(Arc::new(VariantData::new(
380 crate::seqstring::global_string("List".to_string()),
381 vec![],
382 )));
383 push(stack, list)
384 }
385}
386
387#[unsafe(no_mangle)]
397pub unsafe extern "C" fn patch_seq_list_push(stack: Stack) -> Stack {
398 unsafe {
399 let (stack, value) = pop(stack);
400 let (stack, list_val) = pop(stack);
401 let variant_arc = match list_val {
402 Value::Variant(v) => v,
403 _ => panic!("list.push: expected Variant (list), got {:?}", list_val),
404 };
405 push_to_variant(stack, variant_arc, value)
406 }
407}
408
409unsafe fn push_to_variant(stack: Stack, mut variant_arc: Arc<VariantData>, value: Value) -> Stack {
411 unsafe {
412 if let Some(data) = Arc::get_mut(&mut variant_arc) {
413 data.fields.push(value);
415 push(stack, Value::Variant(variant_arc))
416 } else {
417 let mut new_fields = Vec::with_capacity(variant_arc.fields.len() + 1);
419 new_fields.extend(variant_arc.fields.iter().cloned());
420 new_fields.push(value);
421 let new_list = Value::Variant(Arc::new(VariantData::new(
422 variant_arc.tag.clone(),
423 new_fields,
424 )));
425 push(stack, new_list)
426 }
427 }
428}
429
430#[unsafe(no_mangle)]
448pub unsafe extern "C" fn patch_seq_list_push_in_place(stack: Stack) -> Stack {
449 use crate::tagged_stack::{TAG_FALSE, TAG_TRUE, is_tagged_int};
450
451 unsafe {
452 let (stack, value) = pop(stack);
454
455 let list_sv_ptr = stack.sub(1);
458 let list_sv = *list_sv_ptr;
459
460 if is_tagged_int(list_sv) || list_sv == TAG_FALSE || list_sv == TAG_TRUE {
462 panic!("list.push!: expected list on stack, got inline value");
463 }
464
465 let mut outer_arc = Arc::from_raw(list_sv as *const Value);
471 if let Some(inner_val) = Arc::get_mut(&mut outer_arc)
472 && let Value::Variant(variant_arc) = inner_val
473 && let Some(data) = Arc::get_mut(variant_arc)
474 {
475 data.fields.push(value);
476 std::mem::forget(outer_arc); return stack; }
479 std::mem::forget(outer_arc);
481
482 let (stack, list_val) = pop(stack);
484 let variant_arc = match list_val {
485 Value::Variant(v) => v,
486 _ => panic!("list.push!: expected list on stack"),
487 };
488 push_to_variant(stack, variant_arc, value)
489 }
490}
491
492#[unsafe(no_mangle)]
507pub unsafe extern "C" fn patch_seq_list_get(stack: Stack) -> Stack {
508 unsafe {
509 if stack_depth(stack) < 2 {
511 set_runtime_error("list.get: stack underflow (need 2 values)");
512 return stack;
513 }
514 let (stack, index_val) = pop(stack);
515 let (stack, list_val) = pop(stack);
516
517 let index = match index_val {
518 Value::Int(i) => i,
519 _ => {
520 set_runtime_error(format!(
521 "list.get: expected Int (index), got {:?}",
522 index_val
523 ));
524 let stack = push(stack, Value::Int(0));
525 return push(stack, Value::Bool(false));
526 }
527 };
528
529 let variant_data = match list_val {
530 Value::Variant(v) => v,
531 _ => {
532 set_runtime_error(format!(
533 "list.get: expected Variant (list), got {:?}",
534 list_val
535 ));
536 let stack = push(stack, Value::Int(0));
537 return push(stack, Value::Bool(false));
538 }
539 };
540
541 if index < 0 || index as usize >= variant_data.fields.len() {
542 let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false))
545 } else {
546 let value = variant_data.fields[index as usize].clone();
547 let stack = push(stack, value);
548 push(stack, Value::Bool(true))
549 }
550 }
551}
552
553#[unsafe(no_mangle)]
568pub unsafe extern "C" fn patch_seq_list_set(stack: Stack) -> Stack {
569 unsafe {
570 if stack_depth(stack) < 3 {
572 set_runtime_error("list.set: stack underflow (need 3 values)");
573 return stack;
574 }
575 let (stack, value) = pop(stack);
576 let (stack, index_val) = pop(stack);
577 let (stack, list_val) = pop(stack);
578
579 let index = match index_val {
580 Value::Int(i) => i,
581 _ => {
582 set_runtime_error(format!(
583 "list.set: expected Int (index), got {:?}",
584 index_val
585 ));
586 let stack = push(stack, list_val);
588 return push(stack, Value::Bool(false));
589 }
590 };
591
592 let mut arc = match list_val {
593 Value::Variant(v) => v,
594 other => {
595 set_runtime_error(format!(
596 "list.set: expected Variant (list), got {:?}",
597 other
598 ));
599 let stack = push(stack, other);
600 return push(stack, Value::Bool(false));
601 }
602 };
603
604 if index < 0 || index as usize >= arc.fields.len() {
605 let stack = push(stack, Value::Variant(arc));
607 push(stack, Value::Bool(false))
608 } else {
609 if let Some(data) = Arc::get_mut(&mut arc) {
611 data.fields[index as usize] = value;
612 let stack = push(stack, Value::Variant(arc));
613 push(stack, Value::Bool(true))
614 } else {
615 let mut new_fields: Vec<Value> = arc.fields.to_vec();
617 new_fields[index as usize] = value;
618 let new_list =
619 Value::Variant(Arc::new(VariantData::new(arc.tag.clone(), new_fields)));
620 let stack = push(stack, new_list);
621 push(stack, Value::Bool(true))
622 }
623 }
624 }
625}
626
627pub use patch_seq_list_each as list_each;
629pub use patch_seq_list_empty as list_empty;
630pub use patch_seq_list_filter as list_filter;
631pub use patch_seq_list_fold as list_fold;
632pub use patch_seq_list_get as list_get;
633pub use patch_seq_list_length as list_length;
634pub use patch_seq_list_make as list_make;
635pub use patch_seq_list_map as list_map;
636pub use patch_seq_list_push as list_push;
637pub use patch_seq_list_set as list_set;
638
639#[cfg(test)]
640mod tests {
641 use super::*;
642 use crate::seqstring::global_string;
643
644 unsafe extern "C" fn double_quot(stack: Stack) -> Stack {
646 unsafe {
647 let (stack, val) = pop(stack);
648 match val {
649 Value::Int(n) => push(stack, Value::Int(n * 2)),
650 _ => panic!("Expected Int"),
651 }
652 }
653 }
654
655 unsafe extern "C" fn is_positive_quot(stack: Stack) -> Stack {
657 unsafe {
658 let (stack, val) = pop(stack);
659 match val {
660 Value::Int(n) => push(stack, Value::Bool(n > 0)),
661 _ => panic!("Expected Int"),
662 }
663 }
664 }
665
666 unsafe extern "C" fn add_quot(stack: Stack) -> Stack {
668 unsafe {
669 let (stack, b) = pop(stack);
670 let (stack, a) = pop(stack);
671 match (a, b) {
672 (Value::Int(x), Value::Int(y)) => push(stack, Value::Int(x + y)),
673 _ => panic!("Expected two Ints"),
674 }
675 }
676 }
677
678 #[test]
679 fn test_list_map_double() {
680 unsafe {
681 let list = Value::Variant(Arc::new(VariantData::new(
683 global_string("List".to_string()),
684 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
685 )));
686
687 let stack = crate::stack::alloc_test_stack();
688 let stack = push(stack, list);
689 let fn_ptr = double_quot as *const () as usize;
690 let stack = push(
691 stack,
692 Value::Quotation {
693 wrapper: fn_ptr,
694 impl_: fn_ptr,
695 },
696 );
697 let stack = list_map(stack);
698
699 let (_stack, result) = pop(stack);
700 match result {
701 Value::Variant(v) => {
702 assert_eq!(v.fields.len(), 3);
703 assert_eq!(v.fields[0], Value::Int(2));
704 assert_eq!(v.fields[1], Value::Int(4));
705 assert_eq!(v.fields[2], Value::Int(6));
706 }
707 _ => panic!("Expected Variant"),
708 }
709 }
710 }
711
712 #[test]
713 fn test_list_filter_positive() {
714 unsafe {
715 let list = Value::Variant(Arc::new(VariantData::new(
717 global_string("List".to_string()),
718 vec![
719 Value::Int(-1),
720 Value::Int(2),
721 Value::Int(-3),
722 Value::Int(4),
723 Value::Int(0),
724 ],
725 )));
726
727 let stack = crate::stack::alloc_test_stack();
728 let stack = push(stack, list);
729 let fn_ptr = is_positive_quot as *const () as usize;
730 let stack = push(
731 stack,
732 Value::Quotation {
733 wrapper: fn_ptr,
734 impl_: fn_ptr,
735 },
736 );
737 let stack = list_filter(stack);
738
739 let (_stack, result) = pop(stack);
740 match result {
741 Value::Variant(v) => {
742 assert_eq!(v.fields.len(), 2);
743 assert_eq!(v.fields[0], Value::Int(2));
744 assert_eq!(v.fields[1], Value::Int(4));
745 }
746 _ => panic!("Expected Variant"),
747 }
748 }
749 }
750
751 #[test]
752 fn test_list_fold_sum() {
753 unsafe {
754 let list = Value::Variant(Arc::new(VariantData::new(
756 global_string("List".to_string()),
757 vec![
758 Value::Int(1),
759 Value::Int(2),
760 Value::Int(3),
761 Value::Int(4),
762 Value::Int(5),
763 ],
764 )));
765
766 let stack = crate::stack::alloc_test_stack();
767 let stack = push(stack, list);
768 let stack = push(stack, Value::Int(0)); let fn_ptr = add_quot as *const () as usize;
770 let stack = push(
771 stack,
772 Value::Quotation {
773 wrapper: fn_ptr,
774 impl_: fn_ptr,
775 },
776 );
777 let stack = list_fold(stack);
778
779 let (_stack, result) = pop(stack);
780 assert_eq!(result, Value::Int(15)); }
782 }
783
784 #[test]
785 fn test_list_fold_empty() {
786 unsafe {
787 let list = Value::Variant(Arc::new(VariantData::new(
789 global_string("List".to_string()),
790 vec![],
791 )));
792
793 let stack = crate::stack::alloc_test_stack();
794 let stack = push(stack, list);
795 let stack = push(stack, Value::Int(42)); let fn_ptr = add_quot as *const () as usize;
797 let stack = push(
798 stack,
799 Value::Quotation {
800 wrapper: fn_ptr,
801 impl_: fn_ptr,
802 },
803 );
804 let stack = list_fold(stack);
805
806 let (_stack, result) = pop(stack);
807 assert_eq!(result, Value::Int(42)); }
809 }
810
811 #[test]
812 fn test_list_length() {
813 unsafe {
814 let list = Value::Variant(Arc::new(VariantData::new(
815 global_string("List".to_string()),
816 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
817 )));
818
819 let stack = crate::stack::alloc_test_stack();
820 let stack = push(stack, list);
821 let stack = list_length(stack);
822
823 let (_stack, result) = pop(stack);
824 assert_eq!(result, Value::Int(3));
825 }
826 }
827
828 #[test]
829 fn test_list_empty_true() {
830 unsafe {
831 let list = Value::Variant(Arc::new(VariantData::new(
832 global_string("List".to_string()),
833 vec![],
834 )));
835
836 let stack = crate::stack::alloc_test_stack();
837 let stack = push(stack, list);
838 let stack = list_empty(stack);
839
840 let (_stack, result) = pop(stack);
841 assert_eq!(result, Value::Bool(true));
842 }
843 }
844
845 #[test]
846 fn test_list_empty_false() {
847 unsafe {
848 let list = Value::Variant(Arc::new(VariantData::new(
849 global_string("List".to_string()),
850 vec![Value::Int(1)],
851 )));
852
853 let stack = crate::stack::alloc_test_stack();
854 let stack = push(stack, list);
855 let stack = list_empty(stack);
856
857 let (_stack, result) = pop(stack);
858 assert_eq!(result, Value::Bool(false));
859 }
860 }
861
862 #[test]
863 fn test_list_map_empty() {
864 unsafe {
865 let list = Value::Variant(Arc::new(VariantData::new(
866 global_string("List".to_string()),
867 vec![],
868 )));
869
870 let stack = crate::stack::alloc_test_stack();
871 let stack = push(stack, list);
872 let fn_ptr = double_quot as *const () as usize;
873 let stack = push(
874 stack,
875 Value::Quotation {
876 wrapper: fn_ptr,
877 impl_: fn_ptr,
878 },
879 );
880 let stack = list_map(stack);
881
882 let (_stack, result) = pop(stack);
883 match result {
884 Value::Variant(v) => {
885 assert_eq!(v.fields.len(), 0);
886 }
887 _ => panic!("Expected Variant"),
888 }
889 }
890 }
891
892 #[test]
893 fn test_list_map_preserves_tag() {
894 unsafe {
895 let list = Value::Variant(Arc::new(VariantData::new(
897 global_string("CustomTag".to_string()),
898 vec![Value::Int(1), Value::Int(2)],
899 )));
900
901 let stack = crate::stack::alloc_test_stack();
902 let stack = push(stack, list);
903 let fn_ptr = double_quot as *const () as usize;
904 let stack = push(
905 stack,
906 Value::Quotation {
907 wrapper: fn_ptr,
908 impl_: fn_ptr,
909 },
910 );
911 let stack = list_map(stack);
912
913 let (_stack, result) = pop(stack);
914 match result {
915 Value::Variant(v) => {
916 assert_eq!(v.tag.as_str(), "CustomTag"); assert_eq!(v.fields[0], Value::Int(2));
918 assert_eq!(v.fields[1], Value::Int(4));
919 }
920 _ => panic!("Expected Variant"),
921 }
922 }
923 }
924
925 unsafe extern "C" fn add_captured_closure(
928 stack: Stack,
929 env: *const Value,
930 _env_len: usize,
931 ) -> Stack {
932 unsafe {
933 let (stack, val) = pop(stack);
934 let captured = &*env; match (val, captured) {
936 (Value::Int(n), Value::Int(c)) => push(stack, Value::Int(n + c)),
937 _ => panic!("Expected Int"),
938 }
939 }
940 }
941
942 #[test]
943 fn test_list_map_with_closure() {
944 unsafe {
945 let list = Value::Variant(Arc::new(VariantData::new(
947 global_string("List".to_string()),
948 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
949 )));
950
951 let env: std::sync::Arc<[Value]> =
953 std::sync::Arc::from(vec![Value::Int(10)].into_boxed_slice());
954 let closure = Value::Closure {
955 fn_ptr: add_captured_closure as *const () as usize,
956 env,
957 };
958
959 let stack = crate::stack::alloc_test_stack();
960 let stack = push(stack, list);
961 let stack = push(stack, closure);
962 let stack = list_map(stack);
963
964 let (_stack, result) = pop(stack);
965 match result {
966 Value::Variant(v) => {
967 assert_eq!(v.fields.len(), 3);
968 assert_eq!(v.fields[0], Value::Int(11)); assert_eq!(v.fields[1], Value::Int(12)); assert_eq!(v.fields[2], Value::Int(13)); }
972 _ => panic!("Expected Variant"),
973 }
974 }
975 }
976
977 #[test]
978 fn test_list_get_type_error_index() {
979 unsafe {
980 crate::error::clear_runtime_error();
981
982 let list = Value::Variant(Arc::new(VariantData::new(
983 global_string("List".to_string()),
984 vec![Value::Int(1), Value::Int(2)],
985 )));
986
987 let stack = crate::stack::alloc_test_stack();
988 let stack = push(stack, list);
989 let stack = push(stack, Value::Bool(true)); let stack = list_get(stack);
991
992 assert!(crate::error::has_runtime_error());
994 let error = crate::error::take_runtime_error().unwrap();
995 assert!(error.contains("expected Int"));
996
997 let (stack, success) = pop(stack);
999 assert_eq!(success, Value::Bool(false));
1000 let (_stack, value) = pop(stack);
1001 assert_eq!(value, Value::Int(0));
1002 }
1003 }
1004
1005 #[test]
1006 fn test_list_get_type_error_list() {
1007 unsafe {
1008 crate::error::clear_runtime_error();
1009
1010 let stack = crate::stack::alloc_test_stack();
1011 let stack = push(stack, Value::Int(42)); let stack = push(stack, Value::Int(0)); let stack = list_get(stack);
1014
1015 assert!(crate::error::has_runtime_error());
1017 let error = crate::error::take_runtime_error().unwrap();
1018 assert!(error.contains("expected Variant"));
1019
1020 let (stack, success) = pop(stack);
1022 assert_eq!(success, Value::Bool(false));
1023 let (_stack, value) = pop(stack);
1024 assert_eq!(value, Value::Int(0));
1025 }
1026 }
1027
1028 #[test]
1029 fn test_list_set_type_error_index() {
1030 unsafe {
1031 crate::error::clear_runtime_error();
1032
1033 let list = Value::Variant(Arc::new(VariantData::new(
1034 global_string("List".to_string()),
1035 vec![Value::Int(1), Value::Int(2)],
1036 )));
1037
1038 let stack = crate::stack::alloc_test_stack();
1039 let stack = push(stack, list);
1040 let stack = push(stack, Value::Bool(true)); let stack = push(stack, Value::Int(99)); let stack = list_set(stack);
1043
1044 assert!(crate::error::has_runtime_error());
1046 let error = crate::error::take_runtime_error().unwrap();
1047 assert!(error.contains("expected Int"));
1048
1049 let (stack, success) = pop(stack);
1051 assert_eq!(success, Value::Bool(false));
1052 let (_stack, returned_list) = pop(stack);
1053 assert!(matches!(returned_list, Value::Variant(_)));
1054 }
1055 }
1056
1057 #[test]
1058 fn test_list_set_type_error_list() {
1059 unsafe {
1060 crate::error::clear_runtime_error();
1061
1062 let stack = crate::stack::alloc_test_stack();
1063 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);
1067
1068 assert!(crate::error::has_runtime_error());
1070 let error = crate::error::take_runtime_error().unwrap();
1071 assert!(error.contains("expected Variant"));
1072
1073 let (stack, success) = pop(stack);
1075 assert_eq!(success, Value::Bool(false));
1076 let (_stack, returned) = pop(stack);
1077 assert_eq!(returned, Value::Int(42)); }
1079 }
1080}