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)]
295pub unsafe extern "C" fn patch_seq_env_get_bool(
296 env_data: *const Value,
297 env_len: usize,
298 index: i32,
299) -> i64 {
300 if env_data.is_null() {
301 panic!("env_get_bool: null environment pointer");
302 }
303
304 if index < 0 {
305 panic!("env_get_bool: index cannot be negative: {}", index);
306 }
307
308 let idx = index as usize;
309
310 if idx >= env_len {
311 panic!(
312 "env_get_bool: index {} out of bounds for environment of size {}",
313 index, env_len
314 );
315 }
316
317 let value = unsafe { &*env_data.add(idx) };
318
319 match value {
320 Value::Bool(b) => {
321 if *b {
322 1
323 } else {
324 0
325 }
326 }
327 _ => panic!(
328 "env_get_bool: expected Bool at index {}, got {:?}",
329 index, value
330 ),
331 }
332}
333
334#[unsafe(no_mangle)]
344pub unsafe extern "C" fn patch_seq_env_get_float(
345 env_data: *const Value,
346 env_len: usize,
347 index: i32,
348) -> f64 {
349 if env_data.is_null() {
350 panic!("env_get_float: null environment pointer");
351 }
352
353 if index < 0 {
354 panic!("env_get_float: index cannot be negative: {}", index);
355 }
356
357 let idx = index as usize;
358
359 if idx >= env_len {
360 panic!(
361 "env_get_float: index {} out of bounds for environment of size {}",
362 index, env_len
363 );
364 }
365
366 let value = unsafe { &*env_data.add(idx) };
367
368 match value {
369 Value::Float(f) => *f,
370 _ => panic!(
371 "env_get_float: expected Float at index {}, got {:?}",
372 index, value
373 ),
374 }
375}
376
377#[unsafe(no_mangle)]
389pub unsafe extern "C" fn patch_seq_env_get_quotation(
390 env_data: *const Value,
391 env_len: usize,
392 index: i32,
393) -> i64 {
394 if env_data.is_null() {
395 panic!("env_get_quotation: null environment pointer");
396 }
397
398 if index < 0 {
399 panic!("env_get_quotation: index cannot be negative: {}", index);
400 }
401
402 let idx = index as usize;
403
404 if idx >= env_len {
405 panic!(
406 "env_get_quotation: index {} out of bounds for environment of size {}",
407 index, env_len
408 );
409 }
410
411 let value = unsafe { &*env_data.add(idx) };
412
413 match value {
414 Value::Quotation { impl_, .. } => *impl_ as i64,
415 _ => panic!(
416 "env_get_quotation: expected Quotation at index {}, got {:?}",
417 index, value
418 ),
419 }
420}
421
422#[allow(improper_ctypes_definitions)]
433#[unsafe(no_mangle)]
434pub unsafe extern "C" fn patch_seq_make_closure(fn_ptr: u64, env: *mut [Value]) -> Value {
435 if fn_ptr == 0 {
436 panic!("make_closure: null function pointer");
437 }
438
439 if env.is_null() {
440 panic!("make_closure: null environment pointer");
441 }
442
443 let env_box = unsafe { Box::from_raw(env) };
445 let env_arc: Arc<[Value]> = Arc::from(env_box);
446
447 Value::Closure {
448 fn_ptr: fn_ptr as usize,
449 env: env_arc,
450 }
451}
452
453#[unsafe(no_mangle)]
465pub unsafe extern "C" fn patch_seq_push_closure(
466 mut stack: Stack,
467 fn_ptr: u64,
468 capture_count: i32,
469) -> Stack {
470 if fn_ptr == 0 {
471 panic!("push_closure: null function pointer");
472 }
473
474 if capture_count < 0 {
475 panic!(
476 "push_closure: capture_count cannot be negative: {}",
477 capture_count
478 );
479 }
480
481 let count = capture_count as usize;
482
483 let mut captures: Vec<Value> = Vec::with_capacity(count);
485 for _ in 0..count {
486 let (new_stack, value) = unsafe { pop(stack) };
487 captures.push(value);
488 stack = new_stack;
489 }
490
491 let closure = Value::Closure {
493 fn_ptr: fn_ptr as usize,
494 env: Arc::from(captures.into_boxed_slice()),
495 };
496
497 unsafe { push(stack, closure) }
499}
500
501pub use patch_seq_create_env as create_env;
503pub use patch_seq_env_get as env_get;
504pub use patch_seq_env_get_bool as env_get_bool;
505pub use patch_seq_env_get_float as env_get_float;
506pub use patch_seq_env_get_int as env_get_int;
507pub use patch_seq_env_get_quotation as env_get_quotation;
508pub use patch_seq_env_get_string as env_get_string;
509pub use patch_seq_env_push_string as env_push_string;
510pub use patch_seq_env_set as env_set;
511pub use patch_seq_make_closure as make_closure;
512pub use patch_seq_push_closure as push_closure;
513
514#[cfg(test)]
515mod tests {
516 use super::*;
517
518 #[test]
519 fn test_create_env() {
520 let env = create_env(3);
521 assert!(!env.is_null());
522
523 unsafe {
525 let _ = Box::from_raw(env);
526 }
527 }
528
529 #[test]
530 fn test_env_set_and_get() {
531 let env = create_env(3);
532
533 unsafe {
535 env_set(env, 0, Value::Int(42));
536 env_set(env, 1, Value::Bool(true));
537 env_set(env, 2, Value::Int(99));
538 }
539
540 unsafe {
542 let env_slice = &*env;
543 let env_data = env_slice.as_ptr();
544 let env_len = env_slice.len();
545 assert_eq!(env_get(env_data, env_len, 0), Value::Int(42));
546 assert_eq!(env_get(env_data, env_len, 1), Value::Bool(true));
547 assert_eq!(env_get(env_data, env_len, 2), Value::Int(99));
548 }
549
550 unsafe {
552 let _ = Box::from_raw(env);
553 }
554 }
555
556 #[test]
557 fn test_make_closure() {
558 let env = create_env(2);
559
560 unsafe {
561 env_set(env, 0, Value::Int(5));
562 env_set(env, 1, Value::Int(10));
563
564 let closure = make_closure(0x1234, env);
565
566 match closure {
567 Value::Closure { fn_ptr, env } => {
568 assert_eq!(fn_ptr, 0x1234);
569 assert_eq!(env.len(), 2);
570 assert_eq!(env[0], Value::Int(5));
571 assert_eq!(env[1], Value::Int(10));
572 }
573 _ => panic!("Expected Closure value"),
574 }
575 }
576 }
577
578 #[test]
583 fn test_push_closure() {
584 use crate::stack::{pop, push};
585 use crate::value::Value;
586
587 let mut stack = std::ptr::null_mut();
589 stack = unsafe { push(stack, Value::Int(10)) };
590 stack = unsafe { push(stack, Value::Int(5)) };
591
592 let fn_ptr = 0x1234;
594 stack = unsafe { push_closure(stack, fn_ptr, 2) };
595
596 let (stack, closure_value) = unsafe { pop(stack) };
598
599 match closure_value {
601 Value::Closure { fn_ptr: fp, env } => {
602 assert_eq!(fp, fn_ptr as usize);
603 assert_eq!(env.len(), 2);
604 assert_eq!(env[0], Value::Int(5)); assert_eq!(env[1], Value::Int(10)); }
607 _ => panic!("Expected Closure value, got {:?}", closure_value),
608 }
609
610 assert!(stack.is_null());
612 }
613
614 #[test]
615 fn test_push_closure_zero_captures() {
616 use crate::stack::pop;
617 use crate::value::Value;
618
619 let stack = std::ptr::null_mut();
621
622 let fn_ptr = 0x5678;
624 let stack = unsafe { push_closure(stack, fn_ptr, 0) };
625
626 let (stack, closure_value) = unsafe { pop(stack) };
628
629 match closure_value {
631 Value::Closure { fn_ptr: fp, env } => {
632 assert_eq!(fp, fn_ptr as usize);
633 assert_eq!(env.len(), 0);
634 }
635 _ => panic!("Expected Closure value, got {:?}", closure_value),
636 }
637
638 assert!(stack.is_null());
640 }
641
642 #[test]
643 fn test_env_get_bool() {
644 let env = create_env(2);
645
646 unsafe {
647 env_set(env, 0, Value::Bool(true));
648 env_set(env, 1, Value::Bool(false));
649
650 let env_slice = &*env;
651 let env_data = env_slice.as_ptr();
652 let env_len = env_slice.len();
653
654 assert_eq!(env_get_bool(env_data, env_len, 0), 1);
655 assert_eq!(env_get_bool(env_data, env_len, 1), 0);
656
657 let _ = Box::from_raw(env);
658 }
659 }
660
661 #[test]
662 fn test_env_get_float() {
663 let env = create_env(2);
664
665 unsafe {
666 env_set(env, 0, Value::Float(1.234));
667 env_set(env, 1, Value::Float(-5.678));
668
669 let env_slice = &*env;
670 let env_data = env_slice.as_ptr();
671 let env_len = env_slice.len();
672
673 assert!((env_get_float(env_data, env_len, 0) - 1.234).abs() < 0.0001);
674 assert!((env_get_float(env_data, env_len, 1) - (-5.678)).abs() < 0.0001);
675
676 let _ = Box::from_raw(env);
677 }
678 }
679
680 #[test]
681 fn test_env_get_quotation() {
682 let env = create_env(1);
683 let wrapper: usize = 0xDEADBEEF;
684 let impl_: usize = 0xCAFEBABE;
685
686 unsafe {
687 env_set(env, 0, Value::Quotation { wrapper, impl_ });
688
689 let env_slice = &*env;
690 let env_data = env_slice.as_ptr();
691 let env_len = env_slice.len();
692
693 assert_eq!(env_get_quotation(env_data, env_len, 0), impl_ as i64);
695
696 let _ = Box::from_raw(env);
697 }
698 }
699}