/ errors / src / emitter / mod.rs
mod.rs
  1  // Copyright (C) 2019-2025 ADnet Contributors
  2  // This file is part of the ADL library.
  3  
  4  // The ADL library is free software: you can redistribute it and/or modify
  5  // it under the terms of the GNU General Public License as published by
  6  // the Free Software Foundation, either version 3 of the License, or
  7  // (at your option) any later version.
  8  
  9  // The ADL library is distributed in the hope that it will be useful,
 10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 12  // GNU General Public License for more details.
 13  
 14  // You should have received a copy of the GNU General Public License
 15  // along with the ADL library. If not, see <https://www.gnu.org/licenses/>.
 16  
 17  use crate::AdlWarning;
 18  
 19  use super::AdlError;
 20  
 21  use itertools::Itertools as _;
 22  use std::{cell::RefCell, fmt, rc::Rc};
 23  
 24  /// Types that are sinks for compiler errors.
 25  pub trait Emitter {
 26      /// Emit the error `err`.
 27      fn emit_err(&mut self, err: AdlError);
 28  
 29      /// Tracks last emitted error.
 30      fn last_emitted_err_code(&self) -> Option<i32>;
 31  
 32      /// Emit the warning.
 33      fn emit_warning(&mut self, warning: AdlWarning);
 34  }
 35  
 36  /// A trivial `Emitter` using the standard error.
 37  pub struct StderrEmitter {
 38      /// Exit code of the last emitted error.
 39      last_error_code: Option<i32>,
 40  }
 41  
 42  impl Emitter for StderrEmitter {
 43      fn emit_err(&mut self, err: AdlError) {
 44          self.last_error_code = Some(err.exit_code());
 45          eprintln!("{err}");
 46      }
 47  
 48      fn last_emitted_err_code(&self) -> Option<i32> {
 49          self.last_error_code
 50      }
 51  
 52      fn emit_warning(&mut self, warning: AdlWarning) {
 53          eprintln!("{warning}");
 54      }
 55  }
 56  
 57  /// A buffer of `T`s.
 58  #[derive(Debug)]
 59  pub struct Buffer<T>(Vec<T>);
 60  
 61  impl<T> Default for Buffer<T> {
 62      fn default() -> Self {
 63          Self(Vec::new())
 64      }
 65  }
 66  
 67  impl<T> Buffer<T> {
 68      /// Push `x` to the buffer.
 69      pub fn push(&mut self, x: T) {
 70          self.0.push(x);
 71      }
 72  
 73      /// Extract the underlying list of Ts.
 74      pub fn into_inner(self) -> Vec<T> {
 75          self.0
 76      }
 77  
 78      /// Last entry to the buffer.
 79      pub fn last_entry(&self) -> Option<&T> {
 80          self.0.last()
 81      }
 82  
 83      // How many items in the buffer?
 84      pub fn len(&self) -> usize {
 85          self.0.len()
 86      }
 87  
 88      // Is the buffer empty?
 89      pub fn is_empty(&self) -> bool {
 90          self.0.is_empty()
 91      }
 92  }
 93  
 94  impl<T: fmt::Display> fmt::Display for Buffer<T> {
 95      fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 96          self.0.iter().format("").fmt(f)
 97      }
 98  }
 99  
