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