1use crate::seqstring::global_string;
36use crate::stack::{Stack, drop_stack_value, heap_value_mut, pop, pop_sv, push};
37use crate::value::{MapKey, Value, VariantData};
38use std::sync::Arc;
39
40#[unsafe(no_mangle)]
47pub unsafe extern "C" fn patch_seq_make_map(stack: Stack) -> Stack {
48 unsafe { push(stack, Value::Map(Box::default())) }
49}
50
51#[unsafe(no_mangle)]
62pub unsafe extern "C" fn patch_seq_map_get(stack: Stack) -> Stack {
63 unsafe {
64 let (stack, key_val) = pop(stack);
66 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
67 panic!(
68 "map-get: key must be Int, String, or Bool, got {:?}",
69 key_val
70 )
71 });
72
73 let (stack, map_val) = pop(stack);
75 let map = match map_val {
76 Value::Map(m) => m,
77 _ => panic!("map-get: expected Map, got {:?}", map_val),
78 };
79
80 match map.get(&key) {
82 Some(value) => {
83 let stack = push(stack, value.clone());
84 push(stack, Value::Bool(true))
85 }
86 None => {
87 let stack = push(stack, Value::Int(0)); push(stack, Value::Bool(false)) }
90 }
91 }
92}
93
94#[unsafe(no_mangle)]
105pub unsafe extern "C" fn patch_seq_map_set(stack: Stack) -> Stack {
106 unsafe {
107 if let Some(Value::Map(map)) = heap_value_mut(stack.sub(3)) {
111 let (stack, value) = pop(stack);
113 let (stack, key_val) = pop(stack);
114 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
115 panic!(
116 "map-set: key must be Int, String, or Bool, got {:?}",
117 key_val
118 )
119 });
120 map.insert(key, value);
123 return stack; }
125
126 let (stack, value) = pop(stack);
128 let (stack, key_val) = pop(stack);
129 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
130 panic!(
131 "map-set: key must be Int, String, or Bool, got {:?}",
132 key_val
133 )
134 });
135 let (stack, map_val) = pop(stack);
136 let mut map = match map_val {
137 Value::Map(m) => *m,
138 _ => panic!("map-set: expected Map, got {:?}", map_val),
139 };
140 map.insert(key, value);
141 push(stack, Value::Map(Box::new(map)))
142 }
143}
144
145#[unsafe(no_mangle)]
155pub unsafe extern "C" fn patch_seq_map_has(stack: Stack) -> Stack {
156 unsafe {
157 let (stack, key_val) = pop(stack);
159 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
160 panic!(
161 "map-has?: key must be Int, String, or Bool, got {:?}",
162 key_val
163 )
164 });
165
166 let (stack, map_val) = pop(stack);
168 let map = match map_val {
169 Value::Map(m) => m,
170 _ => panic!("map-has?: expected Map, got {:?}", map_val),
171 };
172
173 let has_key = map.contains_key(&key);
174 push(stack, Value::Bool(has_key))
175 }
176}
177
178#[unsafe(no_mangle)]
189pub unsafe extern "C" fn patch_seq_map_remove(stack: Stack) -> Stack {
190 unsafe {
191 if let Some(Value::Map(map)) = heap_value_mut(stack.sub(2)) {
195 let (stack, key_val) = pop(stack);
196 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
197 panic!(
198 "map-remove: key must be Int, String, or Bool, got {:?}",
199 key_val
200 )
201 });
202 map.remove(&key);
205 return stack; }
207
208 let (stack, key_val) = pop(stack);
210 let key = MapKey::from_value(&key_val).unwrap_or_else(|| {
211 panic!(
212 "map-remove: key must be Int, String, or Bool, got {:?}",
213 key_val
214 )
215 });
216 let (stack, map_val) = pop(stack);
217 let mut map = match map_val {
218 Value::Map(m) => *m,
219 _ => panic!("map-remove: expected Map, got {:?}", map_val),
220 };
221 map.remove(&key);
222 push(stack, Value::Map(Box::new(map)))
223 }
224}
225
226#[unsafe(no_mangle)]
236pub unsafe extern "C" fn patch_seq_map_keys(stack: Stack) -> Stack {
237 unsafe {
238 let (stack, map_val) = pop(stack);
239 let map = match map_val {
240 Value::Map(m) => m,
241 _ => panic!("map-keys: expected Map, got {:?}", map_val),
242 };
243
244 let keys: Vec<Value> = map.keys().map(|k| k.to_value()).collect();
245 let variant = Value::Variant(Arc::new(VariantData::new(
246 global_string("List".to_string()),
247 keys,
248 )));
249 push(stack, variant)
250 }
251}
252
253#[unsafe(no_mangle)]
263pub unsafe extern "C" fn patch_seq_map_values(stack: Stack) -> Stack {
264 unsafe {
265 let (stack, map_val) = pop(stack);
266 let map = match map_val {
267 Value::Map(m) => m,
268 _ => panic!("map-values: expected Map, got {:?}", map_val),
269 };
270
271 let values: Vec<Value> = map.values().cloned().collect();
272 let variant = Value::Variant(Arc::new(VariantData::new(
273 global_string("List".to_string()),
274 values,
275 )));
276 push(stack, variant)
277 }
278}
279
280#[unsafe(no_mangle)]
287pub unsafe extern "C" fn patch_seq_map_size(stack: Stack) -> Stack {
288 unsafe {
289 let (stack, map_val) = pop(stack);
290 let map = match map_val {
291 Value::Map(m) => m,
292 _ => panic!("map-size: expected Map, got {:?}", map_val),
293 };
294
295 push(stack, Value::Int(map.len() as i64))
296 }
297}
298
299#[unsafe(no_mangle)]
308pub unsafe extern "C" fn patch_seq_map_empty(stack: Stack) -> Stack {
309 unsafe {
310 let (stack, map_val) = pop(stack);
311 let map = match map_val {
312 Value::Map(m) => m,
313 _ => panic!("map-empty?: expected Map, got {:?}", map_val),
314 };
315
316 let is_empty = map.is_empty();
317 push(stack, Value::Bool(is_empty))
318 }
319}
320
321#[unsafe(no_mangle)]
332pub unsafe extern "C" fn patch_seq_map_each(stack: Stack) -> Stack {
333 unsafe {
334 let (stack, callable) = pop(stack);
336 match &callable {
337 Value::Quotation { .. } | Value::Closure { .. } => {}
338 _ => panic!(
339 "map.each: expected Quotation or Closure, got {:?}",
340 callable
341 ),
342 }
343
344 let (stack, map_val) = pop(stack);
346 let map = match &map_val {
347 Value::Map(m) => m,
348 _ => panic!("map.each: expected Map, got {:?}", map_val),
349 };
350
351 for (key, value) in map.iter() {
353 let temp_base = crate::stack::alloc_stack();
354 let temp_stack = push(temp_base, key.to_value());
355 let temp_stack = push(temp_stack, value.clone());
356 let temp_stack = invoke_callable(temp_stack, &callable);
357 drain_to_base(temp_stack, temp_base);
359 }
360
361 stack
362 }
363}
364
365#[unsafe(no_mangle)]
376pub unsafe extern "C" fn patch_seq_map_fold(stack: Stack) -> Stack {
377 unsafe {
378 let (stack, callable) = pop(stack);
380 match &callable {
381 Value::Quotation { .. } | Value::Closure { .. } => {}
382 _ => panic!(
383 "map.fold: expected Quotation or Closure, got {:?}",
384 callable
385 ),
386 }
387
388 let (stack, mut acc) = pop(stack);
390
391 let (stack, map_val) = pop(stack);
393 let map = match &map_val {
394 Value::Map(m) => m,
395 _ => panic!("map.fold: expected Map, got {:?}", map_val),
396 };
397
398 for (key, value) in map.iter() {
400 let temp_base = crate::stack::alloc_stack();
401 let temp_stack = push(temp_base, acc);
402 let temp_stack = push(temp_stack, key.to_value());
403 let temp_stack = push(temp_stack, value.clone());
404 let temp_stack = invoke_callable(temp_stack, &callable);
405 if temp_stack <= temp_base {
407 panic!("map.fold: quotation consumed accumulator without producing result");
408 }
409 let (remaining, new_acc) = pop(temp_stack);
410 acc = new_acc;
411 if remaining > temp_base {
413 drain_to_base(remaining, temp_base);
414 }
415 }
416
417 push(stack, acc)
418 }
419}
420
421use crate::quotations::invoke_callable;
422
423unsafe fn drain_to_base(mut stack: Stack, base: Stack) {
425 unsafe {
426 while stack > base {
427 let (rest, sv) = pop_sv(stack);
428 drop_stack_value(sv);
429 stack = rest;
430 }
431 }
432}
433
434pub use patch_seq_make_map as make_map;
436pub use patch_seq_map_each as map_each;
437pub use patch_seq_map_empty as map_empty;
438pub use patch_seq_map_fold as map_fold;
439pub use patch_seq_map_get as map_get;
440pub use patch_seq_map_has as map_has;
441pub use patch_seq_map_keys as map_keys;
442pub use patch_seq_map_remove as map_remove;
443pub use patch_seq_map_set as map_set;
444pub use patch_seq_map_size as map_size;
445pub use patch_seq_map_values as map_values;
446
447#[cfg(test)]
448mod tests {
449 use super::*;
450
451 #[test]
452 fn test_make_map() {
453 unsafe {
454 let stack = crate::stack::alloc_test_stack();
455 let stack = make_map(stack);
456
457 let (_stack, result) = pop(stack);
458 match result {
459 Value::Map(m) => assert!(m.is_empty()),
460 _ => panic!("Expected Map"),
461 }
462 }
463 }
464
465 #[test]
466 fn test_map_set_and_get() {
467 unsafe {
468 let stack = crate::stack::alloc_test_stack();
469 let stack = make_map(stack);
470 let stack = push(stack, Value::String("name".into()));
471 let stack = push(stack, Value::String("Alice".into()));
472 let stack = map_set(stack);
473
474 let stack = push(stack, Value::String("name".into()));
476 let stack = map_get(stack);
477
478 let (stack, flag) = pop(stack);
480 assert_eq!(flag, Value::Bool(true));
481 let (_stack, result) = pop(stack);
482 match result {
483 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
484 _ => panic!("Expected String"),
485 }
486 }
487 }
488
489 #[test]
490 fn test_map_set_with_int_key() {
491 unsafe {
492 let stack = crate::stack::alloc_test_stack();
493 let stack = make_map(stack);
494 let stack = push(stack, Value::Int(42));
495 let stack = push(stack, Value::String("answer".into()));
496 let stack = map_set(stack);
497
498 let stack = push(stack, Value::Int(42));
499 let stack = map_get(stack);
500
501 let (stack, flag) = pop(stack);
503 assert_eq!(flag, Value::Bool(true));
504 let (_stack, result) = pop(stack);
505 match result {
506 Value::String(s) => assert_eq!(s.as_str(), "answer"),
507 _ => panic!("Expected String"),
508 }
509 }
510 }
511
512 #[test]
513 fn test_map_has() {
514 unsafe {
515 let stack = crate::stack::alloc_test_stack();
516 let stack = make_map(stack);
517 let stack = push(stack, Value::String("key".into()));
518 let stack = push(stack, Value::Int(100));
519 let stack = map_set(stack);
520
521 let stack = crate::stack::dup(stack);
523 let stack = push(stack, Value::String("key".into()));
524 let stack = map_has(stack);
525 let (stack, result) = pop(stack);
526 assert_eq!(result, Value::Bool(true));
527
528 let stack = push(stack, Value::String("missing".into()));
530 let stack = map_has(stack);
531 let (_stack, result) = pop(stack);
532 assert_eq!(result, Value::Bool(false));
533 }
534 }
535
536 #[test]
537 fn test_map_remove() {
538 unsafe {
539 let stack = crate::stack::alloc_test_stack();
540 let stack = make_map(stack);
541 let stack = push(stack, Value::String("a".into()));
542 let stack = push(stack, Value::Int(1));
543 let stack = map_set(stack);
544 let stack = push(stack, Value::String("b".into()));
545 let stack = push(stack, Value::Int(2));
546 let stack = map_set(stack);
547
548 let stack = push(stack, Value::String("a".into()));
550 let stack = map_remove(stack);
551
552 let stack = crate::stack::dup(stack);
554 let stack = push(stack, Value::String("a".into()));
555 let stack = map_has(stack);
556 let (stack, result) = pop(stack);
557 assert_eq!(result, Value::Bool(false));
558
559 let stack = push(stack, Value::String("b".into()));
561 let stack = map_has(stack);
562 let (_stack, result) = pop(stack);
563 assert_eq!(result, Value::Bool(true));
564 }
565 }
566
567 #[test]
568 fn test_map_size() {
569 unsafe {
570 let stack = crate::stack::alloc_test_stack();
571 let stack = make_map(stack);
572
573 let stack = map_size(stack);
575 let (stack, result) = pop(stack);
576 assert_eq!(result, Value::Int(0));
577
578 let stack = make_map(stack);
580 let stack = push(stack, Value::String("a".into()));
581 let stack = push(stack, Value::Int(1));
582 let stack = map_set(stack);
583 let stack = push(stack, Value::String("b".into()));
584 let stack = push(stack, Value::Int(2));
585 let stack = map_set(stack);
586
587 let stack = map_size(stack);
588 let (_stack, result) = pop(stack);
589 assert_eq!(result, Value::Int(2));
590 }
591 }
592
593 #[test]
594 fn test_map_empty() {
595 unsafe {
596 let stack = crate::stack::alloc_test_stack();
597 let stack = make_map(stack);
598
599 let stack = map_empty(stack);
600 let (stack, result) = pop(stack);
601 assert_eq!(result, Value::Bool(true));
602
603 let stack = make_map(stack);
605 let stack = push(stack, Value::String("key".into()));
606 let stack = push(stack, Value::Int(1));
607 let stack = map_set(stack);
608
609 let stack = map_empty(stack);
610 let (_stack, result) = pop(stack);
611 assert_eq!(result, Value::Bool(false));
612 }
613 }
614
615 #[test]
616 fn test_map_keys_and_values() {
617 unsafe {
618 let stack = crate::stack::alloc_test_stack();
619 let stack = make_map(stack);
620 let stack = push(stack, Value::String("x".into()));
621 let stack = push(stack, Value::Int(10));
622 let stack = map_set(stack);
623 let stack = push(stack, Value::String("y".into()));
624 let stack = push(stack, Value::Int(20));
625 let stack = map_set(stack);
626
627 let stack = crate::stack::dup(stack); let stack = map_keys(stack);
630 let (stack, keys_result) = pop(stack);
631 match keys_result {
632 Value::Variant(v) => {
633 assert_eq!(v.fields.len(), 2);
634 }
636 _ => panic!("Expected Variant"),
637 }
638
639 let stack = map_values(stack);
641 let (_stack, values_result) = pop(stack);
642 match values_result {
643 Value::Variant(v) => {
644 assert_eq!(v.fields.len(), 2);
645 }
647 _ => panic!("Expected Variant"),
648 }
649 }
650 }
651
652 #[test]
653 fn test_map_get_found() {
654 unsafe {
655 let stack = crate::stack::alloc_test_stack();
656 let stack = make_map(stack);
657 let stack = push(stack, Value::String("key".into()));
658 let stack = push(stack, Value::Int(42));
659 let stack = map_set(stack);
660
661 let stack = push(stack, Value::String("key".into()));
662 let stack = map_get(stack);
663
664 let (stack, flag) = pop(stack);
665 let (_stack, value) = pop(stack);
666 assert_eq!(flag, Value::Bool(true));
667 assert_eq!(value, Value::Int(42));
668 }
669 }
670
671 #[test]
672 fn test_map_get_not_found() {
673 unsafe {
674 let stack = crate::stack::alloc_test_stack();
675 let stack = make_map(stack);
676
677 let stack = push(stack, Value::String("missing".into()));
678 let stack = map_get(stack);
679
680 let (stack, flag) = pop(stack);
681 let (_stack, _value) = pop(stack); assert_eq!(flag, Value::Bool(false));
683 }
684 }
685
686 #[test]
687 fn test_map_with_bool_key() {
688 unsafe {
689 let stack = crate::stack::alloc_test_stack();
690 let stack = make_map(stack);
691 let stack = push(stack, Value::Bool(true));
692 let stack = push(stack, Value::String("yes".into()));
693 let stack = map_set(stack);
694 let stack = push(stack, Value::Bool(false));
695 let stack = push(stack, Value::String("no".into()));
696 let stack = map_set(stack);
697
698 let stack = push(stack, Value::Bool(true));
699 let stack = map_get(stack);
700 let (stack, flag) = pop(stack);
702 assert_eq!(flag, Value::Bool(true));
703 let (_stack, result) = pop(stack);
704 match result {
705 Value::String(s) => assert_eq!(s.as_str(), "yes"),
706 _ => panic!("Expected String"),
707 }
708 }
709 }
710
711 #[test]
712 fn test_map_key_overwrite() {
713 unsafe {
715 let stack = crate::stack::alloc_test_stack();
716 let stack = make_map(stack);
717
718 let stack = push(stack, Value::String("key".into()));
720 let stack = push(stack, Value::Int(100));
721 let stack = map_set(stack);
722
723 let stack = push(stack, Value::String("key".into()));
725 let stack = push(stack, Value::Int(200));
726 let stack = map_set(stack);
727
728 let stack = crate::stack::dup(stack);
730 let stack = map_size(stack);
731 let (stack, size) = pop(stack);
732 assert_eq!(size, Value::Int(1));
733
734 let stack = push(stack, Value::String("key".into()));
736 let stack = map_get(stack);
737 let (stack, flag) = pop(stack);
739 assert_eq!(flag, Value::Bool(true));
740 let (_stack, result) = pop(stack);
741 assert_eq!(result, Value::Int(200));
742 }
743 }
744
745 #[test]
746 fn test_map_mixed_key_types() {
747 unsafe {
749 let stack = crate::stack::alloc_test_stack();
750 let stack = make_map(stack);
751
752 let stack = push(stack, Value::String("name".into()));
754 let stack = push(stack, Value::String("Alice".into()));
755 let stack = map_set(stack);
756
757 let stack = push(stack, Value::Int(42));
759 let stack = push(stack, Value::String("answer".into()));
760 let stack = map_set(stack);
761
762 let stack = push(stack, Value::Bool(true));
764 let stack = push(stack, Value::String("yes".into()));
765 let stack = map_set(stack);
766
767 let stack = crate::stack::dup(stack);
769 let stack = map_size(stack);
770 let (stack, size) = pop(stack);
771 assert_eq!(size, Value::Int(3));
772
773 let stack = crate::stack::dup(stack);
776 let stack = push(stack, Value::String("name".into()));
777 let stack = map_get(stack);
778 let (stack, flag) = pop(stack);
779 assert_eq!(flag, Value::Bool(true));
780 let (stack, result) = pop(stack);
781 match result {
782 Value::String(s) => assert_eq!(s.as_str(), "Alice"),
783 _ => panic!("Expected String for name key"),
784 }
785
786 let stack = crate::stack::dup(stack);
787 let stack = push(stack, Value::Int(42));
788 let stack = map_get(stack);
789 let (stack, flag) = pop(stack);
790 assert_eq!(flag, Value::Bool(true));
791 let (stack, result) = pop(stack);
792 match result {
793 Value::String(s) => assert_eq!(s.as_str(), "answer"),
794 _ => panic!("Expected String for int key"),
795 }
796
797 let stack = push(stack, Value::Bool(true));
798 let stack = map_get(stack);
799 let (stack, flag) = pop(stack);
800 assert_eq!(flag, Value::Bool(true));
801 let (_stack, result) = pop(stack);
802 match result {
803 Value::String(s) => assert_eq!(s.as_str(), "yes"),
804 _ => panic!("Expected String for bool key"),
805 }
806 }
807 }
808
809 #[test]
814 fn test_map_fold_empty() {
815 unsafe {
817 use crate::quotations::push_quotation;
818
819 let stack = crate::stack::alloc_test_stack();
820
821 let stack = make_map(stack);
823
824 let stack = push(stack, Value::Int(99));
826
827 unsafe extern "C" fn noop(stack: Stack) -> Stack {
829 stack
830 }
831 let fn_ptr = noop as *const () as usize;
832 let stack = push_quotation(stack, fn_ptr, fn_ptr);
833
834 let stack = patch_seq_map_fold(stack);
835
836 let (_stack, result) = pop(stack);
837 assert_eq!(result, Value::Int(99));
838 }
839 }
840}