Coverage Report

Created: 2025-07-23 06:18

/rust/registry/src/index.crates.io-6f17d22bba15001f/nom-7.1.1/src/error.rs
Line
Count
Source (jump to first uncovered line)
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]
18
  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
23
  fn append(input: I, kind: ErrorKind, other: Self) -> Self;
24
25
  /// Creates an error from an input position and an expected character
26
0
  fn from_char(input: I, _: char) -> Self {
27
0
    Self::from_error_kind(input, ErrorKind::Char)
28
0
  }
Unexecuted instantiation: <nom::error::Error<&str> as nom::error::ParseError<&str>>::from_char
Unexecuted instantiation: <_ as nom::error::ParseError<_>>::from_char
29
30
  /// Combines two existing errors. This function is used to compare errors
31
  /// generated in various branches of `alt`.
32
0
  fn or(self, other: Self) -> Self {
33
0
    other
34
0
  }
Unexecuted instantiation: <nom::error::Error<&str> as nom::error::ParseError<&str>>::or
Unexecuted instantiation: <_ as nom::error::ParseError<_>>::or
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
43
0
  fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self {
44
0
    other
45
0
  }
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
53
  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
67
0
  pub fn new(input: I, code: ErrorKind) -> Error<I> {
68
0
    Error { input, code }
69
0
  }
Unexecuted instantiation: <nom::error::Error<&str>>::new
Unexecuted instantiation: <nom::error::Error<_>>::new
70
}
71
72
impl<I> ParseError<I> for Error<I> {
73
0
  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
74
0
    Error { input, code: kind }
75
0
  }
Unexecuted instantiation: <nom::error::Error<&str> as nom::error::ParseError<&str>>::from_error_kind
Unexecuted instantiation: <nom::error::Error<_> as nom::error::ParseError<_>>::from_error_kind
76
77
0
  fn append(_: I, _: ErrorKind, other: Self) -> Self {
78
0
    other
79
0
  }
Unexecuted instantiation: <nom::error::Error<&str> as nom::error::ParseError<&str>>::append
Unexecuted instantiation: <nom::error::Error<_> as nom::error::ParseError<_>>::append
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
86
0
  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
87
0
    Error { input, code: kind }
88
0
  }
Unexecuted instantiation: <nom::error::Error<&str> as nom::error::FromExternalError<&str, core::num::error::ParseIntError>>::from_external_error
Unexecuted instantiation: <nom::error::Error<_> as nom::error::FromExternalError<_, _>>::from_external_error
89
}
90
91
/// The Display implementation allows the std::error::Error implementation
92
impl<I: fmt::Display> fmt::Display for Error<I> {
93
0
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94
0
    write!(f, "error {:?} at: {}", self.code, self.input)
95
0
  }
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) {
104
0
  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
105
0
    (input, kind)
106
0
  }
107
108
0
  fn append(_: I, _: ErrorKind, other: Self) -> Self {
109
0
    other
110
0
  }
111
}
112
113
impl<I> ContextError<I> for (I, ErrorKind) {}
114
115
impl<I, E> FromExternalError<I, E> for (I, ErrorKind) {
116
0
  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
117
0
    (input, kind)
118
0
  }
119
}
120
121
impl<I> ParseError<I> for () {
122
0
  fn from_error_kind(_: I, _: ErrorKind) -> Self {}
123
124
0
  fn append(_: I, _: ErrorKind, _: Self) -> Self {}
125
}
126
127
impl<I> ContextError<I> for () {}
128
129
impl<I, E> FromExternalError<I, E> for () {
130
0
  fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {}
131
}
132
133
/// Creates an error from the input position and an [ErrorKind]
134
0
pub fn make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E {
135
0
  E::from_error_kind(input, kind)
136
0
}
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
141
0
pub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E {
142
0
  E::append(input, kind, other)
143
0
}
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> {
173
0
  fn from_error_kind(input: I, kind: ErrorKind) -> Self {
174
0
    VerboseError {
175
0
      errors: vec![(input, VerboseErrorKind::Nom(kind))],
176
0
    }
177
0
  }
178
179
0
  fn append(input: I, kind: ErrorKind, mut other: Self) -> Self {
180
0
    other.errors.push((input, VerboseErrorKind::Nom(kind)));
181
0
    other
182
0
  }
183
184
0
  fn from_char(input: I, c: char) -> Self {
185
0
    VerboseError {
186
0
      errors: vec![(input, VerboseErrorKind::Char(c))],
187
0
    }
188
0
  }
189
}
190
191
#[cfg(feature = "alloc")]
192
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
193
impl<I> ContextError<I> for VerboseError<I> {
194
0
  fn add_context(input: I, ctx: &'static str, mut other: Self) -> Self {
195
0
    other.errors.push((input, VerboseErrorKind::Context(ctx)));
196
0
    other
197
0
  }
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
204
0
  fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
205
0
    Self::from_error_kind(input, kind)
206
0
  }
