1use crate::{
95 env::Local,
96 exceptions::{Exception, raise},
97 gc::{Gc, GcInner, Trace},
98 lists::{self, Pair, list_to_vec},
99 ports::{BufferMode, Port, Transcoder},
100 records::{Record, RecordTypeDescriptor, SchemeCompatible, rtd},
101 registry::BridgeFnDebugInfo,
102 runtime::{Runtime, RuntimeInner},
103 symbols::Symbol,
104 syntax::Span,
105 value::Value,
106 vectors::Vector,
107};
108use parking_lot::RwLock;
109use scheme_rs_macros::{cps_bridge, maybe_async, maybe_await};
110use std::{
111 collections::HashMap,
112 fmt,
113 sync::{
114 Arc, OnceLock,
115 atomic::{AtomicUsize, Ordering},
116 },
117};
118
119pub(crate) type ContinuationPtr = unsafe extern "C" fn(
121 runtime: *mut GcInner<RwLock<RuntimeInner>>,
122 env: *const Value,
123 args: *const Value,
124 dyn_state: *mut DynamicState,
125) -> *mut Application;
126
127pub(crate) type UserPtr = unsafe extern "C" fn(
129 runtime: *mut GcInner<RwLock<RuntimeInner>>,
130 env: *const Value,
131 args: *const Value,
132 dyn_state: *mut DynamicState,
133 k: Value,
134) -> *mut Application;
135
136pub type BridgePtr = for<'a> fn(
138 runtime: &'a Runtime,
139 env: &'a [Value],
140 args: &'a [Value],
142 rest_args: &'a [Value],
143 dyn_state: &mut DynamicState,
144 k: Value,
145) -> Application;
146
147#[cfg(feature = "async")]
149pub type AsyncBridgePtr = for<'a> fn(
150 runtime: &'a Runtime,
151 env: &'a [Value],
152 args: &'a [Value],
153 rest_args: &'a [Value],
154 dyn_state: &'a mut DynamicState,
155 k: Value,
156) -> futures::future::BoxFuture<'a, Application>;
157
158#[derive(Copy, Clone, Debug)]
159pub(crate) enum FuncPtr {
160 Bridge(BridgePtr),
162 #[cfg(feature = "async")]
163 AsyncBridge(AsyncBridgePtr),
165 User(UserPtr),
167 Continuation(ContinuationPtr),
169 PromptBarrier {
171 barrier_id: usize,
172 k: ContinuationPtr,
173 },
174}
175
176impl From<BridgePtr> for FuncPtr {
177 fn from(ptr: BridgePtr) -> Self {
178 Self::Bridge(ptr)
179 }
180}
181
182#[cfg(feature = "async")]
183impl From<AsyncBridgePtr> for FuncPtr {
184 fn from(ptr: AsyncBridgePtr) -> Self {
185 Self::AsyncBridge(ptr)
186 }
187}
188
189impl From<UserPtr> for FuncPtr {
190 fn from(ptr: UserPtr) -> Self {
191 Self::User(ptr)
192 }
193}
194
195enum JitFuncPtr {
196 Continuation(ContinuationPtr),
197 User(UserPtr),
198}
199
200#[derive(Clone, Trace)]
201#[repr(align(16))]
202pub(crate) struct ProcedureInner {
203 pub(crate) runtime: Runtime,
208 pub(crate) env: Vec<Value>,
210 #[trace(skip)]
212 pub(crate) func: FuncPtr,
213 pub(crate) num_required_args: usize,
215 pub(crate) variadic: bool,
217 pub(crate) is_variable_transformer: bool,
219 pub(crate) debug_info: Option<Arc<ProcDebugInfo>>,
222}
223
224impl ProcedureInner {
225 pub(crate) fn new(
226 runtime: Runtime,
227 env: Vec<Value>,
228 func: FuncPtr,
229 num_required_args: usize,
230 variadic: bool,
231 debug_info: Option<Arc<ProcDebugInfo>>,
232 ) -> Self {
233 Self {
234 runtime,
235 env,
236 func,
237 num_required_args,
238 variadic,
239 is_variable_transformer: false,
240 debug_info,
241 }
242 }
243
244 pub fn is_continuation(&self) -> bool {
245 matches!(
246 self.func,
247 FuncPtr::Continuation(_) | FuncPtr::PromptBarrier { .. }
248 )
249 }
250
251 pub(crate) fn prepare_args(
252 &self,
253 mut args: Vec<Value>,
254 dyn_state: &mut DynamicState,
255 ) -> Result<(Vec<Value>, Option<Value>), Application> {
256 let cont = (!self.is_continuation()).then(|| args.pop().unwrap());
258
259 if args.len() < self.num_required_args {
261 return Err(raise(
262 self.runtime.clone(),
263 Exception::wrong_num_of_args(self.num_required_args, args.len()).into(),
264 dyn_state,
265 ));
266 }
267
268 if !self.variadic && args.len() > self.num_required_args {
269 return Err(raise(
270 self.runtime.clone(),
271 Exception::wrong_num_of_args(self.num_required_args, args.len()).into(),
272 dyn_state,
273 ));
274 }
275
276 Ok((args, cont))
277 }
278
279 #[cfg(feature = "async")]
280 async fn apply_async_bridge(
281 &self,
282 func: AsyncBridgePtr,
283 args: &[Value],
284 dyn_state: &mut DynamicState,
285 k: Value,
286 ) -> Application {
287 let (args, rest_args) = if self.variadic {
288 args.split_at(self.num_required_args)
289 } else {
290 (args, &[] as &[Value])
291 };
292
293 (func)(&self.runtime, &self.env, args, rest_args, dyn_state, k).await
294 }
295
296 fn apply_sync_bridge(
297 &self,
298 func: BridgePtr,
299 args: &[Value],
300 dyn_state: &mut DynamicState,
301 k: Value,
302 ) -> Application {
303 let (args, rest_args) = if self.variadic {
304 args.split_at(self.num_required_args)
305 } else {
306 (args, &[] as &[Value])
307 };
308
309 (func)(&self.runtime, &self.env, args, rest_args, dyn_state, k)
310 }
311
312 fn apply_jit(
313 &self,
314 func: JitFuncPtr,
315 mut args: Vec<Value>,
316 dyn_state: &mut DynamicState,
317 k: Option<Value>,
318 ) -> Application {
319 if self.variadic {
320 let mut rest_args = Value::null();
321 let extra_args = args.len() - self.num_required_args;
322 for _ in 0..extra_args {
323 rest_args = Value::from(Pair::new(args.pop().unwrap(), rest_args, false));
324 }
325 args.push(rest_args);
326 }
327
328 let app = match func {
329 JitFuncPtr::Continuation(sync_fn) => unsafe {
330 (sync_fn)(
331 Gc::as_ptr(&self.runtime.0),
332 self.env.as_ptr(),
333 args.as_ptr(),
334 dyn_state as *mut DynamicState,
335 )
336 },
337 JitFuncPtr::User(sync_fn) => unsafe {
338 (sync_fn)(
339 Gc::as_ptr(&self.runtime.0),
340 self.env.as_ptr(),
341 args.as_ptr(),
342 dyn_state as *mut DynamicState,
343 Value::from_raw(Value::as_raw(k.as_ref().unwrap())),
344 )
345 },
346 };
347
348 unsafe { *Box::from_raw(app) }
349 }
350
351 #[maybe_async]
353 pub fn apply(&self, args: Vec<Value>, dyn_state: &mut DynamicState) -> Application {
354 if let FuncPtr::PromptBarrier { barrier_id: id, .. } = self.func {
355 dyn_state.pop_marks();
356 match dyn_state.pop_dyn_stack() {
357 Some(DynStackElem::PromptBarrier(PromptBarrier {
358 barrier_id,
359 replaced_k,
360 })) if barrier_id == id => {
361 let (args, _) = match replaced_k.0.prepare_args(args, dyn_state) {
362 Ok(args) => args,
363 Err(raised) => return raised,
364 };
365 return Application::new(replaced_k, args);
366 }
367 Some(other) => dyn_state.push_dyn_stack(other),
368 _ => (),
369 }
370 }
371
372 let (args, k) = match self.prepare_args(args, dyn_state) {
373 Ok(args) => args,
374 Err(raised) => return raised,
375 };
376
377 match self.func {
378 FuncPtr::Bridge(sbridge) => {
379 self.apply_sync_bridge(sbridge, &args, dyn_state, k.unwrap())
380 }
381 #[cfg(feature = "async")]
382 FuncPtr::AsyncBridge(abridge) => {
383 self.apply_async_bridge(abridge, &args, dyn_state, k.unwrap())
384 .await
385 }
386 FuncPtr::User(user) => self.apply_jit(JitFuncPtr::User(user), args, dyn_state, k),
387 FuncPtr::Continuation(k) => {
388 dyn_state.pop_marks();
389 self.apply_jit(JitFuncPtr::Continuation(k), args, dyn_state, None)
390 }
391 FuncPtr::PromptBarrier { k, .. } => {
392 self.apply_jit(JitFuncPtr::Continuation(k), args, dyn_state, None)
393 }
394 }
395 }
396
397 #[cfg(feature = "async")]
398 pub fn apply_sync(&self, args: Vec<Value>, dyn_state: &mut DynamicState) -> Application {
400 if let FuncPtr::PromptBarrier { barrier_id: id, .. } = self.func {
401 dyn_state.pop_marks();
402 match dyn_state.pop_dyn_stack() {
403 Some(DynStackElem::PromptBarrier(PromptBarrier {
404 barrier_id,
405 replaced_k,
406 })) if barrier_id == id => {
407 let (args, _) = match replaced_k.0.prepare_args(args, dyn_state) {
408 Ok(args) => args,
409 Err(raised) => return raised,
410 };
411 return Application::new(replaced_k, args);
412 }
413 Some(other) => dyn_state.push_dyn_stack(other),
414 _ => (),
415 }
416 }
417
418 let (args, k) = match self.prepare_args(args, dyn_state) {
419 Ok(args) => args,
420 Err(raised) => return raised,
421 };
422
423 match self.func {
424 FuncPtr::Bridge(sbridge) => {
425 self.apply_sync_bridge(sbridge, &args, dyn_state, k.unwrap())
426 }
427 FuncPtr::AsyncBridge(_) => raise(
428 self.runtime.clone(),
429 Exception::error("attempt to apply async function in a sync-only context").into(),
430 dyn_state,
431 ),
432 FuncPtr::User(user) => self.apply_jit(JitFuncPtr::User(user), args, dyn_state, k),
433 FuncPtr::Continuation(k) => {
434 dyn_state.pop_marks();
435 self.apply_jit(JitFuncPtr::Continuation(k), args, dyn_state, None)
436 }
437 FuncPtr::PromptBarrier { k, .. } => {
438 self.apply_jit(JitFuncPtr::Continuation(k), args, dyn_state, None)
439 }
440 }
441 }
442}
443
444impl fmt::Debug for ProcedureInner {
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 if self.is_continuation() {
447 return write!(f, "continuation");
448 }
449
450 let Some(ref debug_info) = self.debug_info else {
451 write!(f, "(<lambda>")?;
452 for i in 0..self.num_required_args {
453 write!(f, " ${i}")?;
454 }
455 if self.variadic {
456 write!(f, " . ${}", self.num_required_args)?;
457 }
458 return write!(f, ")");
459 };
460
461 write!(f, "({}", debug_info.name)?;
462
463 if let Some((last, args)) = debug_info.args.split_last() {
464 for arg in args {
465 write!(f, " {arg}")?;
466 }
467 if self.variadic {
468 write!(f, " .")?;
469 }
470 write!(f, " {last}")?;
471 }
472
473 write!(f, ") at {}", debug_info.location)
474 }
475}
476
477#[derive(Clone, Trace)]
482pub struct Procedure(pub(crate) Gc<ProcedureInner>);
483
484impl Procedure {
485 #[allow(private_bounds)]
486 pub fn new(
489 runtime: Runtime,
490 env: Vec<Value>,
491 func: impl Into<FuncPtr>,
492 num_required_args: usize,
493 variadic: bool,
494 ) -> Self {
495 Self::with_debug_info(runtime, env, func.into(), num_required_args, variadic, None)
496 }
497
498 pub(crate) fn with_debug_info(
499 runtime: Runtime,
500 env: Vec<Value>,
501 func: FuncPtr,
502 num_required_args: usize,
503 variadic: bool,
504 debug_info: Option<Arc<ProcDebugInfo>>,
505 ) -> Self {
506 Self(Gc::new(ProcedureInner {
507 runtime,
508 env,
509 func,
510 num_required_args,
511 variadic,
512 is_variable_transformer: false,
513 debug_info,
514 }))
515 }
516
517 pub fn get_runtime(&self) -> Runtime {
519 self.0.runtime.clone()
520 }
521
522 pub fn get_formals(&self) -> (usize, bool) {
525 (self.0.num_required_args, self.0.variadic)
526 }
527
528 pub fn get_debug_info(&self) -> Option<Arc<ProcDebugInfo>> {
530 self.0.debug_info.clone()
531 }
532
533 pub(crate) unsafe fn collect_args(&self, args: *const Value) -> Vec<Value> {
536 let (num_required_args, variadic) = self.get_formals();
538
539 unsafe {
540 let mut collected_args: Vec<_> = (0..num_required_args)
541 .map(|i| args.add(i).as_ref().unwrap().clone())
542 .collect();
543
544 if variadic {
545 let rest_args = args.add(num_required_args).as_ref().unwrap().clone();
546 let mut vec = Vec::new();
547 lists::list_to_vec(&rest_args, &mut vec);
548 collected_args.extend(vec);
549 }
550
551 collected_args
552 }
553 }
554
555 pub fn is_variable_transformer(&self) -> bool {
556 self.0.is_variable_transformer
557 }
558
559 pub fn is_continuation(&self) -> bool {
561 self.0.is_continuation()
562 }
563
564 #[maybe_async]
566 pub fn call(&self, args: &[Value]) -> Result<Vec<Value>, Exception> {
567 let mut args = args.to_vec();
568
569 args.push(halt_continuation(self.get_runtime()));
570
571 maybe_await!(Application::new(self.clone(), args).eval(&mut DynamicState::default()))
572 }
573
574 #[cfg(feature = "async")]
575 pub fn call_sync(&self, args: &[Value]) -> Result<Vec<Value>, Exception> {
576 let mut args = args.to_vec();
577
578 args.push(halt_continuation(self.get_runtime()));
579
580 Application::new(self.clone(), args).eval_sync(&mut DynamicState::default())
581 }
582}
583
584static HALT_CONTINUATION: OnceLock<Value> = OnceLock::new();
585
586pub fn halt_continuation(runtime: Runtime) -> Value {
588 unsafe extern "C" fn halt(
589 _runtime: *mut GcInner<RwLock<RuntimeInner>>,
590 _env: *const Value,
591 args: *const Value,
592 _dyn_state: *mut DynamicState,
593 ) -> *mut Application {
594 unsafe { crate::runtime::halt(Value::into_raw(args.read())) }
595 }
596
597 HALT_CONTINUATION
598 .get_or_init(move || {
599 Value::from(Procedure(Gc::new(ProcedureInner::new(
600 runtime,
601 Vec::new(),
602 FuncPtr::Continuation(halt),
603 0,
604 true,
605 None,
606 ))))
607 })
608 .clone()
609}
610
611impl fmt::Debug for Procedure {
612 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613 self.0.fmt(f)
614 }
615}
616
617impl PartialEq for Procedure {
618 fn eq(&self, rhs: &Procedure) -> bool {
619 Gc::ptr_eq(&self.0, &rhs.0)
620 }
621}
622
623pub(crate) enum OpType {
624 Proc(Procedure),
625 HaltOk,
626 HaltErr,
627}
628
629pub struct Application {
631 op: OpType,
633 args: Vec<Value>,
635}
636
637impl Application {
638 pub fn new(op: Procedure, args: Vec<Value>) -> Self {
639 Self {
640 op: OpType::Proc(op),
641 args,
642 }
643 }
644
645 pub fn halt_ok(args: Vec<Value>) -> Self {
646 Self {
647 op: OpType::HaltOk,
648 args,
649 }
650 }
651
652 pub fn halt_err(arg: Value) -> Self {
653 Self {
654 op: OpType::HaltErr,
655 args: vec![arg],
656 }
657 }
658
659 #[maybe_async]
662 pub fn eval(mut self, dyn_state: &mut DynamicState) -> Result<Vec<Value>, Exception> {
663 loop {
664 let op = match self.op {
665 OpType::Proc(proc) => proc,
666 OpType::HaltOk => return Ok(self.args),
667 OpType::HaltErr => {
668 return Err(Exception(self.args.pop().unwrap()));
669 }
670 };
671 self = maybe_await!(op.0.apply(self.args, dyn_state));
672 }
673 }
674
675 #[cfg(feature = "async")]
676 pub fn eval_sync(mut self, dyn_state: &mut DynamicState) -> Result<Vec<Value>, Exception> {
678 loop {
679 let op = match self.op {
680 OpType::Proc(proc) => proc,
681 OpType::HaltOk => return Ok(self.args),
682 OpType::HaltErr => {
683 return Err(Exception(self.args.pop().unwrap()));
684 }
685 };
686 self = op.0.apply_sync(self.args, dyn_state);
687 }
688 }
689}
690
691#[derive(Debug)]
694pub struct ProcDebugInfo {
695 pub name: Symbol,
697 pub args: Vec<Local>,
699 pub location: Span,
701}
702
703impl ProcDebugInfo {
704 pub fn new(name: Option<Symbol>, args: Vec<Local>, location: Span) -> Self {
705 Self {
706 name: name.unwrap_or_else(|| Symbol::intern("<lambda>")),
707 args,
708 location,
709 }
710 }
711
712 pub fn from_bridge_fn(name: &'static str, debug_info: BridgeFnDebugInfo) -> Self {
713 Self {
714 name: Symbol::intern(name),
715 args: debug_info
716 .args
717 .iter()
718 .map(|arg| Local::gensym_with_name(Symbol::intern(arg)))
719 .collect(),
720 location: Span {
721 line: debug_info.line,
722 column: debug_info.column as usize,
723 offset: debug_info.offset,
724 file: std::sync::Arc::new(debug_info.file.to_string()),
725 },
726 }
727 }
728}
729
730#[cps_bridge(def = "apply arg1 . args", lib = "(rnrs base builtins (6))")]
731pub fn apply(
732 _runtime: &Runtime,
733 _env: &[Value],
734 args: &[Value],
735 rest_args: &[Value],
736 _dyn_state: &mut DynamicState,
737 k: Value,
738) -> Result<Application, Exception> {
739 if rest_args.is_empty() {
740 return Err(Exception::wrong_num_of_args(2, args.len()));
741 }
742 let op: Procedure = args[0].clone().try_into()?;
743 let (last, args) = rest_args.split_last().unwrap();
744 let mut args = args.to_vec();
745 list_to_vec(last, &mut args);
746 args.push(k);
747 Ok(Application::new(op.clone(), args))
748}
749
750#[derive(Clone, Debug, Trace)]
758pub struct DynamicState {
759 dyn_stack: Vec<DynStackElem>,
760 cont_marks: Vec<HashMap<Symbol, Value>>,
761}
762
763impl DynamicState {
764 pub fn new() -> Self {
765 Self {
766 dyn_stack: Vec::new(),
767 cont_marks: vec![HashMap::new()],
772 }
773 }
774
775 pub(crate) fn new_k(
779 &mut self,
780 runtime: Runtime,
781 env: Vec<Value>,
782 k: ContinuationPtr,
783 num_required_args: usize,
784 variadic: bool,
785 ) -> Procedure {
786 self.push_marks();
787 Procedure::with_debug_info(
788 runtime,
789 env,
790 FuncPtr::Continuation(k),
791 num_required_args,
792 variadic,
793 None,
794 )
795 }
796
797 pub(crate) fn push_marks(&mut self) {
798 self.cont_marks.push(HashMap::new());
799 }
800
801 pub(crate) fn pop_marks(&mut self) {
802 self.cont_marks.pop();
803 }
804
805 pub(crate) fn current_marks(&self, tag: Symbol) -> Vec<Value> {
806 self.cont_marks
807 .iter()
808 .rev()
809 .flat_map(|marks| marks.get(&tag).cloned())
810 .collect()
811 }
812
813 pub(crate) fn set_continuation_mark(&mut self, tag: Symbol, val: Value) {
814 self.cont_marks.last_mut().unwrap().insert(tag, val);
815 }
816
817 pub fn current_exception_handler(&self) -> Option<Procedure> {
822 self.dyn_stack.iter().rev().find_map(|elem| match elem {
823 DynStackElem::ExceptionHandler(proc) => Some(proc.clone()),
824 _ => None,
825 })
826 }
827
828 pub fn current_input_port(&self) -> Port {
829 self.dyn_stack
830 .iter()
831 .rev()
832 .find_map(|elem| match elem {
833 DynStackElem::CurrentInputPort(port) => Some(port.clone()),
834 _ => None,
835 })
836 .unwrap_or_else(|| {
837 Port::new(
838 "<stdin>",
839 #[cfg(not(feature = "async"))]
840 std::io::stdin(),
841 #[cfg(feature = "tokio")]
842 tokio::io::stdin(),
843 BufferMode::Line,
844 Some(Transcoder::native()),
845 )
846 })
847 }
848
849 pub fn current_output_port(&self) -> Port {
850 self.dyn_stack
851 .iter()
852 .rev()
853 .find_map(|elem| match elem {
854 DynStackElem::CurrentOutputPort(port) => Some(port.clone()),
855 _ => None,
856 })
857 .unwrap_or_else(|| {
858 Port::new(
859 "<stdout>",
860 #[cfg(not(feature = "async"))]
861 std::io::stdout(),
862 #[cfg(feature = "tokio")]
863 tokio::io::stdout(),
864 BufferMode::None,
867 Some(Transcoder::native()),
868 )
869 })
870 }
871
872 pub(crate) fn push_dyn_stack(&mut self, elem: DynStackElem) {
873 self.dyn_stack.push(elem);
874 }
875
876 pub(crate) fn pop_dyn_stack(&mut self) -> Option<DynStackElem> {
877 self.dyn_stack.pop()
878 }
879
880 pub(crate) fn dyn_stack_get(&self, idx: usize) -> Option<&DynStackElem> {
881 self.dyn_stack.get(idx)
882 }
883
884 pub(crate) fn dyn_stack_last(&self) -> Option<&DynStackElem> {
885 self.dyn_stack.last()
886 }
887
888 pub(crate) fn dyn_stack_len(&self) -> usize {
889 self.dyn_stack.len()
890 }
891
892 pub(crate) fn dyn_stack_is_empty(&self) -> bool {
893 self.dyn_stack.is_empty()
894 }
895}
896
897impl Default for DynamicState {
898 fn default() -> Self {
899 Self::new()
900 }
901}
902
903impl SchemeCompatible for DynamicState {
904 fn rtd() -> Arc<RecordTypeDescriptor> {
905 rtd!(name: "$dyn-stack", sealed: true, opaque: true)
906 }
907}
908
909#[derive(Clone, Debug, PartialEq, Trace)]
910pub(crate) enum DynStackElem {
911 Prompt(Prompt),
912 PromptBarrier(PromptBarrier),
913 Winder(Winder),
914 ExceptionHandler(Procedure),
915 CurrentInputPort(Port),
916 CurrentOutputPort(Port),
917}
918
919pub(crate) unsafe extern "C" fn pop_dyn_stack(
920 _runtime: *mut GcInner<RwLock<RuntimeInner>>,
921 env: *const Value,
922 args: *const Value,
923 dyn_state: *mut DynamicState,
924) -> *mut Application {
925 unsafe {
926 let k: Procedure = env.as_ref().unwrap().clone().try_into().unwrap();
928
929 dyn_state.as_mut().unwrap_unchecked().pop_dyn_stack();
930
931 let args = k.collect_args(args);
932 let app = Application::new(k, args);
933
934 Box::into_raw(Box::new(app))
935 }
936}
937
938#[cps_bridge(def = "print-trace", lib = "(rnrs base builtins (6))")]
939pub fn print_trace(
940 _runtime: &Runtime,
941 _env: &[Value],
942 _args: &[Value],
943 _rest_args: &[Value],
944 dyn_state: &mut DynamicState,
945 k: Value,
946) -> Result<Application, Exception> {
947 println!(
948 "trace: {:#?}",
949 dyn_state.current_marks(Symbol::intern("trace"))
950 );
951 Ok(Application::new(k.try_into()?, vec![]))
952}
953
954#[cps_bridge(
960 def = "call-with-current-continuation proc",
961 lib = "(rnrs base builtins (6))"
962)]
963pub fn call_with_current_continuation(
964 runtime: &Runtime,
965 _env: &[Value],
966 args: &[Value],
967 _rest_args: &[Value],
968 dyn_state: &mut DynamicState,
969 k: Value,
970) -> Result<Application, Exception> {
971 let [proc] = args else { unreachable!() };
972 let proc: Procedure = proc.clone().try_into()?;
973
974 let (req_args, variadic) = {
975 let k: Procedure = k.clone().try_into()?;
976 k.get_formals()
977 };
978
979 let dyn_state = Value::from(Record::from_rust_type(dyn_state.clone()));
980
981 let escape_procedure = Procedure::new(
982 runtime.clone(),
983 vec![k.clone(), dyn_state],
984 FuncPtr::Bridge(escape_procedure),
985 req_args,
986 variadic,
987 );
988
989 let app = Application::new(proc, vec![Value::from(escape_procedure), k]);
990
991 Ok(app)
992}
993
994#[cps_bridge]
997fn escape_procedure(
998 runtime: &Runtime,
999 env: &[Value],
1000 args: &[Value],
1001 rest_args: &[Value],
1002 dyn_state: &mut DynamicState,
1003 _k: Value,
1004) -> Result<Application, Exception> {
1005 let k = env[0].clone();
1007
1008 let saved_dyn_state_val = env[1].clone();
1010 let saved_dyn_state = saved_dyn_state_val
1011 .try_to_rust_type::<DynamicState>()
1012 .unwrap();
1013 let saved_dyn_state_read = saved_dyn_state.as_ref();
1014 dyn_state.cont_marks = saved_dyn_state_read.cont_marks.clone();
1015
1016 let k: Procedure = k.try_into().unwrap();
1018
1019 let args = args.iter().chain(rest_args).cloned().collect::<Vec<_>>();
1020
1021 if dyn_state.dyn_stack_len() == saved_dyn_state_read.dyn_stack_len()
1023 && dyn_state.dyn_stack_last() == saved_dyn_state_read.dyn_stack_last()
1024 {
1025 Ok(Application::new(k, args))
1026 } else {
1027 let args = Value::from(args);
1028 let k = dyn_state.new_k(
1029 runtime.clone(),
1030 vec![Value::from(k), args, saved_dyn_state_val],
1031 unwind,
1032 0,
1033 false,
1034 );
1035 Ok(Application::new(k, Vec::new()))
1036 }
1037}
1038
1039unsafe extern "C" fn unwind(
1040 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1041 env: *const Value,
1042 _args: *const Value,
1043 dyn_state: *mut DynamicState,
1044) -> *mut Application {
1045 unsafe {
1046 let k = env.as_ref().unwrap().clone();
1048
1049 let args = env.add(1).as_ref().unwrap().clone();
1051
1052 let dest_stack_val = env.add(2).as_ref().unwrap().clone();
1054 let dest_stack = dest_stack_val
1055 .clone()
1056 .try_to_rust_type::<DynamicState>()
1057 .unwrap();
1058 let dest_stack_read = dest_stack.as_ref();
1059
1060 let dyn_state = dyn_state.as_mut().unwrap_unchecked();
1061
1062 while !dyn_state.dyn_stack_is_empty()
1063 && (dyn_state.dyn_stack_len() > dest_stack_read.dyn_stack_len()
1064 || dyn_state.dyn_stack_last()
1065 != dest_stack_read.dyn_stack_get(dyn_state.dyn_stack_len() - 1))
1066 {
1067 match dyn_state.pop_dyn_stack() {
1068 None => {
1069 break;
1070 }
1071 Some(DynStackElem::Winder(winder)) => {
1072 let app = Application::new(
1074 winder.out_thunk,
1075 vec![Value::from(dyn_state.new_k(
1076 Runtime::from_raw_inc_rc(runtime),
1077 vec![k, args, dest_stack_val],
1078 unwind,
1079 0,
1080 false,
1081 ))],
1082 );
1083 return Box::into_raw(Box::new(app));
1084 }
1085 _ => (),
1086 };
1087 }
1088
1089 let app = Application::new(
1091 dyn_state.new_k(
1092 Runtime::from_raw_inc_rc(runtime),
1093 vec![k, args, dest_stack_val, Value::from(false)],
1094 wind,
1095 0,
1096 false,
1097 ),
1098 Vec::new(),
1099 );
1100
1101 Box::into_raw(Box::new(app))
1102 }
1103}
1104
1105unsafe extern "C" fn wind(
1106 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1107 env: *const Value,
1108 _args: *const Value,
1109 dyn_state: *mut DynamicState,
1110) -> *mut Application {
1111 unsafe {
1112 let k = env.as_ref().unwrap().clone();
1114
1115 let args = env.add(1).as_ref().unwrap().clone();
1117
1118 let dest_stack_val = env.add(2).as_ref().unwrap().clone();
1120 let dest_stack = dest_stack_val.try_to_rust_type::<DynamicState>().unwrap();
1121 let dest_stack_read = dest_stack.as_ref();
1122
1123 let dyn_state = dyn_state.as_mut().unwrap_unchecked();
1124
1125 let winder = env.add(3).as_ref().unwrap().clone();
1127 if winder.is_true() {
1128 let winder = winder.try_to_rust_type::<Winder>().unwrap();
1129 dyn_state.push_dyn_stack(DynStackElem::Winder(winder.as_ref().clone()));
1130 }
1131
1132 while dyn_state.dyn_stack_len() < dest_stack_read.dyn_stack_len() {
1133 match dest_stack_read
1134 .dyn_stack_get(dyn_state.dyn_stack_len())
1135 .cloned()
1136 {
1137 None => {
1138 break;
1139 }
1140 Some(DynStackElem::Winder(winder)) => {
1141 let app = Application::new(
1143 winder.in_thunk.clone(),
1144 vec![Value::from(dyn_state.new_k(
1145 Runtime::from_raw_inc_rc(runtime),
1146 vec![
1147 k,
1148 args,
1149 dest_stack_val,
1150 Value::from(Record::from_rust_type(winder)),
1151 ],
1152 wind,
1153 0,
1154 false,
1155 ))],
1156 );
1157 return Box::into_raw(Box::new(app));
1158 }
1159 Some(elem) => dyn_state.push_dyn_stack(elem),
1160 }
1161 }
1162
1163 let args: Vector = args.try_into().unwrap();
1164 let args = args.0.vec.read().to_vec();
1165
1166 Box::into_raw(Box::new(Application::new(k.try_into().unwrap(), args)))
1167 }
1168}
1169
1170unsafe extern "C" fn call_consumer_with_values(
1171 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1172 env: *const Value,
1173 args: *const Value,
1174 dyn_state: *mut DynamicState,
1175) -> *mut Application {
1176 unsafe {
1177 let consumer = env.as_ref().unwrap().clone();
1179 let type_name = consumer.type_name();
1180
1181 let consumer: Procedure = match consumer.try_into() {
1182 Ok(consumer) => consumer,
1183 _ => {
1184 let raised = raise(
1185 Runtime::from_raw_inc_rc(runtime),
1186 Exception::invalid_operator(type_name).into(),
1187 dyn_state.as_mut().unwrap_unchecked(),
1188 );
1189 return Box::into_raw(Box::new(raised));
1190 }
1191 };
1192
1193 let k = env.add(1).as_ref().unwrap().clone();
1195
1196 let mut collected_args: Vec<_> = (0..consumer.0.num_required_args)
1197 .map(|i| args.add(i).as_ref().unwrap().clone())
1198 .collect();
1199
1200 if consumer.0.variadic {
1203 let rest_args = args
1204 .add(consumer.0.num_required_args)
1205 .as_ref()
1206 .unwrap()
1207 .clone();
1208 let mut vec = Vec::new();
1209 list_to_vec(&rest_args, &mut vec);
1210 collected_args.extend(vec);
1211 }
1212
1213 collected_args.push(k);
1214
1215 Box::into_raw(Box::new(Application::new(consumer.clone(), collected_args)))
1216 }
1217}
1218
1219#[cps_bridge(
1220 def = "call-with-values producer consumer",
1221 lib = "(rnrs base builtins (6))"
1222)]
1223pub fn call_with_values(
1224 runtime: &Runtime,
1225 _env: &[Value],
1226 args: &[Value],
1227 _rest_args: &[Value],
1228 dyn_state: &mut DynamicState,
1229 k: Value,
1230) -> Result<Application, Exception> {
1231 let [producer, consumer] = args else {
1232 return Err(Exception::wrong_num_of_args(2, args.len()));
1233 };
1234
1235 let producer: Procedure = producer.clone().try_into()?;
1236 let consumer: Procedure = consumer.clone().try_into()?;
1237
1238 let (num_required_args, variadic) = { (consumer.0.num_required_args, consumer.0.variadic) };
1240
1241 let call_consumer_closure = dyn_state.new_k(
1242 runtime.clone(),
1243 vec![Value::from(consumer), k],
1244 call_consumer_with_values,
1245 num_required_args,
1246 variadic,
1247 );
1248
1249 Ok(Application::new(
1250 producer,
1251 vec![Value::from(call_consumer_closure)],
1252 ))
1253}
1254
1255#[derive(Clone, Debug, Trace, PartialEq)]
1261pub(crate) struct Winder {
1262 pub(crate) in_thunk: Procedure,
1263 pub(crate) out_thunk: Procedure,
1264}
1265
1266impl SchemeCompatible for Winder {
1267 fn rtd() -> Arc<RecordTypeDescriptor> {
1268 rtd!(name: "$winder", sealed: true, opaque: true)
1269 }
1270}
1271
1272#[cps_bridge(def = "dynamic-wind in body out", lib = "(rnrs base builtins (6))")]
1273pub fn dynamic_wind(
1274 runtime: &Runtime,
1275 _env: &[Value],
1276 args: &[Value],
1277 _rest_args: &[Value],
1278 dyn_state: &mut DynamicState,
1279 k: Value,
1280) -> Result<Application, Exception> {
1281 let [in_thunk_val, body_thunk_val, out_thunk_val] = args else {
1282 return Err(Exception::wrong_num_of_args(3, args.len()));
1283 };
1284
1285 let in_thunk: Procedure = in_thunk_val.clone().try_into()?;
1286 let _: Procedure = body_thunk_val.clone().try_into()?;
1287
1288 let call_body_thunk_cont = dyn_state.new_k(
1289 runtime.clone(),
1290 vec![
1291 in_thunk_val.clone(),
1292 body_thunk_val.clone(),
1293 out_thunk_val.clone(),
1294 k,
1295 ],
1296 call_body_thunk,
1297 0,
1298 true,
1299 );
1300
1301 Ok(Application::new(
1302 in_thunk,
1303 vec![Value::from(call_body_thunk_cont)],
1304 ))
1305}
1306
1307pub(crate) unsafe extern "C" fn call_body_thunk(
1308 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1309 env: *const Value,
1310 _args: *const Value,
1311 dyn_state: *mut DynamicState,
1312) -> *mut Application {
1313 unsafe {
1314 let in_thunk = env.as_ref().unwrap().clone();
1316
1317 let body_thunk: Procedure = env.add(1).as_ref().unwrap().clone().try_into().unwrap();
1319
1320 let out_thunk = env.add(2).as_ref().unwrap().clone();
1322
1323 let k = env.add(3).as_ref().unwrap().clone();
1325
1326 let dyn_state = dyn_state.as_mut().unwrap_unchecked();
1327
1328 dyn_state.push_dyn_stack(DynStackElem::Winder(Winder {
1329 in_thunk: in_thunk.clone().try_into().unwrap(),
1330 out_thunk: out_thunk.clone().try_into().unwrap(),
1331 }));
1332
1333 let k = dyn_state.new_k(
1334 Runtime::from_raw_inc_rc(runtime),
1335 vec![out_thunk, k],
1336 call_out_thunks,
1337 0,
1338 true,
1339 );
1340
1341 let app = Application::new(body_thunk, vec![Value::from(k)]);
1342
1343 Box::into_raw(Box::new(app))
1344 }
1345}
1346
1347pub(crate) unsafe extern "C" fn call_out_thunks(
1348 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1349 env: *const Value,
1350 args: *const Value,
1351 dyn_state: *mut DynamicState,
1352) -> *mut Application {
1353 unsafe {
1354 let out_thunk: Procedure = env.as_ref().unwrap().clone().try_into().unwrap();
1356
1357 let k = env.add(1).as_ref().unwrap().clone();
1359
1360 let body_thunk_res = args.as_ref().unwrap().clone();
1362
1363 let dyn_state = dyn_state.as_mut().unwrap_unchecked();
1364 dyn_state.pop_dyn_stack();
1365
1366 let cont = dyn_state.new_k(
1367 Runtime::from_raw_inc_rc(runtime),
1368 vec![body_thunk_res, k],
1369 forward_body_thunk_result,
1370 0,
1371 true,
1372 );
1373
1374 let app = Application::new(out_thunk, vec![Value::from(cont)]);
1375
1376 Box::into_raw(Box::new(app))
1377 }
1378}
1379
1380unsafe extern "C" fn forward_body_thunk_result(
1381 _runtime: *mut GcInner<RwLock<RuntimeInner>>,
1382 env: *const Value,
1383 _args: *const Value,
1384 _dyn_state: *mut DynamicState,
1385) -> *mut Application {
1386 unsafe {
1387 let body_thunk_res = env.as_ref().unwrap().clone();
1389 let k: Procedure = env.add(1).as_ref().unwrap().clone().try_into().unwrap();
1391
1392 let mut args = Vec::new();
1393 list_to_vec(&body_thunk_res, &mut args);
1394
1395 Box::into_raw(Box::new(Application::new(k, args)))
1396 }
1397}
1398
1399#[derive(Clone, Debug, PartialEq, Trace)]
1405pub(crate) struct Prompt {
1406 tag: Symbol,
1407 barrier_id: usize,
1408 handler: Procedure,
1409 handler_k: Procedure,
1410}
1411
1412#[derive(Clone, Debug, PartialEq, Trace)]
1413pub(crate) struct PromptBarrier {
1414 barrier_id: usize,
1415 replaced_k: Procedure,
1416}
1417
1418static BARRIER_ID: AtomicUsize = AtomicUsize::new(0);
1419
1420#[cps_bridge(def = "call-with-prompt tag thunk handler", lib = "(prompts)")]
1421pub fn call_with_prompt(
1422 runtime: &Runtime,
1423 _env: &[Value],
1424 args: &[Value],
1425 _rest_args: &[Value],
1426 dyn_state: &mut DynamicState,
1427 k: Value,
1428) -> Result<Application, Exception> {
1429 let [tag, thunk, handler] = args else {
1430 unreachable!()
1431 };
1432
1433 let k_proc: Procedure = k.clone().try_into().unwrap();
1434 let (req_args, variadic) = k_proc.get_formals();
1435 let tag: Symbol = tag.clone().try_into().unwrap();
1436
1437 let barrier_id = BARRIER_ID.fetch_add(1, Ordering::Relaxed);
1438
1439 dyn_state.push_dyn_stack(DynStackElem::Prompt(Prompt {
1440 tag,
1441 handler: handler.clone().try_into().unwrap(),
1442 barrier_id,
1443 handler_k: k.clone().try_into()?,
1444 }));
1445
1446 dyn_state.push_marks();
1447
1448 let prompt_barrier = Procedure::new(
1449 runtime.clone(),
1450 vec![k],
1451 FuncPtr::PromptBarrier {
1452 barrier_id,
1453 k: pop_dyn_stack,
1454 },
1455 req_args,
1456 variadic,
1457 );
1458
1459 Ok(Application::new(
1460 thunk.clone().try_into().unwrap(),
1461 vec![Value::from(prompt_barrier)],
1462 ))
1463}
1464
1465#[cps_bridge(def = "abort-to-prompt tag", lib = "(prompts)")]
1466pub fn abort_to_prompt(
1467 runtime: &Runtime,
1468 _env: &[Value],
1469 args: &[Value],
1470 _rest_args: &[Value],
1471 dyn_state: &mut DynamicState,
1472 k: Value,
1473) -> Result<Application, Exception> {
1474 let [tag] = args else { unreachable!() };
1475
1476 let unwind_to_prompt = dyn_state.new_k(
1477 runtime.clone(),
1478 vec![
1479 k,
1480 tag.clone(),
1481 Value::from(Record::from_rust_type(dyn_state.clone())),
1482 ],
1483 unwind_to_prompt,
1484 0,
1485 false,
1486 );
1487
1488 Ok(Application::new(unwind_to_prompt, Vec::new()))
1489}
1490
1491unsafe extern "C" fn unwind_to_prompt(
1492 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1493 env: *const Value,
1494 _args: *const Value,
1495 dyn_state: *mut DynamicState,
1496) -> *mut Application {
1497 unsafe {
1498 let k = env.as_ref().unwrap().clone();
1500 let tag: Symbol = env.add(1).as_ref().unwrap().clone().try_into().unwrap();
1502 let saved_dyn_state = env.add(2).as_ref().unwrap().clone();
1504
1505 let dyn_state = dyn_state.as_mut().unwrap_unchecked();
1506
1507 loop {
1508 let app = match dyn_state.pop_dyn_stack() {
1509 None => {
1510 Application::halt_err(Value::from(Exception::error(format!(
1512 "No prompt tag {tag} found"
1513 ))))
1514 }
1515 Some(DynStackElem::Prompt(Prompt {
1516 tag: prompt_tag,
1517 barrier_id,
1518 handler,
1519 handler_k,
1520 })) if prompt_tag == tag => {
1521 let saved_dyn_state =
1522 saved_dyn_state.try_to_rust_type::<DynamicState>().unwrap();
1523 let prompt_delimited_dyn_state = DynamicState {
1524 dyn_stack: saved_dyn_state.as_ref().dyn_stack
1525 [dyn_state.dyn_stack_len() + 1..]
1526 .to_vec(),
1527 cont_marks: saved_dyn_state.cont_marks.clone(),
1528 };
1529 let (req_args, var) = {
1530 let k_proc: Procedure = k.clone().try_into().unwrap();
1531 k_proc.get_formals()
1532 };
1533 Application::new(
1534 handler,
1535 vec![
1536 Value::from(Procedure::new(
1537 Runtime::from_raw_inc_rc(runtime),
1538 vec![
1539 k,
1540 Value::from(barrier_id),
1541 Value::from(Record::from_rust_type(prompt_delimited_dyn_state)),
1542 ],
1543 FuncPtr::Bridge(delimited_continuation),
1544 req_args,
1545 var,
1546 )),
1547 Value::from(handler_k),
1548 ],
1549 )
1550 }
1551 Some(DynStackElem::Winder(winder)) => {
1552 Application::new(
1554 winder.out_thunk,
1555 vec![Value::from(dyn_state.new_k(
1556 Runtime::from_raw_inc_rc(runtime),
1557 vec![k, Value::from(tag), saved_dyn_state],
1558 unwind_to_prompt,
1559 0,
1560 false,
1561 ))],
1562 )
1563 }
1564 _ => continue,
1565 };
1566 return Box::into_raw(Box::new(app));
1567 }
1568 }
1569}
1570
1571#[cps_bridge]
1572fn delimited_continuation(
1573 runtime: &Runtime,
1574 env: &[Value],
1575 args: &[Value],
1576 rest_args: &[Value],
1577 dyn_state: &mut DynamicState,
1578 k: Value,
1579) -> Result<Application, Exception> {
1580 let dk = env[0].clone();
1582
1583 let barrier_id: usize = env[1].try_to_scheme_type()?;
1585
1586 let saved_dyn_state_val = env[2].clone();
1588 let saved_dyn_state = saved_dyn_state_val
1589 .try_to_rust_type::<DynamicState>()
1590 .unwrap();
1591 let saved_dyn_state_read = saved_dyn_state.as_ref();
1592 dyn_state.cont_marks = saved_dyn_state_read.cont_marks.clone();
1594
1595 let args = args.iter().chain(rest_args).cloned().collect::<Vec<_>>();
1596
1597 dyn_state.push_dyn_stack(DynStackElem::PromptBarrier(PromptBarrier {
1598 barrier_id,
1599 replaced_k: k.try_into()?,
1600 }));
1601
1602 if saved_dyn_state_read.dyn_stack_is_empty() {
1605 Ok(Application::new(dk.try_into()?, args))
1606 } else {
1607 let args = Value::from(args);
1608 let k = dyn_state.new_k(
1609 runtime.clone(),
1610 vec![
1611 dk,
1612 args,
1613 saved_dyn_state_val,
1614 Value::from(0),
1615 Value::from(false),
1616 ],
1617 wind_delim,
1618 0,
1619 false,
1620 );
1621 Ok(Application::new(k, Vec::new()))
1622 }
1623}
1624
1625unsafe extern "C" fn wind_delim(
1626 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1627 env: *const Value,
1628 _args: *const Value,
1629 dyn_state: *mut DynamicState,
1630) -> *mut Application {
1631 unsafe {
1632 let k = env.as_ref().unwrap().clone();
1634
1635 let args = env.add(1).as_ref().unwrap().clone();
1637
1638 let dest_stack_val = env.add(2).as_ref().unwrap().clone();
1640 let dest_stack = dest_stack_val.try_to_rust_type::<DynamicState>().unwrap();
1641 let dest_stack_read = dest_stack.as_ref();
1642
1643 let mut idx: usize = env.add(3).as_ref().unwrap().cast_to_scheme_type().unwrap();
1645
1646 let dyn_state = dyn_state.as_mut().unwrap_unchecked();
1647
1648 let winder = env.add(4).as_ref().unwrap().clone();
1650 if winder.is_true() {
1651 let winder = winder.try_to_rust_type::<Winder>().unwrap();
1652 dyn_state.push_dyn_stack(DynStackElem::Winder(winder.as_ref().clone()));
1653 }
1654
1655 while let Some(elem) = dest_stack_read.dyn_stack_get(idx) {
1656 idx += 1;
1657
1658 if let DynStackElem::Winder(winder) = elem {
1659 let app = Application::new(
1661 winder.in_thunk.clone(),
1662 vec![Value::from(dyn_state.new_k(
1663 Runtime::from_raw_inc_rc(runtime),
1664 vec![
1665 k,
1666 args,
1667 dest_stack_val,
1668 Value::from(Record::from_rust_type(winder.clone())),
1669 ],
1670 wind,
1671 0,
1672 false,
1673 ))],
1674 );
1675 return Box::into_raw(Box::new(app));
1676 }
1677 dyn_state.push_dyn_stack(elem.clone());
1678 }
1679
1680 let args: Vector = args.try_into().unwrap();
1681 let args = args.0.vec.read().to_vec();
1682
1683 Box::into_raw(Box::new(Application::new(k.try_into().unwrap(), args)))
1684 }
1685}