spade/
error_handling.rs

1use std::{rc::Rc, sync::RwLock};
2
3use spade_codespan_reporting::term::termcolor::Buffer;
4use spade_diagnostics::{diag_list::DiagList, CodeBundle, CompilationError, DiagHandler};
5
6pub struct ErrorHandler<'a> {
7    failed: bool,
8    failed_now: bool,
9    pub error_buffer: &'a mut Buffer,
10    pub diag_handler: DiagHandler,
11    /// Using a RW lock here is just a lazy way of managing the ownership of code to
12    /// be able to report errors even while modifying CodeBundle
13    pub code: Rc<RwLock<CodeBundle>>,
14}
15
16impl<'a> ErrorHandler<'a> {
17    pub fn new(
18        error_buffer: &'a mut Buffer,
19        diag_handler: DiagHandler,
20        code: Rc<RwLock<CodeBundle>>,
21    ) -> Self {
22        ErrorHandler {
23            failed: false,
24            failed_now: false,
25            error_buffer,
26            diag_handler,
27            code: Rc::clone(&code),
28        }
29    }
30
31    pub fn set_failed(&mut self) {
32        self.failed = true;
33        self.failed_now = true;
34    }
35
36    pub fn errors_are_recoverable(&mut self) {
37        self.failed_now = false;
38    }
39
40    pub fn failed(&self) -> bool {
41        self.failed
42    }
43
44    pub fn failed_now(&mut self) -> bool {
45        let result = self.failed_now;
46        self.failed_now = false;
47        result
48    }
49
50    pub fn report(&mut self, err: &impl CompilationError) {
51        self.failed = true;
52        self.failed_now = true;
53        err.report(
54            self.error_buffer,
55            &self.code.read().unwrap(),
56            &mut self.diag_handler,
57        );
58    }
59
60    pub fn drain_diag_list(&mut self, diag_list: &mut DiagList) {
61        for diag in diag_list.drain() {
62            self.report(&diag)
63        }
64    }
65}
66
67pub trait Reportable<T> {
68    /// Report the error, then discard the error, returning Some if it was Ok
69    fn or_report(self, errors: &mut ErrorHandler) -> Option<T>;
70
71    // Report the error and continue without modifying the result
72    fn report(self, errors: &mut ErrorHandler) -> Self;
73}
74
75impl<T, E> Reportable<T> for Result<T, E>
76where
77    E: CompilationError,
78{
79    fn report(self, errors: &mut ErrorHandler) -> Self {
80        if let Err(e) = &self {
81            errors.report(e);
82        }
83        self
84    }
85
86    fn or_report(self, errors: &mut ErrorHandler) -> Option<T> {
87        self.report(errors).ok()
88    }
89}