1use std::sync::{Arc, RwLock};
2
3use spade_codespan_reporting::term::termcolor::Buffer;
4use spade_diagnostics::{
5 diag_list::DiagList, CodeBundle, CompilationError, DiagHandler, Diagnostic,
6};
7
8pub struct ErrorHandler<'a> {
9 failed: bool,
10 failed_now: bool,
11 pub error_buffer: &'a mut Buffer,
12 pub diag_handler: DiagHandler,
13 pub code: Arc<RwLock<CodeBundle>>,
16}
17
18impl<'a> ErrorHandler<'a> {
19 pub fn new(
20 error_buffer: &'a mut Buffer,
21 diag_handler: DiagHandler,
22 code: Arc<RwLock<CodeBundle>>,
23 ) -> Self {
24 ErrorHandler {
25 failed: false,
26 failed_now: false,
27 error_buffer,
28 diag_handler,
29 code: Arc::clone(&code),
30 }
31 }
32
33 pub fn set_failed(&mut self) {
34 self.failed = true;
35 self.failed_now = true;
36 }
37
38 pub fn errors_are_recoverable(&mut self) {
39 self.failed_now = false;
40 }
41
42 pub fn failed(&self) -> bool {
43 self.failed
44 }
45
46 pub fn failed_now(&mut self) -> bool {
47 let result = self.failed_now;
48 self.failed_now = false;
49 result
50 }
51
52 pub fn report(&mut self, err: &impl CompilationError) {
53 let is_fatal = match err.severity() {
54 spade_diagnostics::diagnostic::DiagnosticLevel::Bug => true,
55 spade_diagnostics::diagnostic::DiagnosticLevel::Error => true,
56 spade_diagnostics::diagnostic::DiagnosticLevel::Warning => false,
57 };
58 if is_fatal {
59 self.failed = true;
60 self.failed_now = true;
61 }
62 err.report(
63 self.error_buffer,
64 &self.code.read().unwrap(),
65 &mut self.diag_handler,
66 );
67 }
68
69 pub fn drain_diag_list(&mut self, diag_list: &mut DiagList) {
70 for diag in diag_list.drain() {
71 self.report(&diag)
72 }
73 }
74}
75
76pub trait Reportable<T> {
77 fn or_report(self, errors: &mut ErrorHandler) -> Option<T>;
79
80 fn report(self, errors: &mut ErrorHandler) -> Self;
82
83 fn or_do_report<'a>(self, errors: impl FnOnce() -> &'a mut ErrorHandler<'a>) -> Option<T>;
84}
85
86impl<T, E> Reportable<T> for Result<T, E>
87where
88 E: CompilationError,
89{
90 fn report(self, errors: &mut ErrorHandler) -> Self {
91 if let Err(e) = &self {
92 errors.report(e);
93 }
94 self
95 }
96
97 fn or_report(self, errors: &mut ErrorHandler) -> Option<T> {
98 self.report(errors).ok()
99 }
100
101 fn or_do_report<'a>(self, errors: impl FnOnce() -> &'a mut ErrorHandler<'a>) -> Option<T> {
102 if self.is_err() {
103 let errors = (errors)();
104 self.or_report(errors)
105 } else {
106 self.ok()
107 }
108 }
109}
110
111impl Reportable<()> for Diagnostic {
112 fn or_report(self, errors: &mut ErrorHandler) -> Option<()> {
113 errors.report(&self);
114 None
115 }
116
117 fn report(self, errors: &mut ErrorHandler) -> Self {
118 errors.report(&self);
119 self
120 }
121
122 fn or_do_report<'a>(self, errors: impl FnOnce() -> &'a mut ErrorHandler<'a>) -> Option<()> {
123 let errors = (errors)();
124 self.or_report(errors);
125 None
126 }
127}