Skip to main content

scheme_rs/
exceptions.rs

1//! Exceptional situations and conditions.
2//!
3//! Scheme has two distinct concepts: conditions and exceptions. Exceptions are
4//! values that values passed to the `raise` and `raise-continuable` procedures
5//! and can be any [`Value`]. Conditions are records that contain information
6//! describing an erroneous situation or _condition_.
7//!
8//! Conditions in Scheme are either [simple](`SimpleCondition`) or
9//! [compound](`CompoundCondition`). Scheme-rs provides the ability to inspect
10//! conditions without discerning whether they or simple or compound. Using the
11//! [`condition`](Exception::condition) method, a specific condition and thus
12//! its associated information can be extracted from the condition.
13//!
14//! For example, a common condition is the [`&trace`](StackTrace) condition,
15//! which can be used to extract a stack trace for the exception:
16//!
17//! ```
18//! # use scheme_rs::{exceptions::{Exception, Message, SyntaxViolation, StackTrace}, gc::Gc, syntax::Syntax};
19//! // Code from scheme-rs repl to print errors:
20//! fn print_exception(exception: Exception) {
21//!     let Ok(conditions) = exception.simple_conditions() else {
22//!         println!(
23//!             "Exception occurred with a non-condition value: {:?}",
24//!             exception.0
25//!         );
26//!         return;
27//!     };
28//!     println!("Uncaught exception:");
29//!     for condition in conditions.into_iter() {
30//!         if let Some(message) = condition.cast_to_rust_type::<Message>() {
31//!             println!(" - Message: {}", message.message);
32//!         } else if let Some(syntax) = condition.cast_to_rust_type::<SyntaxViolation>() {
33//!             println!(" - Syntax error in form: {:?}", syntax.form);
34//!             if let Some(subform) = syntax.subform.as_ref() {
35//!                 println!("   (subform: {subform:?})");
36//!             }
37//!         } else if let Some(trace) = condition.cast_to_rust_type::<StackTrace>() {
38//!             println!(" - Stack trace:");
39//!             for (i, trace) in trace.trace.iter().enumerate() {
40//!                 let syntax = trace.cast_to_scheme_type::<Gc<Syntax>>().unwrap();
41//!                 let span = syntax.span();
42//!                 let func_name = syntax.as_ident().unwrap().symbol();
43//!                 println!("{:>6}: {func_name}:{span}", i + 1);
44//!             }
45//!         } else {
46//!             println!(" - Condition: {condition:?}");
47//!         }
48//!     }
49//! }
50//! ```
51
52use crate::{
53    gc::{Gc, GcInner, Trace},
54    lists::slice_to_list,
55    ports::{IoError, IoReadError, IoWriteError},
56    proc::{Application, DynStackElem, DynamicState, FuncPtr, Procedure, pop_dyn_stack},
57    records::{Record, RecordTypeDescriptor, SchemeCompatible, rtd},
58    registry::{bridge, cps_bridge},
59    runtime::{Runtime, RuntimeInner},
60    symbols::Symbol,
61    syntax::{Identifier, Syntax, parse::ParseSyntaxError},
62    value::{UnpackedValue, Value},
63    vectors::Vector,
64};
65use parking_lot::RwLock;
66use scheme_rs_macros::runtime_fn;
67use std::{convert::Infallible, fmt, ops::Range, sync::Arc};
68
69/// A macro for easily creating new condition types.
70pub use scheme_rs_macros::define_condition_type;
71
72impl fmt::Display for Exception {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        <Value as fmt::Debug>::fmt(&self.0, f)
75    }
76}
77
78/// A signal of some sort of erroneous condition.
79#[derive(Debug, Clone)]
80pub struct Exception(pub Value);
81
82impl Exception {
83    pub fn error(message: impl fmt::Display) -> Self {
84        Self(Value::from(Record::from_rust_type(
85            CompoundCondition::from((Assertion::new(), Message::new(message.to_string()))),
86        )))
87    }
88
89    pub fn syntax(form: Syntax, subform: Option<Syntax>) -> Self {
90        Self(Value::from(Record::from_rust_type(SyntaxViolation::new(
91            form, subform,
92        ))))
93    }
94
95    pub fn undefined(ident: Identifier) -> Self {
96        Self(Value::from(Record::from_rust_type(
97            CompoundCondition::from((
98                Undefined::new(),
99                Message::new(format!("Undefined variable {}", ident.sym)),
100            )),
101        )))
102    }
103
104    pub fn type_error(expected: &str, provided: &str) -> Self {
105        Self(Value::from(Record::from_rust_type(
106            CompoundCondition::from((
107                Assertion::new(),
108                Message::new(format!(
109                    "Expected value of type {expected}, provided {provided}"
110                )),
111            )),
112        )))
113    }
114
115    pub fn invalid_operator(provided: &str) -> Self {
116        Self(Value::from(Record::from_rust_type(
117            CompoundCondition::from((
118                Assertion::new(),
119                Message::new(format!(
120                    "Invalid operator, expected procedure, provided {provided}"
121                )),
122            )),
123        )))
124    }
125
126    pub fn invalid_index(index: usize, len: usize) -> Self {
127        Self(Value::from(Record::from_rust_type(
128            CompoundCondition::from((
129                Assertion::new(),
130                Message::new(format!(
131                    "Invalid index of {index} into collection of size {len}"
132                )),
133            )),
134        )))
135    }
136
137    pub fn invalid_range(range: Range<usize>, len: usize) -> Self {
138        Self(Value::from(Record::from_rust_type(
139            CompoundCondition::from((
140                Assertion::new(),
141                Message::new(format!(
142                    "Invalid range of {range:?} into collection of size {len}"
143                )),
144            )),
145        )))
146    }
147
148    pub fn wrong_num_of_unicode_chars(expected: usize, provided: usize) -> Self {
149        Self(Value::from(Record::from_rust_type(
150            CompoundCondition::from((
151                Assertion::new(),
152                Message::new(format!(
153                    "Expected to receive {expected} unicode characters from transform, received {provided}"
154                )),
155            )),
156        )))
157    }
158
159    pub fn wrong_num_of_args(expected: usize, provided: usize) -> Self {
160        Self(Value::from(Record::from_rust_type(
161            CompoundCondition::from((
162                Assertion::new(),
163                Message::new(format!(
164                    "Expected {expected} arguments, provided {provided}"
165                )),
166            )),
167        )))
168    }
169
170    pub fn wrong_num_of_var_args(expected: Range<usize>, provided: usize) -> Self {
171        Self(Value::from(Record::from_rust_type(
172            CompoundCondition::from((
173                Assertion::new(),
174                Message::new(format!(
175                    "Expected {} to {} arguments, provided {provided}",
176                    expected.start, expected.end
177                )),
178            )),
179        )))
180    }
181
182    pub fn implementation_restriction(msg: impl fmt::Display) -> Self {
183        Self(Value::from_rust_type(CompoundCondition::from((
184            Assertion::new(),
185            ImplementationRestriction::new(),
186            Message::new(msg),
187        ))))
188    }
189
190    /// For when we cannot convert a value into the requested type.
191    ///
192    /// Example: Integer to a Complex
193    pub fn conversion_error(expected: &str, provided: &str) -> Self {
194        Self(Value::from(Record::from_rust_type(
195            CompoundCondition::from((
196                Assertion::new(),
197                Message::new(format!("Could not convert {provided} into {expected}")),
198            )),
199        )))
200    }
201
202    /// For when we cannot represent the value into the requested type.
203    ///
204    /// Example: an u128 number as an u8
205    pub fn not_representable(value: &str, r#type: &str) -> Self {
206        Self(Value::from(Record::from_rust_type(
207            CompoundCondition::from((
208                Assertion::new(),
209                Message::new(format!("Could not represent '{value}' in {type} type")),
210            )),
211        )))
212    }
213
214    pub fn io_error(message: impl fmt::Display) -> Self {
215        Self(Value::from(Record::from_rust_type(
216            CompoundCondition::from((IoError::new(), Assertion::new(), Message::new(message))),
217        )))
218    }
219
220    pub fn io_read_error(message: impl fmt::Display) -> Self {
221        Self(Value::from(Record::from_rust_type(
222            CompoundCondition::from((IoReadError::new(), Assertion::new(), Message::new(message))),
223        )))
224    }
225
226    pub fn io_write_error(message: impl fmt::Display) -> Self {
227        Self(Value::from(Record::from_rust_type(
228            CompoundCondition::from((IoWriteError::new(), Assertion::new(), Message::new(message))),
229        )))
230    }
231
232    pub fn invalid_record_index(k: usize) -> Self {
233        Self::error(format!("invalid record index: {k}"))
234    }
235
236    pub fn add_condition(self, condition: impl SchemeCompatible) -> Self {
237        let mut conditions = if let Some(compound) = self.0.cast_to_rust_type::<CompoundCondition>()
238        {
239            compound.0.clone()
240        } else {
241            vec![self.0]
242        };
243
244        conditions.push(Value::from(Record::from_rust_type(condition)));
245
246        Self(Value::from(Record::from_rust_type(CompoundCondition(
247            conditions,
248        ))))
249    }
250
251    pub fn simple_conditions(&self) -> Result<Vec<Value>, Exception> {
252        if self.0.cast_to_rust_type::<SimpleCondition>().is_some() {
253            Ok(vec![self.0.clone()])
254        } else if let Some(compound_condition) = self.0.cast_to_rust_type::<CompoundCondition>() {
255            Ok(compound_condition.0.clone())
256        } else {
257            Err(Exception::error("not a simple or compound condition"))
258        }
259    }
260
261    pub fn condition<T: SchemeCompatible>(&self) -> Result<Option<Gc<T>>, Exception> {
262        for condition in self.simple_conditions()?.into_iter() {
263            if let Some(condition) = condition.cast_to_rust_type::<T>() {
264                return Ok(Some(condition));
265            }
266        }
267        Ok(None)
268    }
269}
270
271impl From<&'_ Value> for Option<Exception> {
272    fn from(value: &'_ Value) -> Self {
273        if let UnpackedValue::Record(record) = &*value.unpacked_ref()
274            && let rtd = record.rtd()
275            && (RecordTypeDescriptor::is_subtype_of(&rtd, &SimpleCondition::rtd())
276                || RecordTypeDescriptor::is_subtype_of(&rtd, &CompoundCondition::rtd()))
277        {
278            Some(Exception(value.clone()))
279        } else {
280            None
281        }
282    }
283}
284
285impl From<std::io::Error> for Exception {
286    fn from(value: std::io::Error) -> Self {
287        Self::from((IoError::new(), Message::new(format!("{value:?}"))))
288    }
289}
290
291impl From<SimpleCondition> for Exception {
292    fn from(simple: SimpleCondition) -> Self {
293        Self(Value::from(Record::from_rust_type(simple)))
294    }
295}
296
297impl From<Warning> for Exception {
298    fn from(warning: Warning) -> Self {
299        Self(Value::from(Record::from_rust_type(warning)))
300    }
301}
302
303impl From<Serious> for Exception {
304    fn from(serious: Serious) -> Self {
305        Self(Value::from(Record::from_rust_type(serious)))
306    }
307}
308
309impl From<Message> for Exception {
310    fn from(message: Message) -> Self {
311        Self(Value::from(Record::from_rust_type(message)))
312    }
313}
314
315impl From<Infallible> for Exception {
316    fn from(infallible: Infallible) -> Self {
317        match infallible {}
318    }
319}
320
321impl From<ParseSyntaxError> for Exception {
322    fn from(error: ParseSyntaxError) -> Self {
323        Self::from((Lexical::new(), Message::new(error)))
324    }
325}
326
327macro_rules! impl_into_condition_for {
328    ($for:ty) => {
329        impl From<$for> for Exception {
330            fn from(e: $for) -> Self {
331                Self::error(e.to_string())
332            }
333        }
334    };
335}
336
337impl_into_condition_for!(std::num::TryFromIntError);
338
339#[derive(Copy, Clone, Default, Trace)]
340pub struct SimpleCondition;
341
342impl SimpleCondition {
343    pub fn new() -> Self {
344        Self
345    }
346}
347
348impl SchemeCompatible for SimpleCondition {
349    fn rtd() -> Arc<RecordTypeDescriptor> {
350        rtd!(
351            lib: "(rnrs conditions (6))",
352            name: "&condition",
353            constructor: || Ok(SimpleCondition)
354        )
355    }
356}
357
358impl fmt::Debug for SimpleCondition {
359    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        Ok(())
361    }
362}
363
364#[bridge(name = "condition?", lib = "(rnrs conditions (6))")]
365pub fn condition_pred(obj: &Value) -> Result<Vec<Value>, Exception> {
366    let is_condition = obj.cast_to_rust_type::<SimpleCondition>().is_some()
367        || obj.cast_to_rust_type::<CompoundCondition>().is_some();
368    Ok(vec![Value::from(is_condition)])
369}
370
371define_condition_type!(
372    lib: "(rnrs conditions (6))",
373    rust_name: Message,
374    scheme_name: "&message",
375    parent: SimpleCondition,
376    fields: {
377        message: String,
378    },
379    constructor: |message| {
380        Ok(Message { parent: Gc::new(SimpleCondition::new()), message: message.to_string() })
381    },
382    debug: |this, f| {
383        write!(f, " ")?;
384        this.message.fmt(f)
385    }
386);
387
388impl Message {
389    pub fn new(message: impl fmt::Display) -> Self {
390        Self {
391            parent: Gc::new(SimpleCondition::new()),
392            message: message.to_string(),
393        }
394    }
395}
396
397define_condition_type!(
398    lib: "(rnrs conditions (6))",
399    rust_name: Warning,
400    scheme_name: "&warning",
401    parent: SimpleCondition,
402);
403
404impl Warning {
405    pub fn new() -> Self {
406        Self {
407            parent: Gc::new(SimpleCondition::new()),
408        }
409    }
410}
411
412impl Default for Warning {
413    fn default() -> Self {
414        Self::new()
415    }
416}
417
418define_condition_type!(
419    lib: "(rnrs conditions (6))",
420    rust_name: Serious,
421    scheme_name: "&serious",
422    parent: SimpleCondition,
423);
424
425impl Serious {
426    pub fn new() -> Self {
427        Self {
428            parent: Gc::new(SimpleCondition::new()),
429        }
430    }
431}
432
433impl Default for Serious {
434    fn default() -> Self {
435        Self::new()
436    }
437}
438
439define_condition_type!(
440    lib: "(rnrs conditions (6))",
441    rust_name: StackTrace,
442    scheme_name: "&trace",
443    parent: SimpleCondition,
444    fields: {
445        trace: Vector,
446    },
447    constructor: |trace| {
448        Ok(StackTrace {
449            parent: Gc::new(SimpleCondition::new()),
450            trace: trace.clone().try_into()?,
451        })
452    },
453    debug: |this, f| {
454        for trace in &*this.trace.0.vec.read() {
455            write!(f, " {trace}")?;
456        }
457        Ok(())
458    }
459);
460
461impl StackTrace {
462    pub fn new(trace: Vec<Value>) -> Self {
463        Self {
464            parent: Gc::new(SimpleCondition::new()),
465            trace: Vector::from(trace),
466        }
467    }
468
469    pub fn trace(&self) -> Vec<Syntax> {
470        todo!()
471    }
472}
473
474define_condition_type!(
475    lib: "(rnrs conditions (6))",
476    rust_name: Error,
477    scheme_name: "&error",
478    parent: Serious,
479);
480
481impl Error {
482    pub fn new() -> Self {
483        Self {
484            parent: Gc::new(Serious::new()),
485        }
486    }
487}
488
489impl Default for Error {
490    fn default() -> Self {
491        Self::new()
492    }
493}
494
495define_condition_type!(
496    lib: "(rnrs conditions (6))",
497    rust_name: ImportError,
498    scheme_name: "&import",
499    parent: Error,
500    fields: {
501        library: String,
502    },
503    constructor: |lib| {
504        Ok(ImportError {  parent: Gc::new(Error::new()), library: lib.to_string() })
505    },
506    debug: |this, f| {
507        write!(f, " library: {}", this.library)
508    }
509);
510
511impl ImportError {
512    pub fn new(library: String) -> Self {
513        Self {
514            parent: Gc::new(Error::new()),
515            library,
516        }
517    }
518}
519
520define_condition_type!(
521    lib: "(rnrs conditions (6))",
522    rust_name: Violation,
523    scheme_name: "&violation",
524    parent: Serious,
525);
526
527impl Violation {
528    pub fn new() -> Self {
529        Self {
530            parent: Gc::new(Serious::new()),
531        }
532    }
533}
534
535impl Default for Violation {
536    fn default() -> Self {
537        Self::new()
538    }
539}
540
541define_condition_type!(
542    lib: "(rnrs conditions (6))",
543    rust_name: Assertion,
544    scheme_name: "&assertion",
545    parent: Violation
546);
547
548impl Assertion {
549    pub fn new() -> Self {
550        Self {
551            parent: Gc::new(Violation::new()),
552        }
553    }
554}
555
556impl Default for Assertion {
557    fn default() -> Self {
558        Self::new()
559    }
560}
561
562define_condition_type!(
563    lib: "(rnrs conditions (6))",
564    rust_name: Irritants,
565    scheme_name: "&irritants",
566    parent: SimpleCondition,
567    fields: {
568        irritants: Value,
569    },
570    constructor: |irritants| {
571        Ok(Irritants { parent: Gc::new(SimpleCondition::new()), irritants })
572    },
573    debug: |this, f| {
574        write!(f, " irritants: {:?}", this.irritants)
575    }
576);
577
578impl Irritants {
579    pub fn new(irritants: Value) -> Self {
580        Irritants {
581            parent: Gc::new(SimpleCondition::new()),
582            irritants,
583        }
584    }
585}
586
587define_condition_type!(
588    lib: "(rnrs conditions (6))",
589    rust_name: Who,
590    scheme_name: "&who",
591    parent: SimpleCondition,
592    fields: {
593        who: Value,
594    },
595    constructor: |who| {
596        Ok(Who { parent: Gc::new(SimpleCondition::new()), who, })
597    },
598    debug: |this, f| {
599        write!(f, " who: {:?}", this.who)
600    }
601);
602
603impl Who {
604    pub fn new(who: Value) -> Self {
605        Who {
606            parent: Gc::new(SimpleCondition::new()),
607            who,
608        }
609    }
610}
611
612define_condition_type!(
613    lib: "(rnrs conditions (6))",
614    rust_name: NonContinuable,
615    scheme_name: "&non-continuable",
616    parent: Violation,
617);
618
619impl Default for NonContinuable {
620    fn default() -> Self {
621        Self {
622            parent: Gc::new(Violation::new()),
623        }
624    }
625}
626define_condition_type!(
627    lib: "(rnrs conditions (6))",
628    rust_name: ImplementationRestriction,
629    scheme_name: "&implementation-restriction",
630    parent: Violation,
631);
632
633impl ImplementationRestriction {
634    pub fn new() -> Self {
635        Self::default()
636    }
637}
638
639impl Default for ImplementationRestriction {
640    fn default() -> Self {
641        Self {
642            parent: Gc::new(Violation::new()),
643        }
644    }
645}
646
647define_condition_type!(
648    lib: "(rnrs conditions (6))",
649    rust_name: Lexical,
650    scheme_name: "&lexical",
651    parent: Violation,
652);
653
654impl Lexical {
655    pub fn new() -> Self {
656        Self {
657            parent: Gc::new(Violation::new()),
658        }
659    }
660}
661
662impl Default for Lexical {
663    fn default() -> Self {
664        Self::new()
665    }
666}
667
668define_condition_type!(
669    lib: "(rnrs conditions (6))",
670    rust_name: SyntaxViolation,
671    scheme_name: "&syntax",
672    parent: Violation,
673    fields: {
674        form: Value,
675        subform: Option<Value>,
676    },
677    constructor: |form, subform| {
678        let subform = if subform.is_true() { Some(subform) } else { None };
679        Ok(SyntaxViolation { parent: Gc::new(Violation::new()), form, subform })
680    },
681    debug: |this, f| {
682        write!(f, " form: {:?} subform: {:?}", this.form, this.subform)
683    }
684);
685
686impl SyntaxViolation {
687    pub fn new(form: Syntax, subform: Option<Syntax>) -> Self {
688        Self {
689            parent: Gc::new(Violation::new()),
690            form: Value::from(form),
691            subform: subform.map(Value::from),
692        }
693    }
694
695    pub fn new_from_values(form: Value, subform: Option<Value>) -> Self {
696        Self {
697            parent: Gc::new(Violation::new()),
698            form,
699            subform,
700        }
701    }
702}
703
704define_condition_type!(
705    lib: "(rnrs conditions (6))",
706    rust_name: Undefined,
707    scheme_name: "&undefined",
708    parent: Violation
709);
710
711impl Undefined {
712    pub fn new() -> Self {
713        Self {
714            parent: Gc::new(Violation::new()),
715        }
716    }
717}
718
719impl Default for Undefined {
720    fn default() -> Self {
721        Self::new()
722    }
723}
724
725#[derive(Clone, Trace)]
726pub struct CompoundCondition(pub(crate) Vec<Value>);
727
728impl SchemeCompatible for CompoundCondition {
729    fn rtd() -> Arc<RecordTypeDescriptor> {
730        rtd!(
731            lib: "(rnrs conditions (6))",
732            name: "compound-condition",
733            sealed: true,
734            opaque: true
735        )
736    }
737}
738
739impl fmt::Debug for CompoundCondition {
740    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
741        for cond in self.0.iter() {
742            write!(f, " ")?;
743            cond.fmt(f)?;
744        }
745        Ok(())
746    }
747}
748
749impl<T> From<T> for Exception
750where
751    CompoundCondition: From<T>,
752{
753    fn from(value: T) -> Self {
754        Self(Value::from(Record::from_rust_type(
755            CompoundCondition::from(value),
756        )))
757    }
758}
759
760impl<A, B> From<(A, B)> for CompoundCondition
761where
762    A: SchemeCompatible,
763    B: SchemeCompatible,
764{
765    fn from(value: (A, B)) -> Self {
766        Self(vec![
767            Value::from(Record::from_rust_type(value.0)),
768            Value::from(Record::from_rust_type(value.1)),
769        ])
770    }
771}
772
773impl<A, B, C> From<(A, B, C)> for CompoundCondition
774where
775    A: SchemeCompatible,
776    B: SchemeCompatible,
777    C: SchemeCompatible,
778{
779    fn from(value: (A, B, C)) -> Self {
780        Self(vec![
781            Value::from(Record::from_rust_type(value.0)),
782            Value::from(Record::from_rust_type(value.1)),
783            Value::from(Record::from_rust_type(value.2)),
784        ])
785    }
786}
787
788#[bridge(name = "condition", lib = "(rnrs conditions (6))")]
789pub fn condition(conditions: &[Value]) -> Result<Vec<Value>, Exception> {
790    match conditions {
791        // TODO: Check if this is a condition
792        [simple_condition] => Ok(vec![simple_condition.clone()]),
793        conditions => Ok(vec![Value::from(Record::from_rust_type(
794            CompoundCondition(conditions.to_vec()),
795        ))]),
796    }
797}
798
799#[bridge(name = "simple-conditions", lib = "(rnrs conditions (6))")]
800pub fn simple_conditions(condition: &Value) -> Result<Vec<Value>, Exception> {
801    Ok(vec![slice_to_list(
802        &Exception(condition.clone()).simple_conditions()?,
803    )])
804}
805
806#[doc(hidden)]
807#[cps_bridge(
808    def = "with-exception-handler handler thunk",
809    lib = "(rnrs exceptions (6))"
810)]
811pub fn with_exception_handler(
812    runtime: &Runtime,
813    _env: &[Value],
814    args: &[Value],
815    _rest_args: &[Value],
816    dyn_state: &mut DynamicState,
817    k: Value,
818) -> Result<Application, Exception> {
819    let [handler, thunk] = args else {
820        unreachable!();
821    };
822
823    let handler: Procedure = handler.clone().try_into()?;
824    let thunk: Procedure = thunk.clone().try_into()?;
825
826    dyn_state.push_dyn_stack(DynStackElem::ExceptionHandler(handler));
827
828    let k_proc: Procedure = k.clone().try_into().unwrap();
829    let (req_args, var) = k_proc.get_formals();
830
831    let k = dyn_state.new_k(
832        runtime.clone(),
833        vec![k.clone()],
834        pop_dyn_stack,
835        req_args,
836        var,
837    );
838
839    Ok(Application::new(thunk, vec![Value::from(k)]))
840}
841
842#[doc(hidden)]
843#[cps_bridge(def = "raise obj", lib = "(rnrs exceptions (6))")]
844pub fn raise_builtin(
845    runtime: &Runtime,
846    _env: &[Value],
847    args: &[Value],
848    _rest_args: &[Value],
849    dyn_state: &mut DynamicState,
850    _k: Value,
851) -> Result<Application, Exception> {
852    Ok(raise(runtime.clone(), args[0].clone(), dyn_state))
853}
854
855/// Raises a non-continuable exception to the current exception handler.
856pub fn raise(runtime: Runtime, raised: Value, dyn_state: &mut DynamicState) -> Application {
857    let raised = if let Some(condition) = raised.cast_to_scheme_type::<Exception>() {
858        let trace = dyn_state.current_marks(Symbol::intern("trace"));
859        Value::from(condition.add_condition(StackTrace::new(trace)))
860    } else {
861        raised
862    };
863
864    Application::new(
865        dyn_state.new_k(runtime, vec![raised], unwind_to_exception_handler, 0, false),
866        Vec::new(),
867    )
868}
869
870#[runtime_fn]
871unsafe extern "C" fn raise_rt(
872    runtime: *mut GcInner<RwLock<RuntimeInner>>,
873    raised: *const (),
874    dyn_state: *mut DynamicState,
875) -> *mut Application {
876    unsafe {
877        let runtime = Runtime::from_raw_inc_rc(runtime);
878        let raised = Value::from_raw(raised);
879        Box::into_raw(Box::new(raise(
880            runtime,
881            raised,
882            dyn_state.as_mut().unwrap_unchecked(),
883        )))
884    }
885}
886
887unsafe extern "C" fn unwind_to_exception_handler(
888    runtime: *mut GcInner<RwLock<RuntimeInner>>,
889    env: *const Value,
890    _args: *const Value,
891    dyn_state: *mut DynamicState,
892) -> *mut Application {
893    unsafe {
894        // env[0] is the raised value:
895        let raised = env.as_ref().unwrap().clone();
896
897        let dyn_state = dyn_state.as_mut().unwrap_unchecked();
898
899        loop {
900            let app = match dyn_state.pop_dyn_stack() {
901                None => {
902                    // If the stack is empty, we should return the error
903                    Application::halt_err(raised)
904                }
905                Some(DynStackElem::Winder(winder)) => {
906                    // If this is a winder, we should call the out winder while unwinding
907                    Application::new(
908                        winder.out_thunk,
909                        vec![Value::from(dyn_state.new_k(
910                            Runtime::from_raw_inc_rc(runtime),
911                            vec![raised],
912                            unwind_to_exception_handler,
913                            0,
914                            false,
915                        ))],
916                    )
917                }
918                Some(DynStackElem::ExceptionHandler(handler)) => Application::new(
919                    handler,
920                    vec![
921                        raised.clone(),
922                        Value::from(dyn_state.new_k(
923                            Runtime::from_raw_inc_rc(runtime),
924                            vec![raised],
925                            reraise_exception,
926                            0,
927                            true,
928                        )),
929                    ],
930                ),
931                _ => continue,
932            };
933            return Box::into_raw(Box::new(app));
934        }
935    }
936}
937
938unsafe extern "C" fn reraise_exception(
939    runtime: *mut GcInner<RwLock<RuntimeInner>>,
940    env: *const Value,
941    _args: *const Value,
942    _dyn_state: *mut DynamicState,
943) -> *mut Application {
944    unsafe {
945        let runtime = Runtime(Gc::from_raw_inc_rc(runtime));
946
947        // env[0] is the exception
948        let exception = env.as_ref().unwrap().clone();
949
950        Box::into_raw(Box::new(Application::new(
951            Procedure::new(
952                runtime,
953                Vec::new(),
954                FuncPtr::Bridge(raise_builtin),
955                1,
956                false,
957            ),
958            vec![exception, Value::undefined()],
959        )))
960    }
961}
962
963/// Raises an exception to the current exception handler and continues with the
964/// value returned by the handler.
965#[doc(hidden)]
966#[cps_bridge(def = "raise-continuable obj", lib = "(rnrs exceptions (6))")]
967pub fn raise_continuable(
968    _runtime: &Runtime,
969    _env: &[Value],
970    args: &[Value],
971    _rest_args: &[Value],
972    dyn_state: &mut DynamicState,
973    k: Value,
974) -> Result<Application, Exception> {
975    let [condition] = args else {
976        unreachable!();
977    };
978
979    let Some(handler) = dyn_state.current_exception_handler() else {
980        return Ok(Application::halt_err(condition.clone()));
981    };
982
983    Ok(Application::new(handler, vec![condition.clone(), k]))
984}
985
986#[bridge(name = "error", lib = "(rnrs base builtins (6))")]
987pub fn error(who: &Value, message: &Value, irritants: &[Value]) -> Result<Vec<Value>, Exception> {
988    let mut conditions = Vec::new();
989    if who.is_true() {
990        conditions.push(Value::from_rust_type(Who::new(who.clone())));
991    }
992    conditions.push(Value::from_rust_type(Message::new(message)));
993    conditions.push(Value::from_rust_type(Irritants::new(slice_to_list(
994        irritants,
995    ))));
996    Err(Exception(Value::from(Exception::from(CompoundCondition(
997        conditions,
998    )))))
999}
1000
1001#[bridge(name = "assertion-violation", lib = "(rnrs base builtins (6))")]
1002pub fn assertion_violation(
1003    who: &Value,
1004    message: &Value,
1005    irritants: &[Value],
1006) -> Result<Vec<Value>, Exception> {
1007    let mut conditions = Vec::new();
1008    conditions.push(Value::from_rust_type(Assertion::new()));
1009    if who.is_true() {
1010        conditions.push(Value::from_rust_type(Who::new(who.clone())));
1011    }
1012    conditions.push(Value::from_rust_type(Message::new(message)));
1013    conditions.push(Value::from_rust_type(Irritants::new(slice_to_list(
1014        irritants,
1015    ))));
1016    Err(Exception(Value::from(Exception::from(CompoundCondition(
1017        conditions,
1018    )))))
1019}