1use std::{
5 error::Error,
6 fmt::{self, Debug, Display, Formatter},
7};
8
9use crate::{location::Location, utf8_parser::Input, util::write_pretty_list};
10
11pub type InputParseError<'a> = ErrorTree<Input<'a>>;
12
13#[derive(Debug)]
14pub struct _PrivateConstructor {
15 private: (),
16}
17
18#[derive(Debug)]
19pub enum InputParseErr<'a> {
20 Recoverable(InputParseError<'a>),
22 Fatal(InputParseError<'a>),
26}
27
28impl<'a> InputParseErr<'a> {
29 pub fn recoverable(e: InputParseError<'a>) -> Self {
30 InputParseErr::Recoverable(e)
31 }
32
33 pub fn fatal(e: InputParseError<'a>) -> Self {
34 InputParseErr::Fatal(e)
35 }
36
37 pub fn is_recoverable(&self) -> bool {
38 match self {
39 InputParseErr::Recoverable(_) => true,
40 InputParseErr::Fatal(_) => false,
41 }
42 }
43}
44
45impl<'a> Display for InputParseErr<'a> {
46 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
47 match self {
48 InputParseErr::Recoverable(e) => write!(f, "{}", e),
49 InputParseErr::Fatal(e) => write!(f, "{}", e),
50 }
51 }
52}
53
54#[non_exhaustive]
55#[derive(Debug, Copy, Clone, PartialEq, Eq)]
56pub enum Expectation {
57 Tag(&'static str),
59
60 Char(char),
62
63 OneOfChars(&'static str),
65
66 OneOfTags(&'static [&'static str]),
68
69 OneOfExpectations(&'static [Self]),
71
72 Alpha,
74
75 Digit,
77
78 DigitFirst,
80
81 HexDigit,
83
84 UnicodeHexSequence { got: u32 },
86
87 OctDigit,
89
90 AlphaNumeric,
92
93 Space,
95
96 RawStringEnd,
98
99 BlockCommentEnd,
101
102 Multispace,
104
105 CrLf,
107
108 Eof,
110
111 Something,
113}
114
115impl Display for Expectation {
116 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
117 match *self {
118 Expectation::Tag(tag) => write!(f, "{:?}", tag),
119 Expectation::Char(c) => write!(f, "{:?}", c),
120 Expectation::OneOfChars(one_of) => {
121 write_pretty_list(f, one_of.chars(), |f, c| write!(f, "{:?}", c))
122 }
123 Expectation::OneOfTags(one_of) => {
124 write_pretty_list(f, one_of.iter(), |f, c| write!(f, "{:?}", c))
125 }
126 Expectation::OneOfExpectations(one_of) => {
127 write_pretty_list(f, one_of.iter(), |f, c| write!(f, "{}", c))
128 }
129 Expectation::Alpha => write!(f, "an ascii letter"),
130 Expectation::Digit => write!(f, "an ascii digit"),
131 Expectation::DigitFirst => write!(f, "a non-zero ascii digit [1-9]"),
132 Expectation::HexDigit => write!(f, "a hexadecimal digit"),
133 Expectation::OctDigit => write!(f, "an octal digit"),
134 Expectation::AlphaNumeric => write!(f, "an ascii alphanumeric character"),
135 Expectation::Space => write!(f, "a space or tab"),
136 Expectation::Multispace => write!(f, "whitespace"),
137 Expectation::BlockCommentEnd => write!(f, "end of block comment (`*/`)"),
138 Expectation::Eof => write!(f, "eof"),
139 Expectation::CrLf => write!(f, "CRLF"),
140 Expectation::Something => write!(f, "not eof"),
141 Expectation::UnicodeHexSequence { got } => {
142 write!(f, "a valid unicode hex sequence (got 0x{:X})", got)
143 }
144 Expectation::RawStringEnd => write!(f, "closing raw string sequence"),
145 }
146 }
147}
148
149#[derive(Debug)]
153pub enum BaseErrorKind {
154 Expected(Expectation),
158
159 External(Box<dyn Error + Send + Sync + 'static>),
160}
161
162impl Display for BaseErrorKind {
163 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
164 match *self {
165 BaseErrorKind::Expected(expectation) => write!(f, "expected {}", expectation),
166 BaseErrorKind::External(ref err) => {
167 writeln!(f, "external error:")?;
168 write!(f, "{}", indent(err))
169 }
170 }
171 }
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
175pub enum StackContext {
176 Context(&'static str),
179}
180
181impl Display for StackContext {
182 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
183 match *self {
184 StackContext::Context(ctx) => write!(f, "could not match {:?}", ctx),
185 }
186 }
187}
188
189#[derive(Debug)]
190pub enum ErrorTree<I> {
191 Base {
194 location: I,
196
197 kind: BaseErrorKind,
199 },
200
201 Stack {
205 base: Box<Self>,
207
208 finalized: bool,
210
211 contexts: Vec<(I, StackContext)>,
213 },
214
215 Alt(Vec<Self>),
218 }
224
225impl<I> ErrorTree<I> {
226 pub(crate) fn max_location(&self) -> &I
227 where
228 I: Ord,
229 {
230 match self {
231 ErrorTree::Base { location, .. } => location,
232 ErrorTree::Stack { base, .. } => base.max_location(),
233 ErrorTree::Alt(v) => v.iter().map(ErrorTree::max_location).max().unwrap(),
234 }
235 }
236
237 pub(crate) fn expected(location: I, expectation: Expectation) -> Self {
238 ErrorTree::Base {
239 location,
240 kind: BaseErrorKind::Expected(expectation),
241 }
242 }
243
244 pub(crate) fn alt(first: Self, second: Self) -> Self {
245 match (first, second) {
246 (ErrorTree::Alt(mut alt), ErrorTree::Alt(alt2)) => {
247 alt.extend(alt2);
248 ErrorTree::Alt(alt)
249 }
250 (ErrorTree::Alt(mut alt), x) | (x, ErrorTree::Alt(mut alt)) => {
251 alt.push(x);
253 ErrorTree::Alt(alt)
254 }
255 (first, second) => ErrorTree::Alt(vec![first, second]),
256 }
257 }
258
259 fn map_locations_ref<T>(self, convert_location: &mut impl FnMut(I) -> T) -> ErrorTree<T> {
260 match self {
261 ErrorTree::Base { location, kind } => ErrorTree::Base {
262 location: convert_location(location),
263 kind,
264 },
265 ErrorTree::Stack {
266 base,
267 contexts,
268 finalized,
269 } => ErrorTree::Stack {
270 base: Box::new(base.map_locations_ref(convert_location)),
271 contexts: contexts
272 .into_iter()
273 .map(|(location, context)| (convert_location(location), context))
274 .collect(),
275 finalized,
276 },
277 ErrorTree::Alt(siblings) => ErrorTree::Alt(
278 siblings
279 .into_iter()
280 .map(|err| err.map_locations_ref(convert_location))
281 .collect(),
282 ),
283 }
284 }
285
286 pub(crate) fn map_locations<T>(self, mut convert_location: impl FnMut(I) -> T) -> ErrorTree<T> {
287 self.map_locations_ref(&mut convert_location)
288 }
289
290 pub(crate) fn calc_locations(self) -> ErrorTree<Location>
291 where
292 I: Into<Location>,
293 {
294 self.map_locations(|i| i.into())
295 }
296}
297
298impl<I: Display> Display for ErrorTree<I> {
299 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
300 match self {
301 ErrorTree::Base { location, kind } => write!(f, "{} at {:#}", kind, location),
302 ErrorTree::Stack {
303 contexts,
304 base,
305 finalized: _,
306 } => {
307 contexts.iter().rev().try_for_each(|(location, context)| {
308 writeln!(f, "{} at {:#} because", context, location)
309 })?;
310
311 write!(f, "{}", indent(base))
312 }
313 ErrorTree::Alt(siblings) => {
314 writeln!(f, "none of these matched:")?;
315 write!(
316 f,
317 "{}",
318 indent(
319 siblings
320 .iter()
321 .map(ToString::to_string)
322 .collect::<Vec<_>>()
323 .join(" or\n")
324 )
325 )
326 }
327 }
328 }
329}
330
331impl<I: Display + Debug> Error for ErrorTree<I> {}
332
333impl<I> ErrorTree<I> {
334 pub fn add_context(location: I, ctx: &'static str, final_context: bool, other: Self) -> Self {
336 let context = (location, StackContext::Context(ctx));
337
338 match other {
339 ErrorTree::Stack {
341 mut contexts,
342 base,
343 finalized: false,
344 } => {
345 contexts.push(context);
346 ErrorTree::Stack {
347 base,
348 contexts,
349 finalized: final_context,
350 }
351 }
352
353 ErrorTree::Stack {
354 finalized: true, ..
355 } => other,
356
357 base => ErrorTree::Stack {
359 base: Box::new(base),
360 contexts: vec![context],
361 finalized: final_context,
362 },
363 }
364 }
365}
366
367impl From<ErrorTree<Location>> for crate::error::Error {
368 fn from(e: ErrorTree<Location>) -> Self {
369 let max_location = *e.max_location();
370 let max_location: Location = max_location.into();
371
372 Self {
373 kind: crate::error::ErrorKind::ParseError(e.to_string()),
374 context: None,
375 }
376 .context_loc(
377 max_location,
378 Location {
379 line: max_location.line,
380 column: max_location.column + 1,
381 },
382 )
383 }
384}
385
386impl From<InputParseError<'_>> for crate::error::Error {
387 fn from(e: InputParseError) -> Self {
388 e.calc_locations().into()
389 }
390}
391
392pub struct Indented(String);
393
394pub fn indent(display: impl Display) -> Indented {
395 Indented(display.to_string())
396}
397
398impl Display for Indented {
399 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
400 let mut s = self.0.as_str();
401 let mut need_indent = true;
402 loop {
403 match need_indent {
404 false => match s.as_bytes().iter().position(|&b| b == b'\n') {
406 None => break f.write_str(s),
408
409 Some(len) => {
412 let (head, tail) = s.split_at(len + 1);
413 f.write_str(head)?;
414 need_indent = true;
415 s = tail;
416 }
417 },
418 true => match s.as_bytes().iter().position(|&b| b != b'\n') {
421 None => break f.write_str(s),
423
424 Some(len) => {
428 let (head, tail) = s.split_at(len);
429 f.write_str(head)?;
430 f.write_str(" ")?;
431 need_indent = false;
432 s = tail;
433 }
434 },
435 }
436 }
437 }
438}