nom_supreme/error.rs
1//! An error type, [`ErrorTree`], designed to retain much more useful
2//! information about parse failures than the built-in nom error types.
3//! Requires the `error` feature to be enabled.
4
5use std::{
6 error::Error,
7 fmt::{self, Debug, Display, Formatter, Write},
8};
9
10use indent_write::fmt::IndentWriter;
11use joinery::JoinableIterator;
12use nom::{
13 error::{ErrorKind as NomErrorKind, FromExternalError, ParseError},
14 ErrorConvert, InputLength,
15};
16
17use crate::{
18 context::ContextError,
19 final_parser::{ExtractContext, RecreateContext},
20 tag::TagError,
21};
22
23/// Enum for generic things that can be expected by nom parsers
24///
25/// Certain nom parsers (think [`digit1`], [`tag`], or [`space1`]) are "base
26/// level" in the sense that, rather than combining subparsers, they scan for a
27/// specific character or specific kind of character. This enum tracks the
28/// different kinds of things that can be expected by these base parses.
29///
30/// Printing an expectation via [`Display`] will only include the thing that
31/// was expected, in a form suitable for being prefixed with "expected" or
32/// suffixed with "was expected".
33///
34/// This enum is non-exhaustive; it is intended to represent everything parse
35/// errors where we know *specifically* what was expected. For instance,
36/// [`take_while`] cannot create an [`Expectation`], because it can't
37/// meaningfully report what its subparser is expecting.
38///
39/// [`digit1`]: nom::character::complete::digit1
40/// [`tag`]: crate::tag::complete::tag
41/// [`space1`]: nom::character::complete::space1
42/// [`take_while`]: nom::bytes::complete::take_while
43#[non_exhaustive]
44#[derive(Debug, Copy, Clone, PartialEq, Eq)]
45pub enum Expectation<T> {
46 /// A tag was expected.
47 Tag(T),
48
49 /// A specific character was expected.
50 Char(char),
51
52 /// An ASCII letter (`[a-zA-Z]`) was expected.
53 Alpha,
54
55 /// A decimal digit (`[0-9]`) was expected.
56 Digit,
57
58 /// A hexadecimal digit (`[0-9a-fA-F]`) was expected.
59 HexDigit,
60
61 /// An octal digit (`[0-7]`) was expected.
62 OctDigit,
63
64 /// An alphanumeric character (`[0-9a-zA-Z]`) was expected.
65 AlphaNumeric,
66
67 /// A space or tab was expected.
68 Space,
69
70 /// A space, tab, newline, or carriage return was expected.
71 Multispace,
72
73 /// `"\r\n"` was expected.
74 CrLf,
75
76 /// Eof was expected.
77 Eof,
78
79 /// Expected something; ie, not Eof.
80 Something,
81}
82
83impl<T: Debug> Display for Expectation<T> {
84 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
85 match *self {
86 Expectation::Tag(ref tag) => write!(f, "{:?}", tag),
87 Expectation::Char(c) => write!(f, "{:?}", c),
88 Expectation::Alpha => write!(f, "an ascii letter"),
89 Expectation::Digit => write!(f, "an ascii digit"),
90 Expectation::HexDigit => write!(f, "a hexadecimal digit"),
91 Expectation::OctDigit => write!(f, "an octal digit"),
92 Expectation::AlphaNumeric => write!(f, "an ascii alphanumeric character"),
93 Expectation::Space => write!(f, "a space or tab"),
94 Expectation::Multispace => write!(f, "whitespace"),
95 Expectation::Eof => write!(f, "eof"),
96 Expectation::CrLf => write!(f, "CRLF"),
97 Expectation::Something => write!(f, "not eof"),
98 }
99 }
100}
101
102/// These are the different specific things that can go wrong at a particular
103/// location during a nom parse. Many of these are collected into an
104/// [`ErrorTree`].
105///
106/// - `T` is the tag type, such as &'static str.
107/// - `E` is the external error type, such as `Box<dyn Error>`.
108#[derive(Debug)]
109pub enum BaseErrorKind<T, E> {
110 /// Something specific was expected, such as a specific
111 /// [character][Expectation::Char] or any [digit](Expectation::Digit).
112 /// See [`Expectation`] for details.
113 Expected(Expectation<T>),
114
115 /// A nom parser failed.
116 Kind(NomErrorKind),
117
118 /// An error outside of nom occurred during parsing; for instance, as a
119 /// result of an error during [`map_res`].
120 ///
121 /// [`map_res`]: crate::parser_ext::ParserExt::map_res
122 // Design note: I've gone back and forth on whether or not to exclude the
123 // ErrorKind from this variant. Right now I'm doing so, because it seems
124 // like in practice it's *always* MapRes.
125 External(E),
126}
127
128impl<T: Debug, E: Display> Display for BaseErrorKind<T, E> {
129 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
130 match *self {
131 BaseErrorKind::Expected(ref expectation) => write!(f, "expected {}", expectation),
132 BaseErrorKind::External(ref err) => {
133 writeln!(f, "external error:")?;
134 let mut f = IndentWriter::new(" ", f);
135 write!(f, "{}", err)
136 }
137 BaseErrorKind::Kind(kind) => write!(f, "error in {:?}", kind),
138 }
139 }
140}
141
142/// Context that can appear in a [stack][GenericErrorTree::Stack], above a base
143/// [`ErrorTree`]. Stack contexts are attached by parser combinators to errors
144/// from their subparsers during stack unwinding.
145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum StackContext<C> {
147 /// A nom combinator attached an [`ErrorKind`][NomErrorKind] as context
148 /// for a subparser error.
149 Kind(NomErrorKind),
150
151 /// The [`context`][crate::parser_ext::ParserExt::context] combinator
152 /// attached a message as context for a subparser error.
153 Context(C),
154}
155
156impl<C: Debug> Display for StackContext<C> {
157 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
158 match *self {
159 StackContext::Kind(kind) => write!(f, "while parsing {:?}", kind),
160 StackContext::Context(ref ctx) => write!(f, "in section {:?}", ctx),
161 }
162 }
163}
164
165/// A comprehensive tree of nom errors describing a parse failure.
166///
167/// This Error type is designed to be [`VerboseError`]`++`. While
168/// [`VerboseError`] can represent a *stack* of errors, this type can represent
169/// a full tree. In addition to representing a particular specific parse error,
170/// it can also represent a stack of nested error contexts (for instance, as
171/// provided by [`context`][crate::ParserExt::context]), or a list of
172/// alternatives that were all tried individually by [`alt`][nom::branch::alt]
173/// and all failed.
174///
175/// In general, the design goal for this type is to discard as little useful
176/// information as possible. That being said, many [`ErrorKind`] variants add
177/// very little useful contextual information to error traces; for example,
178/// [`ErrorKind::Alt`] doesn't add any interesting context to an
179/// [`ErrorTree::Alt`], and its presence in a stack precludes merging together
180/// adjacent sets of [`ErrorTree::Alt`] siblings.
181///
182/// # Examples
183///
184/// ## Base parser errors
185///
186/// An `ErrorTree::Base` is an error that occurred at the "bottom" of the stack,
187/// from a parser looking for 1 specific kind of thing.
188///
189/// ```rust
190/// use cool_asserts::assert_matches;
191/// use nom::{Parser, Err};
192/// use nom::character::complete::{digit1, char};
193/// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation};
194/// use nom_supreme::parser_ext::ParserExt;
195///
196/// let err: Err<ErrorTree<&str>> = digit1.parse("abc").unwrap_err();
197///
198/// assert_matches!(err, Err::Error(ErrorTree::Base{
199/// location: "abc",
200/// kind: BaseErrorKind::Expected(Expectation::Digit),
201/// }));
202///
203/// let err: Err<ErrorTree<&str>> = char('a').and(char('b')).parse("acb").unwrap_err();
204///
205/// assert_matches!(err, Err::Error(ErrorTree::Base{
206/// location: "cb",
207/// kind: BaseErrorKind::Expected(Expectation::Char('b')),
208/// }));
209/// ```
210///
211/// ## Stacks
212///
213/// An [`ErrorTree::Stack`] is created when a parser combinator—typically
214/// [`context`]—attaches additional error context to a subparser error. It can
215/// have any [`ErrorTree`] at the base of the stack.
216///
217/// ```rust
218/// use cool_asserts::assert_matches;
219/// use nom::{Parser, Err};
220/// use nom::character::complete::{alpha1, space1, char,};
221/// use nom::sequence::{separated_pair, delimited};
222/// use nom_supreme::parser_ext::ParserExt;
223/// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation};
224///
225/// // Parse a single identifier, defined as just a string of letters.
226/// let identifier = alpha1.context("identifier");
227///
228/// // Parse a pair of identifiers, separated by whitespace
229/// let identifier_pair = separated_pair(identifier, space1, identifier)
230/// .context("identifier pair");
231///
232/// // Parse a pair of identifiers in parenthesis.
233/// let mut parenthesized = delimited(char('('), identifier_pair, char(')'))
234/// .context("parenthesized");
235///
236/// let err: Err<ErrorTree<&str>> = parenthesized.parse("(abc 123)").unwrap_err();
237///
238/// assert_matches!(err, Err::Error(ErrorTree::Stack {
239/// base,
240/// contexts,
241/// }) => {
242/// assert_matches!(*base, ErrorTree::Base {
243/// location: "123)",
244/// kind: BaseErrorKind::Expected(Expectation::Alpha)
245/// });
246///
247/// assert_eq!(contexts, [
248/// ("123)", StackContext::Context("identifier")),
249/// ("abc 123)", StackContext::Context("identifier pair")),
250/// ("(abc 123)", StackContext::Context("parenthesized")),
251/// ]);
252/// });
253/// ```
254///
255/// ## Alternatives
256///
257/// An [`ErrorTree::Alt`] is created when a series of parsers are all tried,
258/// and all of them fail. Most commonly this will happen via the
259/// [`alt`][nom::branch::alt] combinator or the equivalent [`.or`] postfix
260/// combinator. When all of these subparsers fail, their errors (each
261/// individually their own `ErrorTree`) are aggregated into an
262/// [`ErrorTree::Alt`], indicating that "any one of these things were
263/// expected."
264///
265/// ```rust
266/// use cool_asserts::assert_matches;
267/// use nom::{Parser, Err};
268/// use nom::branch::alt;
269/// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation};
270/// use nom_supreme::parser_ext::ParserExt;
271/// use nom_supreme::tag::complete::tag;
272///
273/// let parse_bool = alt((
274/// tag("true").value(true),
275/// tag("false").value(false),
276/// ));
277///
278/// let mut parse_null_bool = alt((
279/// parse_bool.map(Some),
280/// tag("null").value(None),
281/// ));
282///
283/// assert_eq!(parse_null_bool.parse("true").unwrap(), ("", Some(true)));
284/// assert_eq!(parse_null_bool.parse("false").unwrap(), ("", Some(false)));
285/// assert_eq!(parse_null_bool.parse("null").unwrap(), ("", None));
286///
287/// let err: Err<ErrorTree<&str>> = parse_null_bool.parse("123").unwrap_err();
288///
289/// // This error communicates to the caller that any one of "true", "false",
290/// // or "null" was expected at that location.
291/// assert_matches!(err, Err::Error(ErrorTree::Alt(choices)) => {
292/// assert_matches!(choices.as_slice(), [
293/// ErrorTree::Base {
294/// location: "123",
295/// kind: BaseErrorKind::Expected(Expectation::Tag("true"))},
296/// ErrorTree::Base {
297/// location: "123",
298/// kind: BaseErrorKind::Expected(Expectation::Tag("false"))},
299/// ErrorTree::Base {
300/// location: "123",
301/// kind: BaseErrorKind::Expected(Expectation::Tag("null"))},
302/// ])
303/// });
304/// ```
305///
306/// ## Contexts and Alternatives
307///
308/// Because [`Stack`] and [`Alt`] recursively contain [`ErrorTree`] errors from
309/// subparsers, they can be can combined to create error trees of arbitrary
310/// complexity.
311///
312/// ```rust
313/// use cool_asserts::assert_matches;
314/// use nom::{Parser, Err};
315/// use nom::branch::alt;
316/// use nom_supreme::error::{ErrorTree, BaseErrorKind, StackContext, Expectation};
317/// use nom_supreme::parser_ext::ParserExt;
318/// use nom_supreme::tag::complete::tag;
319///
320/// let parse_bool = alt((
321/// tag("true").value(true),
322/// tag("false").value(false),
323/// )).context("bool");
324///
325/// let mut parse_null_bool = alt((
326/// parse_bool.map(Some),
327/// tag("null").value(None).context("null"),
328/// )).context("null or bool");
329///
330/// assert_eq!(parse_null_bool.parse("true").unwrap(), ("", Some(true)));
331/// assert_eq!(parse_null_bool.parse("false").unwrap(), ("", Some(false)));
332/// assert_eq!(parse_null_bool.parse("null").unwrap(), ("", None));
333///
334/// let err: Err<ErrorTree<&str>> = parse_null_bool.parse("123").unwrap_err();
335///
336/// assert_matches!(err, Err::Error(ErrorTree::Stack{base, contexts}) => {
337/// assert_eq!(contexts, [("123", StackContext::Context("null or bool"))]);
338/// assert_matches!(*base, ErrorTree::Alt(choices) => {
339/// assert_matches!(&choices[0], ErrorTree::Stack{base, contexts} => {
340/// assert_eq!(contexts, &[("123", StackContext::Context("bool"))]);
341/// assert_matches!(&**base, ErrorTree::Alt(choices) => {
342/// assert_matches!(&choices[0], ErrorTree::Base {
343/// location: "123",
344/// kind: BaseErrorKind::Expected(Expectation::Tag("true"))
345/// });
346/// assert_matches!(&choices[1], ErrorTree::Base {
347/// location: "123",
348/// kind: BaseErrorKind::Expected(Expectation::Tag("false"))
349/// });
350/// });
351/// });
352/// assert_matches!(&choices[1], ErrorTree::Stack{base, contexts} => {
353/// assert_eq!(contexts, &[("123", StackContext::Context("null"))]);
354/// assert_matches!(&**base, ErrorTree::Base {
355/// location: "123",
356/// kind: BaseErrorKind::Expected(Expectation::Tag("null"))
357/// });
358/// });
359/// });
360/// });
361/// ```
362///
363/// # Display formatting
364///
365/// TODO WRITE THIS SECTION
366///
367/// [`.or`]: nom::Parser::or
368/// [`Alt`]: GenericErrorTree::Alt
369/// [`context`]: nom::error::context
370/// [`ErrorKind::Alt`]: nom::error::ErrorKind::Alt
371/// [`ErrorKind`]: nom::error::ErrorKind
372/// [`ErrorTree::Alt`]: GenericErrorTree::Alt
373/// [`ErrorTree::Base`]: GenericErrorTree::Base
374/// [`ErrorTree::Stack`]: GenericErrorTree::Stack
375/// [`Stack`]: GenericErrorTree::Stack
376/// [`VerboseError`]: nom::error::VerboseError
377pub type ErrorTree<I> =
378 GenericErrorTree<I, &'static str, &'static str, Box<dyn Error + Send + Sync + 'static>>;
379
380/// Generic version of [`ErrorTree`], which allows for arbitrary `Tag`, `Context`,
381/// and `ExternalError` types. See [`ErrorTree`] for more extensive docs and
382/// examples.
383///
384/// - `Tag` is typically something like `&'static str` or `&'static [u8]`.
385/// - `Context` is typically `&'static str`, and it must be in order to
386/// interoperate with nom's [`context`][nom::error::context] combinator.
387/// `nom-supreme` provides a more generic [`.context`][crate::ParserExt::context]
388/// combinator that allows for any kind of context to be attached to an error.
389/// - `Error` can usually be nothing, as it's unusual for nom parsers to
390/// require external errors. `Box<dyn Error + Send + Sync + 'static>` is
391/// a common catch-all.
392#[derive(Debug)]
393pub enum GenericErrorTree<Location, Tag, Context, ExternalError> {
394 /// A specific error event at a specific location. Often this will indicate
395 /// that something like a tag or character was expected at that location.
396 Base {
397 /// The location of this error in the input
398 location: Location,
399
400 /// The specific error that occurred
401 kind: BaseErrorKind<Tag, ExternalError>,
402 },
403
404 /// A stack indicates a chain of error contexts was provided. The stack
405 /// should be read "backwards"; that is, errors *earlier* in the `Vec`
406 /// occurred "sooner" (deeper in the call stack).
407 Stack {
408 /// The original error
409 base: Box<Self>,
410
411 /// The stack of contexts attached to that error
412 contexts: Vec<(Location, StackContext<Context>)>,
413 },
414
415 /// A series of parsers were tried at the same location (for instance, via
416 /// the [`alt`](nom::branch::alt) combinator) and all of them failed. All
417 /// of the errors in this set are "siblings".
418 Alt(Vec<Self>),
419 // TODO: in a future version of nom-supreme, elaborate on the specific
420 // type combinations here. For instance:
421 // - Alt can only contain Stack or Base
422 // - Stack has a single Base or Alt, followed by a series of contexts
423 // (Context or Kind)
424}
425
426impl<I, T, C, E> GenericErrorTree<I, T, C, E> {
427 /// Helper for `map_locations`. Because it operates recursively, this
428 /// method uses an `&mut impl FnMut`, which can be reborrowed.
429 fn map_locations_ref<I2>(
430 self,
431 convert_location: &mut impl FnMut(I) -> I2,
432 ) -> GenericErrorTree<I2, T, C, E> {
433 // TODO: does the recursive nature of this function present a potential
434 // security risk? Consider replacing it with a breadth-first algorithm,
435 // or capping the maximum recursion depth. Note, though, that recursion
436 // only happens when alternating between different *kinds* of
437 // ErrorTree; nested groups of Alt or Stack are flattened.
438 match self {
439 GenericErrorTree::Base { location, kind } => GenericErrorTree::Base {
440 location: convert_location(location),
441 kind,
442 },
443 GenericErrorTree::Stack { base, contexts } => GenericErrorTree::Stack {
444 base: Box::new(base.map_locations_ref(convert_location)),
445 contexts: contexts
446 .into_iter()
447 .map(|(location, context)| (convert_location(location), context))
448 .collect(),
449 },
450 GenericErrorTree::Alt(siblings) => GenericErrorTree::Alt(
451 siblings
452 .into_iter()
453 .map(|err| err.map_locations_ref(convert_location))
454 .collect(),
455 ),
456 }
457 }
458
459 /// Convert all of the locations in this error using some kind of mapping
460 /// function. This is intended to help add additional context that may not
461 /// have been available when the nom parsers were running, such as line
462 /// and column numbers.
463 pub fn map_locations<I2>(
464 self,
465 mut convert_location: impl FnMut(I) -> I2,
466 ) -> GenericErrorTree<I2, T, C, E> {
467 self.map_locations_ref(&mut convert_location)
468 }
469}
470
471impl<I: Display, T: Debug, C: Debug, E: Display> Display for GenericErrorTree<I, T, C, E> {
472 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
473 match self {
474 GenericErrorTree::Base { location, kind } => write!(f, "{} at {:#}", kind, location),
475 GenericErrorTree::Stack { contexts, base } => {
476 contexts.iter().rev().try_for_each(|(location, context)| {
477 writeln!(f, "{} at {:#},", context, location)
478 })?;
479
480 base.fmt(f)
481 }
482 GenericErrorTree::Alt(siblings) => {
483 writeln!(f, "one of:")?;
484 let mut f = IndentWriter::new(" ", f);
485 write!(f, "{}", siblings.iter().join_with(", or\n"))
486 }
487 }
488 }
489}
490
491impl<I: Display + Debug, T: Debug, C: Debug, E: Display + Debug> Error
492 for GenericErrorTree<I, T, C, E>
493{
494}
495
496impl<I: InputLength, T, C, E> ParseError<I> for GenericErrorTree<I, T, C, E> {
497 /// Create a new error at the given position. Interpret `kind` as an
498 /// [`Expectation`] if possible, to give a more informative error message.
499 fn from_error_kind(location: I, kind: NomErrorKind) -> Self {
500 let kind = match kind {
501 NomErrorKind::Alpha => BaseErrorKind::Expected(Expectation::Alpha),
502 NomErrorKind::Digit => BaseErrorKind::Expected(Expectation::Digit),
503 NomErrorKind::HexDigit => BaseErrorKind::Expected(Expectation::HexDigit),
504 NomErrorKind::OctDigit => BaseErrorKind::Expected(Expectation::OctDigit),
505 NomErrorKind::AlphaNumeric => BaseErrorKind::Expected(Expectation::AlphaNumeric),
506 NomErrorKind::Space => BaseErrorKind::Expected(Expectation::Space),
507 NomErrorKind::MultiSpace => BaseErrorKind::Expected(Expectation::Multispace),
508 NomErrorKind::CrLf => BaseErrorKind::Expected(Expectation::CrLf),
509
510 // Problem: ErrorKind::Eof is used interchangeably by various nom
511 // parsers to mean either "expected Eof" or "expected NOT eof". See
512 // https://github.com/Geal/nom/issues/1259. For now, we examine the
513 // input string to guess what the likely intention is.
514 NomErrorKind::Eof => match location.input_len() {
515 // The input is at Eof, which means that this refers to an
516 // *unexpected* eof.
517 0 => BaseErrorKind::Expected(Expectation::Something),
518
519 // The input is *not* at eof, which means that this refers to
520 // an *expected* eof.
521 _ => BaseErrorKind::Expected(Expectation::Eof),
522 },
523 kind => BaseErrorKind::Kind(kind),
524 };
525
526 GenericErrorTree::Base { location, kind }
527 }
528
529 /// Combine an existing error with a new one. This is how error context is
530 /// accumulated when backtracing. "other" is the original error, and the
531 /// inputs new error from higher in the call stack.
532 ///
533 /// If `other` is already an `GenericErrorTree::Stack`, the context is added to
534 /// the stack; otherwise, a new stack is created, with `other` at the root.
535 fn append(location: I, kind: NomErrorKind, other: Self) -> Self {
536 let context = (location, StackContext::Kind(kind));
537
538 match other {
539 // Don't create a stack of [ErrorKind::Alt, GenericErrorTree::Alt(..)]
540 alt @ GenericErrorTree::Alt(..) if kind == NomErrorKind::Alt => alt,
541
542 // This is already a stack, so push on to it
543 GenericErrorTree::Stack { contexts, base } => GenericErrorTree::Stack {
544 base,
545 contexts: express!(contexts.push(context)),
546 },
547
548 // This isn't a stack; create a new stack
549 base => GenericErrorTree::Stack {
550 base: Box::new(base),
551 contexts: vec![context],
552 },
553 }
554 }
555
556 /// Create an error indicating an expected character at a given position
557 fn from_char(location: I, character: char) -> Self {
558 GenericErrorTree::Base {
559 location,
560 kind: BaseErrorKind::Expected(Expectation::Char(character)),
561 }
562 }
563
564 /// Combine two errors from branches of alt. If either or both errors are
565 /// already [`GenericErrorTree::Alt`], the different error sets are merged;
566 /// otherwise, a new [`GenericErrorTree::Alt`] is created, containing both
567 /// `self` and `other`.
568 fn or(self, other: Self) -> Self {
569 // For now we assume that there's no need to try and preserve
570 // left-to-right ordering of alternatives.
571 let siblings = match (self, other) {
572 (GenericErrorTree::Alt(siblings1), GenericErrorTree::Alt(siblings2)) => {
573 match siblings1.capacity() >= siblings2.capacity() {
574 true => express!(siblings1.extend(siblings2)),
575 false => express!(siblings2.extend(siblings1)),
576 }
577 }
578 (GenericErrorTree::Alt(siblings), err) | (err, GenericErrorTree::Alt(siblings)) => {
579 express!(siblings.push(err))
580 }
581 (err1, err2) => vec![err1, err2],
582 };
583
584 GenericErrorTree::Alt(siblings)
585 }
586}
587
588impl<I, T, C, E> ContextError<I, C> for GenericErrorTree<I, T, C, E> {
589 fn add_context(location: I, ctx: C, other: Self) -> Self {
590 let context = (location, StackContext::Context(ctx));
591
592 match other {
593 // This is already a stack, so push on to it
594 GenericErrorTree::Stack { contexts, base } => GenericErrorTree::Stack {
595 base,
596 contexts: express!(contexts.push(context)),
597 },
598
599 // This isn't a stack, create a new stack
600 base => GenericErrorTree::Stack {
601 base: Box::new(base),
602 contexts: vec![context],
603 },
604 }
605 }
606}
607
608impl<I, T, E> nom::error::ContextError<I> for GenericErrorTree<I, T, &'static str, E> {
609 fn add_context(location: I, ctx: &'static str, other: Self) -> Self {
610 ContextError::add_context(location, ctx, other)
611 }
612}
613
614impl<I, T, C, E, E2> FromExternalError<I, E2> for GenericErrorTree<I, T, C, E>
615where
616 E: From<E2>,
617{
618 /// Create an error from a given external error, such as from FromStr
619 fn from_external_error(location: I, _kind: NomErrorKind, e: E2) -> Self {
620 GenericErrorTree::Base {
621 location,
622 kind: BaseErrorKind::External(e.into()),
623 }
624 }
625}
626
627impl<I, T: AsRef<[u8]>, C, E> TagError<I, T> for GenericErrorTree<I, T, C, E> {
628 fn from_tag(location: I, tag: T) -> Self {
629 GenericErrorTree::Base {
630 location,
631 kind: BaseErrorKind::Expected(match tag.as_ref() {
632 b"\r\n" => Expectation::CrLf,
633 _ => Expectation::Tag(tag),
634 }),
635 }
636 }
637}
638
639impl<I, T, C, E> ErrorConvert<GenericErrorTree<(I, usize), T, C, E>>
640 for GenericErrorTree<I, T, C, E>
641{
642 fn convert(self) -> GenericErrorTree<(I, usize), T, C, E> {
643 self.map_locations(|location| (location, 0))
644 }
645}
646
647impl<I, T, C, E> ErrorConvert<GenericErrorTree<I, T, C, E>>
648 for GenericErrorTree<(I, usize), T, C, E>
649{
650 fn convert(self) -> GenericErrorTree<I, T, C, E> {
651 self.map_locations(move |(location, _offset)| location)
652 }
653}
654
655impl<I, I2, T, C, E> ExtractContext<I, GenericErrorTree<I2, T, C, E>>
656 for GenericErrorTree<I, T, C, E>
657where
658 I: Clone,
659 I2: RecreateContext<I>,
660{
661 fn extract_context(self, original_input: I) -> GenericErrorTree<I2, T, C, E> {
662 self.map_locations(move |location| I2::recreate_context(original_input.clone(), location))
663 }
664}
665
666#[cfg(test)]
667mod tests {
668 use super::*;
669
670 use nom::{
671 bits::{bits, complete::take},
672 sequence::tuple,
673 IResult, Parser,
674 };
675
676 type BitInput<'a> = (&'a [u8], usize);
677
678 fn parse_bool_bit(input: (&[u8], usize)) -> IResult<BitInput, bool, ErrorTree<BitInput>> {
679 take(1usize).map(|bit: u8| bit != 0).parse(input)
680 }
681
682 type Byte = (bool, bool, bool, bool, bool, bool, bool, bool);
683
684 /// Parse 8 bits
685 fn parse_bits(input: &[u8]) -> IResult<&[u8], Byte, ErrorTree<&[u8]>> {
686 bits(tuple((
687 parse_bool_bit,
688 parse_bool_bit,
689 parse_bool_bit,
690 parse_bool_bit,
691 parse_bool_bit,
692 parse_bool_bit,
693 parse_bool_bit,
694 parse_bool_bit,
695 )))
696 .parse(input)
697 }
698
699 /// Test that ErrorTree can be used with a bits parser, which requires
700 /// ErrorConvert
701 #[test]
702 fn error_tree_bits() {
703 let values = [0b1010_1111, 10];
704 let (tail, result) = parse_bits(&values).unwrap();
705
706 assert_eq!(tail, &[10]);
707 assert_eq!(result, (true, false, true, false, true, true, true, true));
708 }
709}