use crate::{
gc::{Gc, GcInner, Trace},
lists::slice_to_list,
ports::{IoDecodingError, IoEncodingError, IoError, IoReadError, IoWriteError},
proc::{Application, ContBarrier, DynStackElem, FuncPtr, Procedure, pop_dyn_stack},
records::{Record, RecordTypeDescriptor, SchemeCompatible, rtd},
registry::{bridge, cps_bridge},
runtime::{Runtime, RuntimeInner},
symbols::Symbol,
syntax::{Identifier, Span, Syntax, parse::ParseSyntaxError},
value::{UnpackedValue, Value},
vectors::Vector,
};
use by_address::ByAddress;
use parking_lot::RwLock;
use scheme_rs_macros::runtime_fn;
use std::{collections::HashMap, convert::Infallible, fmt, ops::Range, sync::Arc};
pub use scheme_rs_macros::define_condition_type;
impl fmt::Display for Exception {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Value as fmt::Debug>::fmt(&self.0, f)
}
}
#[derive(Debug, Clone, Trace)]
pub struct Exception(pub Value);
impl Exception {
pub fn error(message: impl fmt::Display) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((Assertion::new(), Message::new(message.to_string()))),
)))
}
pub fn syntax(form: Syntax, subform: Option<Syntax>) -> Self {
Self(Value::from(Record::from_rust_type(SyntaxViolation::new(
form, subform,
))))
}
pub fn undefined(ident: Identifier) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Undefined::new(),
Message::new(format!("undefined variable {}", ident.sym)),
)),
)))
}
pub fn type_error(expected: &str, provided: &str) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!(
"expected value of type {expected}, provided {provided}"
)),
)),
)))
}
pub fn invalid_operator(provided: &str) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!(
"invalid operator: expected procedure, provided {provided}"
)),
)),
)))
}
pub fn invalid_index(index: usize, len: usize) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!(
"index {index} out of bounds for collection of size {len}"
)),
)),
)))
}
pub fn invalid_range(range: Range<usize>, len: usize) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!(
"range {range:?} out of bounds for collection of size {len}"
)),
)),
)))
}
pub fn wrong_num_of_unicode_chars(expected: usize, provided: usize) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!(
"expected {expected} unicode characters from transform, received {provided}"
)),
)),
)))
}
pub fn wrong_num_of_args(expected: usize, provided: usize) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!(
"expected {expected} arguments, provided {provided}"
)),
)),
)))
}
pub fn wrong_num_of_var_args(expected: Range<usize>, provided: usize) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!(
"expected {} to {} arguments, provided {provided}",
expected.start, expected.end
)),
)),
)))
}
pub fn implementation_restriction(msg: impl fmt::Display) -> Self {
Self(Value::from_rust_type(CompoundCondition::from((
Assertion::new(),
ImplementationRestriction::new(),
Message::new(msg),
))))
}
pub fn conversion_error(expected: &str, provided: &str) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!("cannot convert {provided} into {expected}")),
)),
)))
}
pub fn not_representable(value: &str, r#type: &str) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
Assertion::new(),
Message::new(format!("cannot represent '{value}' as {type}")),
)),
)))
}
pub fn io_error(message: impl fmt::Display) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((IoError::new(), Assertion::new(), Message::new(message))),
)))
}
pub fn io_read_error(message: impl fmt::Display) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((IoReadError::new(), Assertion::new(), Message::new(message))),
)))
}
pub fn io_write_error(message: impl fmt::Display) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((IoWriteError::new(), Assertion::new(), Message::new(message))),
)))
}
pub fn io_decoding_error(message: impl fmt::Display, port: Value) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
IoDecodingError::new(port),
Assertion::new(),
Message::new(message),
)),
)))
}
pub fn io_encoding_error(message: impl fmt::Display, port: Value, chr: char) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from((
IoEncodingError::new(port, chr),
Assertion::new(),
Message::new(message),
)),
)))
}
pub fn invalid_record_index(k: usize) -> Self {
Self::error(format!("invalid record index: {k}"))
}
pub fn add_condition(self, condition: impl SchemeCompatible) -> Self {
let mut conditions = if let Some(compound) = self.0.cast_to_rust_type::<CompoundCondition>()
{
compound.0.clone()
} else {
vec![self.0]
};
conditions.push(Value::from(Record::from_rust_type(condition)));
Self(Value::from(Record::from_rust_type(CompoundCondition(
conditions,
))))
}
pub fn simple_conditions(&self) -> Result<Vec<Value>, Exception> {
if self.0.cast_to_rust_type::<SimpleCondition>().is_some() {
Ok(vec![self.0.clone()])
} else if let Some(compound_condition) = self.0.cast_to_rust_type::<CompoundCondition>() {
Ok(compound_condition.0.clone())
} else {
Err(Exception::error("not a simple or compound condition"))
}
}
pub fn condition<T: SchemeCompatible>(&self) -> Result<Option<Gc<T>>, Exception> {
for condition in self.simple_conditions()?.into_iter() {
if let Some(condition) = condition.cast_to_rust_type::<T>() {
return Ok(Some(condition));
}
}
Ok(None)
}
pub fn pretty_print(
&self,
source_cache: &mut SourceCache,
f: &mut impl fmt::Write,
) -> fmt::Result {
let Ok(conditions) = self.simple_conditions() else {
return writeln!(
f,
"Exception occurred with a non-condition value: {:?}",
self.0
);
};
writeln!(f, "Uncaught exception:")?;
for condition in conditions.into_iter().rev() {
if let Some(message) = condition.cast_to_rust_type::<Message>() {
writeln!(f, " - Message: {}", message.message)?;
} else if let Some(syntax) = condition.cast_to_rust_type::<SyntaxViolation>() {
writeln!(f, " - Syntax error in form: {:?}", syntax.form)?;
source_cache.pretty_print_condition(syntax.as_ref(), f)?;
} else if let Some(trace) = condition.cast_to_rust_type::<StackTrace>() {
if !trace.trace.is_empty() {
writeln!(f, " - Trace:")?;
source_cache.pretty_print_condition(trace.as_ref(), f)?;
}
} else if condition.cast_to_rust_type::<Assertion>().is_some() {
writeln!(f, " - Assertion failed")?;
} else {
writeln!(f, " - Condition: {condition:?}")?;
}
}
Ok(())
}
}
impl From<&'_ Value> for Option<Exception> {
fn from(value: &'_ Value) -> Self {
if let UnpackedValue::Record(record) = &*value.unpacked_ref()
&& let rtd = record.rtd()
&& (RecordTypeDescriptor::is_subtype_of(&rtd, &SimpleCondition::rtd())
|| RecordTypeDescriptor::is_subtype_of(&rtd, &CompoundCondition::rtd()))
{
Some(Exception(value.clone()))
} else {
None
}
}
}
impl From<std::io::Error> for Exception {
fn from(value: std::io::Error) -> Self {
Self::from((IoError::new(), Message::new(format!("{value:?}"))))
}
}
impl From<SimpleCondition> for Exception {
fn from(simple: SimpleCondition) -> Self {
Self(Value::from(Record::from_rust_type(simple)))
}
}
impl From<Warning> for Exception {
fn from(warning: Warning) -> Self {
Self(Value::from(Record::from_rust_type(warning)))
}
}
impl From<Serious> for Exception {
fn from(serious: Serious) -> Self {
Self(Value::from(Record::from_rust_type(serious)))
}
}
impl From<Message> for Exception {
fn from(message: Message) -> Self {
Self(Value::from(Record::from_rust_type(message)))
}
}
impl From<Infallible> for Exception {
fn from(infallible: Infallible) -> Self {
match infallible {}
}
}
impl From<ParseSyntaxError> for Exception {
fn from(error: ParseSyntaxError) -> Self {
Self::from((Lexical::new(), Message::new(error)))
}
}
macro_rules! impl_into_condition_for {
($for:ty) => {
impl From<$for> for Exception {
fn from(e: $for) -> Self {
Self::error(e.to_string())
}
}
};
}
pub trait PrettyCondition {
fn span(&self) -> Span;
fn pretty_print(&self, _w: &mut impl fmt::Write) -> fmt::Result {
Ok(())
}
}
fn print_lines_with_offense_from_span(
span: &Span,
lines: Option<&[String]>,
w: &mut impl fmt::Write,
) -> fmt::Result {
let Some(lines) = lines else {
return Ok(());
};
writeln!(w, "--> {}:{}:{}:", span.file, span.line, span.column)?;
let start = span.line.saturating_sub(2);
let end = (span.line + 3).min(lines.len() as u32);
for i in start..end {
writeln!(w, "{:03} | {}", i + 1, lines[i as usize])?;
if i + 1 == span.line {
writeln!(w, " | {}~ here", " ".repeat(span.column))?; }
}
Ok(())
}
impl_into_condition_for!(std::num::TryFromIntError);
#[derive(Copy, Clone, Default, Trace)]
pub struct SimpleCondition;
impl SimpleCondition {
pub fn new() -> Self {
Self
}
}
impl SchemeCompatible for SimpleCondition {
fn rtd() -> Arc<RecordTypeDescriptor> {
rtd!(
lib: "(rnrs conditions (6))",
name: "&condition",
constructor: || Ok(SimpleCondition)
)
}
}
impl fmt::Debug for SimpleCondition {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
#[bridge(name = "condition?", lib = "(rnrs conditions (6))")]
pub fn condition_pred(obj: &Value) -> Result<Vec<Value>, Exception> {
let is_condition = obj.cast_to_rust_type::<SimpleCondition>().is_some()
|| obj.cast_to_rust_type::<CompoundCondition>().is_some();
Ok(vec![Value::from(is_condition)])
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Message,
scheme_name: "&message",
parent: SimpleCondition,
fields: {
message: String,
},
constructor: |message| {
Ok(Message { parent: Gc::new(SimpleCondition::new()), message: message.to_string() })
},
debug: |this, f| {
write!(f, " ")?;
this.message.fmt(f)
}
);
impl Message {
pub fn new(message: impl fmt::Display) -> Self {
Self {
parent: Gc::new(SimpleCondition::new()),
message: message.to_string(),
}
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Warning,
scheme_name: "&warning",
parent: SimpleCondition,
);
impl Warning {
pub fn new() -> Self {
Self {
parent: Gc::new(SimpleCondition::new()),
}
}
}
impl Default for Warning {
fn default() -> Self {
Self::new()
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Serious,
scheme_name: "&serious",
parent: SimpleCondition,
);
impl Serious {
pub fn new() -> Self {
Self {
parent: Gc::new(SimpleCondition::new()),
}
}
}
impl Default for Serious {
fn default() -> Self {
Self::new()
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: StackTrace,
scheme_name: "&trace",
parent: SimpleCondition,
fields: {
trace: Vector,
},
constructor: |trace| {
Ok(StackTrace {
parent: Gc::new(SimpleCondition::new()),
trace: trace.clone().try_into()?,
})
},
debug: |this, f| {
for trace in &*this.trace.0.vec.read() {
write!(f, " {trace}")?;
}
Ok(())
}
);
impl PrettyCondition for StackTrace {
fn span(&self) -> Span {
let first = self.trace.first().unwrap();
let Some(syntax) = first.cast_to_scheme_type::<Gc<Syntax>>() else {
return Span::default();
};
syntax.span().clone()
}
fn pretty_print(&self, w: &mut impl fmt::Write) -> fmt::Result {
for (i, trace) in self.trace.iter().enumerate() {
let Some(syntax) = trace.cast_to_scheme_type::<Gc<Syntax>>() else {
continue;
};
let span = syntax.span();
let func_name = syntax.as_ident().unwrap().symbol();
writeln!(w, "{:>6}: {func_name}:{span}", i + 1)?;
}
Ok(())
}
}
impl StackTrace {
pub fn new(trace: Vec<Value>) -> Self {
Self {
parent: Gc::new(SimpleCondition::new()),
trace: Vector::from(trace),
}
}
pub fn trace(&self) -> Vec<Syntax> {
todo!()
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Error,
scheme_name: "&error",
parent: Serious,
);
impl Error {
pub fn new() -> Self {
Self {
parent: Gc::new(Serious::new()),
}
}
}
impl Default for Error {
fn default() -> Self {
Self::new()
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: ImportError,
scheme_name: "&import",
parent: Error,
fields: {
library: String,
},
constructor: |lib| {
Ok(ImportError { parent: Gc::new(Error::new()), library: lib.to_string() })
},
debug: |this, f| {
write!(f, " library: {}", this.library)
}
);
impl ImportError {
pub fn new(library: String) -> Self {
Self {
parent: Gc::new(Error::new()),
library,
}
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Violation,
scheme_name: "&violation",
parent: Serious,
);
impl Violation {
pub fn new() -> Self {
Self {
parent: Gc::new(Serious::new()),
}
}
}
impl Default for Violation {
fn default() -> Self {
Self::new()
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Assertion,
scheme_name: "&assertion",
parent: Violation
);
impl Assertion {
pub fn new() -> Self {
Self {
parent: Gc::new(Violation::new()),
}
}
}
impl Default for Assertion {
fn default() -> Self {
Self::new()
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Irritants,
scheme_name: "&irritants",
parent: SimpleCondition,
fields: {
irritants: Value,
},
constructor: |irritants| {
Ok(Irritants { parent: Gc::new(SimpleCondition::new()), irritants })
},
debug: |this, f| {
write!(f, " irritants: {:?}", this.irritants)
}
);
impl Irritants {
pub fn new(irritants: Value) -> Self {
Irritants {
parent: Gc::new(SimpleCondition::new()),
irritants,
}
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Who,
scheme_name: "&who",
parent: SimpleCondition,
fields: {
who: Value,
},
constructor: |who| {
Ok(Who { parent: Gc::new(SimpleCondition::new()), who, })
},
debug: |this, f| {
write!(f, " who: {:?}", this.who)
}
);
impl Who {
pub fn new(who: Value) -> Self {
Who {
parent: Gc::new(SimpleCondition::new()),
who,
}
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: NonContinuable,
scheme_name: "&non-continuable",
parent: Violation,
);
impl Default for NonContinuable {
fn default() -> Self {
Self {
parent: Gc::new(Violation::new()),
}
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: ImplementationRestriction,
scheme_name: "&implementation-restriction",
parent: Violation,
);
impl ImplementationRestriction {
pub fn new() -> Self {
Self::default()
}
}
impl Default for ImplementationRestriction {
fn default() -> Self {
Self {
parent: Gc::new(Violation::new()),
}
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Lexical,
scheme_name: "&lexical",
parent: Violation,
);
impl Lexical {
pub fn new() -> Self {
Self {
parent: Gc::new(Violation::new()),
}
}
}
impl Default for Lexical {
fn default() -> Self {
Self::new()
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: SyntaxViolation,
scheme_name: "&syntax",
parent: Violation,
fields: {
form: Value,
subform: Option<Value>,
},
constructor: |form, subform| {
let subform = if subform.is_true() { Some(subform) } else { None };
Ok(SyntaxViolation { parent: Gc::new(Violation::new()), form, subform })
},
);
impl PrettyCondition for SyntaxViolation {
fn span(&self) -> Span {
self.subform
.as_ref()
.unwrap_or(&self.form)
.cast_to_scheme_type::<Gc<Syntax>>()
.unwrap()
.span()
.clone()
}
}
impl SyntaxViolation {
pub fn new(form: Syntax, subform: Option<Syntax>) -> Self {
Self {
parent: Gc::new(Violation::new()),
form: Value::from(form),
subform: subform.map(Value::from),
}
}
pub fn new_from_values(form: Value, subform: Option<Value>) -> Self {
Self {
parent: Gc::new(Violation::new()),
form,
subform,
}
}
}
define_condition_type!(
lib: "(rnrs conditions (6))",
rust_name: Undefined,
scheme_name: "&undefined",
parent: Violation
);
impl Undefined {
pub fn new() -> Self {
Self {
parent: Gc::new(Violation::new()),
}
}
}
impl Default for Undefined {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Trace)]
pub struct CompoundCondition(pub(crate) Vec<Value>);
impl SchemeCompatible for CompoundCondition {
fn rtd() -> Arc<RecordTypeDescriptor> {
rtd!(
lib: "(rnrs conditions (6))",
name: "compound-condition",
sealed: true,
opaque: true
)
}
}
impl fmt::Debug for CompoundCondition {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for cond in self.0.iter() {
write!(f, " ")?;
cond.fmt(f)?;
}
Ok(())
}
}
impl<T> From<T> for Exception
where
CompoundCondition: From<T>,
{
fn from(value: T) -> Self {
Self(Value::from(Record::from_rust_type(
CompoundCondition::from(value),
)))
}
}
impl<A, B> From<(A, B)> for CompoundCondition
where
A: SchemeCompatible,
B: SchemeCompatible,
{
fn from(value: (A, B)) -> Self {
Self(vec![
Value::from(Record::from_rust_type(value.0)),
Value::from(Record::from_rust_type(value.1)),
])
}
}
impl<A, B, C> From<(A, B, C)> for CompoundCondition
where
A: SchemeCompatible,
B: SchemeCompatible,
C: SchemeCompatible,
{
fn from(value: (A, B, C)) -> Self {
Self(vec![
Value::from(Record::from_rust_type(value.0)),
Value::from(Record::from_rust_type(value.1)),
Value::from(Record::from_rust_type(value.2)),
])
}
}
#[bridge(name = "condition", lib = "(rnrs conditions (6))")]
pub fn condition(conditions: &[Value]) -> Result<Vec<Value>, Exception> {
match conditions {
[simple_condition] => Ok(vec![simple_condition.clone()]),
conditions => Ok(vec![Value::from(Record::from_rust_type(
CompoundCondition(conditions.to_vec()),
))]),
}
}
#[bridge(name = "simple-conditions", lib = "(rnrs conditions (6))")]
pub fn simple_conditions(condition: &Value) -> Result<Vec<Value>, Exception> {
Ok(vec![slice_to_list(
&Exception(condition.clone()).simple_conditions()?,
)])
}
#[doc(hidden)]
#[cps_bridge(
def = "with-exception-handler handler thunk",
lib = "(rnrs exceptions (6))"
)]
pub fn with_exception_handler(
runtime: &Runtime,
_env: &[Value],
args: &[Value],
_rest_args: &[Value],
barrier: &mut ContBarrier,
k: Value,
) -> Result<Application, Exception> {
let [handler, thunk] = args else {
unreachable!();
};
let handler: Procedure = handler.clone().try_into()?;
let thunk: Procedure = thunk.clone().try_into()?;
barrier.push_dyn_stack(DynStackElem::ExceptionHandler(handler));
let k_proc: Procedure = k.clone().try_into().unwrap();
let (req_args, var) = k_proc.get_formals();
let k = barrier.new_k(
runtime.clone(),
vec![k.clone()],
pop_dyn_stack,
req_args,
var,
);
Ok(Application::new(thunk, vec![Value::from(k)]))
}
#[doc(hidden)]
#[cps_bridge(def = "raise obj", lib = "(rnrs exceptions (6))")]
pub fn raise_builtin(
runtime: &Runtime,
_env: &[Value],
args: &[Value],
_rest_args: &[Value],
barrier: &mut ContBarrier,
_k: Value,
) -> Result<Application, Exception> {
Ok(raise(runtime.clone(), args[0].clone(), barrier))
}
pub fn raise(runtime: Runtime, raised: Value, barrier: &mut ContBarrier) -> Application {
let raised = if let Some(condition) = raised.cast_to_scheme_type::<Exception>() {
let trace = barrier.current_marks(Symbol::intern("trace"));
Value::from(condition.add_condition(StackTrace::new(trace)))
} else {
raised
};
Application::new(
barrier.new_k(runtime, vec![raised], unwind_to_exception_handler, 0, false),
Vec::new(),
)
}
#[runtime_fn]
unsafe extern "C" fn raise_rt(
runtime: *mut GcInner<RwLock<RuntimeInner>>,
raised: *const (),
barrier: *mut ContBarrier,
) -> *mut Application {
unsafe {
let runtime = Runtime::from_raw_inc_rc(runtime);
let raised = Value::from_raw(raised);
Box::into_raw(Box::new(raise(
runtime,
raised,
barrier.as_mut().unwrap_unchecked(),
)))
}
}
unsafe extern "C" fn unwind_to_exception_handler(
runtime: *mut GcInner<RwLock<RuntimeInner>>,
env: *const Value,
_args: *const Value,
barrier: *mut ContBarrier,
) -> *mut Application {
unsafe {
let raised = env.as_ref().unwrap().clone();
let barrier = barrier.as_mut().unwrap_unchecked();
loop {
let app = match barrier.pop_dyn_stack() {
None => {
Application::halt_err(raised)
}
Some(DynStackElem::Winder(winder)) => {
Application::new(
winder.out_thunk,
vec![Value::from(barrier.new_k(
Runtime::from_raw_inc_rc(runtime),
vec![raised],
unwind_to_exception_handler,
0,
false,
))],
)
}
Some(DynStackElem::ExceptionHandler(handler)) => Application::new(
handler,
vec![
raised.clone(),
Value::from(barrier.new_k(
Runtime::from_raw_inc_rc(runtime),
vec![raised],
reraise_exception,
0,
true,
)),
],
),
_ => continue,
};
return Box::into_raw(Box::new(app));
}
}
}
unsafe extern "C" fn reraise_exception(
runtime: *mut GcInner<RwLock<RuntimeInner>>,
_env: *const Value,
_args: *const Value,
_barrier: *mut ContBarrier,
) -> *mut Application {
unsafe {
let runtime = Runtime(Gc::from_raw_inc_rc(runtime));
let exception = Value::from_rust_type(NonContinuable::default());
Box::into_raw(Box::new(Application::new(
Procedure::new(
runtime,
Vec::new(),
FuncPtr::Bridge(raise_builtin),
1,
false,
),
vec![exception, Value::undefined()],
)))
}
}
#[doc(hidden)]
#[cps_bridge(def = "raise-continuable obj", lib = "(rnrs exceptions (6))")]
pub fn raise_continuable(
_runtime: &Runtime,
_env: &[Value],
args: &[Value],
_rest_args: &[Value],
barrier: &mut ContBarrier,
k: Value,
) -> Result<Application, Exception> {
let [condition] = args else {
unreachable!();
};
let Some(handler) = barrier.current_exception_handler() else {
return Ok(Application::halt_err(condition.clone()));
};
Ok(Application::new(handler, vec![condition.clone(), k]))
}
#[bridge(name = "error", lib = "(rnrs base builtins (6))")]
pub fn error(who: &Value, message: &Value, irritants: &[Value]) -> Result<Vec<Value>, Exception> {
let mut conditions = Vec::new();
if who.is_true() {
conditions.push(Value::from_rust_type(Who::new(who.clone())));
}
conditions.push(Value::from_rust_type(Message::new(message)));
conditions.push(Value::from_rust_type(Irritants::new(slice_to_list(
irritants,
))));
Err(Exception(Value::from(Exception::from(CompoundCondition(
conditions,
)))))
}
#[bridge(name = "assertion-violation", lib = "(rnrs base builtins (6))")]
pub fn assertion_violation(
who: &Value,
message: &Value,
irritants: &[Value],
) -> Result<Vec<Value>, Exception> {
let mut conditions = Vec::new();
conditions.push(Value::from_rust_type(Assertion::new()));
if who.is_true() {
conditions.push(Value::from_rust_type(Who::new(who.clone())));
}
conditions.push(Value::from_rust_type(Message::new(message)));
conditions.push(Value::from_rust_type(Irritants::new(slice_to_list(
irritants,
))));
Err(Exception(Value::from(Exception::from(CompoundCondition(
conditions,
)))))
}
#[derive(Default, Trace)]
pub struct SourceCache {
cache: HashMap<ByAddress<Arc<str>>, Vec<String>>,
}
impl SourceCache {
pub fn store(&mut self, file_name: Arc<str>, lines: Vec<String>) {
self.cache.insert(ByAddress(file_name), lines);
}
pub fn fetch(&mut self, file_name: &Arc<str>) -> Option<&[String]> {
if !self.cache.contains_key(ByAddress::from_ref(file_name)) {
let lines = std::fs::read_to_string(file_name.as_ref())
.ok()?
.lines()
.map(|x| x.to_string())
.collect::<Vec<_>>();
self.cache.insert(ByAddress(file_name.clone()), lines);
}
self.cache
.get(ByAddress::from_ref(file_name))
.map(|lines| lines.as_ref())
}
pub fn pretty_print_condition(
&mut self,
pe: &impl PrettyCondition,
w: &mut impl fmt::Write,
) -> fmt::Result {
let span = pe.span();
let lines = self.fetch(&span.file);
pe.pretty_print(w)?;
print_lines_with_offense_from_span(&span, lines, w)
}
}