use crate::parsing::Span;
use std::{error, fmt, result};
#[derive(Debug, Clone)]
pub struct Exception {
pub msg: String,
pub error: String,
pub backtrace: Vec<Span>,
}
impl Exception {
pub fn spanned(error: impl Into<String>, msg: impl Into<String>, span: &Span) -> Self {
Self {
msg: msg.into(),
error: error.into(),
backtrace: vec![span.clone()],
}
}
pub fn with_trace(
error: impl Into<String>,
msg: impl Into<String>,
backtrace: &[Span],
) -> Self {
Self {
msg: msg.into(),
error: error.into(),
backtrace: backtrace.to_vec(),
}
}
}
#[macro_export]
macro_rules! raise {
($state: expr, $kind: expr, $string: literal) => {
$crate::raise!($state, $kind, $string,)
};
($state: expr, $kind: expr, $msg: expr) => {
$crate::raise!($state, $kind, "{}", $msg)
};
($state: expr, $kind: expr, $string: literal, $($fmt_args: expr),*) => {
return Err(Exception::with_trace($kind, format!($string, $($fmt_args),*), &$state.backtrace))
};
}
impl fmt::Display for Exception {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}Error: {}", self.error, self.msg)?;
match self.backtrace.len() {
0 => (),
1 => {
write!(f, "\nat {}", self.backtrace[0])?;
}
_ => {
for span in self.backtrace.iter().skip(1).rev() {
write!(f, "\nat {span}")?;
}
}
}
Ok(())
}
}
impl error::Error for Exception {}
pub type Result<T> = result::Result<T, Exception>;