nom8/
error.rs

1//! # Error management
2//!
3//! nom's errors are designed with multiple needs in mind:
4//! - indicate which parser failed and where in the input data
5//! - accumulate more context as the error goes up the parser chain
6//! - have a very low overhead, as errors are often discarded by the calling parser (examples: `many0`, `alt`)
7//! - can be modified according to the user's needs, because some languages need a lot more information
8//!
9//! To match these requirements, nom parsers have to return the following result
10//! type:
11//!
12//! ```rust
13//! pub type IResult<I, O, E=nom8::error::Error<I>> = Result<(I, O), nom8::Err<E>>;
14//!
15//! #[derive(Debug, PartialEq, Eq, Clone, Copy)]
16//! pub enum Needed {
17//!   Unknown,
18//!   Size(u32)
19//! }
20//!
21//! pub enum Err<E> {
22//!     Incomplete(Needed),
23//!     Error(E),
24//!     Failure(E),
25//! }
26//! ```
27//!
28//! The result is either an `Ok((I, O))` containing the remaining input and the
29//! parsed value, or an `Err(nom8::Err<E>)` with `E` the error type.
30//! `nom8::Err<E>` is an enum because combinators can have different behaviours
31//! depending on the value:
32//! - `Error` is a normal parser error. If a child parser of the `alt` combinator returns `Error`, it will try another child parser
33//! - `Failure` is an error from which we cannot recover: The `alt` combinator will not try other branches if a child parser returns `Failure`. This is used when we know we were in the right branch of `alt` and do not need to try other branches
34//! - `Incomplete` indicates that a parser did not have enough data to decide. This can be returned by parsers found in `streaming` submodules. Parsers in the `complete` submodules assume that they have the entire input data, so if it was not sufficient, they will instead return a `Err::Error`. When a parser returns `Incomplete`, we should accumulate more data in the buffer (example: reading from a socket) and call the parser again
35//!
36//! If we are running a parser and know it will not return `Err::Incomplete`, we can
37//! directly extract the error type from `Err::Error` or `Err::Failure` with the
38//! `finish()` method:
39//!
40//! ```rust,ignore
41//! # use nom8::IResult;
42//! # use nom8::prelude::*;
43//! # let parser = nom8::bytes::take_while1(|c: char| c == ' ');
44//! # let input = " ";
45//! let parser_result: IResult<_, _, _> = parser(input);
46//! let result: Result<_, _> = parser_result.finish();
47//! ```
48//!
49//! If we used a borrowed type as input, like `&[u8]` or `&str`, we might want to
50//! convert it to an owned type to transmit it somewhere, with the `to_owned()`
51//! method:
52//!
53//! ```rust,ignore
54//! # use nom8::Err;
55//! # type Value<'s> = &'s [u8];
56//! # let parser = nom8::bytes::take_while1(|c: u8| c == b' ');
57//! # let data = " ";
58//! let result: Result<(&[u8], Value<'_>), Err<Vec<u8>>> =
59//!   parser(data).map_err(|e: E<&[u8]>| e.to_owned());
60//! ```
61//!
62//! nom provides a powerful error system that can adapt to your needs: you can
63//! get reduced error information if you want to improve performance, or you can
64//! get a precise trace of parser application, with fine grained position information.
65//!
66//! This is done through the third type parameter of `IResult`, nom's parser result
67//! type:
68//!
69//! ```rust
70//! pub type IResult<I, O, E=nom8::error::Error<I>> = Result<(I, O), Err<E>>;
71//!
72//! #[derive(Debug, PartialEq, Eq, Clone, Copy)]
73//! pub enum Needed {
74//!   Unknown,
75//!   Size(u32)
76//! }
77//!
78//! pub enum Err<E> {
79//!     Incomplete(Needed),
80//!     Error(E),
81//!     Failure(E),
82//! }
83//! ```
84//!
85//! This error type is completely generic in nom's combinators, so you can choose
86//! exactly which error type you want to use when you define your parsers, or
87//! directly at the call site.
88//! See [the JSON parser](https://github.com/Geal/nom/blob/5405e1173f1052f7e006dcb0b9cfda2b06557b65/examples/json.rs#L209-L286)
89//! for an example of choosing different error types at the call site.
90//!
91//! The `Err<E>` enum expresses 3 conditions for a parser error:
92//! - `Incomplete` indicates that a parser did not have enough data to decide. This can be returned by parsers found in `streaming` submodules to indicate that we should buffer more data from a file or socket. Parsers in the `complete` submodules assume that they have the entire input data, so if it was not sufficient, they will instead return a `Err::Error`
93//! - `Error` is a normal parser error. If a child parser of the `alt` combinator returns `Error`, it will try another child parser
94//! - `Failure` is an error from which we cannot recover: The `alt` combinator will not try other branches if a child parser returns `Failure`. If we know we were in the right branch (example: we found a correct prefix character but input after that was wrong), we can transform a `Err::Error` into a `Err::Failure` with the `cut()` combinator
95//!
96//! ## Common error types
97//!
98//! ### the default error type: nom8::error::Error
99//!
100//! ```rust
101//! # use nom8::error::ErrorKind;
102//! #[derive(Debug, PartialEq)]
103//! pub struct Error<I> {
104//!   /// position of the error in the input data
105//!   pub input: I,
106//!   /// nom error code
107//!   pub code: ErrorKind,
108//! }
109//! ```
110//!
111//! This structure contains a `nom8::error::ErrorKind` indicating which kind of
112//! parser encountered an error (example: `ErrorKind::Tag` for the `tag()`
113//! combinator), and the input position of the error.
114//!
115//! This error type is fast and has very low overhead, so it is suitable for
116//! parsers that are called repeatedly, like in network protocols.
117//! It is very limited though, it will not tell you about the chain of
118//! parser calls, so it is not enough to write user friendly errors.
119//!
120//! Example error returned in a JSON-like parser (from `examples/json.rs`):
121//!
122//! ```rust,ignore
123//! let data = "  { \"a\"\t: 42,
124//! \"b\": [ \"x\", \"y\", 12 ] ,
125//! \"c\": { 1\"hello\" : \"world\"
126//! }
127//! } ";
128//!
129//! // will print:
130//! // Err(
131//! //   Failure(
132//! //       Error {
133//! //           input: "1\"hello\" : \"world\"\n  }\n  } ",
134//! //           code: Char,
135//! //       },
136//! //   ),
137//! // )
138//! println!(
139//!   "{:#?}\n",
140//!   json::<Error<&str>>(data)
141//! );
142//! ```
143//!
144//! ### getting more information: nom8::error::VerboseError
145//!
146//! The  `VerboseError<I>` type accumulates more information about the chain of
147//! parsers that encountered an error:
148//!
149//! ```rust
150//! # use nom8::error::ErrorKind;
151//! #[derive(Clone, Debug, PartialEq)]
152//! pub struct VerboseError<I> {
153//!   /// List of errors accumulated by `VerboseError`, containing the affected
154//!   /// part of input data, and some context
155//!   pub errors: Vec<(I, VerboseErrorKind)>,
156//! }
157//!
158//! #[derive(Clone, Debug, PartialEq)]
159//! /// Error context for `VerboseError`
160//! pub enum VerboseErrorKind {
161//!   /// Static string added by the `context` function
162//!   Context(&'static str),
163//!   /// Indicates which character was expected by the `char` function
164//!   Char(char),
165//!   /// Error kind given by various nom parsers
166//!   Nom(ErrorKind),
167//! }
168//! ```
169//!
170//! It contains the input position and error code for each of those parsers.
171//! It does not accumulate errors from the different branches of `alt`, it will
172//! only contain errors from the last branch it tried.
173//!
174//! It can be used along with the `nom8::error::context` combinator to inform about
175//! the parser chain:
176//!
177//! ```rust,ignore
178//! # use nom8::error::context;
179//! # use nom8::sequence::preceded;
180//! # use nom8::character::char;
181//! # use nom8::combinator::cut;
182//! # use nom8::sequence::terminated;
183//! # let parse_str = nom8::bytes::take_while1(|c| c == ' ');
184//! # let i = " ";
185//! context(
186//!   "string",
187//!   preceded('\"', cut(terminated(parse_str, '\"'))),
188//! )(i);
189//! ```
190//!
191//! It is not very usable if printed directly:
192//!
193//! ```rust,ignore
194//! // parsed verbose: Err(
195//! //   Failure(
196//! //       VerboseError {
197//! //           errors: [
198//! //               (
199//! //                   "1\"hello\" : \"world\"\n  }\n  } ",
200//! //                   Char(
201//! //                       '}',
202//! //                   ),
203//! //               ),
204//! //               (
205//! //                   "{ 1\"hello\" : \"world\"\n  }\n  } ",
206//! //                   Context(
207//! //                       "map",
208//! //                   ),
209//! //               ),
210//! //               (
211//! //                   "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } ",
212//! //                   Context(
213//! //                       "map",
214//! //                   ),
215//! //               ),
216//! //           ],
217//! //       },
218//! //   ),
219//! // )
220//! println!("parsed verbose: {:#?}", json::<VerboseError<&str>>(data));
221//! ```
222//!
223//! But by looking at the original input and the chain of errors, we can build
224//! a more user friendly error message. The `nom8::error::convert_error` function
225//! can build such a message.
226//!
227//! ```rust,ignore
228//! let e = json::<VerboseError<&str>>(data).finish().err().unwrap();
229//! // here we use the `convert_error` function, to transform a `VerboseError<&str>`
230//! // into a printable trace.
231//! //
232//! // This will print:
233//! // verbose errors - `json::<VerboseError<&str>>(data)`:
234//! // 0: at line 2:
235//! //   "c": { 1"hello" : "world"
236//! //          ^
237//! // expected '}', found 1
238//! //
239//! // 1: at line 2, in map:
240//! //   "c": { 1"hello" : "world"
241//! //        ^
242//! //
243//! // 2: at line 0, in map:
244//! //   { "a" : 42,
245//! //   ^
246//! println!(
247//!   "verbose errors - `json::<VerboseError<&str>>(data)`:\n{}",
248//!   convert_error(data, e)
249//! );
250//! ```
251//!
252//! Note that `VerboseError` and `convert_error` are meant as a starting point for
253//! language errors, but that they cannot cover all use cases. So a custom
254//! `convert_error` function should probably be written.
255//!
256//! ### Improving usability: nom_locate and nom-supreme
257//!
258//! These crates were developed to improve the user experience when writing nom
259//! parsers.
260//!
261//! #### nom_locate
262//!
263//! [nom_locate](https://docs.rs/nom_locate/) wraps the input data in a `Span`
264//! type that can be understood by nom parsers. That type provides location
265//! information, like line and column.
266//!
267//! #### nom-supreme
268//!
269//! [nom-supreme](https://docs.rs/nom-supreme/) provides the `ErrorTree<I>` error
270//! type, that provides the same chain of parser errors as `VerboseError`, but also
271//! accumulates errors from the various branches tried by `alt`.
272//!
273//! With this error type, you can explore everything that has been tried by the
274//! parser.
275//!
276//! ## The `ParseError` trait
277//!
278//! If those error types are not enough, we can define our own, by implementing
279//! the `ParseError<I>` trait. All nom combinators are generic over that trait
280//! for their errors, so we only need to define it in the parser result type,
281//! and it will be used everywhere.
282//!
283//! ```rust
284//! # use nom8::error::ErrorKind;
285//! pub trait ParseError<I>: Sized {
286//!     /// Creates an error from the input position and an [ErrorKind]
287//!     fn from_error_kind(input: I, kind: ErrorKind) -> Self;
288//!
289//!     /// Combines an existing error with a new one created from the input
290//!     /// position and an [ErrorKind]. This is useful when backtracking
291//!     /// through a parse tree, accumulating error context on the way
292//!     fn append(input: I, kind: ErrorKind, other: Self) -> Self;
293//!
294//!     /// Combines two existing errors. This function is used to compare errors
295//!     /// generated in various branches of `alt`
296//!     fn or(self, other: Self) -> Self {
297//!         other
298//!     }
299//! }
300//! ```
301//!
302//! Any error type has to implement that trait, that requires ways to build an
303//! error:
304//! - `from_error_kind`: From the input position and the `ErrorKind` enum that indicates in which parser we got an error
305//! - `append`: Allows the creation of a chain of errors as we backtrack through the parser tree (various combinators will add more context)
306//! - `from_char`: Creates an error that indicates which character we were expecting
307//! - `or`: In combinators like `alt`, allows choosing between errors from various branches (or accumulating them)
308//!
309//! We can also implement the `ContextError` trait to support the `context()`
310//! combinator used by `VerboseError<I>`:
311//!
312//! ```rust
313//! pub trait ContextError<I, C>: Sized {
314//!     fn add_context(_input: I, _ctx: C, other: Self) -> Self {
315//!         other
316//!     }
317//! }
318//! ```
319//!
320//! And there is also the `FromExternalError<I, E>` used by `map_res` to wrap
321//! errors returned by other functions:
322//!
323//! ```rust
324//! # use nom8::error::ErrorKind;
325//! pub trait FromExternalError<I, ExternalError> {
326//!   fn from_external_error(input: I, kind: ErrorKind, e: ExternalError) -> Self;
327//! }
328//! ```
329//!
330//! ### Example usage
331//!
332//! Let's define a debugging error type, that will print something every time an
333//! error is generated. This will give us a good insight into what the parser tried.
334//! Since errors can be combined with each other, we want it to keep some info on
335//! the error that was just returned. We'll just store that in a string:
336//!
337//! ```rust
338//! struct DebugError {
339//!     message: String,
340//! }
341//! ```
342//!
343//! Now let's implement `ParseError` and `ContextError` on it:
344//!
345//! ```rust
346//! # use nom8::error::ParseError;
347//! # use nom8::error::ErrorKind;
348//! # use nom8::error::ContextError;
349//! # struct DebugError {
350//! #     message: String,
351//! # }
352//! impl ParseError<&str> for DebugError {
353//!     // on one line, we show the error code and the input that caused it
354//!     fn from_error_kind(input: &str, kind: ErrorKind) -> Self {
355//!         let message = format!("{:?}:\t{:?}\n", kind, input);
356//!         println!("{}", message);
357//!         DebugError { message }
358//!     }
359//!
360//!     // if combining multiple errors, we show them one after the other
361//!     fn append(input: &str, kind: ErrorKind, other: Self) -> Self {
362//!         let message = format!("{}{:?}:\t{:?}\n", other.message, kind, input);
363//!         println!("{}", message);
364//!         DebugError { message }
365//!     }
366//!
367//!     fn or(self, other: Self) -> Self {
368//!         let message = format!("{}\tOR\n{}\n", self.message, other.message);
369//!         println!("{}", message);
370//!         DebugError { message }
371//!     }
372//! }
373//!
374//! impl ContextError<&str, &'static str> for DebugError {
375//!     fn add_context(input: &str, ctx: &'static str, other: Self) -> Self {
376//!         let message = format!("{}\"{}\":\t{:?}\n", other.message, ctx, input);
377//!         println!("{}", message);
378//!         DebugError { message }
379//!     }
380//! }
381//! ```
382//!
383//! So when calling our JSON parser with this error type, we will get a trace
384//! of all the times a parser stoppped and backtracked:
385//!
386//! ```rust,ignore
387//! println!("debug: {:#?}", root::<DebugError>(data));
388//! ```
389//!
390//! ```text
391//! AlphaNumeric:   "\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
392//!
393//! '{':    "42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
394//!
395//! '{':    "42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
396//! "map":  "42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
397//!
398//! [..]
399//!
400//! AlphaNumeric:   "\": { 1\"hello\" : \"world\"\n  }\n  } "
401//!
402//! '"':    "1\"hello\" : \"world\"\n  }\n  } "
403//!
404//! '"':    "1\"hello\" : \"world\"\n  }\n  } "
405//! "string":       "1\"hello\" : \"world\"\n  }\n  } "
406//!
407//! '}':    "1\"hello\" : \"world\"\n  }\n  } "
408//!
409//! '}':    "1\"hello\" : \"world\"\n  }\n  } "
410//! "map":  "{ 1\"hello\" : \"world\"\n  }\n  } "
411//!
412//! '}':    "1\"hello\" : \"world\"\n  }\n  } "
413//! "map":  "{ 1\"hello\" : \"world\"\n  }\n  } "
414//! "map":  "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
415//!
416//! debug: Err(
417//!     Failure(
418//!         DebugError {
419//!             message: "'}':\t\"1\\\"hello\\\" : \\\"world\\\"\\n  }\\n  } \"\n\"map\":\t\"{ 1\\\"hello\\\" : \\\"world
420//! \\"\\n  }\\n  } \"\n\"map\":\t\"{ \\\"a\\\"\\t: 42,\\n  \\\"b\\\": [ \\\"x\\\", \\\"y\\\", 12 ] ,\\n  \\\"c\\\": { 1\
421//! \"hello\\\" : \\\"world\\\"\\n  }\\n  } \"\n",
422//!         },
423//!     ),
424//! )
425//! ```
426//!
427//! Here we can see that when parsing `{ 1\"hello\" : \"world\"\n  }\n  }`, after
428//! getting past the initial `{`, we tried:
429//! - parsing a `"` because we're expecting a key name, and that parser was part of the
430//! "string" parser
431//! - parsing a `}` because the map might be empty. When this fails, we backtrack,
432//! through 2 recursive map parsers:
433//!
434//! ```text
435//! '}':    "1\"hello\" : \"world\"\n  }\n  } "
436//! "map":  "{ 1\"hello\" : \"world\"\n  }\n  } "
437//! "map":  "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
438//! ```
439//!
440//! ## Debugging parsers
441//!
442//! While you are writing your parsers, you will sometimes need to follow
443//! which part of the parser sees which part of the input.
444//!
445//! To that end, nom provides the `dbg_err` function that will observe
446//! a parser's input and output, and print a hexdump of the input if there was an
447//! error. Here is what it could return:
448//!
449#![cfg_attr(feature = "std", doc = "```")]
450#![cfg_attr(not(feature = "std"), doc = "```ignore")]
451//! use nom8::prelude::*;
452//! # use nom8::bytes::tag;
453//! fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
454//!     tag("abcd").dbg_err("tag").parse(i)
455//! }
456//!
457//! let a = &b"efghijkl"[..];
458//!
459//! // Will print the following message:
460//! // tag: Error(Error(Error { input: [101, 102, 103, 104, 105, 106, 107, 108], code: Tag })) at:
461//! // 00000000        65 66 67 68 69 6a 6b 6c         efghijkl
462//! f(a);
463//! ```
464//!
465//! You can go further with the [nom-trace crate](https://github.com/rust-bakery/nom-trace)
466
467use crate::lib::std::fmt;
468use crate::Parser;
469
470/// This trait must be implemented by the error type of a nom parser.
471///
472/// There are already implementations of it for `(Input, ErrorKind)`
473/// and `VerboseError<Input>`.
474///
475/// It provides methods to create an error from some combinators,
476/// and combine existing errors in combinators like `alt`.
477pub trait ParseError<I>: Sized {
478  /// Creates an error from the input position and an [ErrorKind]
479  fn from_error_kind(input: I, kind: ErrorKind) -> Self;
480
481  /// Combines an existing error with a new one created from the input
482  /// position and an [ErrorKind]. This is useful when backtracking
483  /// through a parse tree, accumulating error context on the way
484  fn append(input: I, kind: ErrorKind, other: Self) -> Self;
485
486  /// Creates an error from an input position and an expected character
487  #[deprecated(since = "8.0.0", note = "Replaced with `ContextError`")]
488  fn from_char(input: I, _: char) -> Self {
489    Self::from_error_kind(input, ErrorKind::Char)
490  }
491
492  /// Combines two existing errors. This function is used to compare errors
493  /// generated in various branches of `alt`.
494  fn or(self, other: Self) -> Self {
495    other
496  }
497}
498
499/// This trait is required by the `context` combinator to add a static string
500/// to an existing error
501pub trait ContextError<I, C>: Sized {
502  /// Creates a new error from an input position, a static string and an existing error.
503  /// This is used mainly in the [context] combinator, to add user friendly information
504  /// to errors when backtracking through a parse tree
505  fn add_context(_input: I, _ctx: C, other: Self) -> Self {
506    other
507  }
508}
509
510/// This trait is required by the `map_res` combinator to integrate
511/// error types from external functions, like [std::str::FromStr]
512pub trait FromExternalError<I, E> {
513  /// Creates a new error from an input position, an [ErrorKind] indicating the
514  /// wrapping parser, and an external error
515  fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self;
516}
517
518/// default error type, only contains the error' location and code
519#[derive(Debug, PartialEq)]
520pub struct Error<I> {
521  /// position of the error in the input data
522  pub input: I,
523  /// nom error code
524  pub code: ErrorKind,
525}
526
527impl<I> Error<I> {
528  /// creates a new basic error
529  pub fn new(input: I, code: ErrorKind) -> Error<I> {
530    Error { input, code }
531  }
532}
533
534impl<I> ParseError<I> for Error<I> {
535  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
536    Error { input, code: kind }
537  }
538
539  fn append(_: I, _: ErrorKind, other: Self) -> Self {
540    other
541  }
542}
543
544impl<I, C> ContextError<I, C> for Error<I> {}
545
546impl<I, E> FromExternalError<I, E> for Error<I> {
547  /// Create a new error from an input position and an external error
548  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
549    Error { input, code: kind }
550  }
551}
552
553/// The Display implementation allows the std::error::Error implementation
554impl<I: fmt::Display> fmt::Display for Error<I> {
555  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
556    write!(f, "error {:?} at: {}", self.code, self.input)
557  }
558}
559
560#[cfg(feature = "std")]
561impl<I: fmt::Debug + fmt::Display> std::error::Error for Error<I> {}
562
563// for backward compatibility, keep those trait implementations
564// for the previously used error type
565impl<I> ParseError<I> for (I, ErrorKind) {
566  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
567    (input, kind)
568  }
569
570  fn append(_: I, _: ErrorKind, other: Self) -> Self {
571    other
572  }
573}
574
575impl<I, C> ContextError<I, C> for (I, ErrorKind) {}
576
577impl<I, E> FromExternalError<I, E> for (I, ErrorKind) {
578  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
579    (input, kind)
580  }
581}
582
583impl<I> ParseError<I> for () {
584  fn from_error_kind(_: I, _: ErrorKind) -> Self {}
585
586  fn append(_: I, _: ErrorKind, _: Self) -> Self {}
587}
588
589impl<I, C> ContextError<I, C> for () {}
590
591impl<I, E> FromExternalError<I, E> for () {
592  fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {}
593}
594
595/// Creates an error from the input position and an [ErrorKind]
596#[deprecated(since = "8.0.0", note = "Replaced with `ParseError::from_error_kind`")]
597pub fn make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E {
598  E::from_error_kind(input, kind)
599}
600
601/// Combines an existing error with a new one created from the input
602/// position and an [ErrorKind]. This is useful when backtracking
603/// through a parse tree, accumulating error context on the way
604#[deprecated(since = "8.0.0", note = "Replaced with `ParseError::append`")]
605pub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E {
606  E::append(input, kind, other)
607}
608
609/// This error type accumulates errors and their position when backtracking
610/// through a parse tree. With some post processing (cf `examples/json.rs`),
611/// it can be used to display user friendly error messages
612#[cfg(feature = "alloc")]
613#[derive(Clone, Debug, PartialEq)]
614pub struct VerboseError<I> {
615  /// List of errors accumulated by `VerboseError`, containing the affected
616  /// part of input data, and some context
617  pub errors: crate::lib::std::vec::Vec<(I, VerboseErrorKind)>,
618}
619
620#[cfg(feature = "alloc")]
621#[derive(Clone, Debug, PartialEq)]
622/// Error context for `VerboseError`
623pub enum VerboseErrorKind {
624  /// Static string added by the `context` function
625  Context(&'static str),
626  /// Error kind given by various nom parsers
627  Nom(ErrorKind),
628}
629
630#[cfg(feature = "alloc")]
631impl<I> ParseError<I> for VerboseError<I> {
632  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
633    VerboseError {
634      errors: vec![(input, VerboseErrorKind::Nom(kind))],
635    }
636  }
637
638  fn append(input: I, kind: ErrorKind, mut other: Self) -> Self {
639    other.errors.push((input, VerboseErrorKind::Nom(kind)));
640    other
641  }
642}
643
644#[cfg(feature = "alloc")]
645impl<I> ContextError<I, &'static str> for VerboseError<I> {
646  fn add_context(input: I, ctx: &'static str, mut other: Self) -> Self {
647    other.errors.push((input, VerboseErrorKind::Context(ctx)));
648    other
649  }
650}
651
652#[cfg(feature = "alloc")]
653impl<I, E> FromExternalError<I, E> for VerboseError<I> {
654  /// Create a new error from an input position and an external error
655  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
656    Self::from_error_kind(input, kind)
657  }
658}
659
660#[cfg(feature = "alloc")]
661impl<I: fmt::Display> fmt::Display for VerboseError<I> {
662  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
663    writeln!(f, "Parse error:")?;
664    for (input, error) in &self.errors {
665      match error {
666        VerboseErrorKind::Nom(e) => writeln!(f, "{:?} at: {}", e, input)?,
667        VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?,
668      }
669    }
670
671    Ok(())
672  }
673}
674
675#[cfg(feature = "std")]
676impl<I: fmt::Debug + fmt::Display> std::error::Error for VerboseError<I> {}
677
678use crate::{Err, IResult};
679
680/// Create a new error from an input position, a static string and an existing error.
681/// This is used mainly in the [context] combinator, to add user friendly information
682/// to errors when backtracking through a parse tree
683///
684/// **WARNING:** Deprecated, replaced with [`Parser::context`]
685#[deprecated(since = "8.0.0", note = "Replaced with `Parser::context")]
686pub fn context<I: Clone, E: ContextError<I, &'static str>, F, O>(
687  context: &'static str,
688  mut f: F,
689) -> impl FnMut(I) -> IResult<I, O, E>
690where
691  F: Parser<I, O, E>,
692{
693  move |i: I| match f.parse(i.clone()) {
694    Ok(o) => Ok(o),
695    Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)),
696    Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, context, e))),
697    Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, context, e))),
698  }
699}
700
701/// Implementation of [`Parser::context`]
702#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
703pub struct Context<F, O, C: Clone> {
704  f: F,
705  context: C,
706  phantom: core::marker::PhantomData<O>,
707}
708
709impl<F, O, C: Clone> Context<F, O, C> {
710  pub(crate) fn new(f: F, context: C) -> Self {
711    Self {
712      f,
713      context,
714      phantom: Default::default(),
715    }
716  }
717}
718
719impl<I, O, E, F: Parser<I, O, E>, C> Parser<I, O, E> for Context<F, O, C>
720where
721  I: Clone,
722  C: Clone,
723  E: ContextError<I, C>,
724  F: Parser<I, O, E>,
725{
726  fn parse(&mut self, i: I) -> IResult<I, O, E> {
727    match (self.f).parse(i.clone()) {
728      Ok(o) => Ok(o),
729      Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)),
730      Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, self.context.clone(), e))),
731      Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, self.context.clone(), e))),
732    }
733  }
734}
735
736/// Transforms a `VerboseError` into a trace with input position information
737#[cfg(feature = "alloc")]
738pub fn convert_error<I: core::ops::Deref<Target = str>>(
739  input: I,
740  e: VerboseError<I>,
741) -> crate::lib::std::string::String {
742  use crate::input::Offset;
743  use crate::lib::std::fmt::Write;
744
745  let mut result = crate::lib::std::string::String::new();
746
747  for (i, (substring, kind)) in e.errors.iter().enumerate() {
748    let offset = input.offset(substring);
749
750    if input.is_empty() {
751      match kind {
752        VerboseErrorKind::Context(s) => write!(&mut result, "{}: in {}, got empty input\n\n", i, s),
753        VerboseErrorKind::Nom(e) => write!(&mut result, "{}: in {:?}, got empty input\n\n", i, e),
754      }
755    } else {
756      let prefix = &input.as_bytes()[..offset];
757
758      // Count the number of newlines in the first `offset` bytes of input
759      let line_number = prefix.iter().filter(|&&b| b == b'\n').count() + 1;
760
761      // Find the line that includes the subslice:
762      // Find the *last* newline before the substring starts
763      let line_begin = prefix
764        .iter()
765        .rev()
766        .position(|&b| b == b'\n')
767        .map(|pos| offset - pos)
768        .unwrap_or(0);
769
770      // Find the full line after that newline
771      let line = input[line_begin..]
772        .lines()
773        .next()
774        .unwrap_or(&input[line_begin..])
775        .trim_end();
776
777      // The (1-indexed) column number is the offset of our substring into that line
778      let column_number = line.offset(substring) + 1;
779
780      match kind {
781        VerboseErrorKind::Context(s) => write!(
782          &mut result,
783          "{i}: at line {line_number}, in {context}:\n\
784             {line}\n\
785             {caret:>column$}\n\n",
786          i = i,
787          line_number = line_number,
788          context = s,
789          line = line,
790          caret = '^',
791          column = column_number,
792        ),
793        VerboseErrorKind::Nom(e) => write!(
794          &mut result,
795          "{i}: at line {line_number}, in {nom_err:?}:\n\
796             {line}\n\
797             {caret:>column$}\n\n",
798          i = i,
799          line_number = line_number,
800          nom_err = e,
801          line = line,
802          caret = '^',
803          column = column_number,
804        ),
805      }
806    }
807    // Because `write!` to a `String` is infallible, this `unwrap` is fine.
808    .unwrap();
809  }
810
811  result
812}
813
814/// Indicates which parser returned an error
815#[rustfmt::skip]
816#[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)]
817#[allow(deprecated,missing_docs)]
818pub enum ErrorKind {
819  Tag,
820  MapRes,
821  MapOpt,
822  Alt,
823  IsNot,
824  IsA,
825  SeparatedList,
826  SeparatedNonEmptyList,
827  Many0,
828  Many1,
829  ManyTill,
830  Count,
831  TakeUntil,
832  LengthValue,
833  TagClosure,
834  Alpha,
835  Digit,
836  HexDigit,
837  OctDigit,
838  AlphaNumeric,
839  Space,
840  MultiSpace,
841  LengthValueFn,
842  Eof,
843  Switch,
844  TagBits,
845  OneOf,
846  NoneOf,
847  Char,
848  CrLf,
849  RegexpMatch,
850  RegexpMatches,
851  RegexpFind,
852  RegexpCapture,
853  RegexpCaptures,
854  TakeWhile1,
855  Complete,
856  Fix,
857  Escaped,
858  EscapedTransform,
859  NonEmpty,
860  ManyMN,
861  Not,
862  Permutation,
863  Verify,
864  TakeTill1,
865  TakeWhileMN,
866  TooLarge,
867  Many0Count,
868  Many1Count,
869  Float,
870  Satisfy,
871  Fail,
872}
873
874impl ErrorKind {
875  #[rustfmt::skip]
876  #[allow(deprecated)]
877  /// Converts an ErrorKind to a text description
878  pub fn description(&self) -> &str {
879    match *self {
880      ErrorKind::Tag                       => "Tag",
881      ErrorKind::MapRes                    => "Map on Result",
882      ErrorKind::MapOpt                    => "Map on Option",
883      ErrorKind::Alt                       => "Alternative",
884      ErrorKind::IsNot                     => "IsNot",
885      ErrorKind::IsA                       => "IsA",
886      ErrorKind::SeparatedList             => "Separated list",
887      ErrorKind::SeparatedNonEmptyList     => "Separated non empty list",
888      ErrorKind::Many0                     => "Many0",
889      ErrorKind::Many1                     => "Many1",
890      ErrorKind::Count                     => "Count",
891      ErrorKind::TakeUntil                 => "Take until",
892      ErrorKind::LengthValue               => "Length followed by value",
893      ErrorKind::TagClosure                => "Tag closure",
894      ErrorKind::Alpha                     => "Alphabetic",
895      ErrorKind::Digit                     => "Digit",
896      ErrorKind::AlphaNumeric              => "AlphaNumeric",
897      ErrorKind::Space                     => "Space",
898      ErrorKind::MultiSpace                => "Multiple spaces",
899      ErrorKind::LengthValueFn             => "LengthValueFn",
900      ErrorKind::Eof                       => "End of file",
901      ErrorKind::Switch                    => "Switch",
902      ErrorKind::TagBits                   => "Tag on bitstream",
903      ErrorKind::OneOf                     => "OneOf",
904      ErrorKind::NoneOf                    => "NoneOf",
905      ErrorKind::Char                      => "Char",
906      ErrorKind::CrLf                      => "CrLf",
907      ErrorKind::RegexpMatch               => "RegexpMatch",
908      ErrorKind::RegexpMatches             => "RegexpMatches",
909      ErrorKind::RegexpFind                => "RegexpFind",
910      ErrorKind::RegexpCapture             => "RegexpCapture",
911      ErrorKind::RegexpCaptures            => "RegexpCaptures",
912      ErrorKind::TakeWhile1                => "TakeWhile1",
913      ErrorKind::Complete                  => "Complete",
914      ErrorKind::Fix                       => "Fix",
915      ErrorKind::Escaped                   => "Escaped",
916      ErrorKind::EscapedTransform          => "EscapedTransform",
917      ErrorKind::NonEmpty                  => "NonEmpty",
918      ErrorKind::ManyMN                    => "Many(m, n)",
919      ErrorKind::HexDigit                  => "Hexadecimal Digit",
920      ErrorKind::OctDigit                  => "Octal digit",
921      ErrorKind::Not                       => "Negation",
922      ErrorKind::Permutation               => "Permutation",
923      ErrorKind::ManyTill                  => "ManyTill",
924      ErrorKind::Verify                    => "predicate verification",
925      ErrorKind::TakeTill1                 => "TakeTill1",
926      ErrorKind::TakeWhileMN               => "TakeWhileMN",
927      ErrorKind::TooLarge                  => "Needed data size is too large",
928      ErrorKind::Many0Count                => "Count occurrence of >=0 patterns",
929      ErrorKind::Many1Count                => "Count occurrence of >=1 patterns",
930      ErrorKind::Float                     => "Float",
931      ErrorKind::Satisfy                   => "Satisfy",
932      ErrorKind::Fail                      => "Fail",
933    }
934  }
935}
936
937/// Creates a parse error from a [`ErrorKind`]
938/// and the position in the input
939#[allow(unused_variables)]
940#[macro_export(local_inner_macros)]
941macro_rules! error_position(
942  ($input:expr, $code:expr) => ({
943    $crate::error::ParseError::from_error_kind($input, $code)
944  });
945);
946
947/// Creates a parse error from a [`ErrorKind`],
948/// the position in the input and the next error in
949/// the parsing tree
950#[allow(unused_variables)]
951#[macro_export(local_inner_macros)]
952macro_rules! error_node_position(
953  ($input:expr, $code:expr, $next:expr) => ({
954    $crate::error::ParseError::append($input, $code, $next)
955  });
956);
957
958/// Prints a message and the input if the parser fails.
959///
960/// The message prints the `Error` or `Incomplete`
961/// and the parser's calling code.
962///
963/// It also displays the input in hexdump format
964///
965/// **WARNING:** Deprecated, replaced with [`Parser::dbg_err`]
966///
967/// ```rust
968/// use nom8::{IResult, error::dbg_dmp, bytes::tag};
969///
970/// fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
971///   dbg_dmp(tag("abcd"), "tag")(i)
972/// }
973///
974///   let a = &b"efghijkl"[..];
975///
976/// // Will print the following message:
977/// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) '
978/// // 00000000        65 66 67 68 69 6a 6b 6c         efghijkl
979/// f(a);
980/// ```
981#[deprecated(since = "8.0.0", note = "Replaced with `Parser::dbg_err")]
982#[cfg(feature = "std")]
983pub fn dbg_dmp<'a, F, O, E: std::fmt::Debug>(
984  f: F,
985  context: &'static str,
986) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
987where
988  F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
989{
990  use crate::input::HexDisplay;
991  move |i: &'a [u8]| match f(i) {
992    Err(e) => {
993      println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8));
994      Err(e)
995    }
996    a => a,
997  }
998}
999
1000/// Implementation of [`Parser::dbg_err`]
1001#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
1002#[cfg(feature = "std")]
1003pub struct DbgErr<F, O, C> {
1004  f: F,
1005  context: C,
1006  phantom: core::marker::PhantomData<O>,
1007}
1008
1009#[cfg(feature = "std")]
1010impl<F, O, C> DbgErr<F, O, C> {
1011  pub(crate) fn new(f: F, context: C) -> Self {
1012    Self {
1013      f,
1014      context,
1015      phantom: Default::default(),
1016    }
1017  }
1018}
1019
1020#[cfg(feature = "std")]
1021impl<I, O, E, F: Parser<I, O, E>, C> Parser<I, O, E> for DbgErr<F, O, C>
1022where
1023  I: crate::input::AsBytes,
1024  I: Clone,
1025  E: std::fmt::Debug,
1026  F: Parser<I, O, E>,
1027  C: std::fmt::Display,
1028{
1029  fn parse(&mut self, input: I) -> IResult<I, O, E> {
1030    use crate::input::HexDisplay;
1031    let i = input.clone();
1032    match self.f.parse(i) {
1033      Err(e) => {
1034        let input = input.as_bytes();
1035        eprintln!("{}: Error({:?}) at:\n{}", self.context, e, input.to_hex(8));
1036        Err(e)
1037      }
1038      a => a,
1039    }
1040  }
1041}
1042
1043#[cfg(test)]
1044#[cfg(feature = "alloc")]
1045mod tests {
1046  use super::*;
1047  use crate::bytes::one_of;
1048
1049  #[test]
1050  fn convert_error_panic() {
1051    let input = "";
1052
1053    let _result: IResult<_, _, VerboseError<&str>> = one_of('x')(input);
1054  }
1055}