1use crate::source::Span;
6use std::fmt;
7
8#[macro_export]
10#[cfg(debug_assertions)]
11macro_rules! debugln {
12 ($($arg:tt)*) => { eprintln!("\x1B[34;1mdebug:\x1B[m {}", format!($($arg)*)); }
13}
14
15#[macro_export]
17#[cfg(not(debug_assertions))]
18macro_rules! debugln {
19 ($($arg:tt)*) => {};
20}
21
22#[derive(Debug)]
24pub struct Handler {}
25
26pub static DUMMY_HANDLER: Handler = Handler {};
27
28#[must_use]
30#[derive(Clone, Debug)]
31pub struct DiagnosticBuilder<'a> {
32 pub handler: &'a Handler,
33 pub message: String,
34}
35
36pub type DiagResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
39
40pub trait DiagEmitter {
42 fn emit(&self, diag: DiagBuilder2);
44}
45
46impl<'a, T> DiagEmitter for &'a T
47where
48 T: DiagEmitter + ?Sized,
49{
50 fn emit(&self, diag: DiagBuilder2) {
51 (*self).emit(diag)
52 }
53}
54
55pub trait EmitError {
61 type Output;
62 fn emit<C: DiagEmitter>(self, ctx: C) -> Self::Output;
63}
64
65impl<T, E: EmitError> EmitError for Result<T, E> {
66 type Output = Result<T, E::Output>;
67 fn emit<C: DiagEmitter>(self, ctx: C) -> Result<T, E::Output> {
68 self.map_err(move |e| e.emit(ctx))
69 }
70}
71
72#[must_use]
73#[derive(Clone, Debug)]
74pub struct DiagBuilder2 {
75 pub severity: Severity,
76 pub message: String,
77 pub segments: Vec<DiagSegment>,
78}
79
80#[derive(Clone, Debug)]
81pub enum DiagSegment {
82 Span(Span),
83 Note(String),
84}
85
86pub type DiagResult2<T> = Result<T, DiagBuilder2>;
89
90impl DiagBuilder2 {
91 pub fn new<S: Into<String>>(severity: Severity, message: S) -> DiagBuilder2 {
92 DiagBuilder2 {
93 severity: severity,
94 message: message.into(),
95 segments: Vec::new(),
96 }
97 }
98
99 pub fn bug<S: Into<String>>(message: S) -> DiagBuilder2 {
100 DiagBuilder2::new(Severity::Bug, message)
101 }
102
103 pub fn fatal<S: Into<String>>(message: S) -> DiagBuilder2 {
104 DiagBuilder2::new(Severity::Fatal, message)
105 }
106
107 pub fn error<S: Into<String>>(message: S) -> DiagBuilder2 {
108 DiagBuilder2::new(Severity::Error, message)
109 }
110
111 pub fn warning<S: Into<String>>(message: S) -> DiagBuilder2 {
112 DiagBuilder2::new(Severity::Warning, message)
113 }
114
115 pub fn note<S: Into<String>>(message: S) -> DiagBuilder2 {
116 DiagBuilder2::new(Severity::Note, message)
117 }
118
119 pub fn segment(self, segment: DiagSegment) -> DiagBuilder2 {
120 let mut segments = self.segments;
121 segments.push(segment);
122 DiagBuilder2 {
123 segments: segments,
124 ..self
125 }
126 }
127
128 pub fn span<S: Into<Span>>(self, span: S) -> DiagBuilder2 {
129 self.segment(DiagSegment::Span(span.into()))
130 }
131
132 pub fn add_note<S: Into<String>>(self, message: S) -> DiagBuilder2 {
133 self.segment(DiagSegment::Note(message.into()))
134 }
135
136 pub fn get_severity(&self) -> Severity {
137 self.severity
138 }
139
140 pub fn get_message(&self) -> &String {
141 &self.message
142 }
143
144 pub fn get_segments(&self) -> &[DiagSegment] {
145 &self.segments
146 }
147}
148
149#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
150pub enum Severity {
151 Note,
152 Warning,
153 Error,
154 Fatal,
155 Bug,
156}
157
158impl Severity {
159 pub fn to_str(self) -> &'static str {
160 match self {
161 Severity::Fatal => "fatal",
162 Severity::Error => "error",
163 Severity::Warning => "warning",
164 Severity::Note => "note",
165 Severity::Bug => "compiler bug",
166 }
167 }
168}
169
170impl fmt::Display for Severity {
171 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172 write!(f, "{}", self.to_str())
173 }
174}
175
176impl fmt::Display for DiagBuilder2 {
177 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
178 let mut colorcode = match self.get_severity() {
179 Severity::Bug | Severity::Fatal | Severity::Error => "\x1B[31;1m",
180 Severity::Warning => "\x1B[33;1m",
181 Severity::Note => "\x1B[36;1m",
182 };
183 write!(
184 f,
185 "{}{}:\x1B[m\x1B[1m {}\x1B[m\n",
186 colorcode,
187 self.get_severity(),
188 self.get_message()
189 )?;
190
191 for segment in &self.segments {
192 match *segment {
193 DiagSegment::Span(sp) => {
194 let c = sp.source.get_content();
195
196 let (line, col, line_offset) = sp.begin().human();
198
199 let text: String = c
201 .iter_from(line_offset)
202 .map(|x| x.1)
203 .take_while(|c| *c != '\n' && *c != '\r')
204 .collect();
205 write!(
206 f,
207 " --> {}:{}:{}-{}:\n",
208 sp.source.get_path(),
209 line,
210 col,
211 col + sp.extract().len()
212 )?;
213 write!(f, " | \n")?;
214 write!(f, " | ")?;
215 for (mut i, c) in text.char_indices() {
216 i += line_offset;
217 if sp.begin != sp.end {
218 if i == sp.begin {
219 write!(f, "{}", colorcode)?;
220 }
221 if i == sp.end {
222 write!(f, "\x1B[m")?;
223 }
224 }
225 match c {
226 '\t' => write!(f, " ")?,
227 c => write!(f, "{}", c)?,
228 }
229 }
230 write!(f, "\x1B[m\n")?;
231 write!(f, " | ")?;
232
233 let mut pd = ' ';
235 for (mut i, c) in text.char_indices() {
236 i += line_offset;
237 let d = if (i >= sp.begin && i < sp.end)
238 || (i == sp.begin && sp.begin == sp.end)
239 {
240 '^'
241 } else {
242 ' '
243 };
244 if d != pd {
245 write!(f, "{}", if d == ' ' { "\x1B[m" } else { colorcode })?;
246 }
247 pd = d;
248 match c {
249 '\t' => write!(f, "{}{}{}{}", d, d, d, d)?,
250 _ => write!(f, "{}", d)?,
251 }
252 }
253 write!(f, "\x1B[m\n")?;
254 colorcode = "\x1B[1m";
255 }
256 DiagSegment::Note(ref message) => {
257 write!(f, " = \x1B[1mnote:\x1B[m {}\n", message)?
258 }
259 }
260 }
261
262 if self.get_severity() == Severity::Bug {
263 write!(
264 f,
265 "\nYou have encountered a compiler bug. Sorry about that! We would appreciate if \
266 you open an issue [1] and describe how you triggered the bug, together with a \
267 minimal snippet of code to reproduce it. Thanks!\n"
268 )?;
269 write!(f, "[1]: https://github.com/fabianschuiki/moore\n")?;
270 }
271
272 Ok(())
273 }
274}