use std::fmt::{Debug, Display, Formatter as FmtFormatter, Result as FmtResult}; /// Represents an unrecoverable runtime error that is reported to the user (for /// debugging purposes). Basically a human-readable message with its source /// location. The error is chainable. pub struct RtError { file: &'static str, line: u32, message: String, cause: Option>, } impl RtError { pub(crate) fn new(file: &'static str, line: u32, message: String) -> RtError { return RtError { file, line, message, cause: None, } } pub(crate) fn wrap(self, file: &'static str, line: u32, message: String) -> RtError { return RtError { file, line, message, cause: Some(Box::new(self)) } } } impl Display for RtError { fn fmt(&self, f: &mut FmtFormatter<'_>) -> FmtResult { let mut error = self; loop { write!(f, "[{}:{}] {}", self.file, self.line, self.message)?; match &error.cause { Some(cause) => { writeln!(f, " ...")?; error = cause.as_ref() }, None => { writeln!(f)?; }, } } } } impl Debug for RtError { fn fmt(&self, f: &mut FmtFormatter<'_>) -> FmtResult { return (self as &dyn Display).fmt(f); } } macro_rules! rt_error { ($fmt:expr) => { $crate::runtime2::error::RtError::new(file!(), line!(), $fmt.to_string()) }; ($fmt:expr, $($args:expr),*) => { $crate::runtime2::error::RtError::new(file!(), line!(), format!($fmt, $($args),*)) }; } macro_rules! rt_error_try { ($prev:expr, $($fmt_and_args:expr),*) => { { let result = $prev; match result { Ok(result) => result, Err(result) => return Err(result.wrap(file!(), line!(), format!($($fmt_and_args),*))), } } } }