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 }