1use core::any::Any;
2use core::fmt;
3use std::{borrow::Cow, io};
4
5use span::source::SourceMap;
6pub use span::{FilePosition, Span};
7
8pub trait Error : Any {
61 fn get_span(&self) -> Span;
62 fn write_msg(&self, out: &mut dyn fmt::Write) -> fmt::Result;
63}
64
65pub struct StringError {
66 pub msg: Cow<'static, str>,
67 pub span: Span,
68}
69
70impl Error for StringError {
71 fn write_msg(&self, out: &mut dyn fmt::Write) -> fmt::Result {
72 write!(out, "{}", self.msg)
73 }
74
75 fn get_span(&self) -> Span { self.span }
76}
77
78pub struct ErrorManager {
80 errors: Vec<Box<dyn Error>>,
81 warnings: Vec<Box<dyn Error>>,
82}
83
84fn print_error(err: &dyn Error, src: &SourceMap, out: &mut dyn fmt::Write) -> fmt::Result {
85 let span = err.get_span();
86 let file = src.get_file_of_span(&span).unwrap();
87 let FilePosition {
88 start_line,
89 start_col,
90 ..
91 } = file.file_position(&span);
92 if let Some(fname) = file.filename() {
93 write!(out, "{fname}:")?;
94 }
95 write!(out, "{start_line}:{start_col}: ")?;
96 err.write_msg(out)?;
97 writeln!(out)
98}
99
100impl ErrorManager {
101 pub fn new() -> Self {
102 Self {
103 errors: Vec::new(),
104 warnings: Vec::new(),
105 }
106 }
107
108 pub fn emit_error(&mut self, err: impl Error + 'static) { self.errors.push(Box::new(err)); }
109
110 pub fn emit_warning(&mut self, err: impl Error + 'static) { self.warnings.push(Box::new(err)); }
111
112 pub fn n_errors(&self) -> usize { self.errors.len() }
113
114 pub fn has_errors(&self) -> bool { !self.errors.is_empty() }
115
116 pub fn errors(&self) -> &[Box<dyn Error>] { &self.errors }
117
118 pub fn errors_iterator_cast<E: Error>(&self) -> impl Iterator<Item = &E> {
126 self.errors.iter().map(|err| {
127 let err: &dyn Any = &**err;
128 err.downcast_ref::<E>().unwrap()
129 })
130 }
131
132 pub fn print_errors(&self, src: &SourceMap, out: &mut dyn io::Write) -> fmt::Result {
133 let mut buf = String::new();
134 for err in &self.errors {
135 out.write_all("ERROR ".as_bytes()).unwrap();
136 print_error(&**err, src, &mut buf)?;
137 out.write_all(buf.as_bytes()).unwrap();
138 buf.clear();
139 }
140 Ok(())
141 }
142
143 pub fn n_warnings(&self) -> usize { self.warnings.len() }
144
145 pub fn clear_warnings(&mut self) { self.warnings.clear(); }
146
147 pub fn print_warnings(&self, src: &SourceMap, out: &mut dyn io::Write) -> fmt::Result {
148 let mut buf = String::new();
149 for err in &self.warnings {
150 out.write_all("WARNING ".as_bytes()).unwrap();
151 print_error(&**err, src, &mut buf)?;
152 out.write_all(buf.as_bytes()).unwrap();
153 buf.clear();
154 }
155 Ok(())
156 }
157
158 pub fn merge(&mut self, other: &mut ErrorManager) {
159 self.errors.append(&mut other.errors);
160 self.warnings.append(&mut other.warnings);
161 }
162}
163
164impl Default for ErrorManager {
165 fn default() -> Self { Self::new() }
166}