1use core::fmt;
2use std::error::Error;
3
4use crate::utils;
5use crate::runtime::gc::GcTrace;
6use crate::runtime::strings::StringValue;
7use crate::debug::traceback::{TraceSite, Traceback};
8
9mod errorkinds;
10pub use errorkinds::ErrorKind;
11
12
13pub type ExecResult<T> = Result<T, Box<RuntimeError>>;
14
15
16#[derive(Debug, Clone)]
17pub struct RuntimeError {
18 kind: ErrorKind,
19 message: StringValue,
20 traceback: Vec<TraceSite>,
21 cause: Option<Box<RuntimeError>>,
22}
23
24unsafe impl GcTrace for RuntimeError {
25 fn trace(&self) {
26 self.message.trace();
27
28 for site in self.traceback.iter() {
29 site.trace();
30 }
31
32 if let Some(error) = self.cause.as_ref() {
33 error.trace();
34 }
35 }
36}
37
38impl RuntimeError {
39 pub fn new(kind: ErrorKind, message: StringValue) -> Self {
40 Self {
41 kind, message,
42 traceback: Vec::new(),
43 cause: None,
44 }
45 }
46
47 pub fn kind(&self) -> &ErrorKind { &self.kind }
48
49 pub fn traceback(&self) -> Traceback<'_> {
50 Traceback::build(self.traceback.iter())
51 }
52}
53
54impl Error for RuntimeError {
55 fn source(&self) -> Option<&(dyn Error + 'static)> {
56 self.cause.as_ref().map(
57 |error| &*error as &RuntimeError as &dyn Error
58 )
59 }
60}
61
62impl RuntimeError {
64 pub fn caused_by(mut self: Box<Self>, cause: Box<RuntimeError>) -> Box<Self> {
65 self.cause.replace(cause); self
66 }
67
68 pub fn extend_trace(mut self: Box<Self>, trace: impl Iterator<Item=TraceSite>) -> Box<Self> {
69 self.traceback.extend(trace); self
70 }
71
72 pub fn push_trace(mut self: Box<Self>, site: TraceSite) -> Box<Self> {
73 self.traceback.push(site); self
74 }
75}
76
77#[allow(clippy::useless_format)]
78impl fmt::Display for RuntimeError {
79 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
80 let message = format!("{}", self.message);
81 utils::format_error(fmt, "Runtime error", Some(&message), self.source())
82 }
83}