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
402 let variant_data = match list_val {
403 Value::Variant(v) => v,
404 _ => panic!("list.push: expected Variant (list), got {:?}", list_val),
405 };
406
407 let mut new_fields = Vec::with_capacity(variant_data.fields.len() + 1);
409 new_fields.extend(variant_data.fields.iter().cloned());
410 new_fields.push(value);
411
412 let new_list = Value::Variant(Arc::new(VariantData::new(
413 variant_data.tag.clone(),
414 new_fields,
415 )));
416
417 push(stack, new_list)
418 }
419}
420
421#[unsafe(no_mangle)]
436pub unsafe extern "C" fn patch_seq_list_get(stack: Stack) -> Stack {
437 unsafe {
438 if stack_depth(stack) < 2 {
440 set_runtime_error("list.get: stack underflow (need 2 values)");
441 return stack;
442 }
443 let (stack, index_val) = pop(stack);
444 let (stack, list_val) = pop(stack);
445
446 let index = match index_val {
447 Value::Int(i) => i,
448 _ => {
449 set_runtime_error(format!(
450 "list.get: expected Int (index), got {:?}",
451 index_val
452 ));
453 let stack = push(stack, Value::Int(0));
454 return push(stack, Value::Bool(false));
455 }
456 };
457
458 let variant_data = match list_val {
459 Value::Variant(v) => v,
460 _ => {
461 set_runtime_error(format!(
462 "list.get: expected Variant (list), got {:?}",
463 list_val
464 ));
465 let stack = push(stack, Value::Int(0));
466 return push(stack, Value::Bool(false));
467 }
468 };
469
470 if index < 0 || index as usize >= variant_data.fields.len() {
471 let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false))
474 } else {
475 let value = variant_data.fields[index as usize].clone();
476 let stack = push(stack, value);
477 push(stack, Value::Bool(true))
478 }
479 }
480}
481
482#[unsafe(no_mangle)]
497pub unsafe extern "C" fn patch_seq_list_set(stack: Stack) -> Stack {
498 unsafe {
499 if stack_depth(stack) < 3 {
501 set_runtime_error("list.set: stack underflow (need 3 values)");
502 return stack;
503 }
504 let (stack, value) = pop(stack);
505 let (stack, index_val) = pop(stack);
506 let (stack, list_val) = pop(stack);
507
508 let index = match index_val {
509 Value::Int(i) => i,
510 _ => {
511 set_runtime_error(format!(
512 "list.set: expected Int (index), got {:?}",
513 index_val
514 ));
515 let stack = push(stack, list_val);
517 return push(stack, Value::Bool(false));
518 }
519 };
520
521 let variant_data = match &list_val {
522 Value::Variant(v) => v,
523 _ => {
524 set_runtime_error(format!(
525 "list.set: expected Variant (list), got {:?}",
526 list_val
527 ));
528 let stack = push(stack, list_val);
529 return push(stack, Value::Bool(false));
530 }
531 };
532
533 if index < 0 || index as usize >= variant_data.fields.len() {
534 let stack = push(stack, list_val);
536 push(stack, Value::Bool(false))
537 } else {
538 let mut new_fields: Vec<Value> = variant_data.fields.to_vec();
540 new_fields[index as usize] = value;
541
542 let new_list = Value::Variant(Arc::new(VariantData::new(
543 variant_data.tag.clone(),
544 new_fields,
545 )));
546
547 let stack = push(stack, new_list);
548 push(stack, Value::Bool(true))
549 }
550 }
551}
552
553pub use patch_seq_list_each as list_each;
555pub use patch_seq_list_empty as list_empty;
556pub use patch_seq_list_filter as list_filter;
557pub use patch_seq_list_fold as list_fold;
558pub use patch_seq_list_get as list_get;
559pub use patch_seq_list_length as list_length;
560pub use patch_seq_list_make as list_make;
561pub use patch_seq_list_map as list_map;
562pub use patch_seq_list_push as list_push;
563pub use patch_seq_list_set as list_set;
564
565#[cfg(test)]
566mod tests {
567 use super::*;
568 use crate::seqstring::global_string;
569
570 unsafe extern "C" fn double_quot(stack: Stack) -> Stack {
572 unsafe {
573 let (stack, val) = pop(stack);
574 match val {
575 Value::Int(n) => push(stack, Value::Int(n * 2)),
576 _ => panic!("Expected Int"),
577 }
578 }
579 }
580
581 unsafe extern "C" fn is_positive_quot(stack: Stack) -> Stack {
583 unsafe {
584 let (stack, val) = pop(stack);
585 match val {
586 Value::Int(n) => push(stack, Value::Bool(n > 0)),
587 _ => panic!("Expected Int"),
588 }
589 }
590 }
591
592 unsafe extern "C" fn add_quot(stack: Stack) -> Stack {
594 unsafe {
595 let (stack, b) = pop(stack);
596 let (stack, a) = pop(stack);
597 match (a, b) {
598 (Value::Int(x), Value::Int(y)) => push(stack, Value::Int(x + y)),
599 _ => panic!("Expected two Ints"),
600 }
601 }
602 }
603
604 #[test]
605 fn test_list_map_double() {
606 unsafe {
607 let list = Value::Variant(Arc::new(VariantData::new(
609 global_string("List".to_string()),
610 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
611 )));
612
613 let stack = crate::stack::alloc_test_stack();
614 let stack = push(stack, list);
615 let fn_ptr = double_quot as usize;
616 let stack = push(
617 stack,
618 Value::Quotation {
619 wrapper: fn_ptr,
620 impl_: fn_ptr,
621 },
622 );
623 let stack = list_map(stack);
624
625 let (_stack, result) = pop(stack);
626 match result {
627 Value::Variant(v) => {
628 assert_eq!(v.fields.len(), 3);
629 assert_eq!(v.fields[0], Value::Int(2));
630 assert_eq!(v.fields[1], Value::Int(4));
631 assert_eq!(v.fields[2], Value::Int(6));
632 }
633 _ => panic!("Expected Variant"),
634 }
635 }
636 }
637
638 #[test]
639 fn test_list_filter_positive() {
640 unsafe {
641 let list = Value::Variant(Arc::new(VariantData::new(
643 global_string("List".to_string()),
644 vec![
645 Value::Int(-1),
646 Value::Int(2),
647 Value::Int(-3),
648 Value::Int(4),
649 Value::Int(0),
650 ],
651 )));
652
653 let stack = crate::stack::alloc_test_stack();
654 let stack = push(stack, list);
655 let fn_ptr = is_positive_quot as usize;
656 let stack = push(
657 stack,
658 Value::Quotation {
659 wrapper: fn_ptr,
660 impl_: fn_ptr,
661 },
662 );
663 let stack = list_filter(stack);
664
665 let (_stack, result) = pop(stack);
666 match result {
667 Value::Variant(v) => {
668 assert_eq!(v.fields.len(), 2);
669 assert_eq!(v.fields[0], Value::Int(2));
670 assert_eq!(v.fields[1], Value::Int(4));
671 }
672 _ => panic!("Expected Variant"),
673 }
674 }
675 }
676
677 #[test]
678 fn test_list_fold_sum() {
679 unsafe {
680 let list = Value::Variant(Arc::new(VariantData::new(
682 global_string("List".to_string()),
683 vec![
684 Value::Int(1),
685 Value::Int(2),
686 Value::Int(3),
687 Value::Int(4),
688 Value::Int(5),
689 ],
690 )));
691
692 let stack = crate::stack::alloc_test_stack();
693 let stack = push(stack, list);
694 let stack = push(stack, Value::Int(0)); let fn_ptr = add_quot as usize;
696 let stack = push(
697 stack,
698 Value::Quotation {
699 wrapper: fn_ptr,
700 impl_: fn_ptr,
701 },
702 );
703 let stack = list_fold(stack);
704
705 let (_stack, result) = pop(stack);
706 assert_eq!(result, Value::Int(15)); }
708 }
709
710 #[test]
711 fn test_list_fold_empty() {
712 unsafe {
713 let list = Value::Variant(Arc::new(VariantData::new(
715 global_string("List".to_string()),
716 vec![],
717 )));
718
719 let stack = crate::stack::alloc_test_stack();
720 let stack = push(stack, list);
721 let stack = push(stack, Value::Int(42)); let fn_ptr = add_quot as usize;
723 let stack = push(
724 stack,
725 Value::Quotation {
726 wrapper: fn_ptr,
727 impl_: fn_ptr,
728 },
729 );
730 let stack = list_fold(stack);
731
732 let (_stack, result) = pop(stack);
733 assert_eq!(result, Value::Int(42)); }
735 }
736
737 #[test]
738 fn test_list_length() {
739 unsafe {
740 let list = Value::Variant(Arc::new(VariantData::new(
741 global_string("List".to_string()),
742 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
743 )));
744
745 let stack = crate::stack::alloc_test_stack();
746 let stack = push(stack, list);
747 let stack = list_length(stack);
748
749 let (_stack, result) = pop(stack);
750 assert_eq!(result, Value::Int(3));
751 }
752 }
753
754 #[test]
755 fn test_list_empty_true() {
756 unsafe {
757 let list = Value::Variant(Arc::new(VariantData::new(
758 global_string("List".to_string()),
759 vec![],
760 )));
761
762 let stack = crate::stack::alloc_test_stack();
763 let stack = push(stack, list);
764 let stack = list_empty(stack);
765
766 let (_stack, result) = pop(stack);
767 assert_eq!(result, Value::Bool(true));
768 }
769 }
770
771 #[test]
772 fn test_list_empty_false() {
773 unsafe {
774 let list = Value::Variant(Arc::new(VariantData::new(
775 global_string("List".to_string()),
776 vec![Value::Int(1)],
777 )));
778
779 let stack = crate::stack::alloc_test_stack();
780 let stack = push(stack, list);
781 let stack = list_empty(stack);
782
783 let (_stack, result) = pop(stack);
784 assert_eq!(result, Value::Bool(false));
785 }
786 }
787
788 #[test]
789 fn test_list_map_empty() {
790 unsafe {
791 let list = Value::Variant(Arc::new(VariantData::new(
792 global_string("List".to_string()),
793 vec![],
794 )));
795
796 let stack = crate::stack::alloc_test_stack();
797 let stack = push(stack, list);
798 let fn_ptr = double_quot as usize;
799 let stack = push(
800 stack,
801 Value::Quotation {
802 wrapper: fn_ptr,
803 impl_: fn_ptr,
804 },
805 );
806 let stack = list_map(stack);
807
808 let (_stack, result) = pop(stack);
809 match result {
810 Value::Variant(v) => {
811 assert_eq!(v.fields.len(), 0);
812 }
813 _ => panic!("Expected Variant"),
814 }
815 }
816 }
817
818 #[test]
819 fn test_list_map_preserves_tag() {
820 unsafe {
821 let list = Value::Variant(Arc::new(VariantData::new(
823 global_string("CustomTag".to_string()),
824 vec![Value::Int(1), Value::Int(2)],
825 )));
826
827 let stack = crate::stack::alloc_test_stack();
828 let stack = push(stack, list);
829 let fn_ptr = double_quot as usize;
830 let stack = push(
831 stack,
832 Value::Quotation {
833 wrapper: fn_ptr,
834 impl_: fn_ptr,
835 },
836 );
837 let stack = list_map(stack);
838
839 let (_stack, result) = pop(stack);
840 match result {
841 Value::Variant(v) => {
842 assert_eq!(v.tag.as_str(), "CustomTag"); assert_eq!(v.fields[0], Value::Int(2));
844 assert_eq!(v.fields[1], Value::Int(4));
845 }
846 _ => panic!("Expected Variant"),
847 }
848 }
849 }
850
851 unsafe extern "C" fn add_captured_closure(
854 stack: Stack,
855 env: *const Value,
856 _env_len: usize,
857 ) -> Stack {
858 unsafe {
859 let (stack, val) = pop(stack);
860 let captured = &*env; match (val, captured) {
862 (Value::Int(n), Value::Int(c)) => push(stack, Value::Int(n + c)),
863 _ => panic!("Expected Int"),
864 }
865 }
866 }
867
868 #[test]
869 fn test_list_map_with_closure() {
870 unsafe {
871 let list = Value::Variant(Arc::new(VariantData::new(
873 global_string("List".to_string()),
874 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
875 )));
876
877 let env: std::sync::Arc<[Value]> =
879 std::sync::Arc::from(vec![Value::Int(10)].into_boxed_slice());
880 let closure = Value::Closure {
881 fn_ptr: add_captured_closure as usize,
882 env,
883 };
884
885 let stack = crate::stack::alloc_test_stack();
886 let stack = push(stack, list);
887 let stack = push(stack, closure);
888 let stack = list_map(stack);
889
890 let (_stack, result) = pop(stack);
891 match result {
892 Value::Variant(v) => {
893 assert_eq!(v.fields.len(), 3);
894 assert_eq!(v.fields[0], Value::Int(11)); assert_eq!(v.fields[1], Value::Int(12)); assert_eq!(v.fields[2], Value::Int(13)); }
898 _ => panic!("Expected Variant"),
899 }
900 }
901 }
902
903 #[test]
904 fn test_list_get_type_error_index() {
905 unsafe {
906 crate::error::clear_runtime_error();
907
908 let list = Value::Variant(Arc::new(VariantData::new(
909 global_string("List".to_string()),
910 vec![Value::Int(1), Value::Int(2)],
911 )));
912
913 let stack = crate::stack::alloc_test_stack();
914 let stack = push(stack, list);
915 let stack = push(stack, Value::Bool(true)); let stack = list_get(stack);
917
918 assert!(crate::error::has_runtime_error());
920 let error = crate::error::take_runtime_error().unwrap();
921 assert!(error.contains("expected Int"));
922
923 let (stack, success) = pop(stack);
925 assert_eq!(success, Value::Bool(false));
926 let (_stack, value) = pop(stack);
927 assert_eq!(value, Value::Int(0));
928 }
929 }
930
931 #[test]
932 fn test_list_get_type_error_list() {
933 unsafe {
934 crate::error::clear_runtime_error();
935
936 let stack = crate::stack::alloc_test_stack();
937 let stack = push(stack, Value::Int(42)); let stack = push(stack, Value::Int(0)); let stack = list_get(stack);
940
941 assert!(crate::error::has_runtime_error());
943 let error = crate::error::take_runtime_error().unwrap();
944 assert!(error.contains("expected Variant"));
945
946 let (stack, success) = pop(stack);
948 assert_eq!(success, Value::Bool(false));
949 let (_stack, value) = pop(stack);
950 assert_eq!(value, Value::Int(0));
951 }
952 }
953
954 #[test]
955 fn test_list_set_type_error_index() {
956 unsafe {
957 crate::error::clear_runtime_error();
958
959 let list = Value::Variant(Arc::new(VariantData::new(
960 global_string("List".to_string()),
961 vec![Value::Int(1), Value::Int(2)],
962 )));
963
964 let stack = crate::stack::alloc_test_stack();
965 let stack = push(stack, list);
966 let stack = push(stack, Value::Bool(true)); let stack = push(stack, Value::Int(99)); let stack = list_set(stack);
969
970 assert!(crate::error::has_runtime_error());
972 let error = crate::error::take_runtime_error().unwrap();
973 assert!(error.contains("expected Int"));
974
975 let (stack, success) = pop(stack);
977 assert_eq!(success, Value::Bool(false));
978 let (_stack, returned_list) = pop(stack);
979 assert!(matches!(returned_list, Value::Variant(_)));
980 }
981 }
982
983 #[test]
984 fn test_list_set_type_error_list() {
985 unsafe {
986 crate::error::clear_runtime_error();
987
988 let stack = crate::stack::alloc_test_stack();
989 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);
993
994 assert!(crate::error::has_runtime_error());
996 let error = crate::error::take_runtime_error().unwrap();
997 assert!(error.contains("expected Variant"));
998
999 let (stack, success) = pop(stack);
1001 assert_eq!(success, Value::Bool(false));
1002 let (_stack, returned) = pop(stack);
1003 assert_eq!(returned, Value::Int(42)); }
1005 }
1006}