Skip to main content

scheme_rs/
proc.rs

1//! Scheme Procedures.
2//!
3//! Scheme procedures, more commonly known as [`closures`](https://en.wikipedia.org/wiki/Closure_(computer_programming))
4//! as they capture their environment, are the fundamental and only way to
5//! transfer control from a Rust context to a Scheme context.
6//!
7//! # Calling procedures from Rust
8//!
9//! # Manually creating closures
10//!
11//! Generally procedures are created in Scheme contexts. However, it is
12//! occasionally desirable to create a closure in Rust contexts. This can be
13//! done with a [`cps_bridge`] function and a call to [`Procedure::new`]. The
14//! `env` argument to the CPS function is a reference to the vector passed to
15//! the `new` function:
16//!
17//! ```
18//! # use scheme_rs::{proc::{Procedure, BridgePtr, Application, DynamicState},
19//! # registry::cps_bridge, value::Value, runtime::Runtime, exceptions::Exception};
20//! #[cps_bridge]
21//! fn closure(
22//!     _runtime: &Runtime,
23//!     env: &[Value],
24//!     _args: &[Value],
25//!     _rest_args: &[Value],
26//!     _dyn_state: &mut DynamicState,
27//!     k: Value,
28//! ) -> Result<Application, Exception> {
29//!     Ok(Application::new(k.try_into()?, vec![ env[0].clone() ]))
30//! }
31//!
32//! # fn main() {
33//! # let runtime = Runtime::new();
34//! let closure = Procedure::new(
35//!     runtime,
36//!     vec![ Value::from(3.1415) ],
37//!     closure as BridgePtr,
38//!     0,
39//!     false,
40//! );
41//! # }
42//! ```
43//!
44//! By default the environment is immutable. If the environment needs to be
45//! modified, a [`Cell`](scheme_rs::value::Cell) can be used:
46//!
47//! ```
48//! # use scheme_rs::{
49//! #     proc::{Procedure, BridgePtr, Application, DynamicState},
50//! #     registry::cps_bridge, value::{Value, Cell}, runtime::Runtime,
51//! #     exceptions::Exception,
52//! #     num::Number,
53//! # };
54//! #[cps_bridge]
55//! fn next_num(
56//!     _runtime: &Runtime,
57//!     env: &[Value],
58//!     _args: &[Value],
59//!     _rest_args: &[Value],
60//!     _dyn_state: &mut DynamicState,
61//!     k: Value,
62//! ) -> Result<Application, Exception> {
63//!     // Fetch the cell from the environment:
64//!     let cell: Cell = env[0].try_to_scheme_type()?;
65//!     let curr: Number = cell.get().try_into()?;
66//!
67//!     // Increment the cell
68//!     cell.set(Value::from(curr.clone() + Number::from(1)));
69//!
70//!     // Return the previous value:
71//!     Ok(Application::new(k.try_into()?, vec![ Value::from(curr) ]))
72//! }
73//!
74//! # fn main() {
75//! # let runtime = Runtime::new();
76//! let next_num = Procedure::new(
77//!     runtime,
78//!     // Cells must be converted to values:
79//!     vec![ Value::from(Cell::new(Value::from(3.1415))) ],
80//!     next_num as BridgePtr,
81//!     0,
82//!     false,
83//! );
84//! # }
85//! ```
86//!
87//! # Categories of procedures
88//!
89//! In scheme-rs, procedures can be placed into a few different categories, the
90//! most obvious is that procedures are either _user_ functions or
91//! [_continuations_](https://en.wikipedia.org/wiki/Continuation). This
92//! categorization is mostly transparent to the user.
93
94use 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
119/// A function pointer to a generated continuation.
120pub(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
127/// A function pointer to a generated user function.
128pub(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
136/// A function pointer to a sync Rust bridge function.
137pub type BridgePtr = for<'a> fn(
138    runtime: &'a Runtime,
139    env: &'a [Value],
140    // TODO: Make this a Vec
141    args: &'a [Value],
142    rest_args: &'a [Value],
143    dyn_state: &mut DynamicState,
144    k: Value,
145) -> Application;
146
147/// A function pointer to an async Rust bridge function.
148#[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    /// A function defined in Rust
161    Bridge(BridgePtr),
162    #[cfg(feature = "async")]
163    /// An async function defined in Rust
164    AsyncBridge(AsyncBridgePtr),
165    /// A JIT compiled user function
166    User(UserPtr),
167    /// A JIT compiled (or occasionally defined in Rust) continuation
168    Continuation(ContinuationPtr),
169    /// A continuation that exits a prompt. Can be dynamically replaced
170    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    /// The runtime the Procedure is defined in. This is necessary to ensure that
204    /// dropping the runtime does not de-allocate the function pointer for this
205    /// procedure.
206    // TODO: Do we make this optional in the case of bridge functions?
207    pub(crate) runtime: Runtime,
208    /// Environmental variables used by the procedure.
209    pub(crate) env: Vec<Value>,
210    /// Fuction pointer to the body of the procecure.
211    #[trace(skip)]
212    pub(crate) func: FuncPtr,
213    /// Number of required arguments to this procedure.
214    pub(crate) num_required_args: usize,
215    /// Whether or not this is a variadic function.
216    pub(crate) variadic: bool,
217    /// Whether or not this function is a variable transformer.
218    pub(crate) is_variable_transformer: bool,
219    /// Debug information for this function. Only applicable if the function is
220    /// a user function, i.e. not a continuation.
221    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        // Extract the continuation, if it is required
257        let cont = (!self.is_continuation()).then(|| args.pop().unwrap());
258
259        // Error if the number of arguments provided is incorrect
260        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    /// Apply the arguments to the function, returning the next application.
352    #[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    /// Attempt to call the function, and throw an error if is async
399    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/// The runtime representation of a Procedure, which can be either a user
478/// function or a continuation. Contains a reference to all of the environmental
479/// variables used in the body, along with a function pointer to the body of the
480/// procedure.
481#[derive(Clone, Trace)]
482pub struct Procedure(pub(crate) Gc<ProcedureInner>);
483
484impl Procedure {
485    #[allow(private_bounds)]
486    /// Creates a new procedure. `func` must be a [`BridgePtr`] or an
487    /// `AsyncBridgePtr` if `async` is enabled.
488    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    /// Get the runtime associated with the procedure
518    pub fn get_runtime(&self) -> Runtime {
519        self.0.runtime.clone()
520    }
521
522    /// Return the number of required arguments and whether or not this function
523    /// is variadic
524    pub fn get_formals(&self) -> (usize, bool) {
525        (self.0.num_required_args, self.0.variadic)
526    }
527
528    /// Return the debug information associated with procedure, if it exists.
529    pub fn get_debug_info(&self) -> Option<Arc<ProcDebugInfo>> {
530        self.0.debug_info.clone()
531    }
532
533    /// # Safety
534    /// `args` must be a valid pointer and contain num_required_args + variadic entries.
535    pub(crate) unsafe fn collect_args(&self, args: *const Value) -> Vec<Value> {
536        // I don't really like this, but what are you gonna do?
537        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    /// Return whether or not the procedure is a continuation
560    pub fn is_continuation(&self) -> bool {
561        self.0.is_continuation()
562    }
563
564    /// Applies `args` to the procedure and returns the values it evaluates to.
565    #[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
586/// Return a continuation that returns its expressions to the Rust program.
587pub 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
629/// An application of a function to a given set of values.
630pub struct Application {
631    /// The operator being applied to.
632    op: OpType,
633    /// The arguments being applied to the operator.
634    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    /// Evaluate the application - and all subsequent application - until all that
660    /// remains are values. This is the main trampoline of the evaluation engine.
661    #[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    /// Just like [eval] but throws an error if we encounter an async function.
677    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/// Debug information associated with a procedure, including its name, argument
692/// names, and source location.
693#[derive(Debug)]
694pub struct ProcDebugInfo {
695    /// The name of the function.
696    pub name: Symbol,
697    /// Named arguments for the function.
698    pub args: Vec<Local>,
699    /// Location of the function definition
700    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////////////////////////////////////////////////////////////////////////////////
751//
752// Dynamic state
753//
754
755/// The dynamic state of the running program, including winders, exception
756/// handlers, and continuation marks.
757#[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            // Procedures returned by the JIT compiler are delimited
768            // continuations (of sorts), and therefore we need to preallocate
769            // the initial marks for them since there's no mechanism to allocate
770            // for them when they're run.
771            cont_marks: vec![HashMap::new()],
772        }
773    }
774
775    /// This is the only method you can use to create continuations, in order to
776    /// ensure that a continuation isn't allocated without a corresponding push
777    /// to cont_marks
778    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    // TODO: We should certainly try to optimize these functions. Linear
818    // searching isn't _great_, although in practice I can't imagine this stack
819    // will ever get very large.
820
821    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                    // TODO: Probably should change this to line, but that
865                    // doesn't play nicely with rustyline
866                    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        // env[0] is the continuation
927        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////////////////////////////////////////////////////////////////////////////////
955//
956// Call with current continuation
957//
958
959#[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/// Prepare the continuation for call/cc. Clones the continuation environment
995/// and creates a closure that calls the appropriate winders.
996#[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    // env[0] is the continuation
1006    let k = env[0].clone();
1007
1008    // env[1] is the dyn stack of the continuation
1009    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    // Clone the continuation
1017    let k: Procedure = k.try_into().unwrap();
1018
1019    let args = args.iter().chain(rest_args).cloned().collect::<Vec<_>>();
1020
1021    // Simple optimization: check if we're in the same dyn stack
1022    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        // env[0] is the ultimate continuation
1047        let k = env.as_ref().unwrap().clone();
1048
1049        // env[1] are the arguments to pass to k
1050        let args = env.add(1).as_ref().unwrap().clone();
1051
1052        // env[2] is the stack we are trying to reach
1053        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                    // Call the out winder while unwinding
1073                    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        // Begin winding
1090        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        // env[0] is the ultimate continuation
1113        let k = env.as_ref().unwrap().clone();
1114
1115        // env[1] are the arguments to pass to k
1116        let args = env.add(1).as_ref().unwrap().clone();
1117
1118        // env[2] is the stack we are trying to reach
1119        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        // env[3] is potentially a winder that we should push onto the dyn stack
1126        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                    // Call the in winder while winding
1142                    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        // env[0] is the consumer
1178        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        // env[1] is the continuation
1194        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        // I hate this constant going back and forth from variadic to list. I have
1201        // to figure out a way to make it consistent
1202        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    // Get the details of the consumer:
1239    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////////////////////////////////////////////////////////////////////////////////
1256//
1257// Dynamic wind
1258//
1259
1260#[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        // env[0] is the in thunk
1315        let in_thunk = env.as_ref().unwrap().clone();
1316
1317        // env[1] is the body thunk
1318        let body_thunk: Procedure = env.add(1).as_ref().unwrap().clone().try_into().unwrap();
1319
1320        // env[2] is the out thunk
1321        let out_thunk = env.add(2).as_ref().unwrap().clone();
1322
1323        // env[3] is k, the continuation
1324        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        // env[0] is the out thunk
1355        let out_thunk: Procedure = env.as_ref().unwrap().clone().try_into().unwrap();
1356
1357        // env[1] is k, the remaining continuation
1358        let k = env.add(1).as_ref().unwrap().clone();
1359
1360        // args[0] is the result of the body thunk
1361        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        // env[0] is the result of the body thunk
1388        let body_thunk_res = env.as_ref().unwrap().clone();
1389        // env[1] is k, the continuation.
1390        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////////////////////////////////////////////////////////////////////////////////
1400//
1401// Prompts and delimited continuations
1402//
1403
1404#[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        // env[0] is continuation
1499        let k = env.as_ref().unwrap().clone();
1500        // env[1] is the prompt tag
1501        let tag: Symbol = env.add(1).as_ref().unwrap().clone().try_into().unwrap();
1502        // env[2] is the saved dyn stack
1503        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                    // If the stack is empty, we should return the error
1511                    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                    // If this is a winder, we should call the out winder while unwinding
1553                    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    // env[0] is the delimited continuation
1581    let dk = env[0].clone();
1582
1583    // env[1] is the barrier Id
1584    let barrier_id: usize = env[1].try_to_scheme_type()?;
1585
1586    // env[2] is the dyn stack of the continuation
1587    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    // Restore continuation marks
1593    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    // Simple optimization: if the saved dyn stack is empty, we
1603    // can just call the delimited continuation
1604    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        // env[0] is the ultimate continuation
1633        let k = env.as_ref().unwrap().clone();
1634
1635        // env[1] are the arguments to pass to k
1636        let args = env.add(1).as_ref().unwrap().clone();
1637
1638        // env[2] is the stack we are trying to reach
1639        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        // env[3] is the index into the dest stack we're at
1644        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        // env[4] is potentially a winder that we should push onto the dyn stack
1649        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                // Call the in winder while winding
1660                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}