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}