1use crate::{
53 gc::{Gc, GcInner, Trace},
54 lists::slice_to_list,
55 ports::{IoDecodingError, IoEncodingError, IoError, IoReadError, IoWriteError},
56 proc::{Application, ContBarrier, DynStackElem, 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, Span, Syntax, parse::ParseSyntaxError},
62 value::{UnpackedValue, Value},
63 vectors::Vector,
64};
65use by_address::ByAddress;
66use parking_lot::RwLock;
67use scheme_rs_macros::runtime_fn;
68use std::{collections::HashMap, convert::Infallible, fmt, ops::Range, sync::Arc};
69
70pub use scheme_rs_macros::define_condition_type;
72
73impl fmt::Display for Exception {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 <Value as fmt::Debug>::fmt(&self.0, f)
76 }
77}
78
79#[derive(Debug, Clone, Trace)]
81pub struct Exception(pub Value);
82
83impl Exception {
84 pub fn error(message: impl fmt::Display) -> Self {
85 Self(Value::from(Record::from_rust_type(
86 CompoundCondition::from((Assertion::new(), Message::new(message.to_string()))),
87 )))
88 }
89
90 pub fn syntax(form: Syntax, subform: Option<Syntax>) -> Self {
91 Self(Value::from(Record::from_rust_type(SyntaxViolation::new(
92 form, subform,
93 ))))
94 }
95
96 pub fn undefined(ident: Identifier) -> Self {
97 Self(Value::from(Record::from_rust_type(
98 CompoundCondition::from((
99 Undefined::new(),
100 Message::new(format!("undefined variable {}", ident.sym)),
101 )),
102 )))
103 }
104
105 pub fn type_error(expected: &str, provided: &str) -> Self {
106 Self(Value::from(Record::from_rust_type(
107 CompoundCondition::from((
108 Assertion::new(),
109 Message::new(format!(
110 "expected value of type {expected}, provided {provided}"
111 )),
112 )),
113 )))
114 }
115
116 pub fn invalid_operator(provided: &str) -> Self {
117 Self(Value::from(Record::from_rust_type(
118 CompoundCondition::from((
119 Assertion::new(),
120 Message::new(format!(
121 "invalid operator: expected procedure, provided {provided}"
122 )),
123 )),
124 )))
125 }
126
127 pub fn invalid_index(index: usize, len: usize) -> Self {
128 Self(Value::from(Record::from_rust_type(
129 CompoundCondition::from((
130 Assertion::new(),
131 Message::new(format!(
132 "index {index} out of bounds for collection of size {len}"
133 )),
134 )),
135 )))
136 }
137
138 pub fn invalid_range(range: Range<usize>, len: usize) -> Self {
139 Self(Value::from(Record::from_rust_type(
140 CompoundCondition::from((
141 Assertion::new(),
142 Message::new(format!(
143 "range {range:?} out of bounds for collection of size {len}"
144 )),
145 )),
146 )))
147 }
148
149 pub fn wrong_num_of_unicode_chars(expected: usize, provided: usize) -> Self {
150 Self(Value::from(Record::from_rust_type(
151 CompoundCondition::from((
152 Assertion::new(),
153 Message::new(format!(
154 "expected {expected} unicode characters from transform, received {provided}"
155 )),
156 )),
157 )))
158 }
159
160 pub fn wrong_num_of_args(expected: usize, provided: usize) -> Self {
161 Self(Value::from(Record::from_rust_type(
162 CompoundCondition::from((
163 Assertion::new(),
164 Message::new(format!(
165 "expected {expected} arguments, provided {provided}"
166 )),
167 )),
168 )))
169 }
170
171 pub fn wrong_num_of_var_args(expected: Range<usize>, provided: usize) -> Self {
172 Self(Value::from(Record::from_rust_type(
173 CompoundCondition::from((
174 Assertion::new(),
175 Message::new(format!(
176 "expected {} to {} arguments, provided {provided}",
177 expected.start, expected.end
178 )),
179 )),
180 )))
181 }
182
183 pub fn implementation_restriction(msg: impl fmt::Display) -> Self {
184 Self(Value::from_rust_type(CompoundCondition::from((
185 Assertion::new(),
186 ImplementationRestriction::new(),
187 Message::new(msg),
188 ))))
189 }
190
191 pub fn conversion_error(expected: &str, provided: &str) -> Self {
195 Self(Value::from(Record::from_rust_type(
196 CompoundCondition::from((
197 Assertion::new(),
198 Message::new(format!("cannot convert {provided} into {expected}")),
199 )),
200 )))
201 }
202
203 pub fn not_representable(value: &str, r#type: &str) -> Self {
207 Self(Value::from(Record::from_rust_type(
208 CompoundCondition::from((
209 Assertion::new(),
210 Message::new(format!("cannot represent '{value}' as {type}")),
211 )),
212 )))
213 }
214
215 pub fn io_error(message: impl fmt::Display) -> Self {
216 Self(Value::from(Record::from_rust_type(
217 CompoundCondition::from((IoError::new(), Assertion::new(), Message::new(message))),
218 )))
219 }
220
221 pub fn io_read_error(message: impl fmt::Display) -> Self {
222 Self(Value::from(Record::from_rust_type(
223 CompoundCondition::from((IoReadError::new(), Assertion::new(), Message::new(message))),
224 )))
225 }
226
227 pub fn io_write_error(message: impl fmt::Display) -> Self {
228 Self(Value::from(Record::from_rust_type(
229 CompoundCondition::from((IoWriteError::new(), Assertion::new(), Message::new(message))),
230 )))
231 }
232
233 pub fn io_decoding_error(message: impl fmt::Display, port: Value) -> Self {
234 Self(Value::from(Record::from_rust_type(
235 CompoundCondition::from((
236 IoDecodingError::new(port),
237 Assertion::new(),
238 Message::new(message),
239 )),
240 )))
241 }
242
243 pub fn io_encoding_error(message: impl fmt::Display, port: Value, chr: char) -> Self {
244 Self(Value::from(Record::from_rust_type(
245 CompoundCondition::from((
246 IoEncodingError::new(port, chr),
247 Assertion::new(),
248 Message::new(message),
249 )),
250 )))
251 }
252
253 pub fn invalid_record_index(k: usize) -> Self {
254 Self::error(format!("invalid record index: {k}"))
255 }
256
257 pub fn add_condition(self, condition: impl SchemeCompatible) -> Self {
258 let mut conditions = if let Some(compound) = self.0.cast_to_rust_type::<CompoundCondition>()
259 {
260 compound.0.clone()
261 } else {
262 vec![self.0]
263 };
264
265 conditions.push(Value::from(Record::from_rust_type(condition)));
266
267 Self(Value::from(Record::from_rust_type(CompoundCondition(
268 conditions,
269 ))))
270 }
271
272 pub fn simple_conditions(&self) -> Result<Vec<Value>, Exception> {
273 if self.0.cast_to_rust_type::<SimpleCondition>().is_some() {
274 Ok(vec![self.0.clone()])
275 } else if let Some(compound_condition) = self.0.cast_to_rust_type::<CompoundCondition>() {
276 Ok(compound_condition.0.clone())
277 } else {
278 Err(Exception::error("not a simple or compound condition"))
279 }
280 }
281
282 pub fn condition<T: SchemeCompatible>(&self) -> Result<Option<Gc<T>>, Exception> {
283 for condition in self.simple_conditions()?.into_iter() {
284 if let Some(condition) = condition.cast_to_rust_type::<T>() {
285 return Ok(Some(condition));
286 }
287 }
288 Ok(None)
289 }
290
291 pub fn pretty_print(
292 &self,
293 source_cache: &mut SourceCache,
294 f: &mut impl fmt::Write,
295 ) -> fmt::Result {
296 let Ok(conditions) = self.simple_conditions() else {
297 return writeln!(
298 f,
299 "Exception occurred with a non-condition value: {:?}",
300 self.0
301 );
302 };
303
304 writeln!(f, "Uncaught exception:")?;
305 for condition in conditions.into_iter().rev() {
306 if let Some(message) = condition.cast_to_rust_type::<Message>() {
307 writeln!(f, " - Message: {}", message.message)?;
308 } else if let Some(syntax) = condition.cast_to_rust_type::<SyntaxViolation>() {
309 writeln!(f, " - Syntax error in form: {:?}", syntax.form)?;
310 source_cache.pretty_print_condition(syntax.as_ref(), f)?;
311 } else if let Some(trace) = condition.cast_to_rust_type::<StackTrace>() {
312 if !trace.trace.is_empty() {
313 writeln!(f, " - Trace:")?;
314 source_cache.pretty_print_condition(trace.as_ref(), f)?;
315 }
316 } else if condition.cast_to_rust_type::<Assertion>().is_some() {
317 writeln!(f, " - Assertion failed")?;
318 } else {
319 writeln!(f, " - Condition: {condition:?}")?;
320 }
321 }
322 Ok(())
323 }
324}
325
326impl From<&'_ Value> for Option<Exception> {
327 fn from(value: &'_ Value) -> Self {
328 if let UnpackedValue::Record(record) = &*value.unpacked_ref()
329 && let rtd = record.rtd()
330 && (RecordTypeDescriptor::is_subtype_of(&rtd, &SimpleCondition::rtd())
331 || RecordTypeDescriptor::is_subtype_of(&rtd, &CompoundCondition::rtd()))
332 {
333 Some(Exception(value.clone()))
334 } else {
335 None
336 }
337 }
338}
339
340impl From<std::io::Error> for Exception {
341 fn from(value: std::io::Error) -> Self {
342 Self::from((IoError::new(), Message::new(format!("{value:?}"))))
343 }
344}
345
346impl From<SimpleCondition> for Exception {
347 fn from(simple: SimpleCondition) -> Self {
348 Self(Value::from(Record::from_rust_type(simple)))
349 }
350}
351
352impl From<Warning> for Exception {
353 fn from(warning: Warning) -> Self {
354 Self(Value::from(Record::from_rust_type(warning)))
355 }
356}
357
358impl From<Serious> for Exception {
359 fn from(serious: Serious) -> Self {
360 Self(Value::from(Record::from_rust_type(serious)))
361 }
362}
363
364impl From<Message> for Exception {
365 fn from(message: Message) -> Self {
366 Self(Value::from(Record::from_rust_type(message)))
367 }
368}
369
370impl From<Infallible> for Exception {
371 fn from(infallible: Infallible) -> Self {
372 match infallible {}
373 }
374}
375
376impl From<ParseSyntaxError> for Exception {
377 fn from(error: ParseSyntaxError) -> Self {
378 Self::from((Lexical::new(), Message::new(error)))
379 }
380}
381
382macro_rules! impl_into_condition_for {
383 ($for:ty) => {
384 impl From<$for> for Exception {
385 fn from(e: $for) -> Self {
386 Self::error(e.to_string())
387 }
388 }
389 };
390}
391
392pub trait PrettyCondition {
393 fn span(&self) -> Span;
394
395 fn pretty_print(&self, _w: &mut impl fmt::Write) -> fmt::Result {
396 Ok(())
397 }
398}
399
400fn print_lines_with_offense_from_span(
403 span: &Span,
404 lines: Option<&[String]>,
405 w: &mut impl fmt::Write,
406) -> fmt::Result {
407 let Some(lines) = lines else {
408 return Ok(());
409 };
410
411 writeln!(w, "--> {}:{}:{}:", span.file, span.line, span.column)?;
412 let start = span.line.saturating_sub(2);
413 let end = (span.line + 3).min(lines.len() as u32);
414
415 for i in start..end {
416 writeln!(w, "{:03} | {}", i + 1, lines[i as usize])?;
419 if i + 1 == span.line {
421 writeln!(w, " | {}~ here", " ".repeat(span.column))?; }
423 }
424 Ok(())
425}
426
427impl_into_condition_for!(std::num::TryFromIntError);
428
429#[derive(Copy, Clone, Default, Trace)]
430pub struct SimpleCondition;
431
432impl SimpleCondition {
433 pub fn new() -> Self {
434 Self
435 }
436}
437
438impl SchemeCompatible for SimpleCondition {
439 fn rtd() -> Arc<RecordTypeDescriptor> {
440 rtd!(
441 lib: "(rnrs conditions (6))",
442 name: "&condition",
443 constructor: || Ok(SimpleCondition)
444 )
445 }
446}
447
448impl fmt::Debug for SimpleCondition {
449 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 Ok(())
451 }
452}
453
454#[bridge(name = "condition?", lib = "(rnrs conditions (6))")]
455pub fn condition_pred(obj: &Value) -> Result<Vec<Value>, Exception> {
456 let is_condition = obj.cast_to_rust_type::<SimpleCondition>().is_some()
457 || obj.cast_to_rust_type::<CompoundCondition>().is_some();
458 Ok(vec![Value::from(is_condition)])
459}
460
461define_condition_type!(
462 lib: "(rnrs conditions (6))",
463 rust_name: Message,
464 scheme_name: "&message",
465 parent: SimpleCondition,
466 fields: {
467 message: String,
468 },
469 constructor: |message| {
470 Ok(Message { parent: Gc::new(SimpleCondition::new()), message: message.to_string() })
471 },
472 debug: |this, f| {
473 write!(f, " ")?;
474 this.message.fmt(f)
475 }
476);
477
478impl Message {
479 pub fn new(message: impl fmt::Display) -> Self {
480 Self {
481 parent: Gc::new(SimpleCondition::new()),
482 message: message.to_string(),
483 }
484 }
485}
486
487define_condition_type!(
488 lib: "(rnrs conditions (6))",
489 rust_name: Warning,
490 scheme_name: "&warning",
491 parent: SimpleCondition,
492);
493
494impl Warning {
495 pub fn new() -> Self {
496 Self {
497 parent: Gc::new(SimpleCondition::new()),
498 }
499 }
500}
501
502impl Default for Warning {
503 fn default() -> Self {
504 Self::new()
505 }
506}
507
508define_condition_type!(
509 lib: "(rnrs conditions (6))",
510 rust_name: Serious,
511 scheme_name: "&serious",
512 parent: SimpleCondition,
513);
514
515impl Serious {
516 pub fn new() -> Self {
517 Self {
518 parent: Gc::new(SimpleCondition::new()),
519 }
520 }
521}
522
523impl Default for Serious {
524 fn default() -> Self {
525 Self::new()
526 }
527}
528
529define_condition_type!(
530 lib: "(rnrs conditions (6))",
531 rust_name: StackTrace,
532 scheme_name: "&trace",
533 parent: SimpleCondition,
534 fields: {
535 trace: Vector,
536 },
537 constructor: |trace| {
538 Ok(StackTrace {
539 parent: Gc::new(SimpleCondition::new()),
540 trace: trace.clone().try_into()?,
541 })
542 },
543 debug: |this, f| {
544 for trace in &*this.trace.0.vec.read() {
545 write!(f, " {trace}")?;
546 }
547 Ok(())
548 }
549);
550
551impl PrettyCondition for StackTrace {
552 fn span(&self) -> Span {
553 let first = self.trace.first().unwrap();
554 let Some(syntax) = first.cast_to_scheme_type::<Gc<Syntax>>() else {
555 return Span::default();
556 };
557 syntax.span().clone()
558 }
559
560 fn pretty_print(&self, w: &mut impl fmt::Write) -> fmt::Result {
561 for (i, trace) in self.trace.iter().enumerate() {
562 let Some(syntax) = trace.cast_to_scheme_type::<Gc<Syntax>>() else {
563 continue;
564 };
565 let span = syntax.span();
566 let func_name = syntax.as_ident().unwrap().symbol();
567 writeln!(w, "{:>6}: {func_name}:{span}", i + 1)?;
568 }
569 Ok(())
570 }
571}
572
573impl StackTrace {
574 pub fn new(trace: Vec<Value>) -> Self {
575 Self {
576 parent: Gc::new(SimpleCondition::new()),
577 trace: Vector::from(trace),
578 }
579 }
580
581 pub fn trace(&self) -> Vec<Syntax> {
582 todo!()
583 }
584}
585
586define_condition_type!(
587 lib: "(rnrs conditions (6))",
588 rust_name: Error,
589 scheme_name: "&error",
590 parent: Serious,
591);
592
593impl Error {
594 pub fn new() -> Self {
595 Self {
596 parent: Gc::new(Serious::new()),
597 }
598 }
599}
600
601impl Default for Error {
602 fn default() -> Self {
603 Self::new()
604 }
605}
606
607define_condition_type!(
608 lib: "(rnrs conditions (6))",
609 rust_name: ImportError,
610 scheme_name: "&import",
611 parent: Error,
612 fields: {
613 library: String,
614 },
615 constructor: |lib| {
616 Ok(ImportError { parent: Gc::new(Error::new()), library: lib.to_string() })
617 },
618 debug: |this, f| {
619 write!(f, " library: {}", this.library)
620 }
621);
622
623impl ImportError {
624 pub fn new(library: String) -> Self {
625 Self {
626 parent: Gc::new(Error::new()),
627 library,
628 }
629 }
630}
631
632define_condition_type!(
633 lib: "(rnrs conditions (6))",
634 rust_name: Violation,
635 scheme_name: "&violation",
636 parent: Serious,
637);
638
639impl Violation {
640 pub fn new() -> Self {
641 Self {
642 parent: Gc::new(Serious::new()),
643 }
644 }
645}
646
647impl Default for Violation {
648 fn default() -> Self {
649 Self::new()
650 }
651}
652
653define_condition_type!(
654 lib: "(rnrs conditions (6))",
655 rust_name: Assertion,
656 scheme_name: "&assertion",
657 parent: Violation
658);
659
660impl Assertion {
661 pub fn new() -> Self {
662 Self {
663 parent: Gc::new(Violation::new()),
664 }
665 }
666}
667
668impl Default for Assertion {
669 fn default() -> Self {
670 Self::new()
671 }
672}
673
674define_condition_type!(
675 lib: "(rnrs conditions (6))",
676 rust_name: Irritants,
677 scheme_name: "&irritants",
678 parent: SimpleCondition,
679 fields: {
680 irritants: Value,
681 },
682 constructor: |irritants| {
683 Ok(Irritants { parent: Gc::new(SimpleCondition::new()), irritants })
684 },
685 debug: |this, f| {
686 write!(f, " irritants: {:?}", this.irritants)
687 }
688);
689
690impl Irritants {
691 pub fn new(irritants: Value) -> Self {
692 Irritants {
693 parent: Gc::new(SimpleCondition::new()),
694 irritants,
695 }
696 }
697}
698
699define_condition_type!(
700 lib: "(rnrs conditions (6))",
701 rust_name: Who,
702 scheme_name: "&who",
703 parent: SimpleCondition,
704 fields: {
705 who: Value,
706 },
707 constructor: |who| {
708 Ok(Who { parent: Gc::new(SimpleCondition::new()), who, })
709 },
710 debug: |this, f| {
711 write!(f, " who: {:?}", this.who)
712 }
713);
714
715impl Who {
716 pub fn new(who: Value) -> Self {
717 Who {
718 parent: Gc::new(SimpleCondition::new()),
719 who,
720 }
721 }
722}
723
724define_condition_type!(
725 lib: "(rnrs conditions (6))",
726 rust_name: NonContinuable,
727 scheme_name: "&non-continuable",
728 parent: Violation,
729);
730
731impl Default for NonContinuable {
732 fn default() -> Self {
733 Self {
734 parent: Gc::new(Violation::new()),
735 }
736 }
737}
738define_condition_type!(
739 lib: "(rnrs conditions (6))",
740 rust_name: ImplementationRestriction,
741 scheme_name: "&implementation-restriction",
742 parent: Violation,
743);
744
745impl ImplementationRestriction {
746 pub fn new() -> Self {
747 Self::default()
748 }
749}
750
751impl Default for ImplementationRestriction {
752 fn default() -> Self {
753 Self {
754 parent: Gc::new(Violation::new()),
755 }
756 }
757}
758
759define_condition_type!(
760 lib: "(rnrs conditions (6))",
761 rust_name: Lexical,
762 scheme_name: "&lexical",
763 parent: Violation,
764);
765
766impl Lexical {
767 pub fn new() -> Self {
768 Self {
769 parent: Gc::new(Violation::new()),
770 }
771 }
772}
773
774impl Default for Lexical {
775 fn default() -> Self {
776 Self::new()
777 }
778}
779
780define_condition_type!(
781 lib: "(rnrs conditions (6))",
782 rust_name: SyntaxViolation,
783 scheme_name: "&syntax",
784 parent: Violation,
785 fields: {
786 form: Value,
787 subform: Option<Value>,
788 },
789 constructor: |form, subform| {
790 let subform = if subform.is_true() { Some(subform) } else { None };
791 Ok(SyntaxViolation { parent: Gc::new(Violation::new()), form, subform })
792 },
793);
794
795impl PrettyCondition for SyntaxViolation {
796 fn span(&self) -> Span {
797 self.subform
798 .as_ref()
799 .unwrap_or(&self.form)
800 .cast_to_scheme_type::<Gc<Syntax>>()
801 .unwrap()
802 .span()
803 .clone()
804 }
805}
806
807impl SyntaxViolation {
808 pub fn new(form: Syntax, subform: Option<Syntax>) -> Self {
809 Self {
810 parent: Gc::new(Violation::new()),
811 form: Value::from(form),
812 subform: subform.map(Value::from),
813 }
814 }
815
816 pub fn new_from_values(form: Value, subform: Option<Value>) -> Self {
817 Self {
818 parent: Gc::new(Violation::new()),
819 form,
820 subform,
821 }
822 }
823}
824
825define_condition_type!(
826 lib: "(rnrs conditions (6))",
827 rust_name: Undefined,
828 scheme_name: "&undefined",
829 parent: Violation
830);
831
832impl Undefined {
833 pub fn new() -> Self {
834 Self {
835 parent: Gc::new(Violation::new()),
836 }
837 }
838}
839
840impl Default for Undefined {
841 fn default() -> Self {
842 Self::new()
843 }
844}
845
846#[derive(Clone, Trace)]
847pub struct CompoundCondition(pub(crate) Vec<Value>);
848
849impl SchemeCompatible for CompoundCondition {
850 fn rtd() -> Arc<RecordTypeDescriptor> {
851 rtd!(
852 lib: "(rnrs conditions (6))",
853 name: "compound-condition",
854 sealed: true,
855 opaque: true
856 )
857 }
858}
859
860impl fmt::Debug for CompoundCondition {
861 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
862 for cond in self.0.iter() {
863 write!(f, " ")?;
864 cond.fmt(f)?;
865 }
866 Ok(())
867 }
868}
869
870impl<T> From<T> for Exception
871where
872 CompoundCondition: From<T>,
873{
874 fn from(value: T) -> Self {
875 Self(Value::from(Record::from_rust_type(
876 CompoundCondition::from(value),
877 )))
878 }
879}
880
881impl<A, B> From<(A, B)> for CompoundCondition
882where
883 A: SchemeCompatible,
884 B: SchemeCompatible,
885{
886 fn from(value: (A, B)) -> Self {
887 Self(vec![
888 Value::from(Record::from_rust_type(value.0)),
889 Value::from(Record::from_rust_type(value.1)),
890 ])
891 }
892}
893
894impl<A, B, C> From<(A, B, C)> for CompoundCondition
895where
896 A: SchemeCompatible,
897 B: SchemeCompatible,
898 C: SchemeCompatible,
899{
900 fn from(value: (A, B, C)) -> Self {
901 Self(vec![
902 Value::from(Record::from_rust_type(value.0)),
903 Value::from(Record::from_rust_type(value.1)),
904 Value::from(Record::from_rust_type(value.2)),
905 ])
906 }
907}
908
909#[bridge(name = "condition", lib = "(rnrs conditions (6))")]
910pub fn condition(conditions: &[Value]) -> Result<Vec<Value>, Exception> {
911 match conditions {
912 [simple_condition] => Ok(vec![simple_condition.clone()]),
914 conditions => Ok(vec![Value::from(Record::from_rust_type(
915 CompoundCondition(conditions.to_vec()),
916 ))]),
917 }
918}
919
920#[bridge(name = "simple-conditions", lib = "(rnrs conditions (6))")]
921pub fn simple_conditions(condition: &Value) -> Result<Vec<Value>, Exception> {
922 Ok(vec![slice_to_list(
923 &Exception(condition.clone()).simple_conditions()?,
924 )])
925}
926
927#[doc(hidden)]
928#[cps_bridge(
929 def = "with-exception-handler handler thunk",
930 lib = "(rnrs exceptions (6))"
931)]
932pub fn with_exception_handler(
933 runtime: &Runtime,
934 _env: &[Value],
935 args: &[Value],
936 _rest_args: &[Value],
937 barrier: &mut ContBarrier,
938 k: Value,
939) -> Result<Application, Exception> {
940 let [handler, thunk] = args else {
941 unreachable!();
942 };
943
944 let handler: Procedure = handler.clone().try_into()?;
945 let thunk: Procedure = thunk.clone().try_into()?;
946
947 barrier.push_dyn_stack(DynStackElem::ExceptionHandler(handler));
948
949 let k_proc: Procedure = k.clone().try_into().unwrap();
950 let (req_args, var) = k_proc.get_formals();
951
952 let k = barrier.new_k(
953 runtime.clone(),
954 vec![k.clone()],
955 pop_dyn_stack,
956 req_args,
957 var,
958 );
959
960 Ok(Application::new(thunk, vec![Value::from(k)]))
961}
962
963#[doc(hidden)]
964#[cps_bridge(def = "raise obj", lib = "(rnrs exceptions (6))")]
965pub fn raise_builtin(
966 runtime: &Runtime,
967 _env: &[Value],
968 args: &[Value],
969 _rest_args: &[Value],
970 barrier: &mut ContBarrier,
971 _k: Value,
972) -> Result<Application, Exception> {
973 Ok(raise(runtime.clone(), args[0].clone(), barrier))
974}
975
976pub fn raise(runtime: Runtime, raised: Value, barrier: &mut ContBarrier) -> Application {
978 let raised = if let Some(condition) = raised.cast_to_scheme_type::<Exception>() {
979 let trace = barrier.current_marks(Symbol::intern("trace"));
980 Value::from(condition.add_condition(StackTrace::new(trace)))
981 } else {
982 raised
983 };
984
985 Application::new(
986 barrier.new_k(runtime, vec![raised], unwind_to_exception_handler, 0, false),
987 Vec::new(),
988 )
989}
990
991#[runtime_fn]
992unsafe extern "C" fn raise_rt(
993 runtime: *mut GcInner<RwLock<RuntimeInner>>,
994 raised: *const (),
995 barrier: *mut ContBarrier,
996) -> *mut Application {
997 unsafe {
998 let runtime = Runtime::from_raw_inc_rc(runtime);
999 let raised = Value::from_raw(raised);
1000 Box::into_raw(Box::new(raise(
1001 runtime,
1002 raised,
1003 barrier.as_mut().unwrap_unchecked(),
1004 )))
1005 }
1006}
1007
1008unsafe extern "C" fn unwind_to_exception_handler(
1009 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1010 env: *const Value,
1011 _args: *const Value,
1012 barrier: *mut ContBarrier,
1013) -> *mut Application {
1014 unsafe {
1015 let raised = env.as_ref().unwrap().clone();
1017
1018 let barrier = barrier.as_mut().unwrap_unchecked();
1019
1020 loop {
1021 let app = match barrier.pop_dyn_stack() {
1022 None => {
1023 Application::halt_err(raised)
1025 }
1026 Some(DynStackElem::Winder(winder)) => {
1027 Application::new(
1029 winder.out_thunk,
1030 vec![Value::from(barrier.new_k(
1031 Runtime::from_raw_inc_rc(runtime),
1032 vec![raised],
1033 unwind_to_exception_handler,
1034 0,
1035 false,
1036 ))],
1037 )
1038 }
1039 Some(DynStackElem::ExceptionHandler(handler)) => Application::new(
1040 handler,
1041 vec![
1042 raised.clone(),
1043 Value::from(barrier.new_k(
1044 Runtime::from_raw_inc_rc(runtime),
1045 vec![raised],
1046 reraise_exception,
1047 0,
1048 true,
1049 )),
1050 ],
1051 ),
1052 _ => continue,
1053 };
1054 return Box::into_raw(Box::new(app));
1055 }
1056 }
1057}
1058
1059unsafe extern "C" fn reraise_exception(
1060 runtime: *mut GcInner<RwLock<RuntimeInner>>,
1061 _env: *const Value,
1062 _args: *const Value,
1063 _barrier: *mut ContBarrier,
1064) -> *mut Application {
1065 unsafe {
1066 let runtime = Runtime(Gc::from_raw_inc_rc(runtime));
1067
1068 let exception = Value::from_rust_type(NonContinuable::default());
1073
1074 Box::into_raw(Box::new(Application::new(
1075 Procedure::new(
1076 runtime,
1077 Vec::new(),
1078 FuncPtr::Bridge(raise_builtin),
1079 1,
1080 false,
1081 ),
1082 vec![exception, Value::undefined()],
1083 )))
1084 }
1085}
1086
1087#[doc(hidden)]
1090#[cps_bridge(def = "raise-continuable obj", lib = "(rnrs exceptions (6))")]
1091pub fn raise_continuable(
1092 _runtime: &Runtime,
1093 _env: &[Value],
1094 args: &[Value],
1095 _rest_args: &[Value],
1096 barrier: &mut ContBarrier,
1097 k: Value,
1098) -> Result<Application, Exception> {
1099 let [condition] = args else {
1100 unreachable!();
1101 };
1102
1103 let Some(handler) = barrier.current_exception_handler() else {
1104 return Ok(Application::halt_err(condition.clone()));
1105 };
1106
1107 Ok(Application::new(handler, vec![condition.clone(), k]))
1108}
1109
1110#[bridge(name = "error", lib = "(rnrs base builtins (6))")]
1111pub fn error(who: &Value, message: &Value, irritants: &[Value]) -> Result<Vec<Value>, Exception> {
1112 let mut conditions = Vec::new();
1113 if who.is_true() {
1114 conditions.push(Value::from_rust_type(Who::new(who.clone())));
1115 }
1116 conditions.push(Value::from_rust_type(Message::new(message)));
1117 conditions.push(Value::from_rust_type(Irritants::new(slice_to_list(
1118 irritants,
1119 ))));
1120 Err(Exception(Value::from(Exception::from(CompoundCondition(
1121 conditions,
1122 )))))
1123}
1124
1125#[bridge(name = "assertion-violation", lib = "(rnrs base builtins (6))")]
1126pub fn assertion_violation(
1127 who: &Value,
1128 message: &Value,
1129 irritants: &[Value],
1130) -> Result<Vec<Value>, Exception> {
1131 let mut conditions = Vec::new();
1132 conditions.push(Value::from_rust_type(Assertion::new()));
1133 if who.is_true() {
1134 conditions.push(Value::from_rust_type(Who::new(who.clone())));
1135 }
1136 conditions.push(Value::from_rust_type(Message::new(message)));
1137 conditions.push(Value::from_rust_type(Irritants::new(slice_to_list(
1138 irritants,
1139 ))));
1140 Err(Exception(Value::from(Exception::from(CompoundCondition(
1141 conditions,
1142 )))))
1143}
1144
1145#[derive(Default, Trace)]
1147pub struct SourceCache {
1148 cache: HashMap<ByAddress<Arc<str>>, Vec<String>>,
1149}
1150
1151impl SourceCache {
1152 pub fn store(&mut self, file_name: Arc<str>, lines: Vec<String>) {
1153 self.cache.insert(ByAddress(file_name), lines);
1154 }
1155
1156 pub fn fetch(&mut self, file_name: &Arc<str>) -> Option<&[String]> {
1158 if !self.cache.contains_key(ByAddress::from_ref(file_name)) {
1159 let lines = std::fs::read_to_string(file_name.as_ref())
1160 .ok()?
1161 .lines()
1162 .map(|x| x.to_string())
1163 .collect::<Vec<_>>();
1164 self.cache.insert(ByAddress(file_name.clone()), lines);
1165 }
1166 self.cache
1167 .get(ByAddress::from_ref(file_name))
1168 .map(|lines| lines.as_ref())
1169 }
1170
1171 pub fn pretty_print_condition(
1172 &mut self,
1173 pe: &impl PrettyCondition,
1174 w: &mut impl fmt::Write,
1175 ) -> fmt::Result {
1176 let span = pe.span();
1177 let lines = self.fetch(&span.file);
1178 pe.pretty_print(w)?;
1179 print_lines_with_offense_from_span(&span, lines, w)
1180 }
1181}