16855e09eSopenharmony_ci# Error management
26855e09eSopenharmony_ci
36855e09eSopenharmony_cinom's errors are designed with multiple needs in mind:
46855e09eSopenharmony_ci- indicate which parser failed and where in the input data
56855e09eSopenharmony_ci- accumulate more context as the error goes up the parser chain
66855e09eSopenharmony_ci- have a very low overhead, as errors are often discarded by the calling parser (examples: `many0`, `alt`)
76855e09eSopenharmony_ci- can be modified according to the user's needs, because some languages need a lot more information
86855e09eSopenharmony_ci
96855e09eSopenharmony_ciTo match these requirements, nom parsers have to return the following result
106855e09eSopenharmony_citype:
116855e09eSopenharmony_ci
126855e09eSopenharmony_ci```rust
136855e09eSopenharmony_cipub type IResult<I, O, E=nom::error::Error<I>> = Result<(I, O), nom::Err<E>>;
146855e09eSopenharmony_ci
156855e09eSopenharmony_cipub enum Err<E> {
166855e09eSopenharmony_ci    Incomplete(Needed),
176855e09eSopenharmony_ci    Error(E),
186855e09eSopenharmony_ci    Failure(E),
196855e09eSopenharmony_ci}
206855e09eSopenharmony_ci```
216855e09eSopenharmony_ci
226855e09eSopenharmony_ciThe result is either an `Ok((I, O))` containing the remaining input and the
236855e09eSopenharmony_ciparsed value, or an `Err(nom::Err<E>)` with `E` the error type.
246855e09eSopenharmony_ci`nom::Err<E>` is an enum because combinators can have different behaviours
256855e09eSopenharmony_cidepending on the value. The `Err<E>` enum expresses 3 conditions for a parser error:
266855e09eSopenharmony_ci- `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`. When a parser returns `Incomplete`, we should accumulate more data in the buffer (example: reading from a socket) and call the parser again
276855e09eSopenharmony_ci- `Error` is a normal parser error. If a child parser of the `alt` combinator returns `Error`, it will try another child parser
286855e09eSopenharmony_ci- `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
296855e09eSopenharmony_ci
306855e09eSopenharmony_ciIf we are running a parser and know it will not return `Err::Incomplete`, we can
316855e09eSopenharmony_cidirectly extract the error type from `Err::Error` or `Err::Failure` with the
326855e09eSopenharmony_ci`finish()` method:
336855e09eSopenharmony_ci
346855e09eSopenharmony_ci```rust
356855e09eSopenharmony_cilet parser_result: IResult<I, O, E> = parser(input);
366855e09eSopenharmony_cilet result: Result<(I, O), E> = parser_result.finish();
376855e09eSopenharmony_ci```
386855e09eSopenharmony_ci
396855e09eSopenharmony_ciIf we used a borrowed type as input, like `&[u8]` or `&str`, we might want to
406855e09eSopenharmony_ciconvert it to an owned type to transmit it somewhere, with the `to_owned()`
416855e09eSopenharmony_cimethod:
426855e09eSopenharmony_ci
436855e09eSopenharmony_ci```rust
446855e09eSopenharmony_cilet result: Result<(&[u8], Value), Err<Vec<u8>>> =
456855e09eSopenharmony_ci  parser(data).map_err(|e: E<&[u8]>| -> e.to_owned());
466855e09eSopenharmony_ci```
476855e09eSopenharmony_ci
486855e09eSopenharmony_cinom provides a powerful error system that can adapt to your needs: you can
496855e09eSopenharmony_ciget reduced error information if you want to improve performance, or you can
506855e09eSopenharmony_ciget a precise trace of parser application, with fine grained position information.
516855e09eSopenharmony_ci
526855e09eSopenharmony_ciThis is done through the third type parameter of `IResult`, nom's parser result
536855e09eSopenharmony_citype:
546855e09eSopenharmony_ci
556855e09eSopenharmony_ci```rust
566855e09eSopenharmony_cipub type IResult<I, O, E=nom::error::Error<I>> = Result<(I, O), Err<E>>;
576855e09eSopenharmony_ci
586855e09eSopenharmony_cipub enum Err<E> {
596855e09eSopenharmony_ci    Incomplete(Needed),
606855e09eSopenharmony_ci    Error(E),
616855e09eSopenharmony_ci    Failure(E),
626855e09eSopenharmony_ci}
636855e09eSopenharmony_ci```
646855e09eSopenharmony_ci
656855e09eSopenharmony_ciThis error type is completely generic in nom's combinators, so you can choose
666855e09eSopenharmony_ciexactly which error type you want to use when you define your parsers, or
676855e09eSopenharmony_cidirectly at the call site.
686855e09eSopenharmony_ciSee [the JSON parser](https://github.com/Geal/nom/blob/5405e1173f1052f7e006dcb0b9cfda2b06557b65/examples/json.rs#L209-L286)
696855e09eSopenharmony_cifor an example of choosing different error types at the call site.
706855e09eSopenharmony_ci
716855e09eSopenharmony_ci## Common error types
726855e09eSopenharmony_ci
736855e09eSopenharmony_ci### the default error type: nom::error::Error
746855e09eSopenharmony_ci
756855e09eSopenharmony_ci```rust
766855e09eSopenharmony_ci#[derive(Debug, PartialEq)]
776855e09eSopenharmony_cipub struct Error<I> {
786855e09eSopenharmony_ci  /// position of the error in the input data
796855e09eSopenharmony_ci  pub input: I,
806855e09eSopenharmony_ci  /// nom error code
816855e09eSopenharmony_ci  pub code: ErrorKind,
826855e09eSopenharmony_ci}
836855e09eSopenharmony_ci```
846855e09eSopenharmony_ci
856855e09eSopenharmony_ciThis structure contains a `nom::error::ErrorKind` indicating which kind of
866855e09eSopenharmony_ciparser encountered an error (example: `ErrorKind::Tag` for the `tag()`
876855e09eSopenharmony_cicombinator), and the input position of the error.
886855e09eSopenharmony_ci
896855e09eSopenharmony_ciThis error type is fast and has very low overhead, so it is suitable for
906855e09eSopenharmony_ciparsers that are called repeatedly, like in network protocols.
916855e09eSopenharmony_ciIt is very limited though, it will not tell you about the chain of
926855e09eSopenharmony_ciparser calls, so it is not enough to write user friendly errors.
936855e09eSopenharmony_ci
946855e09eSopenharmony_ciExample error returned in a JSON-like parser (from `examples/json.rs`):
956855e09eSopenharmony_ci
966855e09eSopenharmony_ci```rust
976855e09eSopenharmony_cilet data = "  { \"a\"\t: 42,
986855e09eSopenharmony_ci\"b\": [ \"x\", \"y\", 12 ] ,
996855e09eSopenharmony_ci\"c\": { 1\"hello\" : \"world\"
1006855e09eSopenharmony_ci}
1016855e09eSopenharmony_ci} ";
1026855e09eSopenharmony_ci
1036855e09eSopenharmony_ci// will print:
1046855e09eSopenharmony_ci// Err(
1056855e09eSopenharmony_ci//   Failure(
1066855e09eSopenharmony_ci//       Error {
1076855e09eSopenharmony_ci//           input: "1\"hello\" : \"world\"\n  }\n  } ",
1086855e09eSopenharmony_ci//           code: Char,
1096855e09eSopenharmony_ci//       },
1106855e09eSopenharmony_ci//   ),
1116855e09eSopenharmony_ci// )
1126855e09eSopenharmony_ciprintln!(
1136855e09eSopenharmony_ci  "{:#?}\n",
1146855e09eSopenharmony_ci  json::<Error<&str>>(data)
1156855e09eSopenharmony_ci);
1166855e09eSopenharmony_ci```
1176855e09eSopenharmony_ci
1186855e09eSopenharmony_ci### getting more information: nom::error::VerboseError
1196855e09eSopenharmony_ci
1206855e09eSopenharmony_ciThe  `VerboseError<I>` type accumulates more information about the chain of
1216855e09eSopenharmony_ciparsers that encountered an error:
1226855e09eSopenharmony_ci
1236855e09eSopenharmony_ci```rust
1246855e09eSopenharmony_ci#[derive(Clone, Debug, PartialEq)]
1256855e09eSopenharmony_cipub struct VerboseError<I> {
1266855e09eSopenharmony_ci  /// List of errors accumulated by `VerboseError`, containing the affected
1276855e09eSopenharmony_ci  /// part of input data, and some context
1286855e09eSopenharmony_ci  pub errors: crate::lib::std::vec::Vec<(I, VerboseErrorKind)>,
1296855e09eSopenharmony_ci}
1306855e09eSopenharmony_ci
1316855e09eSopenharmony_ci#[derive(Clone, Debug, PartialEq)]
1326855e09eSopenharmony_ci/// Error context for `VerboseError`
1336855e09eSopenharmony_cipub enum VerboseErrorKind {
1346855e09eSopenharmony_ci  /// Static string added by the `context` function
1356855e09eSopenharmony_ci  Context(&'static str),
1366855e09eSopenharmony_ci  /// Indicates which character was expected by the `char` function
1376855e09eSopenharmony_ci  Char(char),
1386855e09eSopenharmony_ci  /// Error kind given by various nom parsers
1396855e09eSopenharmony_ci  Nom(ErrorKind),
1406855e09eSopenharmony_ci}
1416855e09eSopenharmony_ci```
1426855e09eSopenharmony_ci
1436855e09eSopenharmony_ciIt contains the input position and error code for each of those parsers.
1446855e09eSopenharmony_ciIt does not accumulate errors from the different branches of `alt`, it will
1456855e09eSopenharmony_cionly contain errors from the last branch it tried.
1466855e09eSopenharmony_ci
1476855e09eSopenharmony_ciIt can be used along with the `nom::error::context` combinator to inform about
1486855e09eSopenharmony_cithe parser chain:
1496855e09eSopenharmony_ci
1506855e09eSopenharmony_ci```rust
1516855e09eSopenharmony_cicontext(
1526855e09eSopenharmony_ci  "string",
1536855e09eSopenharmony_ci  preceded(char('\"'), cut(terminated(parse_str, char('\"')))),
1546855e09eSopenharmony_ci)(i)
1556855e09eSopenharmony_ci```
1566855e09eSopenharmony_ci
1576855e09eSopenharmony_ciIt is not very usable if printed directly:
1586855e09eSopenharmony_ci
1596855e09eSopenharmony_ci```rust
1606855e09eSopenharmony_ci// parsed verbose: Err(
1616855e09eSopenharmony_ci//   Failure(
1626855e09eSopenharmony_ci//       VerboseError {
1636855e09eSopenharmony_ci//           errors: [
1646855e09eSopenharmony_ci//               (
1656855e09eSopenharmony_ci//                   "1\"hello\" : \"world\"\n  }\n  } ",
1666855e09eSopenharmony_ci//                   Char(
1676855e09eSopenharmony_ci//                       '}',
1686855e09eSopenharmony_ci//                   ),
1696855e09eSopenharmony_ci//               ),
1706855e09eSopenharmony_ci//               (
1716855e09eSopenharmony_ci//                   "{ 1\"hello\" : \"world\"\n  }\n  } ",
1726855e09eSopenharmony_ci//                   Context(
1736855e09eSopenharmony_ci//                       "map",
1746855e09eSopenharmony_ci//                   ),
1756855e09eSopenharmony_ci//               ),
1766855e09eSopenharmony_ci//               (
1776855e09eSopenharmony_ci//                   "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } ",
1786855e09eSopenharmony_ci//                   Context(
1796855e09eSopenharmony_ci//                       "map",
1806855e09eSopenharmony_ci//                   ),
1816855e09eSopenharmony_ci//               ),
1826855e09eSopenharmony_ci//           ],
1836855e09eSopenharmony_ci//       },
1846855e09eSopenharmony_ci//   ),
1856855e09eSopenharmony_ci// )
1866855e09eSopenharmony_ciprintln!("parsed verbose: {:#?}", json::<VerboseError<&str>>(data));
1876855e09eSopenharmony_ci```
1886855e09eSopenharmony_ci
1896855e09eSopenharmony_ciBut by looking at the original input and the chain of errors, we can build
1906855e09eSopenharmony_cia more user friendly error message. The `nom::error::convert_error` function
1916855e09eSopenharmony_cican build such a message.
1926855e09eSopenharmony_ci
1936855e09eSopenharmony_ci```rust
1946855e09eSopenharmony_cilet e = json::<VerboseError<&str>>(data).finish().err().unwrap();
1956855e09eSopenharmony_ci// here we use the `convert_error` function, to transform a `VerboseError<&str>`
1966855e09eSopenharmony_ci// into a printable trace.
1976855e09eSopenharmony_ci//
1986855e09eSopenharmony_ci// This will print:
1996855e09eSopenharmony_ci// verbose errors - `json::<VerboseError<&str>>(data)`:
2006855e09eSopenharmony_ci// 0: at line 2:
2016855e09eSopenharmony_ci//   "c": { 1"hello" : "world"
2026855e09eSopenharmony_ci//          ^
2036855e09eSopenharmony_ci// expected '}', found 1
2046855e09eSopenharmony_ci//
2056855e09eSopenharmony_ci// 1: at line 2, in map:
2066855e09eSopenharmony_ci//   "c": { 1"hello" : "world"
2076855e09eSopenharmony_ci//        ^
2086855e09eSopenharmony_ci//
2096855e09eSopenharmony_ci// 2: at line 0, in map:
2106855e09eSopenharmony_ci//   { "a" : 42,
2116855e09eSopenharmony_ci//   ^
2126855e09eSopenharmony_ciprintln!(
2136855e09eSopenharmony_ci  "verbose errors - `json::<VerboseError<&str>>(data)`:\n{}",
2146855e09eSopenharmony_ci  convert_error(data, e)
2156855e09eSopenharmony_ci);
2166855e09eSopenharmony_ci```
2176855e09eSopenharmony_ci
2186855e09eSopenharmony_ciNote that `VerboseError` and `convert_error` are meant as a starting point for
2196855e09eSopenharmony_cilanguage errors, but that they cannot cover all use cases. So a custom
2206855e09eSopenharmony_ci`convert_error` function should probably be written.
2216855e09eSopenharmony_ci
2226855e09eSopenharmony_ci### Improving usability: nom_locate and nom-supreme
2236855e09eSopenharmony_ci
2246855e09eSopenharmony_ciThese crates were developed to improve the user experience when writing nom
2256855e09eSopenharmony_ciparsers.
2266855e09eSopenharmony_ci
2276855e09eSopenharmony_ci#### nom_locate
2286855e09eSopenharmony_ci
2296855e09eSopenharmony_ci[nom_locate](https://docs.rs/nom_locate/) wraps the input data in a `Span`
2306855e09eSopenharmony_citype that can be understood by nom parsers. That type provides location
2316855e09eSopenharmony_ciinformation, like line and column.
2326855e09eSopenharmony_ci
2336855e09eSopenharmony_ci#### nom-supreme
2346855e09eSopenharmony_ci
2356855e09eSopenharmony_ci[nom-supreme](https://docs.rs/nom-supreme/) provides the `ErrorTree<I>` error
2366855e09eSopenharmony_citype, that provides the same chain of parser errors as `VerboseError`, but also
2376855e09eSopenharmony_ciaccumulates errors from the various branches tried by `alt`.
2386855e09eSopenharmony_ci
2396855e09eSopenharmony_ciWith this error type, you can explore everything that has been tried by the
2406855e09eSopenharmony_ciparser.
2416855e09eSopenharmony_ci
2426855e09eSopenharmony_ci## The `ParseError` trait
2436855e09eSopenharmony_ci
2446855e09eSopenharmony_ciIf those error types are not enough, we can define our own, by implementing
2456855e09eSopenharmony_cithe `ParseError<I>` trait. All nom combinators are generic over that trait
2466855e09eSopenharmony_cifor their errors, so we only need to define it in the parser result type,
2476855e09eSopenharmony_ciand it will be used everywhere.
2486855e09eSopenharmony_ci
2496855e09eSopenharmony_ci```rust
2506855e09eSopenharmony_cipub trait ParseError<I>: Sized {
2516855e09eSopenharmony_ci    /// Creates an error from the input position and an [ErrorKind]
2526855e09eSopenharmony_ci    fn from_error_kind(input: I, kind: ErrorKind) -> Self;
2536855e09eSopenharmony_ci
2546855e09eSopenharmony_ci    /// Combines an existing error with a new one created from the input
2556855e09eSopenharmony_ci    /// position and an [ErrorKind]. This is useful when backtracking
2566855e09eSopenharmony_ci    /// through a parse tree, accumulating error context on the way
2576855e09eSopenharmony_ci    fn append(input: I, kind: ErrorKind, other: Self) -> Self;
2586855e09eSopenharmony_ci
2596855e09eSopenharmony_ci    /// Creates an error from an input position and an expected character
2606855e09eSopenharmony_ci    fn from_char(input: I, _: char) -> Self {
2616855e09eSopenharmony_ci        Self::from_error_kind(input, ErrorKind::Char)
2626855e09eSopenharmony_ci    }
2636855e09eSopenharmony_ci
2646855e09eSopenharmony_ci    /// Combines two existing errors. This function is used to compare errors
2656855e09eSopenharmony_ci    /// generated in various branches of `alt`
2666855e09eSopenharmony_ci    fn or(self, other: Self) -> Self {
2676855e09eSopenharmony_ci        other
2686855e09eSopenharmony_ci    }
2696855e09eSopenharmony_ci}
2706855e09eSopenharmony_ci```
2716855e09eSopenharmony_ci
2726855e09eSopenharmony_ciAny error type has to implement that trait, that requires ways to build an
2736855e09eSopenharmony_cierror:
2746855e09eSopenharmony_ci- `from_error_kind`: From the input position and the `ErrorKind` enum that indicates in which parser we got an error
2756855e09eSopenharmony_ci- `append`: Allows the creation of a chain of errors as we backtrack through the parser tree (various combinators will add more context)
2766855e09eSopenharmony_ci- `from_char`: Creates an error that indicates which character we were expecting
2776855e09eSopenharmony_ci- `or`: In combinators like `alt`, allows choosing between errors from various branches (or accumulating them)
2786855e09eSopenharmony_ci
2796855e09eSopenharmony_ciWe can also implement the `ContextError` trait to support the `context()`
2806855e09eSopenharmony_cicombinator used by `VerboseError<I>`:
2816855e09eSopenharmony_ci
2826855e09eSopenharmony_ci```rust
2836855e09eSopenharmony_cipub trait ContextError<I>: Sized {
2846855e09eSopenharmony_ci    fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self {
2856855e09eSopenharmony_ci        other
2866855e09eSopenharmony_ci    }
2876855e09eSopenharmony_ci}
2886855e09eSopenharmony_ci```
2896855e09eSopenharmony_ci
2906855e09eSopenharmony_ciAnd there is also the `FromExternalError<I, E>` used by `map_res` to wrap
2916855e09eSopenharmony_cierrors returned by other functions:
2926855e09eSopenharmony_ci
2936855e09eSopenharmony_ci```rust
2946855e09eSopenharmony_cipub trait FromExternalError<I, ExternalError> {
2956855e09eSopenharmony_ci  fn from_external_error(input: I, kind: ErrorKind, e: ExternalError) -> Self;
2966855e09eSopenharmony_ci}
2976855e09eSopenharmony_ci```
2986855e09eSopenharmony_ci
2996855e09eSopenharmony_ci### Example usage
3006855e09eSopenharmony_ci
3016855e09eSopenharmony_ciLet's define a debugging error type, that will print something every time an
3026855e09eSopenharmony_cierror is generated. This will give us a good insight into what the parser tried.
3036855e09eSopenharmony_ciSince errors can be combined with each other, we want it to keep some info on
3046855e09eSopenharmony_cithe error that was just returned. We'll just store that in a string:
3056855e09eSopenharmony_ci
3066855e09eSopenharmony_ci```rust
3076855e09eSopenharmony_cistruct DebugError {
3086855e09eSopenharmony_ci    message: String,
3096855e09eSopenharmony_ci}
3106855e09eSopenharmony_ci```
3116855e09eSopenharmony_ci
3126855e09eSopenharmony_ciNow let's implement `ParseError` and `ContextError` on it:
3136855e09eSopenharmony_ci
3146855e09eSopenharmony_ci```rust
3156855e09eSopenharmony_ciimpl ParseError<&str> for DebugError {
3166855e09eSopenharmony_ci    // on one line, we show the error code and the input that caused it
3176855e09eSopenharmony_ci    fn from_error_kind(input: &str, kind: ErrorKind) -> Self {
3186855e09eSopenharmony_ci        let message = format!("{:?}:\t{:?}\n", kind, input);
3196855e09eSopenharmony_ci        println!("{}", message);
3206855e09eSopenharmony_ci        DebugError { message }
3216855e09eSopenharmony_ci    }
3226855e09eSopenharmony_ci
3236855e09eSopenharmony_ci    // if combining multiple errors, we show them one after the other
3246855e09eSopenharmony_ci    fn append(input: &str, kind: ErrorKind, other: Self) -> Self {
3256855e09eSopenharmony_ci        let message = format!("{}{:?}:\t{:?}\n", other.message, kind, input);
3266855e09eSopenharmony_ci        println!("{}", message);
3276855e09eSopenharmony_ci        DebugError { message }
3286855e09eSopenharmony_ci    }
3296855e09eSopenharmony_ci
3306855e09eSopenharmony_ci    fn from_char(input: &str, c: char) -> Self {
3316855e09eSopenharmony_ci        let message = format!("'{}':\t{:?}\n", c, input);
3326855e09eSopenharmony_ci        println!("{}", message);
3336855e09eSopenharmony_ci        DebugError { message }
3346855e09eSopenharmony_ci    }
3356855e09eSopenharmony_ci
3366855e09eSopenharmony_ci    fn or(self, other: Self) -> Self {
3376855e09eSopenharmony_ci        let message = format!("{}\tOR\n{}\n", self.message, other.message);
3386855e09eSopenharmony_ci        println!("{}", message);
3396855e09eSopenharmony_ci        DebugError { message }
3406855e09eSopenharmony_ci    }
3416855e09eSopenharmony_ci}
3426855e09eSopenharmony_ci
3436855e09eSopenharmony_ciimpl ContextError<&str> for DebugError {
3446855e09eSopenharmony_ci    fn add_context(input: &str, ctx: &'static str, other: Self) -> Self {
3456855e09eSopenharmony_ci        let message = format!("{}\"{}\":\t{:?}\n", other.message, ctx, input);
3466855e09eSopenharmony_ci        println!("{}", message);
3476855e09eSopenharmony_ci        DebugError { message }
3486855e09eSopenharmony_ci    }
3496855e09eSopenharmony_ci}
3506855e09eSopenharmony_ci```
3516855e09eSopenharmony_ci
3526855e09eSopenharmony_ciSo when calling our JSON parser with this error type, we will get a trace
3536855e09eSopenharmony_ciof all the times a parser stoppped and backtracked:
3546855e09eSopenharmony_ci
3556855e09eSopenharmony_ci```rust
3566855e09eSopenharmony_ciprintln!("debug: {:#?}", root::<DebugError>(data));
3576855e09eSopenharmony_ci```
3586855e09eSopenharmony_ci
3596855e09eSopenharmony_ci```
3606855e09eSopenharmony_ciAlphaNumeric:   "\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
3616855e09eSopenharmony_ci
3626855e09eSopenharmony_ci'{':    "42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
3636855e09eSopenharmony_ci
3646855e09eSopenharmony_ci'{':    "42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
3656855e09eSopenharmony_ci"map":  "42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
3666855e09eSopenharmony_ci
3676855e09eSopenharmony_ci[..]
3686855e09eSopenharmony_ci
3696855e09eSopenharmony_ciAlphaNumeric:   "\": { 1\"hello\" : \"world\"\n  }\n  } "
3706855e09eSopenharmony_ci
3716855e09eSopenharmony_ci'"':    "1\"hello\" : \"world\"\n  }\n  } "
3726855e09eSopenharmony_ci
3736855e09eSopenharmony_ci'"':    "1\"hello\" : \"world\"\n  }\n  } "
3746855e09eSopenharmony_ci"string":       "1\"hello\" : \"world\"\n  }\n  } "
3756855e09eSopenharmony_ci
3766855e09eSopenharmony_ci'}':    "1\"hello\" : \"world\"\n  }\n  } "
3776855e09eSopenharmony_ci
3786855e09eSopenharmony_ci'}':    "1\"hello\" : \"world\"\n  }\n  } "
3796855e09eSopenharmony_ci"map":  "{ 1\"hello\" : \"world\"\n  }\n  } "
3806855e09eSopenharmony_ci
3816855e09eSopenharmony_ci'}':    "1\"hello\" : \"world\"\n  }\n  } "
3826855e09eSopenharmony_ci"map":  "{ 1\"hello\" : \"world\"\n  }\n  } "
3836855e09eSopenharmony_ci"map":  "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
3846855e09eSopenharmony_ci
3856855e09eSopenharmony_cidebug: Err(
3866855e09eSopenharmony_ci    Failure(
3876855e09eSopenharmony_ci        DebugError {
3886855e09eSopenharmony_ci            message: "'}':\t\"1\\\"hello\\\" : \\\"world\\\"\\n  }\\n  } \"\n\"map\":\t\"{ 1\\\"hello\\\" : \\\"world
3896855e09eSopenharmony_ci\\"\\n  }\\n  } \"\n\"map\":\t\"{ \\\"a\\\"\\t: 42,\\n  \\\"b\\\": [ \\\"x\\\", \\\"y\\\", 12 ] ,\\n  \\\"c\\\": { 1\
3906855e09eSopenharmony_ci\"hello\\\" : \\\"world\\\"\\n  }\\n  } \"\n",
3916855e09eSopenharmony_ci        },
3926855e09eSopenharmony_ci    ),
3936855e09eSopenharmony_ci)
3946855e09eSopenharmony_ci```
3956855e09eSopenharmony_ci
3966855e09eSopenharmony_ciHere we can see that when parsing `{ 1\"hello\" : \"world\"\n  }\n  }`, after
3976855e09eSopenharmony_cigetting past the initial `{`, we tried:
3986855e09eSopenharmony_ci- parsing a `"` because we're expecting a key name, and that parser was part of the
3996855e09eSopenharmony_ci"string" parser
4006855e09eSopenharmony_ci- parsing a `}` because the map might be empty. When this fails, we backtrack,
4016855e09eSopenharmony_cithrough 2 recursive map parsers:
4026855e09eSopenharmony_ci
4036855e09eSopenharmony_ci```
4046855e09eSopenharmony_ci'}':    "1\"hello\" : \"world\"\n  }\n  } "
4056855e09eSopenharmony_ci"map":  "{ 1\"hello\" : \"world\"\n  }\n  } "
4066855e09eSopenharmony_ci"map":  "{ \"a\"\t: 42,\n  \"b\": [ \"x\", \"y\", 12 ] ,\n  \"c\": { 1\"hello\" : \"world\"\n  }\n  } "
4076855e09eSopenharmony_ci```
4086855e09eSopenharmony_ci
4096855e09eSopenharmony_ci## Debugging parsers
4106855e09eSopenharmony_ci
4116855e09eSopenharmony_ciWhile you are writing your parsers, you will sometimes need to follow
4126855e09eSopenharmony_ciwhich part of the parser sees which part of the input.
4136855e09eSopenharmony_ci
4146855e09eSopenharmony_ciTo that end, nom provides the `dbg_dmp` function that will observe
4156855e09eSopenharmony_cia parser's input and output, and print a hexdump of the input if there was an
4166855e09eSopenharmony_cierror. Here is what it could return:
4176855e09eSopenharmony_ci
4186855e09eSopenharmony_ci```rust
4196855e09eSopenharmony_cifn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
4206855e09eSopenharmony_ci    dbg_dmp(tag("abcd"), "tag")(i)
4216855e09eSopenharmony_ci}
4226855e09eSopenharmony_ci
4236855e09eSopenharmony_cilet a = &b"efghijkl"[..];
4246855e09eSopenharmony_ci
4256855e09eSopenharmony_ci// Will print the following message:
4266855e09eSopenharmony_ci// tag: Error(Error(Error { input: [101, 102, 103, 104, 105, 106, 107, 108], code: Tag })) at:
4276855e09eSopenharmony_ci// 00000000        65 66 67 68 69 6a 6b 6c         efghijkl
4286855e09eSopenharmony_cif(a);
4296855e09eSopenharmony_ci```
4306855e09eSopenharmony_ci
4316855e09eSopenharmony_ciYou can go further with the [nom-trace crate](https://github.com/rust-bakery/nom-trace)
432