1use crate::stack::{Stack, pop, push};
29use crate::value::Value;
30use std::sync::Arc;
31
32pub const MAX_CAPTURES: usize = 1024;
35
36#[allow(improper_ctypes_definitions)]
46#[unsafe(no_mangle)]
47pub extern "C" fn patch_seq_create_env(size: i32) -> *mut [Value] {
48 if size < 0 {
49 panic!("create_env: size cannot be negative: {}", size);
50 }
51
52 let size_usize = size as usize;
53 if size_usize > MAX_CAPTURES {
54 panic!(
55 "create_env: size {} exceeds MAX_CAPTURES ({})",
56 size_usize, MAX_CAPTURES
57 );
58 }
59
60 let mut vec: Vec<Value> = Vec::with_capacity(size_usize);
61
62 for _ in 0..size {
64 vec.push(Value::Int(0));
65 }
66
67 Box::into_raw(vec.into_boxed_slice())
68}
69
70#[allow(improper_ctypes_definitions)]
80#[unsafe(no_mangle)]
81pub unsafe extern "C" fn patch_seq_env_set(env: *mut [Value], index: i32, value: Value) {
82 if env.is_null() {
83 panic!("env_set: null environment pointer");
84 }
85
86 if index < 0 {
87 panic!("env_set: index cannot be negative: {}", index);
88 }
89
90 let env_slice = unsafe { &mut *env };
91 let idx = index as usize;
92
93 if idx >= env_slice.len() {
94 panic!(
95 "env_set: index {} out of bounds for environment of size {}",
96 index,
97 env_slice.len()
98 );
99 }
100
101 env_slice[idx] = value;
102}
103
104#[allow(improper_ctypes_definitions)]
115#[unsafe(no_mangle)]
116pub unsafe extern "C" fn patch_seq_env_get(
117 env_data: *const Value,
118 env_len: usize,
119 index: i32,
120) -> Value {
121 if env_data.is_null() {
122 panic!("env_get: null environment pointer");
123 }
124
125 if index < 0 {
126 panic!("env_get: index cannot be negative: {}", index);
127 }
128
129 let idx = index as usize;
130
131 if idx >= env_len {
132 panic!(
133 "env_get: index {} out of bounds for environment of size {}",
134 index, env_len
135 );
136 }
137
138 unsafe { (*env_data.add(idx)).clone() }
140}
141
142#[unsafe(no_mangle)]
158pub unsafe extern "C" fn patch_seq_env_get_int(
159 env_data: *const Value,
160 env_len: usize,
161 index: i32,
162) -> i64 {
163 if env_data.is_null() {
164 panic!("env_get_int: null environment pointer");
165 }
166
167 if index < 0 {
168 panic!("env_get_int: index cannot be negative: {}", index);
169 }
170
171 let idx = index as usize;
172
173 if idx >= env_len {
174 panic!(
175 "env_get_int: index {} out of bounds for environment of size {}",
176 index, env_len
177 );
178 }
179
180 let value = unsafe { &*env_data.add(idx) };
182
183 match value {
184 Value::Int(n) => *n,
185 _ => panic!(
186 "env_get_int: expected Int at index {}, got {:?}",
187 index, value
188 ),
189 }
190}
191
192#[allow(improper_ctypes_definitions)]
203#[unsafe(no_mangle)]
204pub unsafe extern "C" fn patch_seq_env_get_string(
205 env_data: *const Value,
206 env_len: usize,
207 index: i32,
208) -> crate::seqstring::SeqString {
209 if env_data.is_null() {
210 panic!("env_get_string: null environment pointer");
211 }
212
213 if index < 0 {
214 panic!("env_get_string: index cannot be negative: {}", index);
215 }
216
217 let idx = index as usize;
218
219 if idx >= env_len {
220 panic!(
221 "env_get_string: index {} out of bounds for environment of size {}",
222 index, env_len
223 );
224 }
225
226 let value = unsafe { &*env_data.add(idx) };
228
229 match value {
230 Value::String(s) => s.clone(),
231 _ => panic!(
232 "env_get_string: expected String at index {}, got {:?}",
233 index, value
234 ),
235 }
236}
237
238#[unsafe(no_mangle)]
250pub unsafe extern "C" fn patch_seq_env_push_string(
251 stack: Stack,
252 env_data: *const Value,
253 env_len: usize,
254 index: i32,
255) -> Stack {
256 if env_data.is_null() {
257 panic!("env_push_string: null environment pointer");
258 }
259
260 if index < 0 {
261 panic!("env_push_string: index cannot be negative: {}", index);
262 }
263
264 let idx = index as usize;
265
266 if idx >= env_len {
267 panic!(
268 "env_push_string: index {} out of bounds for environment of size {}",
269 index, env_len
270 );
271 }
272
273 let value = unsafe { &*env_data.add(idx) };
275
276 match value {
277 Value::String(s) => unsafe { push(stack, Value::String(s.clone())) },
278 _ => panic!(
279 "env_push_string: expected String at index {}, got {:?}",
280 index, value
281 ),
282 }
283}
284
285#[unsafe(no_mangle)]
298pub unsafe extern "C" fn patch_seq_env_push_value(
299 stack: Stack,
300 env_data: *const Value,
301 env_len: usize,
302 index: i32,
303) -> Stack {
304 if env_data.is_null() {
305 panic!("env_push_value: null environment pointer");
306 }
307
308 if index < 0 {
309 panic!("env_push_value: index cannot be negative: {}", index);
310 }
311
312 let idx = index as usize;
313
314 if idx >= env_len {
315 panic!(
316 "env_push_value: index {} out of bounds for environment of size {}",
317 index, env_len
318 );
319 }
320
321 let value = unsafe { (*env_data.add(idx)).clone() };
329 debug_assert!(
330 !matches!(value, Value::Int(_) | Value::Bool(_) | Value::Float(_)),
331 "env_push_value called for primitive type {:?} — use the specialized getter",
332 value
333 );
334 unsafe { push(stack, value) }
335}
336
337#[unsafe(no_mangle)]
348pub unsafe extern "C" fn patch_seq_env_get_bool(
349 env_data: *const Value,
350 env_len: usize,
351 index: i32,
352) -> i64 {
353 if env_data.is_null() {
354 panic!("env_get_bool: null environment pointer");
355 }
356
357 if index < 0 {
358 panic!("env_get_bool: index cannot be negative: {}", index);
359 }
360
361 let idx = index as usize;
362
363 if idx >= env_len {
364 panic!(
365 "env_get_bool: index {} out of bounds for environment of size {}",
366 index, env_len
367 );
368 }
369
370 let value = unsafe { &*env_data.add(idx) };
371
372 match value {
373 Value::Bool(b) => {
374 if *b {
375 1
376 } else {
377 0
378 }
379 }
380 _ => panic!(
381 "env_get_bool: expected Bool at index {}, got {:?}",
382 index, value
383 ),
384 }
385}
386
387#[unsafe(no_mangle)]
397pub unsafe extern "C" fn patch_seq_env_get_float(
398 env_data: *const Value,
399 env_len: usize,
400 index: i32,
401) -> f64 {
402 if env_data.is_null() {
403 panic!("env_get_float: null environment pointer");
404 }
405
406 if index < 0 {
407 panic!("env_get_float: index cannot be negative: {}", index);
408 }
409
410 let idx = index as usize;
411
412 if idx >= env_len {
413 panic!(
414 "env_get_float: index {} out of bounds for environment of size {}",
415 index, env_len
416 );
417 }
418
419 let value = unsafe { &*env_data.add(idx) };
420
421 match value {
422 Value::Float(f) => *f,
423 _ => panic!(
424 "env_get_float: expected Float at index {}, got {:?}",
425 index, value
426 ),
427 }
428}
429
430#[unsafe(no_mangle)]
442pub unsafe extern "C" fn patch_seq_env_get_quotation(
443 env_data: *const Value,
444 env_len: usize,
445 index: i32,
446) -> i64 {
447 if env_data.is_null() {
448 panic!("env_get_quotation: null environment pointer");
449 }
450
451 if index < 0 {
452 panic!("env_get_quotation: index cannot be negative: {}", index);
453 }
454
455 let idx = index as usize;
456
457 if idx >= env_len {
458 panic!(
459 "env_get_quotation: index {} out of bounds for environment of size {}",
460 index, env_len
461 );
462 }
463
464 let value = unsafe { &*env_data.add(idx) };
465
466 match value {
467 Value::Quotation { impl_, .. } => *impl_ as i64,
468 _ => panic!(
469 "env_get_quotation: expected Quotation at index {}, got {:?}",
470 index, value
471 ),
472 }
473}
474
475#[allow(improper_ctypes_definitions)]
486#[unsafe(no_mangle)]
487pub unsafe extern "C" fn patch_seq_make_closure(fn_ptr: u64, env: *mut [Value]) -> Value {
488 if fn_ptr == 0 {
489 panic!("make_closure: null function pointer");
490 }
491
492 if env.is_null() {
493 panic!("make_closure: null environment pointer");
494 }
495
496 let env_box = unsafe { Box::from_raw(env) };
498 let env_arc: Arc<[Value]> = Arc::from(env_box);
499
500 Value::Closure {
501 fn_ptr: fn_ptr as usize,
502 env: env_arc,
503 }
504}
505
506#[unsafe(no_mangle)]
518pub unsafe extern "C" fn patch_seq_push_closure(
519 mut stack: Stack,
520 fn_ptr: u64,
521 capture_count: i32,
522) -> Stack {
523 if fn_ptr == 0 {
524 panic!("push_closure: null function pointer");
525 }
526
527 if capture_count < 0 {
528 panic!(
529 "push_closure: capture_count cannot be negative: {}",
530 capture_count
531 );
532 }
533
534 let count = capture_count as usize;
535
536 let mut captures: Vec<Value> = Vec::with_capacity(count);
541 for _ in 0..count {
542 let (new_stack, value) = unsafe { pop(stack) };
543 captures.push(value);
544 stack = new_stack;
545 }
546 captures.reverse();
547
548 let closure = Value::Closure {
550 fn_ptr: fn_ptr as usize,
551 env: Arc::from(captures.into_boxed_slice()),
552 };
553
554 unsafe { push(stack, closure) }
556}
557
558pub use patch_seq_create_env as create_env;
560pub use patch_seq_env_get as env_get;
561pub use patch_seq_env_get_bool as env_get_bool;
562pub use patch_seq_env_get_float as env_get_float;
563pub use patch_seq_env_get_int as env_get_int;
564pub use patch_seq_env_get_quotation as env_get_quotation;
565pub use patch_seq_env_get_string as env_get_string;
566pub use patch_seq_env_push_string as env_push_string;
567pub use patch_seq_env_push_value as env_push_value;
568pub use patch_seq_env_set as env_set;
569pub use patch_seq_make_closure as make_closure;
570pub use patch_seq_push_closure as push_closure;
571
572#[cfg(test)]
573mod tests {
574 use super::*;
575
576 #[test]
577 fn test_create_env() {
578 let env = create_env(3);
579 assert!(!env.is_null());
580
581 unsafe {
583 let _ = Box::from_raw(env);
584 }
585 }
586
587 #[test]
588 fn test_env_set_and_get() {
589 let env = create_env(3);
590
591 unsafe {
593 env_set(env, 0, Value::Int(42));
594 env_set(env, 1, Value::Bool(true));
595 env_set(env, 2, Value::Int(99));
596 }
597
598 unsafe {
600 let env_slice = &*env;
601 let env_data = env_slice.as_ptr();
602 let env_len = env_slice.len();
603 assert_eq!(env_get(env_data, env_len, 0), Value::Int(42));
604 assert_eq!(env_get(env_data, env_len, 1), Value::Bool(true));
605 assert_eq!(env_get(env_data, env_len, 2), Value::Int(99));
606 }
607
608 unsafe {
610 let _ = Box::from_raw(env);
611 }
612 }
613
614 #[test]
615 fn test_make_closure() {
616 let env = create_env(2);
617
618 unsafe {
619 env_set(env, 0, Value::Int(5));
620 env_set(env, 1, Value::Int(10));
621
622 let closure = make_closure(0x1234, env);
623
624 match closure {
625 Value::Closure { fn_ptr, env } => {
626 assert_eq!(fn_ptr, 0x1234);
627 assert_eq!(env.len(), 2);
628 assert_eq!(env[0], Value::Int(5));
629 assert_eq!(env[1], Value::Int(10));
630 }
631 _ => panic!("Expected Closure value"),
632 }
633 }
634 }
635
636 #[test]
641 fn test_push_closure() {
642 use crate::stack::{pop, push};
643 use crate::value::Value;
644
645 let mut stack = crate::stack::alloc_test_stack();
647 stack = unsafe { push(stack, Value::Int(10)) };
648 stack = unsafe { push(stack, Value::Int(5)) };
649
650 let fn_ptr = 0x1234;
652 stack = unsafe { push_closure(stack, fn_ptr, 2) };
653
654 let (_stack, closure_value) = unsafe { pop(stack) };
656
657 match closure_value {
663 Value::Closure { fn_ptr: fp, env } => {
664 assert_eq!(fp, fn_ptr as usize);
665 assert_eq!(env.len(), 2);
666 assert_eq!(env[0], Value::Int(10)); assert_eq!(env[1], Value::Int(5)); }
669 _ => panic!("Expected Closure value, got {:?}", closure_value),
670 }
671
672 }
674
675 #[test]
676 fn test_push_closure_zero_captures() {
677 use crate::stack::pop;
678 use crate::value::Value;
679
680 let stack = crate::stack::alloc_test_stack();
682
683 let fn_ptr = 0x5678;
685 let stack = unsafe { push_closure(stack, fn_ptr, 0) };
686
687 let (_stack, closure_value) = unsafe { pop(stack) };
689
690 match closure_value {
692 Value::Closure { fn_ptr: fp, env } => {
693 assert_eq!(fp, fn_ptr as usize);
694 assert_eq!(env.len(), 0);
695 }
696 _ => panic!("Expected Closure value, got {:?}", closure_value),
697 }
698
699 }
701
702 #[test]
703 fn test_env_get_bool() {
704 let env = create_env(2);
705
706 unsafe {
707 env_set(env, 0, Value::Bool(true));
708 env_set(env, 1, Value::Bool(false));
709
710 let env_slice = &*env;
711 let env_data = env_slice.as_ptr();
712 let env_len = env_slice.len();
713
714 assert_eq!(env_get_bool(env_data, env_len, 0), 1);
715 assert_eq!(env_get_bool(env_data, env_len, 1), 0);
716
717 let _ = Box::from_raw(env);
718 }
719 }
720
721 #[test]
722 fn test_env_get_float() {
723 let env = create_env(2);
724
725 unsafe {
726 env_set(env, 0, Value::Float(1.234));
727 env_set(env, 1, Value::Float(-5.678));
728
729 let env_slice = &*env;
730 let env_data = env_slice.as_ptr();
731 let env_len = env_slice.len();
732
733 assert!((env_get_float(env_data, env_len, 0) - 1.234).abs() < 0.0001);
734 assert!((env_get_float(env_data, env_len, 1) - (-5.678)).abs() < 0.0001);
735
736 let _ = Box::from_raw(env);
737 }
738 }
739
740 #[test]
741 fn test_env_get_quotation() {
742 let env = create_env(1);
743 let wrapper: usize = 0xDEADBEEF;
744 let impl_: usize = 0xCAFEBABE;
745
746 unsafe {
747 env_set(env, 0, Value::Quotation { wrapper, impl_ });
748
749 let env_slice = &*env;
750 let env_data = env_slice.as_ptr();
751 let env_len = env_slice.len();
752
753 assert_eq!(env_get_quotation(env_data, env_len, 0), impl_ as i64);
755
756 let _ = Box::from_raw(env);
757 }
758 }
759}