207
}
208
209
#[cfg(feature = "alloc")]
210
impl<I: fmt::Display> fmt::Display for VerboseError<I> {
211
0
  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212
0
    writeln!(f, "Parse error:")?;
213
0
    for (input, error) in &self.errors {
214
0
      match error {
215
0
        VerboseErrorKind::Nom(e) => writeln!(f, "{:?} at: {}", e, input)?,
216
0
        VerboseErrorKind::Char(c) => writeln!(f, "expected '{}' at: {}", c, input)?,
217
0
        VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?,
218
      }
219
    }
220
221
0
    Ok(())
222
0
  }
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
233
0
pub fn context<I: Clone, E: ContextError<I>, F, O>(
234
0
  context: &'static str,
235
0
  mut f: F,
236
0
) -> impl FnMut(I) -> IResult<I, O, E>
237
0
where
238
0
  F: Parser<I, O, E>,
239
0
{
240
0
  move |i: I| match f.parse(i.clone()) {
241
0
    Ok(o) => Ok(o),
242
0
    Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)),
243
0
    Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, context, e))),
244
0
    Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, context, e))),
245
0
  }
246
0
}
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")))]
251
0
pub fn convert_error<I: core::ops::Deref<Target = str>>(
252
0
  input: I,
253
0
  e: VerboseError<I>,
254
0
) -> crate::lib::std::string::String {
255
  use crate::lib::std::fmt::Write;
256
  use crate::traits::Offset;
257
258
0
  let mut result = crate::lib::std::string::String::new();
259
260
0
  for (i, (substring, kind)) in e.errors.iter().enumerate() {
261
0
    let offset = input.offset(substring);
262
0
263
0
    if input.is_empty() {
264
0
      match kind {
265
0
        VerboseErrorKind::Char(c) => {
266
0
          write!(&mut result, "{}: expected '{}', got empty input\n\n", i, c)
267
        }
268
0
        VerboseErrorKind::Context(s) => write!(&mut result, "{}: in {}, got empty input\n\n", i, s),
269
0
        VerboseErrorKind::Nom(e) => write!(&mut result, "{}: in {:?}, got empty input\n\n", i, e),
270
      }
271
    } else {
272
0
      let prefix = &input.as_bytes()[..offset];
273
0
274
0
      // Count the number of newlines in the first `offset` bytes of input
275
0
      let line_number = prefix.iter().filter(|&&b| b == b'\n').count() + 1;
276
0
277
0
      // Find the line that includes the subslice:
278
0
      // Find the *last* newline before the substring starts
279
0
      let line_begin = prefix
280
0
        .iter()
281
0
        .rev()
282
0
        .position(|&b| b == b'\n')
283
0
        .map(|pos| offset - pos)
284
0
        .unwrap_or(0);
285
0
286
0
      // Find the full line after that newline
287
0
      let line = input[line_begin..]
288
0
        .lines()
289
0
        .next()
290
0
        .unwrap_or(&input[line_begin..])
291
0
        .trim_end();
292
0
293
0
      // The (1-indexed) column number is the offset of our substring into that line
294
0
      let column_number = line.offset(substring) + 1;
295
0
296
0
      match kind {
297
0
        VerboseErrorKind::Char(c) => {
298
0
          if let Some(actual) = substring.chars().next() {
299
0
            write!(
300
0
              &mut result,
301
0
              "{i}: at line {line_number}:\n\
302
0
               {line}\n\
303
0
               {caret:>column$}\n\
304
0
               expected '{expected}', found {actual}\n\n",
305
0
              i = i,
306
0
              line_number = line_number,
307
0
              line = line,
308
0
              caret = '^',
309
0
              column = column_number,
310
0
              expected = c,
311
0
              actual = actual,
312
0
            )
313
          } else {
314
0
            write!(
315
0
              &mut result,
316
0
              "{i}: at line {line_number}:\n\
317
0
               {line}\n\
318
0
               {caret:>column$}\n\
319
0
               expected '{expected}', got end of input\n\n",
320
0
              i = i,
321
0
              line_number = line_number,
322
0
              line = line,
323
0
              caret = '^',
324
0
              column = column_number,
325
0
              expected = c,
326
0
            )
327
          }
328
        }
329
0
        VerboseErrorKind::Context(s) => write!(
330
0
          &mut result,
331
0
          "{i}: at line {line_number}, in {context}:\n\
332
0
             {line}\n\
333
0
             {caret:>column$}\n\n",
334
0
          i = i,
335
0
          line_number = line_number,
336
0
          context = s,
337
0
          line = line,
338
0
          caret = '^',
339
0
          column = column_number,
340
0
        ),
341
0
        VerboseErrorKind::Nom(e) => write!(
342
0
          &mut result,
343
0
          "{i}: at line {line_number}, in {nom_err:?}:\n\
344
0
             {line}\n\
345
0
             {caret:>column$}\n\n",
346
0
          i = i,
347
0
          line_number = line_number,
348
0
          nom_err = e,
349
0
          line = line,
350
0
          caret = '^',
351
0
          column = column_number,
352
0
        ),
353
      }
354
    }
355
    // Because `write!` to a `String` is infallible, this `unwrap` is fine.
356
0
    .unwrap();
357
  }
358
359
0
  result
360
0
}
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
425
0
pub fn error_to_u32(e: &ErrorKind) -> u32 {
426
0
  match *e {
427
0
    ErrorKind::Tag                       => 1,
428
0
    ErrorKind::MapRes                    => 2,
429
0
    ErrorKind::MapOpt                    => 3,
430
0
    ErrorKind::Alt                       => 4,
431
0
    ErrorKind::IsNot                     => 5,
432
0
    ErrorKind::IsA                       => 6,
433
0
    ErrorKind::SeparatedList             => 7,
434
0
    ErrorKind::SeparatedNonEmptyList     => 8,
435
0
    ErrorKind::Many1                     => 9,
436
0
    ErrorKind::Count                     => 10,
437
0
    ErrorKind::TakeUntil                 => 12,
438
0
    ErrorKind::LengthValue               => 15,
439
0
    ErrorKind::TagClosure                => 16,
440
0
    ErrorKind::Alpha                     => 17,
441
0
    ErrorKind::Digit                     => 18,
442
0
    ErrorKind::AlphaNumeric              => 19,
443
0
    ErrorKind::Space                     => 20,
444
0
    ErrorKind::MultiSpace                => 21,
445
0
    ErrorKind::LengthValueFn             => 22,
446
0
    ErrorKind::Eof                       => 23,
447
0
    ErrorKind::Switch                    => 27,
448
0
    ErrorKind::TagBits                   => 28,
449
0
    ErrorKind::OneOf                     => 29,
450
0
    ErrorKind::NoneOf                    => 30,
451
0
    ErrorKind::Char                      => 40,
452
0
    ErrorKind::CrLf                      => 41,
453
0
    ErrorKind::RegexpMatch               => 42,
454
0
    ErrorKind::RegexpMatches             => 43,
455
0
    ErrorKind::RegexpFind                => 44,
456
0
    ErrorKind::RegexpCapture             => 45,
457
0
    ErrorKind::RegexpCaptures            => 46,
458
0
    ErrorKind::TakeWhile1                => 47,
459
0
    ErrorKind::Complete                  => 48,
460
0
    ErrorKind::Fix                       => 49,
461
0
    ErrorKind::Escaped                   => 50,
462
0
    ErrorKind::EscapedTransform          => 51,
463
0
    ErrorKind::NonEmpty                  => 56,
464
0
    ErrorKind::ManyMN                    => 57,
465
0
    ErrorKind::HexDigit                  => 59,
466
0
    ErrorKind::OctDigit                  => 61,
467
0
    ErrorKind::Many0                     => 62,
468
0
    ErrorKind::Not                       => 63,
469
0
    ErrorKind::Permutation               => 64,
470
0
    ErrorKind::ManyTill                  => 65,
471
0
    ErrorKind::Verify                    => 66,
472
0
    ErrorKind::TakeTill1                 => 67,
473
0
    ErrorKind::TakeWhileMN               => 69,
474
0
    ErrorKind::TooLarge                  => 70,
475
0
    ErrorKind::Many0Count                => 71,
476
0
    ErrorKind::Many1Count                => 72,
477
0
    ErrorKind::Float                     => 73,
478
0
    ErrorKind::Satisfy                   => 74,
479
0
    ErrorKind::Fail                      => 75,
480
  }
481
0
}
482
483
impl ErrorKind {
484
  #[rustfmt::skip]
485
  #[allow(deprecated)]
486
  /// Converts an ErrorKind to a text description
487
0
  pub fn description(&self) -> &str {
488
0
    match *self {
489
0
      ErrorKind::Tag                       => "Tag",
490
0
      ErrorKind::MapRes                    => "Map on Result",
491
0
      ErrorKind::MapOpt                    => "Map on Option",
492
0
      ErrorKind::Alt                       => "Alternative",
493
0
      ErrorKind::IsNot                     => "IsNot",
494
0
      ErrorKind::IsA                       => "IsA",
495
0
      ErrorKind::SeparatedList             => "Separated list",
496
0
      ErrorKind::SeparatedNonEmptyList     => "Separated non empty list",
497
0
      ErrorKind::Many0                     => "Many0",
498
0
      ErrorKind::Many1                     => "Many1",
499
0
      ErrorKind::Count                     => "Count",
500
0
      ErrorKind::TakeUntil                 => "Take until",
501
0
      ErrorKind::LengthValue               => "Length followed by value",
502
0
      ErrorKind::TagClosure                => "Tag closure",
503
0
      ErrorKind::Alpha                     => "Alphabetic",
504
0
      ErrorKind::Digit                     => "Digit",
505
0
      ErrorKind::AlphaNumeric              => "AlphaNumeric",
506
0
      ErrorKind::Space                     => "Space",
507
0
      ErrorKind::MultiSpace                => "Multiple spaces",
508
0
      ErrorKind::LengthValueFn             => "LengthValueFn",
509
0
      ErrorKind::Eof                       => "End of file",
510
0
      ErrorKind::Switch                    => "Switch",
511
0
      ErrorKind::TagBits                   => "Tag on bitstream",
512
0
      ErrorKind::OneOf                     => "OneOf",
513
0
      ErrorKind::NoneOf                    => "NoneOf",
514
0
      ErrorKind::Char                      => "Char",
515
0
      ErrorKind::CrLf                      => "CrLf",
516
0
      ErrorKind::RegexpMatch               => "RegexpMatch",
517
0
      ErrorKind::RegexpMatches             => "RegexpMatches",
518
0
      ErrorKind::RegexpFind                => "RegexpFind",
519
0
      ErrorKind::RegexpCapture             => "RegexpCapture",
520
0
      ErrorKind::RegexpCaptures            => "RegexpCaptures",
521
0
      ErrorKind::TakeWhile1                => "TakeWhile1",
522
0
      ErrorKind::Complete                  => "Complete",
523
0
      ErrorKind::Fix                       => "Fix",
524
0
      ErrorKind::Escaped                   => "Escaped",
525
0
      ErrorKind::EscapedTransform          => "EscapedTransform",
526
0
      ErrorKind::NonEmpty                  => "NonEmpty",
527
0
      ErrorKind::ManyMN                    => "Many(m, n)",
528
0
      ErrorKind::HexDigit                  => "Hexadecimal Digit",
529
0
      ErrorKind::OctDigit                  => "Octal digit",
530
0
      ErrorKind::Not                       => "Negation",
531
0
      ErrorKind::Permutation               => "Permutation",
532
0
      ErrorKind::ManyTill                  => "ManyTill",
533
0
      ErrorKind::Verify                    => "predicate verification",
534
0
      ErrorKind::TakeTill1                 => "TakeTill1",
535
0
      ErrorKind::TakeWhileMN               => "TakeWhileMN",
536
0
      ErrorKind::TooLarge                  => "Needed data size is too large",
537
0
      ErrorKind::Many0Count                => "Count occurrence of >=0 patterns",
538
0
      ErrorKind::Many1Count                => "Count occurrence of >=1 patterns",
539
0
      ErrorKind::Float                     => "Float",
540
0
      ErrorKind::Satisfy                   => "Satisfy",
541
0
      ErrorKind::Fail                      => "Fail",
542
    }
543
0
  }
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")))]
590
0
pub fn dbg_dmp<'a, F, O, E: std::fmt::Debug>(
591
0
  f: F,
592
0
  context: &'static str,
593
0
) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O, E>
594
0
where
595
0
  F: Fn(&'a [u8]) -> IResult<&'a [u8], O, E>,
596
0
{
597
  use crate::HexDisplay;
598
0
  move |i: &'a [u8]| match f(i) {
599
0
    Err(e) => {
600
0
      println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8));
601
0
      Err(e)
602
    }
603
0
    a => a,
604
0
  }
605
0
}
606
607
#[cfg(test)]
608
#[cfg(feature = "alloc")]
609
mod tests {
610
  use super::*;
611
  use crate::character::complete::char;
612
613
  #[test]
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
*/