100  /// A buffer of `AdlError`s.
101  pub type ErrBuffer = Buffer<AdlError>;
102  /// A buffer of `AdlWarning`s.
103  pub type WarningBuffer = Buffer<AdlWarning>;
104  
105  /// An `Emitter` that collects into a list.
106  #[derive(Default, Clone)]
107  pub struct BufferEmitter(Rc<RefCell<ErrBuffer>>, Rc<RefCell<WarningBuffer>>);
108  
109  impl BufferEmitter {
110      /// Returns a new buffered emitter.
111      pub fn new() -> Self {
112          BufferEmitter(<_>::default(), <_>::default())
113      }
114  
115      /// Extracts all the errors collected in this emitter.
116      pub fn extract_errs(&self) -> ErrBuffer {
117          self.0.take()
118      }
119  
120      /// Extracts all the errors collected in this emitter.
121      pub fn extract_warnings(&self) -> WarningBuffer {
122          self.1.take()
123      }
124  }
125  
126  impl Emitter for BufferEmitter {
127      fn emit_err(&mut self, err: AdlError) {
128          self.0.borrow_mut().push(err);
129      }
130  
131      fn last_emitted_err_code(&self) -> Option<i32> {
132          let temp = &*self.0.borrow();
133          temp.last_entry().map(|entry| entry.exit_code())
134      }
135  
136      fn emit_warning(&mut self, warning: AdlWarning) {
137          self.1.borrow_mut().push(warning);
138      }
139  }
140  
141  /// A handler deals with errors and other compiler output.
142  #[derive(Clone)]
143  pub struct Handler {
144      inner: Rc<RefCell<HandlerInner>>,
145  }
146  
147  pub struct HandlerInner {
148      /// Number of errors emitted thus far.
149      err_count: usize,
150      /// Number of warnings emitted thus far.
151      warn_count: usize,
152      /// The Emitter used.
153      emitter: Box<dyn Emitter>,
154  }
155  
156  impl Default for Handler {
157      fn default() -> Self {
158          Self::new(StderrEmitter { last_error_code: None })
159      }
160  }
161  
162  impl Handler {
163      /// Construct a `Handler` using the given `emitter`.
164      pub fn new<T: 'static + Emitter>(emitter: T) -> Self {
165          Handler {
166              inner: Rc::new(RefCell::new(HandlerInner { err_count: 0, warn_count: 0, emitter: Box::new(emitter) })),
167          }
168      }
169  
170      /// Construct a `Handler` that will append to `buf`.
171      pub fn new_with_buf() -> (Self, BufferEmitter) {
172          let buf = BufferEmitter::default();
173          let handler = Self::new(buf.clone());
174          (handler, buf)
175      }
176  
177      /// Runs `logic` provided a handler that collects all errors into the `String`,
178      /// or if there were none, returns some `T`.
179      pub fn with<T>(logic: impl for<'a> FnOnce(&'a Handler) -> Result<T, AdlError>) -> Result<T, ErrBuffer> {
180          let (handler, buf) = Handler::new_with_buf();
181          handler.extend_if_error(logic(&handler)).map_err(|_| buf.extract_errs())
182      }
183  
184      /// Gets the last emitted error's exit code.
185      fn last_emitted_err_code(&self) -> Option<i32> {
186          self.inner.borrow().emitter.last_emitted_err_code()
187      }
188  
189      /// Emit the error `err`.
190      pub fn emit_err(&self, err: impl Into<AdlError>) {
191          let mut inner = self.inner.borrow_mut();
192          inner.err_count = inner.err_count.saturating_add(1);
193          inner.emitter.emit_err(err.into());
194      }
195  
196      /// Emit the error `err`.
197      pub fn emit_warning(&self, warning: impl Into<AdlWarning>) {
198          let mut inner = self.inner.borrow_mut();
199          inner.warn_count = inner.warn_count.saturating_add(1);
200          inner.emitter.emit_warning(warning.into());
201      }
202  
203      /// The number of errors thus far.
204      pub fn err_count(&self) -> usize {
205          self.inner.borrow().err_count
206      }
207  
208      /// The number of warnings thus far.
209      pub fn warning_count(&self) -> usize {
210          self.inner.borrow().warn_count
211      }
212  
213      /// Did we have any errors thus far?
214      pub fn had_errors(&self) -> bool {
215          self.err_count() > 0
216      }
217  
218      /// Gets the last emitted error's exit code if it exists.
219      /// Then exits the program with it if it did exist.
220      pub fn last_err(&self) -> Result<(), AdlError> {
221          if let Some(code) = self.last_emitted_err_code() { Err(AdlError::LastErrorCode(code)) } else { Ok(()) }
222      }
223  
224      /// Extend handler with `error` given `res = Err(error)`.
225      #[allow(clippy::result_unit_err)]
226      pub fn extend_if_error<T>(&self, res: Result<T, AdlError>) -> Result<T, ()> {
227          match res {
228              Ok(_) if self.had_errors() => Err(()),
229              Ok(x) => Ok(x),
230              Err(e) => {
231                  self.emit_err(e);
232                  Err(())
233              }
234          }
235      }
236  }
237  
238  #[cfg(test)]
239  mod tests {
240      use super::*;
241      use crate::ParserError;
242      use adl_span::{Span, create_session_if_not_set_then};
243  
244      #[test]
245      fn fresh_no_errors() {
246          let handler = Handler::new(BufferEmitter::new());
247          assert_eq!(handler.err_count(), 0);
248          assert!(!handler.had_errors());
249      }
250  
251      #[test]
252      fn buffer_works() {
253          create_session_if_not_set_then(|_| {
254              let res: Result<(), _> = Handler::with(|h| {
255                  let s = Span::default();
256                  assert_eq!(h.err_count(), 0);
257                  h.emit_err(ParserError::invalid_import_list(s));
258                  assert_eq!(h.err_count(), 1);
259                  h.emit_err(ParserError::unexpected_eof(s));
260                  assert_eq!(h.err_count(), 2);
261                  Err(ParserError::spread_in_array_init(s).into())
262              });
263  
264              assert_eq!(res.unwrap_err().len(), 3);
265  
266              let res: Result<(), _> = Handler::with(|h| {
267                  let s = Span::default();
268                  h.emit_err(ParserError::invalid_import_list(s));
269                  h.emit_err(ParserError::unexpected_eof(s));
270                  Ok(())
271              });
272              assert_eq!(res.unwrap_err().len(), 2);
273  
274              Handler::with(|_| Ok(())).unwrap();
275          })
276      }
277  }