1use crate::stack::{Stack, is_empty, pop, push};
23use crate::value::{Value, VariantData};
24use std::sync::Arc;
25
26unsafe fn drain_stack(mut stack: Stack) {
31 unsafe {
32 while !is_empty(stack) {
33 let (rest, _) = pop(stack);
34 stack = rest;
35 }
36 }
37}
38
39unsafe fn call_with_value(stack: Stack, value: Value, callable: &Value) -> Stack {
44 unsafe {
45 let stack = push(stack, value);
46
47 match callable {
48 Value::Quotation { wrapper, .. } => {
49 let fn_ref: unsafe extern "C" fn(Stack) -> Stack = std::mem::transmute(*wrapper);
50 fn_ref(stack)
51 }
52 Value::Closure { fn_ptr, env } => {
53 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
54 std::mem::transmute(*fn_ptr);
55 fn_ref(stack, env.as_ptr(), env.len())
56 }
57 _ => panic!("list operation: expected Quotation or Closure"),
58 }
59 }
60}
61
62#[unsafe(no_mangle)]
72pub unsafe extern "C" fn patch_seq_list_map(stack: Stack) -> Stack {
73 unsafe {
74 let (stack, callable) = pop(stack);
76
77 match &callable {
79 Value::Quotation { .. } | Value::Closure { .. } => {}
80 _ => panic!(
81 "list-map: expected Quotation or Closure, got {:?}",
82 callable
83 ),
84 }
85
86 let (stack, list_val) = pop(stack);
88
89 let variant_data = match list_val {
90 Value::Variant(v) => v,
91 _ => panic!("list-map: expected Variant (list), got {:?}", list_val),
92 };
93
94 let mut results = Vec::with_capacity(variant_data.fields.len());
96
97 for field in variant_data.fields.iter() {
98 let temp_stack = call_with_value(std::ptr::null_mut(), field.clone(), &callable);
100
101 if is_empty(temp_stack) {
103 panic!("list-map: quotation consumed element without producing result");
104 }
105 let (remaining, result) = pop(temp_stack);
106 results.push(result);
107
108 if !is_empty(remaining) {
110 drain_stack(remaining);
111 }
112 }
113
114 let new_variant = Value::Variant(Arc::new(VariantData::new(variant_data.tag, results)));
116
117 push(stack, new_variant)
118 }
119}
120
121#[unsafe(no_mangle)]
131pub unsafe extern "C" fn patch_seq_list_filter(stack: Stack) -> Stack {
132 unsafe {
133 let (stack, callable) = pop(stack);
135
136 match &callable {
138 Value::Quotation { .. } | Value::Closure { .. } => {}
139 _ => panic!(
140 "list-filter: expected Quotation or Closure, got {:?}",
141 callable
142 ),
143 }
144
145 let (stack, list_val) = pop(stack);
147
148 let variant_data = match list_val {
149 Value::Variant(v) => v,
150 _ => panic!("list-filter: expected Variant (list), got {:?}", list_val),
151 };
152
153 let mut results = Vec::new();
155
156 for field in variant_data.fields.iter() {
157 let temp_stack = call_with_value(std::ptr::null_mut(), field.clone(), &callable);
159
160 if is_empty(temp_stack) {
162 panic!("list-filter: quotation consumed element without producing result");
163 }
164 let (remaining, result) = pop(temp_stack);
165
166 let keep = match result {
167 Value::Int(n) => n != 0,
168 _ => panic!("list-filter: quotation must return Int, got {:?}", result),
169 };
170
171 if keep {
172 results.push(field.clone());
173 }
174
175 if !is_empty(remaining) {
177 drain_stack(remaining);
178 }
179 }
180
181 let new_variant = Value::Variant(Arc::new(VariantData::new(variant_data.tag, results)));
183
184 push(stack, new_variant)
185 }
186}
187
188#[unsafe(no_mangle)]
198pub unsafe extern "C" fn patch_seq_list_fold(stack: Stack) -> Stack {
199 unsafe {
200 let (stack, callable) = pop(stack);
202
203 match &callable {
205 Value::Quotation { .. } | Value::Closure { .. } => {}
206 _ => panic!(
207 "list-fold: expected Quotation or Closure, got {:?}",
208 callable
209 ),
210 }
211
212 let (stack, init) = pop(stack);
214
215 let (stack, list_val) = pop(stack);
217
218 let variant_data = match list_val {
219 Value::Variant(v) => v,
220 _ => panic!("list-fold: expected Variant (list), got {:?}", list_val),
221 };
222
223 let mut acc = init;
225
226 for field in variant_data.fields.iter() {
227 let temp_stack = push(std::ptr::null_mut(), acc);
229 let temp_stack = push(temp_stack, field.clone());
230
231 let temp_stack = match &callable {
232 Value::Quotation { wrapper, .. } => {
233 let fn_ref: unsafe extern "C" fn(Stack) -> Stack =
234 std::mem::transmute(*wrapper);
235 fn_ref(temp_stack)
236 }
237 Value::Closure { fn_ptr, env } => {
238 let fn_ref: unsafe extern "C" fn(Stack, *const Value, usize) -> Stack =
239 std::mem::transmute(*fn_ptr);
240 fn_ref(temp_stack, env.as_ptr(), env.len())
241 }
242 _ => unreachable!(),
243 };
244
245 if is_empty(temp_stack) {
247 panic!("list-fold: quotation consumed inputs without producing result");
248 }
249 let (remaining, new_acc) = pop(temp_stack);
250 acc = new_acc;
251
252 if !is_empty(remaining) {
254 drain_stack(remaining);
255 }
256 }
257
258 push(stack, acc)
259 }
260}
261
262#[unsafe(no_mangle)]
272pub unsafe extern "C" fn patch_seq_list_each(stack: Stack) -> Stack {
273 unsafe {
274 let (stack, callable) = pop(stack);
276
277 match &callable {
279 Value::Quotation { .. } | Value::Closure { .. } => {}
280 _ => panic!(
281 "list-each: expected Quotation or Closure, got {:?}",
282 callable
283 ),
284 }
285
286 let (stack, list_val) = pop(stack);
288
289 let variant_data = match list_val {
290 Value::Variant(v) => v,
291 _ => panic!("list-each: expected Variant (list), got {:?}", list_val),
292 };
293
294 for field in variant_data.fields.iter() {
296 let temp_stack = call_with_value(std::ptr::null_mut(), field.clone(), &callable);
297 if !is_empty(temp_stack) {
299 drain_stack(temp_stack);
300 }
301 }
302
303 stack
304 }
305}
306
307#[unsafe(no_mangle)]
317pub unsafe extern "C" fn patch_seq_list_length(stack: Stack) -> Stack {
318 unsafe { crate::variant_ops::patch_seq_variant_field_count(stack) }
319}
320
321#[unsafe(no_mangle)]
330pub unsafe extern "C" fn patch_seq_list_empty(stack: Stack) -> Stack {
331 unsafe {
332 let (stack, list_val) = pop(stack);
333
334 let is_empty = match list_val {
335 Value::Variant(v) => {
336 if v.fields.is_empty() {
337 1i64
338 } else {
339 0i64
340 }
341 }
342 _ => panic!("list-empty?: expected Variant (list), got {:?}", list_val),
343 };
344
345 push(stack, Value::Int(is_empty))
346 }
347}
348
349pub use patch_seq_list_each as list_each;
351pub use patch_seq_list_empty as list_empty;
352pub use patch_seq_list_filter as list_filter;
353pub use patch_seq_list_fold as list_fold;
354pub use patch_seq_list_length as list_length;
355pub use patch_seq_list_map as list_map;
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360
361 unsafe extern "C" fn double_quot(stack: Stack) -> Stack {
363 unsafe {
364 let (stack, val) = pop(stack);
365 match val {
366 Value::Int(n) => push(stack, Value::Int(n * 2)),
367 _ => panic!("Expected Int"),
368 }
369 }
370 }
371
372 unsafe extern "C" fn is_positive_quot(stack: Stack) -> Stack {
374 unsafe {
375 let (stack, val) = pop(stack);
376 match val {
377 Value::Int(n) => push(stack, Value::Int(if n > 0 { 1 } else { 0 })),
378 _ => panic!("Expected Int"),
379 }
380 }
381 }
382
383 unsafe extern "C" fn add_quot(stack: Stack) -> Stack {
385 unsafe {
386 let (stack, b) = pop(stack);
387 let (stack, a) = pop(stack);
388 match (a, b) {
389 (Value::Int(x), Value::Int(y)) => push(stack, Value::Int(x + y)),
390 _ => panic!("Expected two Ints"),
391 }
392 }
393 }
394
395 #[test]
396 fn test_list_map_double() {
397 unsafe {
398 let list = Value::Variant(Arc::new(VariantData::new(
400 0,
401 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
402 )));
403
404 let stack = std::ptr::null_mut();
405 let stack = push(stack, list);
406 let fn_ptr = double_quot as usize;
407 let stack = push(
408 stack,
409 Value::Quotation {
410 wrapper: fn_ptr,
411 impl_: fn_ptr,
412 },
413 );
414 let stack = list_map(stack);
415
416 let (stack, result) = pop(stack);
417 match result {
418 Value::Variant(v) => {
419 assert_eq!(v.fields.len(), 3);
420 assert_eq!(v.fields[0], Value::Int(2));
421 assert_eq!(v.fields[1], Value::Int(4));
422 assert_eq!(v.fields[2], Value::Int(6));
423 }
424 _ => panic!("Expected Variant"),
425 }
426 assert!(stack.is_null());
427 }
428 }
429
430 #[test]
431 fn test_list_filter_positive() {
432 unsafe {
433 let list = Value::Variant(Arc::new(VariantData::new(
435 0,
436 vec![
437 Value::Int(-1),
438 Value::Int(2),
439 Value::Int(-3),
440 Value::Int(4),
441 Value::Int(0),
442 ],
443 )));
444
445 let stack = std::ptr::null_mut();
446 let stack = push(stack, list);
447 let fn_ptr = is_positive_quot as usize;
448 let stack = push(
449 stack,
450 Value::Quotation {
451 wrapper: fn_ptr,
452 impl_: fn_ptr,
453 },
454 );
455 let stack = list_filter(stack);
456
457 let (stack, result) = pop(stack);
458 match result {
459 Value::Variant(v) => {
460 assert_eq!(v.fields.len(), 2);
461 assert_eq!(v.fields[0], Value::Int(2));
462 assert_eq!(v.fields[1], Value::Int(4));
463 }
464 _ => panic!("Expected Variant"),
465 }
466 assert!(stack.is_null());
467 }
468 }
469
470 #[test]
471 fn test_list_fold_sum() {
472 unsafe {
473 let list = Value::Variant(Arc::new(VariantData::new(
475 0,
476 vec![
477 Value::Int(1),
478 Value::Int(2),
479 Value::Int(3),
480 Value::Int(4),
481 Value::Int(5),
482 ],
483 )));
484
485 let stack = std::ptr::null_mut();
486 let stack = push(stack, list);
487 let stack = push(stack, Value::Int(0)); let fn_ptr = add_quot as usize;
489 let stack = push(
490 stack,
491 Value::Quotation {
492 wrapper: fn_ptr,
493 impl_: fn_ptr,
494 },
495 );
496 let stack = list_fold(stack);
497
498 let (stack, result) = pop(stack);
499 assert_eq!(result, Value::Int(15)); assert!(stack.is_null());
501 }
502 }
503
504 #[test]
505 fn test_list_fold_empty() {
506 unsafe {
507 let list = Value::Variant(Arc::new(VariantData::new(0, vec![])));
509
510 let stack = std::ptr::null_mut();
511 let stack = push(stack, list);
512 let stack = push(stack, Value::Int(42)); let fn_ptr = add_quot as usize;
514 let stack = push(
515 stack,
516 Value::Quotation {
517 wrapper: fn_ptr,
518 impl_: fn_ptr,
519 },
520 );
521 let stack = list_fold(stack);
522
523 let (stack, result) = pop(stack);
524 assert_eq!(result, Value::Int(42)); assert!(stack.is_null());
526 }
527 }
528
529 #[test]
530 fn test_list_length() {
531 unsafe {
532 let list = Value::Variant(Arc::new(VariantData::new(
533 0,
534 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
535 )));
536
537 let stack = std::ptr::null_mut();
538 let stack = push(stack, list);
539 let stack = list_length(stack);
540
541 let (stack, result) = pop(stack);
542 assert_eq!(result, Value::Int(3));
543 assert!(stack.is_null());
544 }
545 }
546
547 #[test]
548 fn test_list_empty_true() {
549 unsafe {
550 let list = Value::Variant(Arc::new(VariantData::new(0, vec![])));
551
552 let stack = std::ptr::null_mut();
553 let stack = push(stack, list);
554 let stack = list_empty(stack);
555
556 let (stack, result) = pop(stack);
557 assert_eq!(result, Value::Int(1));
558 assert!(stack.is_null());
559 }
560 }
561
562 #[test]
563 fn test_list_empty_false() {
564 unsafe {
565 let list = Value::Variant(Arc::new(VariantData::new(0, vec![Value::Int(1)])));
566
567 let stack = std::ptr::null_mut();
568 let stack = push(stack, list);
569 let stack = list_empty(stack);
570
571 let (stack, result) = pop(stack);
572 assert_eq!(result, Value::Int(0));
573 assert!(stack.is_null());
574 }
575 }
576
577 #[test]
578 fn test_list_map_empty() {
579 unsafe {
580 let list = Value::Variant(Arc::new(VariantData::new(0, vec![])));
581
582 let stack = std::ptr::null_mut();
583 let stack = push(stack, list);
584 let fn_ptr = double_quot as usize;
585 let stack = push(
586 stack,
587 Value::Quotation {
588 wrapper: fn_ptr,
589 impl_: fn_ptr,
590 },
591 );
592 let stack = list_map(stack);
593
594 let (stack, result) = pop(stack);
595 match result {
596 Value::Variant(v) => {
597 assert_eq!(v.fields.len(), 0);
598 }
599 _ => panic!("Expected Variant"),
600 }
601 assert!(stack.is_null());
602 }
603 }
604
605 #[test]
606 fn test_list_map_preserves_tag() {
607 unsafe {
608 let list = Value::Variant(Arc::new(VariantData::new(
610 42,
611 vec![Value::Int(1), Value::Int(2)],
612 )));
613
614 let stack = std::ptr::null_mut();
615 let stack = push(stack, list);
616 let fn_ptr = double_quot as usize;
617 let stack = push(
618 stack,
619 Value::Quotation {
620 wrapper: fn_ptr,
621 impl_: fn_ptr,
622 },
623 );
624 let stack = list_map(stack);
625
626 let (stack, result) = pop(stack);
627 match result {
628 Value::Variant(v) => {
629 assert_eq!(v.tag, 42); assert_eq!(v.fields[0], Value::Int(2));
631 assert_eq!(v.fields[1], Value::Int(4));
632 }
633 _ => panic!("Expected Variant"),
634 }
635 assert!(stack.is_null());
636 }
637 }
638
639 unsafe extern "C" fn add_captured_closure(
642 stack: Stack,
643 env: *const Value,
644 _env_len: usize,
645 ) -> Stack {
646 unsafe {
647 let (stack, val) = pop(stack);
648 let captured = &*env; match (val, captured) {
650 (Value::Int(n), Value::Int(c)) => push(stack, Value::Int(n + c)),
651 _ => panic!("Expected Int"),
652 }
653 }
654 }
655
656 #[test]
657 fn test_list_map_with_closure() {
658 unsafe {
659 let list = Value::Variant(Arc::new(VariantData::new(
661 0,
662 vec![Value::Int(1), Value::Int(2), Value::Int(3)],
663 )));
664
665 let env: std::sync::Arc<[Value]> =
667 std::sync::Arc::from(vec![Value::Int(10)].into_boxed_slice());
668 let closure = Value::Closure {
669 fn_ptr: add_captured_closure as usize,
670 env,
671 };
672
673 let stack = std::ptr::null_mut();
674 let stack = push(stack, list);
675 let stack = push(stack, closure);
676 let stack = list_map(stack);
677
678 let (stack, result) = pop(stack);
679 match result {
680 Value::Variant(v) => {
681 assert_eq!(v.fields.len(), 3);
682 assert_eq!(v.fields[0], Value::Int(11)); assert_eq!(v.fields[1], Value::Int(12)); assert_eq!(v.fields[2], Value::Int(13)); }
686 _ => panic!("Expected Variant"),
687 }
688 assert!(stack.is_null());
689 }
690 }
691}