• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Error management
2 //!
3 //! Parsers are generic over their error type, requiring that it implements
4 //! the `error::ParseError<Input>` trait.
5 
6 use crate::internal::Parser;
7 use crate::lib::std::fmt;
8 
9 /// This trait must be implemented by the error type of a nom parser.
10 ///
11 /// There are already implementations of it for `(Input, ErrorKind)`
12 /// and `VerboseError<Input>`.
13 ///
14 /// It provides methods to create an error from some combinators,
15 /// and combine existing errors in combinators like `alt`.
16 pub trait ParseError<I>: Sized {
17   /// Creates an error from the input position and an [ErrorKind]
from_error_kind(input: I, kind: ErrorKind) -> Self18   fn from_error_kind(input: I, kind: ErrorKind) -> Self;
19 
20   /// Combines an existing error with a new one created from the input
21   /// position and an [ErrorKind]. This is useful when backtracking
22   /// through a parse tree, accumulating error context on the way
append(input: I, kind: ErrorKind, other: Self) -> Self23   fn append(input: I, kind: ErrorKind, other: Self) -> Self;
24 
25   /// Creates an error from an input position and an expected character
from_char(input: I, _: char) -> Self26   fn from_char(input: I, _: char) -> Self {
27     Self::from_error_kind(input, ErrorKind::Char)
28   }
29 
30   /// Combines two existing errors. This function is used to compare errors
31   /// generated in various branches of `alt`.
or(self, other: Self) -> Self32   fn or(self, other: Self) -> Self {
33     other
34   }
35 }
36 
37 /// This trait is required by the `context` combinator to add a static string
38 /// to an existing error
39 pub trait ContextError<I>: Sized {
40   /// Creates a new error from an input position, a static string and an existing error.
41   /// This is used mainly in the [context] combinator, to add user friendly information
42   /// to errors when backtracking through a parse tree
add_context(_input: I, _ctx: &'static str, other: Self) -> Self43   fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self {
44     other
45   }
46 }
47 
48 /// This trait is required by the `map_res` combinator to integrate
49 /// error types from external functions, like [std::str::FromStr]
50 pub trait FromExternalError<I, E> {
51   /// Creates a new error from an input position, an [ErrorKind] indicating the
52   /// wrapping parser, and an external error
from_external_error(input: I, kind: ErrorKind, e: E) -> Self53   fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self;
54 }
55 
56 /// default error type, only contains the error' location and code
57 #[derive(Debug, PartialEq)]
58 pub struct Error<I> {
59   /// position of the error in the input data
60   pub input: I,
61   /// nom error code
62   pub code: ErrorKind,
63 }
64 
65 impl<I> Error<I> {
66   /// creates a new basic error
new(input: I, code: ErrorKind) -> Error<I>67   pub fn new(input: I, code: ErrorKind) -> Error<I> {
68     Error { input, code }
69   }
70 }
71 
72 impl<I> ParseError<I> for Error<I> {
from_error_kind(input: I, kind: ErrorKind) -> Self73   fn from_error_kind(input: I, kind: ErrorKind) -> Self {
74     Error { input, code: kind }
75   }
76 
append(_: I, _: ErrorKind, other: Self) -> Self77   fn append(_: I, _: ErrorKind, other: Self) -> Self {
78     other
79   }
80 }
81 
82 impl<I> ContextError<I> for Error<I> {}
83 
84 impl<I, E> FromExternalError<I, E> for Error<I> {
85   /// Create a new error from an input position and an external error
from_external_error(input: I, kind: ErrorKind, _e: E) -> Self86   fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
87     Error { input, code: kind }
88   }
89 }
90 
91 /// The Display implementation allows the std::error::Error implementation
92 impl<I: fmt::Display> fmt::Display for Error<I> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result93   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94     write!(f, "error {:?} at: {}", self.code, self.input)
95   }
96 }
97 
98 #[cfg(feature = "std")]
99 impl<I: fmt::Debug + fmt::Display> std::error::Error for Error<I> {}
100 
101 // for backward compatibility, keep those trait implementations
102 // for the previously used error type
103 impl<I> ParseError<I> for (I, ErrorKind) {
from_error_kind(input: I, kind: ErrorKind) -> Self104   fn from_error_kind(input: I, kind: ErrorKind) -> Self {
105     (input, kind)
106   }
107 
append(_: I, _: ErrorKind, other: Self) -> Self108   fn append(_: I, _: ErrorKind, other: Self) -> Self {
109     other
110   }
111 }
112 
113 impl<I> ContextError<I> for (I, ErrorKind) {}
114 
115 impl<I, E> FromExternalError<I, E> for (I, ErrorKind) {
from_external_error(input: I, kind: ErrorKind, _e: E) -> Self116   fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
117     (input, kind)
118   }
119 }
120 
121 impl<I> ParseError<I> for () {
from_error_kind(_: I, _: ErrorKind) -> Self122   fn from_error_kind(_: I, _: ErrorKind) -> Self {}
123 
append(_: I, _: ErrorKind, _: Self) -> Self124   fn append(_: I, _: ErrorKind, _: Self) -> Self {}
125 }
126 
127 impl<I> ContextError<I> for () {}
128 
129 impl<I, E> FromExternalError<I, E> for () {
from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self130   fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {}
131 }
132 
133 /// Creates an error from the input position and an [ErrorKind]
make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E134 pub fn make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E {
135   E::from_error_kind(input, kind)
136 }
137 
138 /// Combines an existing error with a new one created from the input
139 /// position and an [ErrorKind]. This is useful when backtracking
140 /// through a parse tree, accumulating error context on the way
append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E141 pub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E {
142   E::append(input, kind, other)
143 }
144 
145 /// This error type accumulates errors and their position when backtracking
146 /// through a parse tree. With some post processing (cf `examples/json.rs`),
147 /// it can be used to display user friendly error messages
148 #[cfg(feature = "alloc")]
149 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
150 #[derive(Clone, Debug, PartialEq)]
151 pub struct VerboseError<I> {
152   /// List of errors accumulated by `VerboseError`, containing the affected
153   /// part of input data, and some context
154   pub errors: crate::lib::std::vec::Vec<(I, VerboseErrorKind)>,
155 }
156 
157 #[cfg(feature = "alloc")]
158 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
159 #[derive(Clone, Debug, PartialEq)]
160 /// Error context for `VerboseError`
161 pub enum VerboseErrorKind {
162   /// Static string added by the `context` function
163   Context(&'static str),
164   /// Indicates which character was expected by the `char` function
165   Char(char),
166   /// Error kind given by various nom parsers
167   Nom(ErrorKind),
168 }
169 
170 #[cfg(feature = "alloc")]
171 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
172 impl<I> ParseError<I> for VerboseError<I> {
from_error_kind(input: I, kind: ErrorKind) -> Self173   fn from_error_kind(input: I, kind: ErrorKind) -> Self {
174     VerboseError {
175       errors: vec![(input, VerboseErrorKind::Nom(kind))],
176     }
177   }
178 
append(input: I, kind: ErrorKind, mut other: Self) -> Self179   fn append(input: I, kind: ErrorKind, mut other: Self) -> Self {
180     other.errors.push((input, VerboseErrorKind::Nom(kind)));
181     other
182   }
183 
from_char(input: I, c: char) -> Self184   fn from_char(input: I, c: char) -> Self {
185     VerboseError {
186       errors: vec![(input, VerboseErrorKind::Char(c))],
187     }
188   }
189 }
190 
191 #[cfg(feature = "alloc")]
192 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
193 impl<I> ContextError<I> for VerboseError<I> {
add_context(input: I, ctx: &'static str, mut other: Self) -> Self194   fn add_context(input: I, ctx: &'static str, mut other: Self) -> Self {
195     other.errors.push((input, VerboseErrorKind::Context(ctx)));
196     other
197   }
198 }
199 
200 #[cfg(feature = "alloc")]
201 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
202 impl<I, E> FromExternalError<I, E> for VerboseError<I> {
203   /// Create a new error from an input position and an external error
from_external_error(input: I, kind: ErrorKind, _e: E) -> Self204   fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
205     Self::from_error_kind(input, kind)
206   }
207 }
208 
209 #[cfg(feature = "alloc")]
210 impl<I: fmt::Display> fmt::Display for VerboseError<I> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result211   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212     writeln!(f, "Parse error:")?;
213     for (input, error) in &self.errors {
214       match error {
215         VerboseErrorKind::Nom(e) => writeln!(f, "{:?} at: {}", e, input)?,
216         VerboseErrorKind::Char(c) => writeln!(f, "expected '{}' at: {}", c, input)?,
217         VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?,
218       }
219     }
220 
221     Ok(())
222   }
223 }
224 
225 #[cfg(feature = "std")]
226 impl<I: fmt::Debug + fmt::Display> std::error::Error for VerboseError<I> {}
227 
228 use crate::internal::{Err, IResult};
229 
230 /// Create a new error from an input position, a static string and an existing error.
231 /// This is used mainly in the [context] combinator, to add user friendly information
232 /// to errors when backtracking through a parse tree
context<I: Clone, E: ContextError<I>, F, O>( context: &'static str, mut f: F, ) -> impl FnMut(I) -> IResult<I, O, E> where F: Parser<I, O, E>,233 pub fn context<I: Clone, E: ContextError<I>, F, O>(
234   context: &'static str,
235   mut f: F,
236 ) -> impl FnMut(I) -> IResult<I, O, E>
237 where
238   F: Parser<I, O, E>,
239 {
240   move |i: I| match f.parse(i.clone()) {
241     Ok(o) => Ok(o),
242     Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)),
243     Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, context, e))),
244     Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, context, e))),
245   }
246 }
247 
248 /// Transforms a `VerboseError` into a trace with input position information
249 #[cfg(feature = "alloc")]
250 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
convert_error<I: core::ops::Deref<Target = str>>( input: I, e: VerboseError<I>, ) -> crate::lib::std::string::String251 pub fn convert_error<I: core::ops::Deref<Target = str>>(
252   input: I,
253   e: VerboseError<I>,
254 ) -> crate::lib::std::string::String {
255   use crate::lib::std::fmt::Write;
256   use crate::traits::Offset;
257 
258   let mut result = crate::lib::std::string::String::new();
259 
260   for (i, (substring, kind)) in e.errors.iter().enumerate() {
261     let offset = input.offset(substring);
262 
263     if input.is_empty() {
264       match kind {
265         VerboseErrorKind::Char(c) => {
266           write!(&mut result, "{}: expected '{}', got empty input\n\n", i, c)
267         }
268         VerboseErrorKind::Context(s) => write!(&mut result, "{}: in {}, got empty input\n\n", i, s),
269         VerboseErrorKind::Nom(e) => write!(&mut result, "{}: in {:?}, got empty input\n\n", i, e),
270       }
271     } else {
272       let prefix = &input.as_bytes()[..offset];
273 
274       // Count the number of newlines in the first `offset` bytes of input
275       let line_number = prefix.iter().filter(|&&b| b == b'\n').count() + 1;
276 
277       // Find the line that includes the subslice:
278       // Find the *last* newline before the substring starts
279       let line_begin = prefix
280         .iter()
281         .rev()
282         .position(|&b| b == b'\n')
283         .map(|pos| offset - pos)
284         .unwrap_or(0);
285 
286       // Find the full line after that newline
287       let line = input[line_begin..]
288         .lines()
289         .next()
290         .unwrap_or(&input[line_begin..])
291         .trim_end();
292 
293       // The (1-indexed) column number is the offset of our substring into that line
294       let column_number = line.offset(substring) + 1;
295 
296       match kind {
297         VerboseErrorKind::Char(c) => {
298           if let Some(actual) = substring.chars().next() {
299             write!(
300               &mut result,
301               "{i}: at line {line_number}:\n\
302                {line}\n\
303                {caret:>column$}\n\
304                expected '{expected}', found {actual}\n\n",
305               i = i,
306               line_number = line_number,
307               line = line,
308               caret = '^',
309               column = column_number,
310               expected = c,
311               actual = actual,
312             )
313           } else {
314             write!(
315               &mut result,
316               "{i}: at line {line_number}:\n\
317                {line}\n\
318                {caret:>column$}\n\
319                expected '{expected}', got end of input\n\n",
320               i = i,
321               line_number = line_number,
322               line = line,
323               caret = '^',
324               column = column_number,
325               expected = c,
326             )
327           }
328         }
329         VerboseErrorKind::Context(s) => write!(
330           &mut result,
331           "{i}: at line {line_number}, in {context}:\n\
332              {line}\n\
333              {caret:>column$}\n\n",
334           i = i,
335           line_number = line_number,
336           context = s,
337           line = line,
338           caret = '^',
339           column = column_number,
340         ),
341         VerboseErrorKind::Nom(e) => write!(
342           &mut result,
343           "{i}: at line {line_number}, in {nom_err:?}:\n\
344              {line}\n\
345              {caret:>column$}\n\n",
346           i = i,
347           line_number = line_number,
348           nom_err = e,
349           line = line,
350           caret = '^',
351           column = column_number,
352         ),
353       }
354     }
355     // Because `write!` to a `String` is infallible, this `unwrap` is fine.
356     .unwrap();
357   }
358 
359   result
360 }
361 
362 /// Indicates which parser returned an error
363 #[rustfmt::skip]
364 #[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)]
365 #[allow(deprecated,missing_docs)]
366 pub enum ErrorKind {
367   Tag,
368   MapRes,
369   MapOpt,
370   Alt,
371   IsNot,
372   IsA,
373   SeparatedList,
374   SeparatedNonEmptyList,
375   Many0,
376   Many1,
377   ManyTill,
378   Count,
379   TakeUntil,
380   LengthValue,
381   TagClosure,
382   Alpha,
383   Digit,
384   HexDigit,
385   OctDigit,
386   AlphaNumeric,
387   Space,
388   MultiSpace,
389   LengthValueFn,
390   Eof,
391   Switch,
392   TagBits,
393   OneOf,
394   NoneOf,
395   Char,
396   CrLf,
397   RegexpMatch,
398   RegexpMatches,
399   RegexpFind,
400   RegexpCapture,
401   RegexpCaptures,
402   TakeWhile1,
403   Complete,
404   Fix,
405   Escaped,
406   EscapedTransform,
407   NonEmpty,
408   ManyMN,
409   Not,
410   Permutation,
411   Verify,
412   TakeTill1,
413   TakeWhileMN,
414   TooLarge,
415   Many0Count,
416   Many1Count,
417   Float,
418   Satisfy,
419   Fail,
420 }
421 
422 #[rustfmt::skip]
423 #[allow(deprecated)]
424 /// Converts an ErrorKind to a number
error_to_u32(e: &ErrorKind) -> u32425 pub fn error_to_u32(e: &ErrorKind) -> u32 {
426   match *e {
427     ErrorKind::Tag                       => 1,
428     ErrorKind::MapRes                    => 2,
429     ErrorKind::MapOpt                    => 3,
430     ErrorKind::Alt                       => 4,
431     ErrorKind::IsNot                     => 5,
432     ErrorKind::IsA                       => 6,
433     ErrorKind::SeparatedList             => 7,
434     ErrorKind::SeparatedNonEmptyList     => 8,
435     ErrorKind::Many1                     => 9,
436     ErrorKind::Count                     => 10,
437     ErrorKind::TakeUntil                 => 12,
438     ErrorKind::LengthValue               => 15,
439     ErrorKind::TagClosure                => 16,
440     ErrorKind::Alpha                     => 17,
441     ErrorKind::Digit                     => 18,
442     ErrorKind::AlphaNumeric              => 19,
443     ErrorKind::Space                     => 20,
444     ErrorKind::MultiSpace                => 21,
445     ErrorKind::LengthValueFn             => 22,
446     ErrorKind::Eof                       => 23,
447     ErrorKind::Switch                    => 27,
448     ErrorKind::TagBits                   => 28,
449     ErrorKind::OneOf                     => 29,
450     ErrorKind::NoneOf                    => 30,
451     ErrorKind::Char                      => 40,
452     ErrorKind::CrLf                      => 41,
453     ErrorKind::RegexpMatch               => 42,
454     ErrorKind::RegexpMatches             => 43,
455     ErrorKind::RegexpFind                => 44,
456     ErrorKind::RegexpCapture             => 45,
457     ErrorKind::RegexpCaptures            => 46,
458     ErrorKind::TakeWhile1                => 47,
459     ErrorKind::Complete                  => 48,
460     ErrorKind::Fix                       => 49,
461     ErrorKind::Escaped                   => 50,
462     ErrorKind::EscapedTransform          => 51,
463     ErrorKind::NonEmpty                  => 56,
464     ErrorKind::ManyMN                    => 57,
465     ErrorKind::HexDigit                  => 59,
466     ErrorKind::OctDigit                  => 61,
467     ErrorKind::Many0                     => 62,
468     ErrorKind::Not                       => 63,
469     ErrorKind::Permutation               => 64,
470     ErrorKind::ManyTill                  => 65,
471     ErrorKind::Verify                    => 66,
472     ErrorKind::TakeTill1                 => 67,
473     ErrorKind::TakeWhileMN               => 69,
474     ErrorKind::TooLarge                  => 70,
475     ErrorKind::Many0Count                => 71,
476     ErrorKind::Many1Count                => 72,
477     ErrorKind::Float                     => 73,
478     ErrorKind::Satisfy                   => 74,
479     ErrorKind::Fail                      => 75,
480   }
481 }
482 
483 impl ErrorKind {
484   #[rustfmt::skip]
485   #[allow(deprecated)]
486   /// Converts an ErrorKind to a text description
description(&self) -> &str487   pub fn description(&self) -> &str {
488     match *self {
489       ErrorKind::Tag                       => "Tag",
490       ErrorKind::MapRes                    => "Map on Result",
491       ErrorKind::MapOpt                    => "Map on Option",
492       ErrorKind::Alt                       => "Alternative",
493       ErrorKind::IsNot                     => "IsNot",
494       ErrorKind::IsA                       => "IsA",
495       ErrorKind::SeparatedList             => "Separated list",
496       ErrorKind::SeparatedNonEmptyList     => "Separated non empty list",
497       ErrorKind::Many0                     => "Many0",
498       ErrorKind::Many1                     => "Many1",
499       ErrorKind::Count                     => "Count",
500       ErrorKind::TakeUntil                 => "Take until",
501       ErrorKind::LengthValue               => "Length followed by value",
502       ErrorKind::TagClosure                => "Tag closure",
503       ErrorKind::Alpha                     => "Alphabetic",
504       ErrorKind::Digit                     => "Digit",
505       ErrorKind::AlphaNumeric              => "AlphaNumeric",
506       ErrorKind::Space                     => "Space",
507       ErrorKind::MultiSpace                => "Multiple spaces",
508       ErrorKind::LengthValueFn             => "LengthValueFn",
509       ErrorKind::Eof                       => "End of file",
510       ErrorKind::Switch                    => "Switch",
511       ErrorKind::TagBits                   => "Tag on bitstream",
512       ErrorKind::OneOf                     => "OneOf",
513       ErrorKind::NoneOf                    => "NoneOf",
514       ErrorKind::Char                      => "Char",
515       ErrorKind::CrLf                      => "CrLf",
516       ErrorKind::RegexpMatch               => "RegexpMatch",
517       ErrorKind::RegexpMatches             => "RegexpMatches",
518       ErrorKind::RegexpFind                => "RegexpFind",
519       ErrorKind::RegexpCapture             => "RegexpCapture",
520       ErrorKind::RegexpCaptures            => "RegexpCaptures",
521       ErrorKind::TakeWhile1                => "TakeWhile1",
522       ErrorKind::Complete                  => "Complete",
523       ErrorKind::Fix                       => "Fix",
524       ErrorKind::Escaped                   => "Escaped",
525       ErrorKind::EscapedTransform          => "EscapedTransform",
526       ErrorKind::NonEmpty                  => "NonEmpty",
527       ErrorKind::ManyMN                    => "Many(m, n)",
528       ErrorKind::HexDigit                  => "Hexadecimal Digit",
529       ErrorKind::OctDigit                  => "Octal digit",
530       ErrorKind::Not                       => "Negation",
531       ErrorKind::Permutation               => "Permutation",
532       ErrorKind::ManyTill                  => "ManyTill",
533       ErrorKind::Verify                    => "predicate verification",
534       ErrorKind::TakeTill1                 => "TakeTill1",
535       ErrorKind::TakeWhileMN               => "TakeWhileMN",
536       ErrorKind::TooLarge                  => "Needed data size is too large",
537       ErrorKind::Many0Count                => "Count occurrence of >=0 patterns",
538       ErrorKind::Many1Count                => "Count occurrence of >=1 patterns",
539       ErrorKind::Float                     => "Float",
540       ErrorKind::Satisfy                   => "Satisfy",
541       ErrorKind::Fail                      => "Fail",
542     }
543   }
544 }
545 
546 /// Creates a parse error from a `nom::ErrorKind`
547 /// and the position in the input
548 #[allow(unused_variables)]
549 #[macro_export(local_inner_macros)]
550 macro_rules! error_position(
551   ($input:expr, $code:expr) => ({
552     $crate::error::make_error($input, $code)
553   });
554 );
555 
556 /// Creates a parse error from a `nom::ErrorKind`,
557 /// the position in the input and the next error in
558 /// the parsing tree
559 #[allow(unused_variables)]
560 #[macro_export(local_inner_macros)]
561 macro_rules! error_node_position(
562   ($input:expr, $code:expr, $next:expr) => ({
563     $crate::error::append_error($input, $code, $next)
564   });
565 );
566 
567 /// Prints a message and the input if the parser fails.
568 ///
569 /// The message prints the `Error` or `Incomplete`
570 /// and the parser's calling code.
571 ///
572 /// It also displays the input in hexdump format
573 ///
574 /// ```rust
575 /// use nom::{IResult, error::dbg_dmp, bytes::complete::tag};
576 ///
577 /// fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
578 ///   dbg_dmp(tag("abcd"), "tag")(i)
579 /// }
580 ///
581 ///   let a = &b"efghijkl"[..];
582 ///
583 /// // Will print the following message:
584 /// // Error(Position(0, [101, 102, 103, 104, 105, 106, 107, 108])) at l.5 by ' tag ! ( "abcd" ) '
585 /// // 00000000        65 66 67 68 69 6a 6b 6c         efghijkl
586 /// f(a);
587 /// ```
588 #[cfg(feature = "std")]
589 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
dbg_dmp<'a, F, O, E: std::fmt::Debug>( f: F, context: &'static str, ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E> where F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,590 pub fn dbg_dmp<'a, F, O, E: std::fmt::Debug>(
591   f: F,
592   context: &'static str,
593 ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
594 where
595   F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
596 {
597   use crate::HexDisplay;
598   move |i: &'a [u8]| match f(i) {
599     Err(e) => {
600       println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8));
601       Err(e)
602     }
603     a => a,
604   }
605 }
606 
607 #[cfg(test)]
608 #[cfg(feature = "alloc")]
609 mod tests {
610   use super::*;
611   use crate::character::complete::char;
612 
613   #[test]
convert_error_panic()614   fn convert_error_panic() {
615     let input = "";
616 
617     let _result: IResult<_, _, VerboseError<&str>> = char('x')(input);
618   }
619 }
620 
621 /*
622 #[cfg(feature = "alloc")]
623 use lib::std::{vec::Vec, collections::HashMap};
624 
625 #[cfg(feature = "std")]
626 use lib::std::hash::Hash;
627 
628 #[cfg(feature = "std")]
629 pub fn add_error_pattern<'a, I: Clone + Hash + Eq, O, E: Clone + Hash + Eq>(
630   h: &mut HashMap<VerboseError<I>, &'a str>,
631   e: VerboseError<I>,
632   message: &'a str,
633 ) -> bool {
634   h.insert(e, message);
635   true
636 }
637 
638 pub fn slice_to_offsets(input: &[u8], s: &[u8]) -> (usize, usize) {
639   let start = input.as_ptr();
640   let off1 = s.as_ptr() as usize - start as usize;
641   let off2 = off1 + s.len();
642   (off1, off2)
643 }
644 
645 #[cfg(feature = "std")]
646 pub fn prepare_errors<O, E: Clone>(input: &[u8], e: VerboseError<&[u8]>) -> Option<Vec<(ErrorKind, usize, usize)>> {
647   let mut v: Vec<(ErrorKind, usize, usize)> = Vec::new();
648 
649   for (p, kind) in e.errors.drain(..) {
650     let (o1, o2) = slice_to_offsets(input, p);
651     v.push((kind, o1, o2));
652   }
653 
654   v.reverse();
655   Some(v)
656 }
657 
658 #[cfg(feature = "std")]
659 pub fn print_error<O, E: Clone>(input: &[u8], res: VerboseError<&[u8]>) {
660   if let Some(v) = prepare_errors(input, res) {
661     let colors = generate_colors(&v);
662     println!("parser codes: {}", print_codes(&colors, &HashMap::new()));
663     println!("{}", print_offsets(input, 0, &v));
664   } else {
665     println!("not an error");
666   }
667 }
668 
669 #[cfg(feature = "std")]
670 pub fn generate_colors<E>(v: &[(ErrorKind, usize, usize)]) -> HashMap<u32, u8> {
671   let mut h: HashMap<u32, u8> = HashMap::new();
672   let mut color = 0;
673 
674   for &(ref c, _, _) in v.iter() {
675     h.insert(error_to_u32(c), color + 31);
676     color = color + 1 % 7;
677   }
678 
679   h
680 }
681 
682 pub fn code_from_offset(v: &[(ErrorKind, usize, usize)], offset: usize) -> Option<u32> {
683   let mut acc: Option<(u32, usize, usize)> = None;
684   for &(ref ek, s, e) in v.iter() {
685     let c = error_to_u32(ek);
686     if s <= offset && offset <= e {
687       if let Some((_, start, end)) = acc {
688         if start <= s && e <= end {
689           acc = Some((c, s, e));
690         }
691       } else {
692         acc = Some((c, s, e));
693       }
694     }
695   }
696   if let Some((code, _, _)) = acc {
697     return Some(code);
698   } else {
699     return None;
700   }
701 }
702 
703 #[cfg(feature = "alloc")]
704 pub fn reset_color(v: &mut Vec<u8>) {
705   v.push(0x1B);
706   v.push(b'[');
707   v.push(0);
708   v.push(b'm');
709 }
710 
711 #[cfg(feature = "alloc")]
712 pub fn write_color(v: &mut Vec<u8>, color: u8) {
713   v.push(0x1B);
714   v.push(b'[');
715   v.push(1);
716   v.push(b';');
717   let s = color.to_string();
718   let bytes = s.as_bytes();
719   v.extend(bytes.iter().cloned());
720   v.push(b'm');
721 }
722 
723 #[cfg(feature = "std")]
724 #[cfg_attr(feature = "cargo-clippy", allow(implicit_hasher))]
725 pub fn print_codes(colors: &HashMap<u32, u8>, names: &HashMap<u32, &str>) -> String {
726   let mut v = Vec::new();
727   for (code, &color) in colors {
728     if let Some(&s) = names.get(code) {
729       let bytes = s.as_bytes();
730       write_color(&mut v, color);
731       v.extend(bytes.iter().cloned());
732     } else {
733       let s = code.to_string();
734       let bytes = s.as_bytes();
735       write_color(&mut v, color);
736       v.extend(bytes.iter().cloned());
737     }
738     reset_color(&mut v);
739     v.push(b' ');
740   }
741   reset_color(&mut v);
742 
743   String::from_utf8_lossy(&v[..]).into_owned()
744 }
745 
746 #[cfg(feature = "std")]
747 pub fn print_offsets(input: &[u8], from: usize, offsets: &[(ErrorKind, usize, usize)]) -> String {
748   let mut v = Vec::with_capacity(input.len() * 3);
749   let mut i = from;
750   let chunk_size = 8;
751   let mut current_code: Option<u32> = None;
752   let mut current_code2: Option<u32> = None;
753 
754   let colors = generate_colors(&offsets);
755 
756   for chunk in input.chunks(chunk_size) {
757     let s = format!("{:08x}", i);
758     for &ch in s.as_bytes().iter() {
759       v.push(ch);
760     }
761     v.push(b'\t');
762 
763     let mut k = i;
764     let mut l = i;
765     for &byte in chunk {
766       if let Some(code) = code_from_offset(&offsets, k) {
767         if let Some(current) = current_code {
768           if current != code {
769             reset_color(&mut v);
770             current_code = Some(code);
771             if let Some(&color) = colors.get(&code) {
772               write_color(&mut v, color);
773             }
774           }
775         } else {
776           current_code = Some(code);
777           if let Some(&color) = colors.get(&code) {
778             write_color(&mut v, color);
779           }
780         }
781       }
782       v.push(CHARS[(byte >> 4) as usize]);
783       v.push(CHARS[(byte & 0xf) as usize]);
784       v.push(b' ');
785       k = k + 1;
786     }
787 
788     reset_color(&mut v);
789 
790     if chunk_size > chunk.len() {
791       for _ in 0..(chunk_size - chunk.len()) {
792         v.push(b' ');
793         v.push(b' ');
794         v.push(b' ');
795       }
796     }
797     v.push(b'\t');
798 
799     for &byte in chunk {
800       if let Some(code) = code_from_offset(&offsets, l) {
801         if let Some(current) = current_code2 {
802           if current != code {
803             reset_color(&mut v);
804             current_code2 = Some(code);
805             if let Some(&color) = colors.get(&code) {
806               write_color(&mut v, color);
807             }
808           }
809         } else {
810           current_code2 = Some(code);
811           if let Some(&color) = colors.get(&code) {
812             write_color(&mut v, color);
813           }
814         }
815       }
816       if (byte >= 32 && byte <= 126) || byte >= 128 {
817         v.push(byte);
818       } else {
819         v.push(b'.');
820       }
821       l = l + 1;
822     }
823     reset_color(&mut v);
824 
825     v.push(b'\n');
826     i = i + chunk_size;
827   }
828 
829   String::from_utf8_lossy(&v[..]).into_owned()
830 }
831 */
832