1use crate::{
2 error::CompileError,
3 warning::{CompileInfo, CompileWarning},
4};
5use core::cell::RefCell;
6
7#[derive(Default, Debug, Clone)]
9pub struct Handler {
10 inner: RefCell<HandlerDiagnostics>,
13}
14
15#[derive(Default, Debug, Clone)]
18struct HandlerDiagnostics {
19 errors: Vec<CompileError>,
21 warnings: Vec<CompileWarning>,
23 infos: Vec<CompileInfo>,
25}
26
27impl Handler {
28 pub fn from_parts(
29 errors: Vec<CompileError>,
30 warnings: Vec<CompileWarning>,
31 infos: Vec<CompileInfo>,
32 ) -> Self {
33 Self {
34 inner: RefCell::new(HandlerDiagnostics {
35 errors,
36 warnings,
37 infos,
38 }),
39 }
40 }
41
42 pub fn emit_err(&self, err: CompileError) -> ErrorEmitted {
44 self.inner.borrow_mut().errors.push(err);
45 ErrorEmitted { _priv: () }
46 }
47
48 pub fn cancel(&self) -> ErrorEmitted {
50 ErrorEmitted { _priv: () }
51 }
52
53 pub fn emit_warn(&self, warn: CompileWarning) {
55 self.inner.borrow_mut().warnings.push(warn);
56 }
57
58 pub fn emit_info(&self, info: CompileInfo) {
60 self.inner.borrow_mut().infos.push(info);
61 }
62
63 pub fn has_errors(&self) -> bool {
64 !self.inner.borrow().errors.is_empty()
65 }
66
67 pub fn find_error(&self, f: impl FnMut(&&CompileError) -> bool) -> Option<CompileError> {
68 self.inner.borrow().errors.iter().find(f).cloned()
69 }
70
71 pub fn has_warnings(&self) -> bool {
72 !self.inner.borrow().warnings.is_empty()
73 }
74
75 pub fn scope<T>(
76 &self,
77 f: impl FnOnce(&Handler) -> Result<T, ErrorEmitted>,
78 ) -> Result<T, ErrorEmitted> {
79 let scoped_handler = Handler::default();
80 let closure_res = f(&scoped_handler);
81
82 match self.append(scoped_handler) {
83 Some(err) => Err(err),
84 None => closure_res,
85 }
86 }
87
88 pub fn consume(self) -> (Vec<CompileError>, Vec<CompileWarning>, Vec<CompileInfo>) {
90 let inner = self.inner.into_inner();
91 (inner.errors, inner.warnings, inner.infos)
92 }
93
94 pub fn append(&self, other: Handler) -> Option<ErrorEmitted> {
95 let other_has_errors = other.has_errors();
96
97 let (errors, warnings, infos) = other.consume();
98 for warn in warnings {
99 self.emit_warn(warn);
100 }
101 for err in errors {
102 self.emit_err(err);
103 }
104 for inf in infos {
105 self.emit_info(inf);
106 }
107
108 if other_has_errors {
109 Some(ErrorEmitted { _priv: () })
110 } else {
111 None
112 }
113 }
114
115 pub fn dedup(&self) {
116 let mut inner = self.inner.borrow_mut();
117 inner.errors = dedup_unsorted(inner.errors.clone());
118 inner.warnings = dedup_unsorted(inner.warnings.clone());
119 }
120
121 pub fn retain_err<F>(&self, f: F)
127 where
128 F: FnMut(&CompileError) -> bool,
129 {
130 self.inner.borrow_mut().errors.retain(f)
131 }
132
133 pub fn map_and_emit_errors_from(
136 &self,
137 other: Handler,
138 mut f: impl FnMut(CompileError) -> Option<CompileError>,
139 ) -> Result<(), ErrorEmitted> {
140 let mut emitted = Ok(());
141
142 let (errs, _, _) = other.consume();
143 for err in errs {
144 if let Some(err) = (f)(err) {
145 emitted = Err(self.emit_err(err));
146 }
147 }
148
149 emitted
150 }
151}
152
153#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
155pub struct ErrorEmitted {
156 _priv: (),
157}
158
159fn dedup_unsorted<T: PartialEq + std::hash::Hash + Clone + Eq>(mut data: Vec<T>) -> Vec<T> {
165 use std::collections::HashSet;
166
167 let mut seen = HashSet::new();
168 data.retain(|item| seen.insert(item.clone()));
169 data
170}