1use crate::{error::CompileError, warning::CompileWarning};
2use core::cell::RefCell;
3
4#[derive(Default, Debug, Clone)]
6pub struct Handler {
7 inner: RefCell<HandlerInner>,
10}
11
12#[derive(Default, Debug, Clone)]
15struct HandlerInner {
16 errors: Vec<CompileError>,
18 warnings: Vec<CompileWarning>,
20}
21
22impl Handler {
23 pub fn from_parts(errors: Vec<CompileError>, warnings: Vec<CompileWarning>) -> Self {
24 Self {
25 inner: RefCell::new(HandlerInner { errors, warnings }),
26 }
27 }
28
29 pub fn emit_err(&self, err: CompileError) -> ErrorEmitted {
31 self.inner.borrow_mut().errors.push(err);
32 ErrorEmitted { _priv: () }
33 }
34
35 pub fn cancel(&self) -> ErrorEmitted {
37 ErrorEmitted { _priv: () }
38 }
39
40 pub fn emit_warn(&self, warn: CompileWarning) {
42 self.inner.borrow_mut().warnings.push(warn);
43 }
44
45 pub fn has_errors(&self) -> bool {
46 !self.inner.borrow().errors.is_empty()
47 }
48
49 pub fn find_error(&self, f: impl FnMut(&&CompileError) -> bool) -> Option<CompileError> {
50 self.inner.borrow().errors.iter().find(f).cloned()
51 }
52
53 pub fn has_warnings(&self) -> bool {
54 !self.inner.borrow().warnings.is_empty()
55 }
56
57 pub fn scope<T>(
58 &self,
59 f: impl FnOnce(&Handler) -> Result<T, ErrorEmitted>,
60 ) -> Result<T, ErrorEmitted> {
61 let scoped_handler = Handler::default();
62 let closure_res = f(&scoped_handler);
63
64 match self.append(scoped_handler) {
65 Some(err) => Err(err),
66 None => closure_res,
67 }
68 }
69
70 pub fn consume(self) -> (Vec<CompileError>, Vec<CompileWarning>) {
72 let inner = self.inner.into_inner();
73 (inner.errors, inner.warnings)
74 }
75
76 pub fn append(&self, other: Handler) -> Option<ErrorEmitted> {
77 let other_has_errors = other.has_errors();
78
79 let (errors, warnings) = other.consume();
80 for warn in warnings {
81 self.emit_warn(warn);
82 }
83 for err in errors {
84 self.emit_err(err);
85 }
86
87 if other_has_errors {
88 Some(ErrorEmitted { _priv: () })
89 } else {
90 None
91 }
92 }
93
94 pub fn dedup(&self) {
95 let mut inner = self.inner.borrow_mut();
96 inner.errors = dedup_unsorted(inner.errors.clone());
97 inner.warnings = dedup_unsorted(inner.warnings.clone());
98 }
99
100 pub fn retain_err<F>(&self, f: F)
106 where
107 F: FnMut(&CompileError) -> bool,
108 {
109 self.inner.borrow_mut().errors.retain(f)
110 }
111
112 pub fn map_and_emit_errors_from(
115 &self,
116 other: Handler,
117 mut f: impl FnMut(CompileError) -> Option<CompileError>,
118 ) -> Result<(), ErrorEmitted> {
119 let mut emitted = Ok(());
120
121 let (errs, _) = other.consume();
122 for err in errs {
123 if let Some(err) = (f)(err) {
124 emitted = Err(self.emit_err(err));
125 }
126 }
127
128 emitted
129 }
130}
131
132#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
134pub struct ErrorEmitted {
135 _priv: (),
136}
137
138fn dedup_unsorted<T: PartialEq + std::hash::Hash + Clone + Eq>(mut data: Vec<T>) -> Vec<T> {
144 use std::collections::HashSet;
145
146 let mut seen = HashSet::new();
147 data.retain(|item| seen.insert(item.clone()));
148 data
149}