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
65 match callable {
66 Value::Quotation { wrapper, .. } => {
67 let fn_ref: unsafe extern "C" fn(Stack) -> Stack = std::mem::transmute(*wrapper);
68 fn_ref(stack)
69 }
70 Value::Closure { fn_ptr, env } => {
71 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
72 std::mem::transmute(*fn_ptr);
73 fn_ref(stack, env.as_ptr(), env.len())
74 }
75 _ => panic!("list operation: expected Quotation or Closure"),
76 }
77 }
78}
79
80#[unsafe(no_mangle)]
90pub unsafe extern "C" fn patch_seq_list_map(stack: Stack) -> Stack {
91 unsafe {
92 let (stack, callable) = pop(stack);
94
95 match &callable {
97 Value::Quotation { .. } | Value::Closure { .. } => {}
98 _ => panic!(
99 "list-map: expected Quotation or Closure, got {:?}",
100 callable
101 ),
102 }
103
104 let (stack, list_val) = pop(stack);
106
107 let variant_data = match list_val {
108 Value::Variant(v) => v,
109 _ => panic!("list-map: expected Variant (list), got {:?}", list_val),
110 };
111
112 let mut results = Vec::with_capacity(variant_data.fields.len());
114
115 for field in variant_data.fields.iter() {
116 let temp_base = crate::stack::alloc_stack();
118 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
119
120 if temp_stack <= temp_base {
122 panic!("list-map: quotation consumed element without producing result");
123 }
124 let (remaining, result) = pop(temp_stack);
125 results.push(result);
126
127 if remaining > temp_base {
129 drain_stack_to_base(remaining, temp_base);
130 }
131 }
132
133 let new_variant = Value::Variant(Arc::new(VariantData::new(
135 variant_data.tag.clone(),
136 results,
137 )));
138
139 push(stack, new_variant)
140 }
141}
142
143#[unsafe(no_mangle)]
153pub unsafe extern "C" fn patch_seq_list_filter(stack: Stack) -> Stack {
154 unsafe {
155 let (stack, callable) = pop(stack);
157
158 match &callable {
160 Value::Quotation { .. } | Value::Closure { .. } => {}
161 _ => panic!(
162 "list-filter: expected Quotation or Closure, got {:?}",
163 callable
164 ),
165 }
166
167 let (stack, list_val) = pop(stack);
169
170 let variant_data = match list_val {
171 Value::Variant(v) => v,
172 _ => panic!("list-filter: expected Variant (list), got {:?}", list_val),
173 };
174
175 let mut results = Vec::new();
177
178 for field in variant_data.fields.iter() {
179 let temp_base = crate::stack::alloc_stack();
181 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
182
183 if temp_stack <= temp_base {
185 panic!("list-filter: quotation consumed element without producing result");
186 }
187 let (remaining, result) = pop(temp_stack);
188
189 let keep = match result {
190 Value::Bool(b) => b,
191 _ => panic!("list-filter: quotation must return Bool, got {:?}", result),
192 };
193
194 if keep {
195 results.push(field.clone());
196 }
197
198 if remaining > temp_base {
200 drain_stack_to_base(remaining, temp_base);
201 }
202 }
203
204 let new_variant = Value::Variant(Arc::new(VariantData::new(
206 variant_data.tag.clone(),
207 results,
208 )));
209
210 push(stack, new_variant)
211 }
212}
213
214#[unsafe(no_mangle)]
224pub unsafe extern "C" fn patch_seq_list_fold(stack: Stack) -> Stack {
225 unsafe {
226 let (stack, callable) = pop(stack);
228
229 match &callable {
231 Value::Quotation { .. } | Value::Closure { .. } => {}
232 _ => panic!(
233 "list-fold: expected Quotation or Closure, got {:?}",
234 callable
235 ),
236 }
237
238 let (stack, init) = pop(stack);
240
241 let (stack, list_val) = pop(stack);
243
244 let variant_data = match list_val {
245 Value::Variant(v) => v,
246 _ => panic!("list-fold: expected Variant (list), got {:?}", list_val),
247 };
248
249 let mut acc = init;
251
252 for field in variant_data.fields.iter() {
253 let temp_base = crate::stack::alloc_stack();
255 let temp_stack = push(temp_base, acc);
256 let temp_stack = push(temp_stack, field.clone());
257
258 let temp_stack = match &callable {
259 Value::Quotation { wrapper, .. } => {
260 let fn_ref: unsafe extern "C" fn(Stack) -> Stack =
261 std::mem::transmute(*wrapper);
262 fn_ref(temp_stack)
263 }
264 Value::Closure { fn_ptr, env } => {
265 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
266 std::mem::transmute(*fn_ptr);
267 fn_ref(temp_stack, env.as_ptr(), env.len())
268 }
269 _ => unreachable!(),
270 };
271
272 if temp_stack <= temp_base {
274 panic!("list-fold: quotation consumed inputs without producing result");
275 }
276 let (remaining, new_acc) = pop(temp_stack);
277 acc = new_acc;
278
279 if remaining > temp_base {
281 drain_stack_to_base(remaining, temp_base);
282 }
283 }
284
285 push(stack, acc)
286 }
287}
288
289#[unsafe(no_mangle)]
299pub unsafe extern "C" fn patch_seq_list_each(stack: Stack) -> Stack {
300 unsafe {
301 let (stack, callable) = pop(stack);
303
304 match &callable {
306 Value::Quotation { .. } | Value::Closure { .. } => {}
307 _ => panic!(
308 "list-each: expected Quotation or Closure, got {:?}",
309 callable
310 ),
311 }
312
313 let (stack, list_val) = pop(stack);
315
316 let variant_data = match list_val {
317 Value::Variant(v) => v,
318 _ => panic!("list-each: expected Variant (list), got {:?}", list_val),
319 };
320
321 for field in variant_data.fields.iter() {
323 let temp_base = crate::stack::alloc_stack();
324 let temp_stack = call_with_value(temp_base, field.clone(), &callable);
325 if temp_stack > temp_base {
327 drain_stack_to_base(temp_stack, temp_base);
328 }
329 }
330
331 stack
332 }
333}
334
335#[unsafe(no_mangle)]
345pub unsafe extern "C" fn patch_seq_list_length(stack: Stack) -> Stack {
346 unsafe { crate::variant_ops::patch_seq_variant_field_count(stack) }
347}
348
349#[unsafe(no_mangle)]
358pub unsafe extern "C" fn patch_seq_list_empty(stack: Stack) -> Stack {
359 unsafe {
360 let (stack, list_val) = pop(stack);
361
362 let is_empty = match list_val {
363 Value::Variant(v) => v.fields.is_empty(),
364 _ => panic!("list-empty?: expected Variant (list), got {:?}", list_val),
365 };
366
367 push(stack, Value::Bool(is_empty))
368 }
369}
370
371#[unsafe(no_mangle)]
380pub unsafe extern "C" fn patch_seq_list_make(stack: Stack) -> Stack {
381 unsafe {
382 let list = Value::Variant(Arc::new(VariantData::new(
383 crate::seqstring::global_string("List".to_string()),
384 vec![],
385 )));
386 push(stack, list)
387 }
388}
389
390#[unsafe(no_mangle)]
401pub unsafe extern "C" fn patch_seq_list_push(stack: Stack) -> Stack {
402 unsafe {
403 if let Some(Value::Variant(variant_arc)) = peek_heap_mut_second(stack)
407 && let Some(data) = Arc::get_mut(variant_arc)
408 {
409 let (stack, value) = pop(stack);
414 data.fields.push(value);
415 return stack; }
417
418 let (stack, value) = pop(stack);
420 let (stack, list_val) = pop(stack);
421 let variant_arc = match list_val {
422 Value::Variant(v) => v,
423 _ => panic!("list.push: expected Variant (list), got {:?}", list_val),
424 };
425 push_to_variant(stack, variant_arc, value)
426 }
427}
428
429unsafe fn push_to_variant(stack: Stack, mut variant_arc: Arc<VariantData>, value: Value) -> Stack {
431 unsafe {
432 if let Some(data) = Arc::get_mut(&mut variant_arc) {
433 data.fields.push(value);
435 push(stack, Value::Variant(variant_arc))
436 } else {
437 let mut new_fields = Vec::with_capacity(variant_arc.fields.len() + 1);
439 new_fields.extend(variant_arc.fields.iter().cloned());
440 new_fields.push(value);
441 let new_list = Value::Variant(Arc::new(VariantData::new(
442 variant_arc.tag.clone(),
443 new_fields,
444 )));
445 push(stack, new_list)
446 }
447 }
448}
449
450#[unsafe(no_mangle)]
465pub unsafe extern "C" fn patch_seq_list_get(stack: Stack) -> Stack {
466 unsafe {
467 if stack_depth(stack) < 2 {
469 set_runtime_error("list.get: stack underflow (need 2 values)");
470 return stack;
471 }
472 let (stack, index_val) = pop(stack);
473 let (stack, list_val) = pop(stack);
474
475 let index = match index_val {
476 Value::Int(i) => i,
477 _ => {
478 set_runtime_error(format!(
479 "list.get: expected Int (index), got {:?}",
480 index_val
481 ));
482 let stack = push(stack, Value::Int(0));
483 return push(stack, Value::Bool(false));
484 }
485 };
486
487 let variant_data = match list_val {
488 Value::Variant(v) => v,
489 _ => {
490 set_runtime_error(format!(
491 "list.get: expected Variant (list), got {:?}",
492 list_val
493 ));
494 let stack = push(stack, Value::Int(0));
495 return push(stack, Value::Bool(false));
496 }
497 };
498
499 if index < 0 || index as usize >= variant_data.fields.len() {
500 let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false))
503 } else {
504 let value = variant_data.fields[index as usize].clone();
505 let stack = push(stack, value);
506 push(stack, Value::Bool(true))
507 }
508 }
509}
510
511#[unsafe(no_mangle)]
531pub unsafe extern "C" fn patch_seq_list_set(stack: Stack) -> Stack {
532 unsafe {
533 if stack_depth(stack) < 3 {
535 set_runtime_error("list.set: stack underflow (need 3 values)");
536 return stack;
537 }
538
539 if let Some(Value::Variant(variant_arc)) = heap_value_mut(stack.sub(3))
544 && let Some(data) = Arc::get_mut(variant_arc)
545 {
546 let index_sv = *stack.sub(2);
549 if crate::tagged_stack::is_tagged_int(index_sv) {
550 let index = crate::tagged_stack::untag_int(index_sv);
551 if index >= 0 && (index as usize) < data.fields.len() {
552 let (stack, value) = pop(stack);
556 let (stack, _index) = pop(stack);
557 data.fields[index as usize] = value;
558 return push(stack, Value::Bool(true));
559 }
560 let (stack, _value) = pop(stack);
562 let (stack, _index) = pop(stack);
563 return push(stack, Value::Bool(false));
564 }
565 }
566
567 let (stack, value) = pop(stack);
569 let (stack, index_val) = pop(stack);
570 let (stack, list_val) = pop(stack);
571
572 let index = match index_val {
573 Value::Int(i) => i,
574 _ => {
575 set_runtime_error(format!(
576 "list.set: expected Int (index), got {:?}",
577 index_val
578 ));
579 let stack = push(stack, list_val);
580 return push(stack, Value::Bool(false));
581 }
582 };
583
584 let mut arc = match list_val {
585 Value::Variant(v) => v,
586 other => {
587 set_runtime_error(format!(
588 "list.set: expected Variant (list), got {:?}",
589 other
590 ));
591 let stack = push(stack, other);
592 return push(stack, Value::Bool(false));
593 }
594 };
595
596 if index < 0 || index as usize >= arc.fields.len() {
597 let stack = push(stack, Value::Variant(arc));
598 push(stack, Value::Bool(false))
599 } else if let Some(data) = Arc::get_mut(&mut arc) {
600 data.fields[index as usize] = value;
601 let stack = push(stack, Value::Variant(arc));
602 push(stack, Value::Bool(true))
603 } else {
604 let mut new_fields: Vec<Value> = arc.fields.to_vec();
605 new_fields[index as usize] = value;
606 let new_list = Value::Variant(Arc::new(VariantData::new(arc.tag.clone(), new_fields)));
607 let stack = push(stack, new_list);
608 push(stack, Value::Bool(true))
609 }
610 }
611}
612
613pub use patch_seq_list_each as list_each;
615pub use patch_seq_list_empty as list_empty;
616pub use patch_seq_list_filter as list_filter;
617pub use patch_seq_list_fold as list_fold;
618pub use patch_seq_list_get as list_get;
619pub use patch_seq_list_length as list_length;
620pub use patch_seq_list_make as list_make;
621pub use patch_seq_list_map as list_map;
622pub use patch_seq_list_push as list_push;
623pub use patch_seq_list_set as list_set;
624
625#[cfg(test)]
626mod tests {
627 use super::*;
628 use crate::seqstring::global_string;
629
630 unsafe extern "C" fn double_quot(stack: Stack) -> Stack {
632 unsafe {
633 let (stack, val) = pop(stack);
634 match val {
635 Value::Int(n) => push(stack, Value::Int(n * 2)),
636 _ => panic!("Expected Int"),
637 }
638 }
639 }
640
641 unsafe extern "C" fn is_positive_quot(stack: Stack) -> Stack {
643 unsafe {
644 let (stack, val) = pop(stack);
645 match val {
646 Value::Int(n) => push(stack, Value::Bool(n > 0)),
647 _ => panic!("Expected Int"),
648 }
649 }
650 }
651
652 unsafe extern "C" fn add_quot(stack: Stack) -> Stack {
654 unsafe {
655 let (stack, b) = pop(stack);
656 let (stack, a) = pop(stack);
657 match (a, b) {
658 (Value::Int(x), Value::Int(y)) => push(stack, Value::Int(x + y)),
659 _ => panic!("Expected two Ints"),
660 }
661 }
662 }
663
664 #[test]
665 fn test_list_map_double() {
666 unsafe {
667 let list = Value::Variant(Arc::new(VariantData::new(
669 global_string("List".to_string()),
670 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
671 )));
672
673 let stack = crate::stack::alloc_test_stack();
674 let stack = push(stack, list);
675 let fn_ptr = double_quot as *const () as usize;
676 let stack = push(
677 stack,
678 Value::Quotation {
679 wrapper: fn_ptr,
680 impl_: fn_ptr,
681 },
682 );
683 let stack = list_map(stack);
684
685 let (_stack, result) = pop(stack);
686 match result {
687 Value::Variant(v) => {
688 assert_eq!(v.fields.len(), 3);
689 assert_eq!(v.fields[0], Value::Int(2));
690 assert_eq!(v.fields[1], Value::Int(4));
691 assert_eq!(v.fields[2], Value::Int(6));
692 }
693 _ => panic!("Expected Variant"),
694 }
695 }
696 }
697
698 #[test]
699 fn test_list_filter_positive() {
700 unsafe {
701 let list = Value::Variant(Arc::new(VariantData::new(
703 global_string("List".to_string()),
704 vec![
705 Value::Int(-1),
706 Value::Int(2),
707 Value::Int(-3),
708 Value::Int(4),
709 Value::Int(0),
710 ],
711 )));
712
713 let stack = crate::stack::alloc_test_stack();
714 let stack = push(stack, list);
715 let fn_ptr = is_positive_quot as *const () as usize;
716 let stack = push(
717 stack,
718 Value::Quotation {
719 wrapper: fn_ptr,
720 impl_: fn_ptr,
721 },
722 );
723 let stack = list_filter(stack);
724
725 let (_stack, result) = pop(stack);
726 match result {
727 Value::Variant(v) => {
728 assert_eq!(v.fields.len(), 2);
729 assert_eq!(v.fields[0], Value::Int(2));
730 assert_eq!(v.fields[1], Value::Int(4));
731 }
732 _ => panic!("Expected Variant"),
733 }
734 }
735 }
736
737 #[test]
738 fn test_list_fold_sum() {
739 unsafe {
740 let list = Value::Variant(Arc::new(VariantData::new(
742 global_string("List".to_string()),
743 vec![
744 Value::Int(1),
745 Value::Int(2),
746 Value::Int(3),
747 Value::Int(4),
748 Value::Int(5),
749 ],
750 )));
751
752 let stack = crate::stack::alloc_test_stack();
753 let stack = push(stack, list);
754 let stack = push(stack, Value::Int(0)); let fn_ptr = add_quot as *const () as usize;
756 let stack = push(
757 stack,
758 Value::Quotation {
759 wrapper: fn_ptr,
760 impl_: fn_ptr,
761 },
762 );
763 let stack = list_fold(stack);
764
765 let (_stack, result) = pop(stack);
766 assert_eq!(result, Value::Int(15)); }
768 }
769
770 #[test]
771 fn test_list_fold_empty() {
772 unsafe {
773 let list = Value::Variant(Arc::new(VariantData::new(
775 global_string("List".to_string()),
776 vec![],
777 )));
778
779 let stack = crate::stack::alloc_test_stack();
780 let stack = push(stack, list);
781 let stack = push(stack, Value::Int(42)); let fn_ptr = add_quot as *const () as usize;
783 let stack = push(
784 stack,
785 Value::Quotation {
786 wrapper: fn_ptr,
787 impl_: fn_ptr,
788 },
789 );
790 let stack = list_fold(stack);
791
792 let (_stack, result) = pop(stack);
793 assert_eq!(result, Value::Int(42)); }
795 }
796
797 #[test]
798 fn test_list_length() {
799 unsafe {
800 let list = Value::Variant(Arc::new(VariantData::new(
801 global_string("List".to_string()),
802 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
803 )));
804
805 let stack = crate::stack::alloc_test_stack();
806 let stack = push(stack, list);
807 let stack = list_length(stack);
808
809 let (_stack, result) = pop(stack);
810 assert_eq!(result, Value::Int(3));
811 }
812 }
813
814 #[test]
815 fn test_list_empty_true() {
816 unsafe {
817 let list = Value::Variant(Arc::new(VariantData::new(
818 global_string("List".to_string()),
819 vec![],
820 )));
821
822 let stack = crate::stack::alloc_test_stack();
823 let stack = push(stack, list);
824 let stack = list_empty(stack);
825
826 let (_stack, result) = pop(stack);
827 assert_eq!(result, Value::Bool(true));
828 }
829 }
830
831 #[test]
832 fn test_list_empty_false() {
833 unsafe {
834 let list = Value::Variant(Arc::new(VariantData::new(
835 global_string("List".to_string()),
836 vec![Value::Int(1)],
837 )));
838
839 let stack = crate::stack::alloc_test_stack();
840 let stack = push(stack, list);
841 let stack = list_empty(stack);
842
843 let (_stack, result) = pop(stack);
844 assert_eq!(result, Value::Bool(false));
845 }
846 }
847
848 #[test]
849 fn test_list_map_empty() {
850 unsafe {
851 let list = Value::Variant(Arc::new(VariantData::new(
852 global_string("List".to_string()),
853 vec![],
854 )));
855
856 let stack = crate::stack::alloc_test_stack();
857 let stack = push(stack, list);
858 let fn_ptr = double_quot as *const () as usize;
859 let stack = push(
860 stack,
861 Value::Quotation {
862 wrapper: fn_ptr,
863 impl_: fn_ptr,
864 },
865 );
866 let stack = list_map(stack);
867
868 let (_stack, result) = pop(stack);
869 match result {
870 Value::Variant(v) => {
871 assert_eq!(v.fields.len(), 0);
872 }
873 _ => panic!("Expected Variant"),
874 }
875 }
876 }
877
878 #[test]
879 fn test_list_map_preserves_tag() {
880 unsafe {
881 let list = Value::Variant(Arc::new(VariantData::new(
883 global_string("CustomTag".to_string()),
884 vec![Value::Int(1), Value::Int(2)],
885 )));
886
887 let stack = crate::stack::alloc_test_stack();
888 let stack = push(stack, list);
889 let fn_ptr = double_quot as *const () as usize;
890 let stack = push(
891 stack,
892 Value::Quotation {
893 wrapper: fn_ptr,
894 impl_: fn_ptr,
895 },
896 );
897 let stack = list_map(stack);
898
899 let (_stack, result) = pop(stack);
900 match result {
901 Value::Variant(v) => {
902 assert_eq!(v.tag.as_str(), "CustomTag"); assert_eq!(v.fields[0], Value::Int(2));
904 assert_eq!(v.fields[1], Value::Int(4));
905 }
906 _ => panic!("Expected Variant"),
907 }
908 }
909 }
910
911 unsafe extern "C" fn add_captured_closure(
914 stack: Stack,
915 env: *const Value,
916 _env_len: usize,
917 ) -> Stack {
918 unsafe {
919 let (stack, val) = pop(stack);
920 let captured = &*env; match (val, captured) {
922 (Value::Int(n), Value::Int(c)) => push(stack, Value::Int(n + c)),
923 _ => panic!("Expected Int"),
924 }
925 }
926 }
927
928 #[test]
929 fn test_list_map_with_closure() {
930 unsafe {
931 let list = Value::Variant(Arc::new(VariantData::new(
933 global_string("List".to_string()),
934 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
935 )));
936
937 let env: std::sync::Arc<[Value]> =
939 std::sync::Arc::from(vec![Value::Int(10)].into_boxed_slice());
940 let closure = Value::Closure {
941 fn_ptr: add_captured_closure as *const () as usize,
942 env,
943 };
944
945 let stack = crate::stack::alloc_test_stack();
946 let stack = push(stack, list);
947 let stack = push(stack, closure);
948 let stack = list_map(stack);
949
950 let (_stack, result) = pop(stack);
951 match result {
952 Value::Variant(v) => {
953 assert_eq!(v.fields.len(), 3);
954 assert_eq!(v.fields[0], Value::Int(11)); assert_eq!(v.fields[1], Value::Int(12)); assert_eq!(v.fields[2], Value::Int(13)); }
958 _ => panic!("Expected Variant"),
959 }
960 }
961 }
962
963 #[test]
964 fn test_list_get_type_error_index() {
965 unsafe {
966 crate::error::clear_runtime_error();
967
968 let list = Value::Variant(Arc::new(VariantData::new(
969 global_string("List".to_string()),
970 vec![Value::Int(1), Value::Int(2)],
971 )));
972
973 let stack = crate::stack::alloc_test_stack();
974 let stack = push(stack, list);
975 let stack = push(stack, Value::Bool(true)); let stack = list_get(stack);
977
978 assert!(crate::error::has_runtime_error());
980 let error = crate::error::take_runtime_error().unwrap();
981 assert!(error.contains("expected Int"));
982
983 let (stack, success) = pop(stack);
985 assert_eq!(success, Value::Bool(false));
986 let (_stack, value) = pop(stack);
987 assert_eq!(value, Value::Int(0));
988 }
989 }
990
991 #[test]
992 fn test_list_get_type_error_list() {
993 unsafe {
994 crate::error::clear_runtime_error();
995
996 let stack = crate::stack::alloc_test_stack();
997 let stack = push(stack, Value::Int(42)); let stack = push(stack, Value::Int(0)); let stack = list_get(stack);
1000
1001 assert!(crate::error::has_runtime_error());
1003 let error = crate::error::take_runtime_error().unwrap();
1004 assert!(error.contains("expected Variant"));
1005
1006 let (stack, success) = pop(stack);
1008 assert_eq!(success, Value::Bool(false));
1009 let (_stack, value) = pop(stack);
1010 assert_eq!(value, Value::Int(0));
1011 }
1012 }
1013
1014 #[test]
1015 fn test_list_set_type_error_index() {
1016 unsafe {
1017 crate::error::clear_runtime_error();
1018
1019 let list = Value::Variant(Arc::new(VariantData::new(
1020 global_string("List".to_string()),
1021 vec![Value::Int(1), Value::Int(2)],
1022 )));
1023
1024 let stack = crate::stack::alloc_test_stack();
1025 let stack = push(stack, list);
1026 let stack = push(stack, Value::Bool(true)); let stack = push(stack, Value::Int(99)); let stack = list_set(stack);
1029
1030 assert!(crate::error::has_runtime_error());
1032 let error = crate::error::take_runtime_error().unwrap();
1033 assert!(error.contains("expected Int"));
1034
1035 let (stack, success) = pop(stack);
1037 assert_eq!(success, Value::Bool(false));
1038 let (_stack, returned_list) = pop(stack);
1039 assert!(matches!(returned_list, Value::Variant(_)));
1040 }
1041 }
1042
1043 #[test]
1044 fn test_list_set_type_error_list() {
1045 unsafe {
1046 crate::error::clear_runtime_error();
1047
1048 let stack = crate::stack::alloc_test_stack();
1049 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);
1053
1054 assert!(crate::error::has_runtime_error());
1056 let error = crate::error::take_runtime_error().unwrap();
1057 assert!(error.contains("expected Variant"));
1058
1059 let (stack, success) = pop(stack);
1061 assert_eq!(success, Value::Bool(false));
1062 let (_stack, returned) = pop(stack);
1063 assert_eq!(returned, Value::Int(42)); }
1065 }
1066}