error_manager/
lib.rs

1use core::any::Any;
2use core::fmt;
3use std::{borrow::Cow, io};
4
5use span::source::SourceMap;
6pub use span::{FilePosition, Span};
7
8/// An error sent to the [`ErrorManager`]
9///
10/// # Rationale for `Error: Any`
11/// [`ErrorManager`] stores errors on a `Box<dyn Error>`. This is
12/// convenient, beacause we can pass arround the same `ErrorManager` to
13/// multiple compilation stages, each one defining custom error types.
14/// Since they all implement [Error], they can be emitted to the same `ErrorManager`.
15///
16/// The problem comes when we need to get back the original Error type.
17/// For example, if we're testing the identification stage, we know it'll send
18/// `IdentificationError` to the `ErrorManager`.
19///
20/// If Error extends Any we can upcast the `&dyn Error`, to `&dyn Any`,
21/// and use `downcast_ref` to get the concrete error type
22///
23/// ## Example
24/// ```
25/// use error_manager::{Error, ErrorManager, Span};
26/// use core::any::Any;
27/// use core::fmt;
28///
29/// struct MyError(Span);
30///
31/// impl Error for MyError {
32///     fn get_span(&self) -> Span { self.0 }
33///     fn write_msg(&self, out: &mut dyn fmt::Write) -> fmt::Result {
34///         Ok(())
35///     }
36/// }
37///
38/// fn do_something(em: &mut ErrorManager) {
39///     // Something goes wrong...
40///     em.emit_error(MyError(Span { offset: 12, len: 6 }));
41/// }
42///
43/// let mut em = ErrorManager::new();
44/// do_something(&mut em);
45///
46/// // Now we test the collected errors
47/// let mut errors = em.errors().iter().map(|err| {
48///     let err: &dyn Any = &**err;
49///     err.downcast_ref::<MyError>().unwrap()
50/// });
51///
52/// let expected = errors.next().unwrap();
53/// assert_eq!(expected.0, Span { offset: 12, len: 6 });
54/// ```
55///
56/// This allows us to test errors more effectively.
57/// Another option would be to write the error we get from the `ErrorManager`
58/// into a String, and test that string.
59/// But that would require memory allocations, and more virtual calls.
60pub trait Error : Any {
61    fn get_span(&self) -> Span;
62    fn write_msg(&self, out: &mut dyn fmt::Write) -> fmt::Result;
63}
64
65pub struct StringError {
66    pub msg: Cow<'static, str>,
67    pub span: Span,
68}
69
70impl Error for StringError {
71    fn write_msg(&self, out: &mut dyn fmt::Write) -> fmt::Result {
72        write!(out, "{}", self.msg)
73    }
74
75    fn get_span(&self) -> Span { self.span }
76}
77
78/// Registers [errors](Error)
79pub struct ErrorManager {
80    errors: Vec<Box<dyn Error>>,
81    warnings: Vec<Box<dyn Error>>,
82}
83
84fn print_error(err: &dyn Error, src: &SourceMap, out: &mut dyn fmt::Write) -> fmt::Result {
85    let span = err.get_span();
86    let file = src.get_file_of_span(&span).unwrap();
87    let FilePosition {
88        start_line,
89        start_col,
90        ..
91    } = file.file_position(&span);
92    if let Some(fname) = file.filename() {
93        write!(out, "{fname}:")?;
94    }
95    write!(out, "{start_line}:{start_col}: ")?;
96    err.write_msg(out)?;
97    writeln!(out)
98}
99
100impl ErrorManager {
101    pub fn new() -> Self {
102        Self {
103            errors: Vec::new(),
104            warnings: Vec::new(),
105        }
106    }
107
108    pub fn emit_error(&mut self, err: impl Error + 'static) { self.errors.push(Box::new(err)); }
109
110    pub fn emit_warning(&mut self, err: impl Error + 'static) { self.warnings.push(Box::new(err)); }
111
112    pub fn n_errors(&self) -> usize { self.errors.len() }
113
114    pub fn has_errors(&self) -> bool { !self.errors.is_empty() }
115
116    pub fn errors(&self) -> &[Box<dyn Error>] { &self.errors }
117
118    /// Gets an iterator over the errors inside `self`, casting them to the
119    /// concrete error type specified
120    ///
121    /// This is **super** unsafe, and should only be used on tests
122    ///
123    /// # Panics
124    /// If if fails to downcast an error into `E`
125    pub fn errors_iterator_cast<E: Error>(&self) -> impl Iterator<Item = &E> {
126        self.errors.iter().map(|err| {
127            let err: &dyn Any = &**err;
128            err.downcast_ref::<E>().unwrap()
129        })
130    }
131
132    pub fn print_errors(&self, src: &SourceMap, out: &mut dyn io::Write) -> fmt::Result {
133        let mut buf = String::new();
134        for err in &self.errors {
135            out.write_all("ERROR ".as_bytes()).unwrap();
136            print_error(&**err, src, &mut buf)?;
137            out.write_all(buf.as_bytes()).unwrap();
138            buf.clear();
139        }
140        Ok(())
141    }
142
143    pub fn n_warnings(&self) -> usize { self.warnings.len() }
144
145    pub fn clear_warnings(&mut self) { self.warnings.clear(); }
146
147    pub fn print_warnings(&self, src: &SourceMap, out: &mut dyn io::Write) -> fmt::Result {
148        let mut buf = String::new();
149        for err in &self.warnings {
150            out.write_all("WARNING ".as_bytes()).unwrap();
151            print_error(&**err, src, &mut buf)?;
152            out.write_all(buf.as_bytes()).unwrap();
153            buf.clear();
154        }
155        Ok(())
156    }
157
158    pub fn merge(&mut self, other: &mut ErrorManager) {
159        self.errors.append(&mut other.errors);
160        self.warnings.append(&mut other.warnings);
161    }
162}
163
164impl Default for ErrorManager {
165    fn default() -> Self { Self::new() }
166}