diff --git a/src/runtime2/error.rs b/src/runtime2/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..eb765640db1b8aed849b581f5b402c03c20e6105 --- /dev/null +++ b/src/runtime2/error.rs @@ -0,0 +1,70 @@ +use std::fmt::{Write, 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).unwrap(); + match &error.cause { + Some(cause) => { + writeln!(f, " ..."); + error = cause.as_ref() + }, + None => { + writeln!(f).unwrap(); + }, + } + } + } +} + +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),*))), + } + } + } +} \ No newline at end of file