sphinx/runtime/
errors.rs

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
62// traceback construction
63impl 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}