1use crate::son::{SonConfig, value_to_son};
17use crate::tagged_stack::{
18 DEFAULT_STACK_CAPACITY, StackValue, TAG_FALSE, TAG_TRUE, TaggedStack, is_tagged_int, tag_int,
19 untag_int,
20};
21use crate::value::Value;
22use std::cell::Cell;
23use std::sync::Arc;
24
25pub type Stack = *mut StackValue;
27
28#[inline]
29pub fn stack_value_size() -> usize {
30 std::mem::size_of::<StackValue>()
31}
32
33pub const DISC_INT: u64 = 0;
40pub const DISC_FLOAT: u64 = 1;
41pub const DISC_BOOL: u64 = 2;
42pub const DISC_STRING: u64 = 3;
43pub const DISC_VARIANT: u64 = 4;
44pub const DISC_MAP: u64 = 5;
45pub const DISC_QUOTATION: u64 = 6;
46pub const DISC_CLOSURE: u64 = 7;
47pub const DISC_CHANNEL: u64 = 8;
48pub const DISC_WEAVECTX: u64 = 9;
49pub const DISC_SYMBOL: u64 = 10;
50
51#[inline]
54fn is_inline(sv: StackValue) -> bool {
55 is_tagged_int(sv) || sv == TAG_FALSE || sv == TAG_TRUE
56}
57
58#[inline]
60pub fn value_to_stack_value(value: Value) -> StackValue {
61 match value {
62 Value::Int(i) => tag_int(i),
63 Value::Bool(false) => TAG_FALSE,
64 Value::Bool(true) => TAG_TRUE,
65 other => {
66 Arc::into_raw(Arc::new(other)) as u64
68 }
69 }
70}
71
72#[inline]
78pub unsafe fn stack_value_to_value(sv: StackValue) -> Value {
79 if is_tagged_int(sv) {
80 Value::Int(untag_int(sv))
81 } else if sv == TAG_FALSE {
82 Value::Bool(false)
83 } else if sv == TAG_TRUE {
84 Value::Bool(true)
85 } else {
86 let arc = unsafe { Arc::from_raw(sv as *const Value) };
88 Arc::try_unwrap(arc).unwrap_or_else(|arc| (*arc).clone())
92 }
93}
94
95#[unsafe(no_mangle)]
100pub unsafe extern "C" fn patch_seq_clone_value(src: *const StackValue, dst: *mut StackValue) {
101 unsafe {
102 let sv = *src;
103 let cloned = clone_stack_value(sv);
104 *dst = cloned;
105 }
106}
107
108#[inline]
116pub unsafe fn clone_stack_value(sv: StackValue) -> StackValue {
117 if is_inline(sv) {
118 sv
120 } else {
121 unsafe {
123 let arc = Arc::from_raw(sv as *const Value);
124 let cloned = Arc::clone(&arc);
125 std::mem::forget(arc); Arc::into_raw(cloned) as u64
127 }
128 }
129}
130
131#[inline]
136pub unsafe fn drop_stack_value(sv: StackValue) {
137 if is_inline(sv) {
138 return;
140 }
141 unsafe {
143 let _ = Arc::from_raw(sv as *const Value);
144 }
145}
146
147#[inline]
156pub unsafe fn push(stack: Stack, value: Value) -> Stack {
157 unsafe {
158 let sv = value_to_stack_value(value);
159 *stack = sv;
160 stack.add(1)
161 }
162}
163
164#[inline]
169pub unsafe fn push_sv(stack: Stack, sv: StackValue) -> Stack {
170 unsafe {
171 *stack = sv;
172 stack.add(1)
173 }
174}
175
176#[inline]
181pub unsafe fn pop(stack: Stack) -> (Stack, Value) {
182 unsafe {
183 let new_sp = stack.sub(1);
184 let sv = *new_sp;
185 (new_sp, stack_value_to_value(sv))
186 }
187}
188
189#[inline]
194pub unsafe fn pop_sv(stack: Stack) -> (Stack, StackValue) {
195 unsafe {
196 let new_sp = stack.sub(1);
197 let sv = *new_sp;
198 (new_sp, sv)
199 }
200}
201
202#[inline]
207pub unsafe fn pop_two(stack: Stack, _op_name: &str) -> (Stack, Value, Value) {
208 unsafe {
209 let (sp, b) = pop(stack);
210 let (sp, a) = pop(sp);
211 (sp, a, b)
212 }
213}
214
215#[inline]
220pub unsafe fn peek(stack: Stack) -> Value {
221 unsafe {
222 let sv = *stack.sub(1);
223 let cloned = clone_stack_value(sv);
224 stack_value_to_value(cloned)
225 }
226}
227
228#[inline]
233pub unsafe fn peek_sv(stack: Stack) -> StackValue {
234 unsafe { *stack.sub(1) }
235}
236
237#[inline]
262pub unsafe fn heap_value_mut<'a>(slot: *mut StackValue) -> Option<&'a mut Value> {
263 unsafe {
264 let sv = *slot;
265 if is_inline(sv) {
267 return None;
268 }
269 let mut arc = Arc::from_raw(sv as *const Value);
272 let val_ref = Arc::get_mut(&mut arc).map(|v| &mut *(v as *mut Value));
273 std::mem::forget(arc); val_ref
275 }
276}
277
278#[inline]
283pub unsafe fn peek_heap_mut<'a>(stack: Stack) -> Option<&'a mut Value> {
284 unsafe { heap_value_mut(stack.sub(1)) }
285}
286
287#[inline]
293pub unsafe fn peek_heap_mut_second<'a>(stack: Stack) -> Option<&'a mut Value> {
294 unsafe { heap_value_mut(stack.sub(2)) }
295}
296
297#[unsafe(no_mangle)]
306pub unsafe extern "C" fn patch_seq_dup(stack: Stack) -> Stack {
307 unsafe {
308 let sv = peek_sv(stack);
309 let cloned = clone_stack_value(sv);
310 push_sv(stack, cloned)
311 }
312}
313
314#[inline]
323pub unsafe fn drop_top(stack: Stack) -> Stack {
324 unsafe {
325 let (new_sp, sv) = pop_sv(stack);
326 drop_stack_value(sv);
327 new_sp
328 }
329}
330
331#[unsafe(no_mangle)]
334pub unsafe extern "C" fn patch_seq_drop_op(stack: Stack) -> Stack {
335 unsafe { drop_top(stack) }
336}
337
338#[allow(improper_ctypes_definitions)]
341#[unsafe(no_mangle)]
342pub unsafe extern "C" fn patch_seq_push_value(stack: Stack, value: Value) -> Stack {
343 unsafe { push(stack, value) }
344}
345
346#[unsafe(no_mangle)]
351pub unsafe extern "C" fn patch_seq_swap(stack: Stack) -> Stack {
352 unsafe {
353 let ptr_b = stack.sub(1);
354 let ptr_a = stack.sub(2);
355 let a = *ptr_a;
356 let b = *ptr_b;
357 *ptr_a = b;
358 *ptr_b = a;
359 stack
360 }
361}
362
363#[unsafe(no_mangle)]
368pub unsafe extern "C" fn patch_seq_over(stack: Stack) -> Stack {
369 unsafe {
370 let sv_a = *stack.sub(2);
371 let cloned = clone_stack_value(sv_a);
372 push_sv(stack, cloned)
373 }
374}
375
376#[unsafe(no_mangle)]
381pub unsafe extern "C" fn patch_seq_rot(stack: Stack) -> Stack {
382 unsafe {
383 let ptr_c = stack.sub(1);
384 let ptr_b = stack.sub(2);
385 let ptr_a = stack.sub(3);
386 let a = *ptr_a;
387 let b = *ptr_b;
388 let c = *ptr_c;
389 *ptr_a = b;
390 *ptr_b = c;
391 *ptr_c = a;
392 stack
393 }
394}
395
396#[unsafe(no_mangle)]
401pub unsafe extern "C" fn patch_seq_nip(stack: Stack) -> Stack {
402 unsafe {
403 let ptr_b = stack.sub(1);
404 let ptr_a = stack.sub(2);
405 let a = *ptr_a;
406 let b = *ptr_b;
407 drop_stack_value(a);
408 *ptr_a = b;
409 stack.sub(1)
410 }
411}
412
413#[unsafe(no_mangle)]
418pub unsafe extern "C" fn patch_seq_tuck(stack: Stack) -> Stack {
419 unsafe {
420 let ptr_b = stack.sub(1);
421 let ptr_a = stack.sub(2);
422 let a = *ptr_a;
423 let b = *ptr_b;
424 let b_clone = clone_stack_value(b);
425 *ptr_a = b;
426 *ptr_b = a;
427 push_sv(stack, b_clone)
428 }
429}
430
431#[unsafe(no_mangle)]
436pub unsafe extern "C" fn patch_seq_2dup(stack: Stack) -> Stack {
437 unsafe {
438 let sv_a = *stack.sub(2);
439 let sv_b = *stack.sub(1);
440 let a_clone = clone_stack_value(sv_a);
441 let b_clone = clone_stack_value(sv_b);
442 let sp = push_sv(stack, a_clone);
443 push_sv(sp, b_clone)
444 }
445}
446
447#[inline]
456unsafe fn pop_and_validate_index(stack: Stack, op_name: &str) -> Result<(Stack, usize), Stack> {
457 unsafe {
458 let (sp, n_val) = pop(stack);
459 let n_raw = match n_val {
460 Value::Int(i) => i,
461 _ => {
462 crate::error::set_runtime_error(format!(
463 "{}: expected Int index on top of stack",
464 op_name
465 ));
466 return Err(sp);
467 }
468 };
469 if n_raw < 0 {
470 crate::error::set_runtime_error(format!(
471 "{}: index cannot be negative (got {})",
472 op_name, n_raw
473 ));
474 return Err(sp);
475 }
476 Ok((sp, n_raw as usize))
477 }
478}
479
480#[inline]
483fn check_depth_for_index(sp: Stack, n: usize, op_name: &str) -> bool {
484 let base = get_stack_base();
485 let depth = (sp as usize - base as usize) / std::mem::size_of::<StackValue>();
486 if n >= depth {
487 crate::error::set_runtime_error(format!(
488 "{}: index {} exceeds stack depth {} (need at least {} values)",
489 op_name,
490 n,
491 depth,
492 n + 1
493 ));
494 return false;
495 }
496 true
497}
498
499#[unsafe(no_mangle)]
504pub unsafe extern "C" fn patch_seq_pick_op(stack: Stack) -> Stack {
505 unsafe {
506 let (sp, n) = match pop_and_validate_index(stack, "pick") {
507 Ok(x) => x,
508 Err(sp) => return sp,
509 };
510 if !check_depth_for_index(sp, n, "pick") {
511 return sp;
512 }
513
514 let sv = *sp.sub(n + 1);
515 let cloned = clone_stack_value(sv);
516 push_sv(sp, cloned)
517 }
518}
519
520#[unsafe(no_mangle)]
525pub unsafe extern "C" fn patch_seq_roll(stack: Stack) -> Stack {
526 unsafe {
527 let (sp, n) = match pop_and_validate_index(stack, "roll") {
528 Ok(x) => x,
529 Err(sp) => return sp,
530 };
531
532 if n == 0 {
533 return sp;
534 }
535 if n == 1 {
536 return patch_seq_swap(sp);
537 }
538 if n == 2 {
539 return patch_seq_rot(sp);
540 }
541
542 if !check_depth_for_index(sp, n, "roll") {
543 return sp;
544 }
545
546 let src_ptr = sp.sub(n + 1);
547 let saved = *src_ptr;
548 std::ptr::copy(src_ptr.add(1), src_ptr, n);
549 *sp.sub(1) = saved;
550
551 sp
552 }
553}
554
555may::coroutine_local!(static STACK_BASE: Cell<usize> = Cell::new(0));
560
561#[unsafe(no_mangle)]
564pub unsafe extern "C" fn patch_seq_set_stack_base(base: Stack) {
565 STACK_BASE.with(|cell| {
566 cell.set(base as usize);
567 });
568}
569
570#[inline]
572pub fn get_stack_base() -> Stack {
573 STACK_BASE.with(|cell| cell.get() as *mut StackValue)
574}
575
576#[unsafe(no_mangle)]
579pub unsafe extern "C" fn clone_stack(sp: Stack) -> Stack {
580 unsafe {
581 let (new_sp, _base) = clone_stack_with_base(sp);
582 new_sp
583 }
584}
585
586pub unsafe fn clone_stack_with_base(sp: Stack) -> (Stack, Stack) {
589 let base = get_stack_base();
590 if base.is_null() {
591 panic!("clone_stack: stack base not set");
592 }
593
594 let depth = unsafe { sp.offset_from(base) as usize };
595
596 if depth == 0 {
597 let new_stack = TaggedStack::new(DEFAULT_STACK_CAPACITY);
598 let new_base = new_stack.base;
599 std::mem::forget(new_stack);
600 return (new_base, new_base);
601 }
602
603 let capacity = depth.max(DEFAULT_STACK_CAPACITY);
604 let new_stack = TaggedStack::new(capacity);
605 let new_base = new_stack.base;
606 std::mem::forget(new_stack);
607
608 unsafe {
609 for i in 0..depth {
610 let sv = *base.add(i);
611 let cloned = clone_stack_value(sv);
612 *new_base.add(i) = cloned;
613 }
614 }
615
616 unsafe { (new_base.add(depth), new_base) }
617}
618
619pub fn alloc_stack() -> Stack {
629 let stack = TaggedStack::with_default_capacity();
630 let base = stack.base;
631 std::mem::forget(stack);
632 base
633}
634
635pub fn alloc_test_stack() -> Stack {
641 let stack = alloc_stack();
642 unsafe { patch_seq_set_stack_base(stack) };
643 stack
644}
645
646#[unsafe(no_mangle)]
651pub unsafe extern "C" fn patch_seq_stack_dump(sp: Stack) -> Stack {
652 let base = get_stack_base();
653 if base.is_null() {
654 eprintln!("[stack.dump: base not set]");
655 return sp;
656 }
657
658 let depth = (sp as usize - base as usize) / std::mem::size_of::<StackValue>();
659
660 if depth == 0 {
661 println!("»");
662 } else {
663 use std::io::Write;
664 print!("» ");
665 for i in 0..depth {
666 if i > 0 {
667 print!(" ");
668 }
669 unsafe {
670 let sv = *base.add(i);
671 print_stack_value(sv);
672 }
673 }
674 println!();
675 let _ = std::io::stdout().flush();
676
677 for i in 0..depth {
679 unsafe {
680 let sv = *base.add(i);
681 drop_stack_value(sv);
682 }
683 }
684 }
685
686 base
687}
688
689fn print_stack_value(sv: StackValue) {
690 let cloned = unsafe { clone_stack_value(sv) };
691 let value = unsafe { stack_value_to_value(cloned) };
692 let son = value_to_son(&value, &SonConfig::compact());
693 print!("{}", son);
694}
695
696pub use patch_seq_2dup as two_dup;
701pub use patch_seq_dup as dup;
702pub use patch_seq_nip as nip;
703pub use patch_seq_over as over;
704pub use patch_seq_pick_op as pick;
705pub use patch_seq_roll as roll;
706pub use patch_seq_rot as rot;
707pub use patch_seq_swap as swap;
708pub use patch_seq_tuck as tuck;
709
710#[macro_export]
711macro_rules! test_stack {
712 () => {{ $crate::stack::alloc_test_stack() }};
713}
714
715#[cfg(test)]
716mod tests {
717 use super::*;
718
719 #[test]
720 fn test_pick_negative_index_sets_error() {
721 unsafe {
722 crate::error::clear_runtime_error();
723 let stack = alloc_test_stack();
724 let stack = push(stack, Value::Int(100));
725 let stack = push(stack, Value::Int(-1));
726
727 let _stack = patch_seq_pick_op(stack);
728
729 assert!(crate::error::has_runtime_error());
730 let error = crate::error::take_runtime_error().unwrap();
731 assert!(error.contains("negative"));
732 }
733 }
734
735 #[test]
736 fn test_pick_out_of_bounds_sets_error() {
737 unsafe {
738 crate::error::clear_runtime_error();
739 let stack = alloc_test_stack();
740 let stack = push(stack, Value::Int(100));
741 let stack = push(stack, Value::Int(10));
742
743 let _stack = patch_seq_pick_op(stack);
744
745 assert!(crate::error::has_runtime_error());
746 let error = crate::error::take_runtime_error().unwrap();
747 assert!(error.contains("exceeds stack depth"));
748 }
749 }
750
751 #[test]
752 fn test_roll_negative_index_sets_error() {
753 unsafe {
754 crate::error::clear_runtime_error();
755 let stack = alloc_test_stack();
756 let stack = push(stack, Value::Int(100));
757 let stack = push(stack, Value::Int(-1));
758
759 let _stack = patch_seq_roll(stack);
760
761 assert!(crate::error::has_runtime_error());
762 let error = crate::error::take_runtime_error().unwrap();
763 assert!(error.contains("negative"));
764 }
765 }
766
767 #[test]
768 fn test_roll_out_of_bounds_sets_error() {
769 unsafe {
770 crate::error::clear_runtime_error();
771 let stack = alloc_test_stack();
772 let stack = push(stack, Value::Int(100));
773 let stack = push(stack, Value::Int(10));
774
775 let _stack = patch_seq_roll(stack);
776
777 assert!(crate::error::has_runtime_error());
778 let error = crate::error::take_runtime_error().unwrap();
779 assert!(error.contains("exceeds stack depth"));
780 }
781 }
782
783 #[test]
784 fn test_int_roundtrip() {
785 unsafe {
786 let stack = alloc_test_stack();
787 let stack = push(stack, Value::Int(42));
788 let (_, val) = pop(stack);
789 assert_eq!(val, Value::Int(42));
790 }
791 }
792
793 #[test]
794 fn test_bool_roundtrip() {
795 unsafe {
796 let stack = alloc_test_stack();
797 let stack = push(stack, Value::Bool(true));
798 let stack = push(stack, Value::Bool(false));
799 let (stack, val_f) = pop(stack);
800 let (_, val_t) = pop(stack);
801 assert_eq!(val_f, Value::Bool(false));
802 assert_eq!(val_t, Value::Bool(true));
803 }
804 }
805
806 #[test]
807 fn test_float_roundtrip() {
808 unsafe {
809 let stack = alloc_test_stack();
810 let stack = push(stack, Value::Float(std::f64::consts::PI));
811 let (_, val) = pop(stack);
812 assert_eq!(val, Value::Float(std::f64::consts::PI));
813 }
814 }
815
816 #[test]
817 fn test_string_roundtrip() {
818 unsafe {
819 let stack = alloc_test_stack();
820 let s = crate::seqstring::SeqString::from("hello");
821 let stack = push(stack, Value::String(s));
822 let (_, val) = pop(stack);
823 match val {
824 Value::String(s) => assert_eq!(s.as_bytes(), b"hello"),
825 other => panic!("Expected String, got {:?}", other),
826 }
827 }
828 }
829
830 #[test]
831 fn test_symbol_roundtrip() {
832 unsafe {
833 let stack = alloc_test_stack();
834 let s = crate::seqstring::SeqString::from("my-sym");
835 let stack = push(stack, Value::Symbol(s));
836 let (_, val) = pop(stack);
837 match val {
838 Value::Symbol(s) => assert_eq!(s.as_bytes(), b"my-sym"),
839 other => panic!("Expected Symbol, got {:?}", other),
840 }
841 }
842 }
843
844 #[test]
845 fn test_variant_roundtrip() {
846 unsafe {
847 let stack = alloc_test_stack();
848 let tag = crate::seqstring::SeqString::from("Foo");
849 let data = crate::value::VariantData::new(tag, vec![Value::Int(1), Value::Int(2)]);
850 let stack = push(stack, Value::Variant(std::sync::Arc::new(data)));
851 let (_, val) = pop(stack);
852 match val {
853 Value::Variant(v) => {
854 assert_eq!(v.tag.as_bytes(), b"Foo");
855 assert_eq!(v.fields.len(), 2);
856 }
857 other => panic!("Expected Variant, got {:?}", other),
858 }
859 }
860 }
861
862 #[test]
863 fn test_map_roundtrip() {
864 unsafe {
865 let stack = alloc_test_stack();
866 let mut map = std::collections::HashMap::new();
867 map.insert(crate::value::MapKey::Int(1), Value::Int(100));
868 let stack = push(stack, Value::Map(Box::new(map)));
869 let (_, val) = pop(stack);
870 match val {
871 Value::Map(m) => {
872 assert_eq!(m.len(), 1);
873 assert_eq!(m.get(&crate::value::MapKey::Int(1)), Some(&Value::Int(100)));
874 }
875 other => panic!("Expected Map, got {:?}", other),
876 }
877 }
878 }
879
880 #[test]
881 fn test_quotation_roundtrip() {
882 unsafe {
883 let stack = alloc_test_stack();
884 let stack = push(
885 stack,
886 Value::Quotation {
887 wrapper: 0x1000,
888 impl_: 0x2000,
889 },
890 );
891 let (_, val) = pop(stack);
892 match val {
893 Value::Quotation { wrapper, impl_ } => {
894 assert_eq!(wrapper, 0x1000);
895 assert_eq!(impl_, 0x2000);
896 }
897 other => panic!("Expected Quotation, got {:?}", other),
898 }
899 }
900 }
901
902 #[test]
903 fn test_closure_roundtrip() {
904 unsafe {
905 let stack = alloc_test_stack();
906 let env: std::sync::Arc<[Value]> = std::sync::Arc::from(vec![Value::Int(42)]);
907 let stack = push(
908 stack,
909 Value::Closure {
910 fn_ptr: 0x3000,
911 env,
912 },
913 );
914 let (_, val) = pop(stack);
915 match val {
916 Value::Closure { fn_ptr, env } => {
917 assert_eq!(fn_ptr, 0x3000);
918 assert_eq!(env.len(), 1);
919 }
920 other => panic!("Expected Closure, got {:?}", other),
921 }
922 }
923 }
924
925 #[test]
926 fn test_channel_roundtrip() {
927 unsafe {
928 let stack = alloc_test_stack();
929 let (sender, receiver) = may::sync::mpmc::channel::<crate::value::ChannelMsg>();
930 let ch = std::sync::Arc::new(crate::value::ChannelData {
931 sender,
932 receiver,
933 closed: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
934 });
935 let stack = push(stack, Value::Channel(ch));
936 let (_, val) = pop(stack);
937 assert!(matches!(val, Value::Channel(_)));
938 }
939 }
940
941 #[test]
942 fn test_weavectx_roundtrip() {
943 unsafe {
944 let stack = alloc_test_stack();
945 let (ys, yr) = may::sync::mpmc::channel();
946 let (rs, rr) = may::sync::mpmc::channel();
947 let yield_chan = std::sync::Arc::new(crate::value::WeaveChannelData {
948 sender: ys,
949 receiver: yr,
950 });
951 let resume_chan = std::sync::Arc::new(crate::value::WeaveChannelData {
952 sender: rs,
953 receiver: rr,
954 });
955 let stack = push(
956 stack,
957 Value::WeaveCtx {
958 yield_chan,
959 resume_chan,
960 },
961 );
962 let (_, val) = pop(stack);
963 assert!(matches!(val, Value::WeaveCtx { .. }));
964 }
965 }
966
967 #[test]
968 fn test_dup_pop_pop_heap_type() {
969 unsafe {
972 let stack = alloc_test_stack();
973 let stack = push(stack, Value::Float(2.5));
974 let stack = patch_seq_dup(stack);
976 let (stack, val1) = pop(stack);
978 let (_, val2) = pop(stack);
979 assert_eq!(val1, Value::Float(2.5));
980 assert_eq!(val2, Value::Float(2.5));
981 }
982 }
983}