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