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 let had_errors = scoped_handler.has_errors();
64
65 self.append(scoped_handler);
66
67 if had_errors {
68 Err(ErrorEmitted { _priv: () })
69 } else {
70 closure_res
71 }
72 }
73
74 pub fn consume(self) -> (Vec<CompileError>, Vec<CompileWarning>) {
76 let inner = self.inner.into_inner();
77 (inner.errors, inner.warnings)
78 }
79
80 pub fn append(&self, other: Handler) {
81 let (errors, warnings) = other.consume();
82 for warn in warnings {
83 self.emit_warn(warn);
84 }
85 for err in errors {
86 self.emit_err(err);
87 }
88 }
89
90 pub fn dedup(&self) {
91 let mut inner = self.inner.borrow_mut();
92 inner.errors = dedup_unsorted(inner.errors.clone());
93 inner.warnings = dedup_unsorted(inner.warnings.clone());
94 }
95
96 pub fn retain_err<F>(&self, f: F)
102 where
103 F: FnMut(&CompileError) -> bool,
104 {
105 self.inner.borrow_mut().errors.retain(f)
106 }
107
108 pub fn map_and_emit_errors_from(
111 &self,
112 other: Handler,
113 mut f: impl FnMut(CompileError) -> Option<CompileError>,
114 ) -> Result<(), ErrorEmitted> {
115 let mut emitted = Ok(());
116
117 let (errs, _) = other.consume();
118 for err in errs {
119 if let Some(err) = (f)(err) {
120 emitted = Err(self.emit_err(err));
121 }
122 }
123
124 emitted
125 }
126}
127
128#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
130pub struct ErrorEmitted {
131 _priv: (),
132}
133
134fn dedup_unsorted<T: PartialEq + std::hash::Hash + Clone + Eq>(mut data: Vec<T>) -> Vec<T> {
140 use std::collections::HashSet;
141
142 let mut seen = HashSet::new();
143 data.retain(|item| seen.insert(item.clone()));
144 data
145}