1//! # Error management
2//!
3//! Errors are designed with multiple needs in mind:
4//! - Accumulate more [context][Parser::context] as the error goes up the parser chain
5//! - Distinguish between [recoverable errors,
6//! unrecoverable errors, and more data is needed][ErrMode]
7//! - Have a very low overhead, as errors are often discarded by the calling parser (examples: `many0`, `alt`)
8//! - Can be modified according to the user's needs, because some languages need a lot more information
9//! - Help thread-through the [stream][crate::stream]
10//!
11//! To abstract these needs away from the user, generally `winnow` parsers use the [`IResult`]
12//! alias, rather than [`Result`][std::result::Result]. [`finish`][FinishIResult::finish] is
13//! provided for top-level parsers to integrate with your application's error reporting.
14//!
15//! Error types include:
16//! - `()`
17//! - [`Error`]
18//! - [`VerboseError`]
19//! - [Custom errors][crate::_topic::error]
20
21#[cfg(feature = "alloc")]
22use crate::lib::std::borrow::ToOwned;
23use crate::lib::std::fmt;
24use core::num::NonZeroUsize;
25
26use crate::stream::Stream;
27use crate::stream::StreamIsPartial;
28#[allow(unused_imports)] // Here for intra-doc links
29use crate::Parser;
30
31/// Holds the result of [`Parser`]
32///
33/// - `Ok((I, O))` is the remaining [input][crate::stream] and the parsed value
34/// - [`Err(ErrMode<E>)`][ErrMode] is the error along with how to respond to it
35///
36/// By default, the error type (`E`) is [`Error`]
37///
38/// At the top-level of your parser, you can use the [`FinishIResult::finish`] method to convert
39/// it to a more common result type
40pub type IResult<I, O, E = Error<I>> = Result<(I, O), ErrMode<E>>;
41
42/// Extension trait to convert a parser's [`IResult`] to a more manageable type
43#[deprecated(since = "0.4.0", note = "Replaced with `Parser::parse`")]
44pub trait FinishIResult<I, O, E> {
45 /// Converts the parser's [`IResult`] to a type that is more consumable by callers.
46 ///
47 /// Errors if the parser is not at the [end of input][crate::combinator::eof]. See
48 /// [`FinishIResult::finish_err`] if the remaining input is needed.
49 ///
50 /// # Panic
51 ///
52 /// If the result is `Err(ErrMode::Incomplete(_))`, this method will panic.
53 /// - **Complete parsers:** It will not be an issue, `Incomplete` is never used
54 /// - **Partial parsers:** `Incomplete` will be returned if there's not enough data
55 /// for the parser to decide, and you should gather more data before parsing again.
56 /// Once the parser returns either `Ok(_)`, `Err(ErrMode::Backtrack(_))` or `Err(ErrMode::Cut(_))`,
57 /// you can get out of the parsing loop and call `finish_err()` on the parser's result
58 ///
59 /// # Example
60 ///
61 /// ```rust
62 /// # #[cfg(feature = "std")] {
63 /// use winnow::prelude::*;
64 /// use winnow::ascii::hex_uint;
65 /// use winnow::error::Error;
66 ///
67 /// struct Hex(u64);
68 ///
69 /// fn parse(value: &str) -> Result<Hex, Error<String>> {
70 /// hex_uint.map(Hex).parse_next(value).finish().map_err(Error::into_owned)
71 /// }
72 /// # }
73 /// ```
74 #[deprecated(since = "0.4.0", note = "Replaced with `Parser::parse`")]
75 fn finish(self) -> Result<O, E>;
76
77 /// Converts the parser's [`IResult`] to a type that is more consumable by errors.
78 ///
79 /// It keeps the same `Ok` branch, and merges `ErrMode::Backtrack` and `ErrMode::Cut` into the `Err`
80 /// side.
81 ///
82 /// # Panic
83 ///
84 /// If the result is `Err(ErrMode::Incomplete(_))`, this method will panic as [`ErrMode::Incomplete`]
85 /// should only be set when the input is [`StreamIsPartial<false>`] which this isn't implemented
86 /// for.
87 #[deprecated(since = "0.4.0", note = "Replaced with `Parser::parse`")]
88 fn finish_err(self) -> Result<(I, O), E>;
89}
90
91#[allow(deprecated)]
92impl<I, O, E> FinishIResult<I, O, E> for IResult<I, O, E>
93where
94 I: Stream,
95 // Force users to deal with `Incomplete` when `StreamIsPartial<true>`
96 I: StreamIsPartial,
97 I: Clone,
98 E: ParseError<I>,
99{
100 fn finish(self) -> Result<O, E> {
101 debug_assert!(
102 !I::is_partial_supported(),
103 "partial streams need to handle `ErrMode::Incomplete`"
104 );
105
106 let (i, o) = self.finish_err()?;
107 crate::combinator::eof(i).finish_err()?;
108 Ok(o)
109 }
110
111 fn finish_err(self) -> Result<(I, O), E> {
112 debug_assert!(
113 !I::is_partial_supported(),
114 "partial streams need to handle `ErrMode::Incomplete`"
115 );
116
117 match self {
118 Ok(res) => Ok(res),
119 Err(ErrMode::Backtrack(e)) | Err(ErrMode::Cut(e)) => Err(e),
120 Err(ErrMode::Incomplete(_)) => {
121 panic!("complete parsers should not report `Err(ErrMode::Incomplete(_))`")
122 }
123 }
124 }
125}
126
127/// Contains information on needed data if a parser returned `Incomplete`
128///
129/// **Note:** This is only possible for `Stream` that are [partial][`StreamIsPartial`],
130/// like [`Partial`][crate::Partial].
131#[derive(Debug, PartialEq, Eq, Clone, Copy)]
132#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
133pub enum Needed {
134 /// Needs more data, but we do not know how much
135 Unknown,
136 /// Contains the required data size in bytes
137 Size(NonZeroUsize),
138}
139
140impl Needed {
141 /// Creates `Needed` instance, returns `Needed::Unknown` if the argument is zero
142 pub fn new(s: usize) -> Self {
143 match NonZeroUsize::new(s) {
144 Some(sz: NonZero) => Needed::Size(sz),
145 None => Needed::Unknown,
146 }
147 }
148
149 /// Indicates if we know how many bytes we need
150 pub fn is_known(&self) -> bool {
151 *self != Needed::Unknown
152 }
153
154 /// Maps a `Needed` to `Needed` by applying a function to a contained `Size` value.
155 #[inline]
156 pub fn map<F: Fn(NonZeroUsize) -> usize>(self, f: F) -> Needed {
157 match self {
158 Needed::Unknown => Needed::Unknown,
159 Needed::Size(n: NonZero) => Needed::new(f(n)),
160 }
161 }
162}
163
164/// The `Err` enum indicates the parser was not successful
165#[derive(Debug, Clone, PartialEq)]
166#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
167pub enum ErrMode<E> {
168 /// There was not enough data to determine the appropriate action
169 ///
170 /// More data needs to be buffered before retrying the parse.
171 ///
172 /// This must only be set when the [`Stream`] is [partial][`StreamIsPartial`], like with
173 /// [`Partial`][crate::Partial]
174 ///
175 /// Convert this into an `Backtrack` with [`Parser::complete_err`]
176 Incomplete(Needed),
177 /// The parser failed with a recoverable error (the default).
178 ///
179 /// For example, a parser for json values might include a
180 /// [`dec_uint`][crate::ascii::dec_uint] as one case in an [`alt`][crate::combinator::alt]
181 /// combiantor. If it fails, the next case should be tried.
182 Backtrack(E),
183 /// The parser had an unrecoverable error.
184 ///
185 /// The parser was on the right branch, so directly report it to the user rather than trying
186 /// other branches. You can use [`cut_err()`][crate::combinator::cut_err] combinator to switch
187 /// from `ErrMode::Backtrack` to `ErrMode::Cut`.
188 ///
189 /// For example, one case in an [`alt`][crate::combinator::alt] combinator found a unique prefix
190 /// and you want any further errors parsing the case to be reported to the user.
191 Cut(E),
192}
193
194impl<E> ErrMode<E> {
195 /// Tests if the result is Incomplete
196 pub fn is_incomplete(&self) -> bool {
197 matches!(self, ErrMode::Incomplete(_))
198 }
199
200 /// Prevent backtracking, bubbling the error up to the top
201 pub fn cut(self) -> Self {
202 match self {
203 ErrMode::Backtrack(e) => ErrMode::Cut(e),
204 rest => rest,
205 }
206 }
207
208 /// Enable backtracking support
209 pub fn backtrack(self) -> Self {
210 match self {
211 ErrMode::Cut(e) => ErrMode::Backtrack(e),
212 rest => rest,
213 }
214 }
215
216 /// Applies the given function to the inner error
217 pub fn map<E2, F>(self, f: F) -> ErrMode<E2>
218 where
219 F: FnOnce(E) -> E2,
220 {
221 match self {
222 ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
223 ErrMode::Cut(t) => ErrMode::Cut(f(t)),
224 ErrMode::Backtrack(t) => ErrMode::Backtrack(f(t)),
225 }
226 }
227
228 /// Automatically converts between errors if the underlying type supports it
229 pub fn convert<F>(self) -> ErrMode<F>
230 where
231 E: ErrorConvert<F>,
232 {
233 self.map(ErrorConvert::convert)
234 }
235}
236
237impl<I, E: ParseError<I>> ParseError<I> for ErrMode<E> {
238 fn from_error_kind(input: I, kind: ErrorKind) -> Self {
239 ErrMode::Backtrack(E::from_error_kind(input, kind))
240 }
241
242 #[cfg_attr(debug_assertions, track_caller)]
243 fn assert(input: I, message: &'static str) -> Self
244 where
245 I: crate::lib::std::fmt::Debug,
246 {
247 ErrMode::Backtrack(E::assert(input, message))
248 }
249
250 fn append(self, input: I, kind: ErrorKind) -> Self {
251 match self {
252 ErrMode::Backtrack(e) => ErrMode::Backtrack(e.append(input, kind)),
253 e => e,
254 }
255 }
256
257 fn or(self, other: Self) -> Self {
258 match (self, other) {
259 (ErrMode::Backtrack(e), ErrMode::Backtrack(o)) => ErrMode::Backtrack(e.or(o)),
260 (ErrMode::Incomplete(e), _) | (_, ErrMode::Incomplete(e)) => ErrMode::Incomplete(e),
261 (ErrMode::Cut(e), _) | (_, ErrMode::Cut(e)) => ErrMode::Cut(e),
262 }
263 }
264}
265
266impl<I, EXT, E> FromExternalError<I, EXT> for ErrMode<E>
267where
268 E: FromExternalError<I, EXT>,
269{
270 fn from_external_error(input: I, kind: ErrorKind, e: EXT) -> Self {
271 ErrMode::Backtrack(E::from_external_error(input, kind, e))
272 }
273}
274
275impl<T> ErrMode<Error<T>> {
276 /// Maps `ErrMode<Error<T>>` to `ErrMode<Error<U>>` with the given `F: T -> U`
277 pub fn map_input<U, F>(self, f: F) -> ErrMode<Error<U>>
278 where
279 F: FnOnce(T) -> U,
280 {
281 match self {
282 ErrMode::Incomplete(n: Needed) => ErrMode::Incomplete(n),
283 ErrMode::Cut(Error { input: T, kind: ErrorKind }) => ErrMode::Cut(Error {
284 input: f(input),
285 kind,
286 }),
287 ErrMode::Backtrack(Error { input: T, kind: ErrorKind }) => ErrMode::Backtrack(Error {
288 input: f(input),
289 kind,
290 }),
291 }
292 }
293}
294
295impl<E: Eq> Eq for ErrMode<E> {}
296
297impl<E> fmt::Display for ErrMode<E>
298where
299 E: fmt::Debug,
300{
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 match self {
303 ErrMode::Incomplete(Needed::Size(u: &NonZero)) => write!(f, "Parsing requires {} bytes/chars", u),
304 ErrMode::Incomplete(Needed::Unknown) => write!(f, "Parsing requires more data"),
305 ErrMode::Cut(c: &E) => write!(f, "Parsing Failure: {:?}", c),
306 ErrMode::Backtrack(c: &E) => write!(f, "Parsing Error: {:?}", c),
307 }
308 }
309}
310
311/// The basic [`Parser`] trait for errors
312///
313/// It provides methods to create an error from some combinators,
314/// and combine existing errors in combinators like `alt`.
315pub trait ParseError<I>: Sized {
316 /// Creates an error from the input position and an [`ErrorKind`]
317 fn from_error_kind(input: I, kind: ErrorKind) -> Self;
318
319 /// Process a parser assertion
320 #[cfg_attr(debug_assertions, track_caller)]
321 fn assert(input: I, _message: &'static str) -> Self
322 where
323 I: crate::lib::std::fmt::Debug,
324 {
325 #[cfg(debug_assertions)]
326 panic!("assert `{}` failed at {:#?}", _message, input);
327 #[cfg(not(debug_assertions))]
328 Self::from_error_kind(input, ErrorKind::Assert)
329 }
330
331 /// Like [`ParseError::from_error_kind`] but merges it with the existing error.
332 ///
333 /// This is useful when backtracking through a parse tree, accumulating error context on the
334 /// way.
335 fn append(self, input: I, kind: ErrorKind) -> Self;
336
337 /// Combines errors from two different parse branches.
338 ///
339 /// For example, this would be used by [`alt`][crate::combinator::alt] to report the error from
340 /// each case.
341 fn or(self, other: Self) -> Self {
342 other
343 }
344}
345
346/// Used by [`Parser::context`] to add custom data to error while backtracking
347///
348/// May be implemented multiple times for different kinds of context.
349pub trait ContextError<I, C = &'static str>: Sized {
350 /// Append to an existing error custom data
351 ///
352 /// This is used mainly by [`Parser::context`], to add user friendly information
353 /// to errors when backtracking through a parse tree
354 fn add_context(self, _input: I, _ctx: C) -> Self {
355 self
356 }
357}
358
359/// Create a new error with an external error, from [`std::str::FromStr`]
360///
361/// This trait is required by the [`Parser::try_map`] combinator.
362pub trait FromExternalError<I, E> {
363 /// Like [`ParseError::from_error_kind`] but also include an external error.
364 fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self;
365}
366
367/// Equivalent of `From` implementation to avoid orphan rules in bits parsers
368pub trait ErrorConvert<E> {
369 /// Transform to another error type
370 fn convert(self) -> E;
371}
372
373/// Default error type, only contains the error' location and kind
374///
375/// This is a low-overhead error that only provides basic information. For less overhead, see
376/// `()`. Fore more information, see [`VerboseError`].
377///:w
378/// **Note:** [context][Parser::context] and inner errors (like from [`Parser::try_map`]) will be
379/// dropped.
380#[derive(Copy, Clone, Debug, Eq, PartialEq)]
381pub struct Error<I> {
382 /// The input stream, pointing to the location where the error occurred
383 pub input: I,
384 /// A rudimentary error kind
385 pub kind: ErrorKind,
386}
387
388impl<I> Error<I> {
389 /// Creates a new basic error
390 pub fn new(input: I, kind: ErrorKind) -> Error<I> {
391 Error { input, kind }
392 }
393}
394
395#[cfg(feature = "alloc")]
396impl<'i, I: ToOwned + ?Sized> Error<&'i I> {
397 /// Obtaining ownership
398 pub fn into_owned(self) -> Error<<I as ToOwned>::Owned> {
399 Error {
400 input: self.input.to_owned(),
401 kind: self.kind,
402 }
403 }
404}
405
406impl<I> ParseError<I> for Error<I> {
407 fn from_error_kind(input: I, kind: ErrorKind) -> Self {
408 Error { input, kind }
409 }
410
411 fn append(self, _: I, _: ErrorKind) -> Self {
412 self
413 }
414}
415
416impl<I, C> ContextError<I, C> for Error<I> {}
417
418impl<I, E> FromExternalError<I, E> for Error<I> {
419 /// Create a new error from an input position and an external error
420 fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
421 Error { input, kind }
422 }
423}
424
425impl<I> ErrorConvert<Error<(I, usize)>> for Error<I> {
426 fn convert(self) -> Error<(I, usize)> {
427 Error {
428 input: (self.input, 0),
429 kind: self.kind,
430 }
431 }
432}
433
434impl<I> ErrorConvert<Error<I>> for Error<(I, usize)> {
435 fn convert(self) -> Error<I> {
436 Error {
437 input: self.input.0,
438 kind: self.kind,
439 }
440 }
441}
442
443/// The Display implementation allows the `std::error::Error` implementation
444impl<I: fmt::Display> fmt::Display for Error<I> {
445 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
446 write!(f, "error {:?} at: {}", self.kind, self.input)
447 }
448}
449
450#[cfg(feature = "std")]
451impl<I: fmt::Debug + fmt::Display + Sync + Send + 'static> std::error::Error for Error<I> {}
452
453impl<I> ParseError<I> for () {
454 fn from_error_kind(_: I, _: ErrorKind) -> Self {}
455
456 fn append(self, _: I, _: ErrorKind) -> Self {}
457}
458
459impl<I, C> ContextError<I, C> for () {}
460
461impl<I, E> FromExternalError<I, E> for () {
462 fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {}
463}
464
465impl ErrorConvert<()> for () {
466 fn convert(self) {}
467}
468
469/// Accumulates error information while backtracking
470///
471/// For less overhead (and information), see [`Error`].
472///
473/// [`convert_error`] provides an example of how to render this for end-users.
474///
475/// **Note:** This will only capture the last failed branch for combinators like
476/// [`alt`][crate::combinator::alt].
477#[cfg(feature = "alloc")]
478#[derive(Clone, Debug, Eq, PartialEq)]
479pub struct VerboseError<I> {
480 /// Accumulated error information
481 pub errors: crate::lib::std::vec::Vec<(I, VerboseErrorKind)>,
482}
483
484#[cfg(feature = "alloc")]
485impl<'i, I: ToOwned + ?Sized> VerboseError<&'i I> {
486 /// Obtaining ownership
487 pub fn into_owned(self) -> VerboseError<<I as ToOwned>::Owned> {
488 #[allow(clippy::redundant_clone)] // false positive
489 VerboseError {
490 errors: self
491 .errors
492 .into_iter()
493 .map(|(i: &I, k: VerboseErrorKind)| (i.to_owned(), k))
494 .collect(),
495 }
496 }
497}
498
499#[cfg(feature = "alloc")]
500#[derive(Clone, Debug, Eq, PartialEq)]
501/// Error context for `VerboseError`
502pub enum VerboseErrorKind {
503 /// Static string added by the `context` function
504 Context(&'static str),
505 /// Error kind given by various parsers
506 Winnow(ErrorKind),
507}
508
509#[cfg(feature = "alloc")]
510impl<I> ParseError<I> for VerboseError<I> {
511 fn from_error_kind(input: I, kind: ErrorKind) -> Self {
512 VerboseError {
513 errors: vec![(input, VerboseErrorKind::Winnow(kind))],
514 }
515 }
516
517 fn append(mut self, input: I, kind: ErrorKind) -> Self {
518 self.errors.push((input, VerboseErrorKind::Winnow(kind)));
519 self
520 }
521}
522
523#[cfg(feature = "alloc")]
524impl<I> ContextError<I, &'static str> for VerboseError<I> {
525 fn add_context(mut self, input: I, ctx: &'static str) -> Self {
526 self.errors.push((input, VerboseErrorKind::Context(ctx)));
527 self
528 }
529}
530
531#[cfg(feature = "alloc")]
532impl<I, E> FromExternalError<I, E> for VerboseError<I> {
533 /// Create a new error from an input position and an external error
534 fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
535 Self::from_error_kind(input, kind)
536 }
537}
538
539#[cfg(feature = "alloc")]
540impl<I> ErrorConvert<VerboseError<I>> for VerboseError<(I, usize)> {
541 fn convert(self) -> VerboseError<I> {
542 VerboseError {
543 errors: self.errors.into_iter().map(|(i: (I, usize), e: VerboseErrorKind)| (i.0, e)).collect(),
544 }
545 }
546}
547
548#[cfg(feature = "alloc")]
549impl<I> ErrorConvert<VerboseError<(I, usize)>> for VerboseError<I> {
550 fn convert(self) -> VerboseError<(I, usize)> {
551 VerboseError {
552 errors: self.errors.into_iter().map(|(i: I, e: VerboseErrorKind)| ((i, 0), e)).collect(),
553 }
554 }
555}
556
557#[cfg(feature = "alloc")]
558impl<I: fmt::Display> fmt::Display for VerboseError<I> {
559 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
560 writeln!(f, "Parse error:")?;
561 for (input: &I, error: &VerboseErrorKind) in &self.errors {
562 match error {
563 VerboseErrorKind::Winnow(e: &ErrorKind) => writeln!(f, "{:?} at: {}", e, input)?,
564 VerboseErrorKind::Context(s: &&str) => writeln!(f, "in section '{}', at: {}", s, input)?,
565 }
566 }
567
568 Ok(())
569 }
570}
571
572#[cfg(feature = "std")]
573impl<I: fmt::Debug + fmt::Display + Sync + Send + 'static> std::error::Error for VerboseError<I> {}
574
575/// Transforms a `VerboseError` into a trace with input position information
576#[cfg(feature = "alloc")]
577pub fn convert_error<I: core::ops::Deref<Target = str>>(
578 input: I,
579 e: VerboseError<I>,
580) -> crate::lib::std::string::String {
581 use crate::lib::std::fmt::Write;
582 use crate::stream::Offset;
583
584 let mut result = crate::lib::std::string::String::new();
585
586 for (i, (substring, kind)) in e.errors.iter().enumerate() {
587 let offset = input.offset_to(substring);
588
589 if input.is_empty() {
590 match kind {
591 VerboseErrorKind::Context(s) => {
592 write!(&mut result, "{}: in {}, got empty input\n\n", i, s)
593 }
594 VerboseErrorKind::Winnow(e) => {
595 write!(&mut result, "{}: in {:?}, got empty input\n\n", i, e)
596 }
597 }
598 } else {
599 let prefix = &input.as_bytes()[..offset];
600
601 // Count the number of newlines in the first `offset` bytes of input
602 let line_number = prefix.iter().filter(|&&b| b == b'\n').count() + 1;
603
604 // Find the line that includes the subslice:
605 // Find the *last* newline before the substring starts
606 let line_begin = prefix
607 .iter()
608 .rev()
609 .position(|&b| b == b'\n')
610 .map(|pos| offset - pos)
611 .unwrap_or(0);
612
613 // Find the full line after that newline
614 let line = input[line_begin..]
615 .lines()
616 .next()
617 .unwrap_or(&input[line_begin..])
618 .trim_end();
619
620 // The (1-indexed) column number is the offset of our substring into that line
621 let column_number = line.offset_to(substring) + 1;
622
623 match kind {
624 VerboseErrorKind::Context(s) => write!(
625 &mut result,
626 "{i}: at line {line_number}, in {context}:\n\
627 {line}\n\
628 {caret:>column$}\n\n",
629 i = i,
630 line_number = line_number,
631 context = s,
632 line = line,
633 caret = '^',
634 column = column_number,
635 ),
636 VerboseErrorKind::Winnow(e) => write!(
637 &mut result,
638 "{i}: at line {line_number}, in {kind:?}:\n\
639 {line}\n\
640 {caret:>column$}\n\n",
641 i = i,
642 line_number = line_number,
643 kind = e,
644 line = line,
645 caret = '^',
646 column = column_number,
647 ),
648 }
649 }
650 // Because `write!` to a `String` is infallible, this `unwrap` is fine.
651 .unwrap();
652 }
653
654 result
655}
656
657/// Provide some minor debug context for errors
658#[rustfmt::skip]
659#[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)]
660#[allow(missing_docs)]
661pub enum ErrorKind {
662 Assert,
663 Token,
664 Tag,
665 Alt,
666 Many,
667 Eof,
668 Slice,
669 Complete,
670 Not,
671 Verify,
672 Fail,
673}
674
675impl ErrorKind {
676 #[rustfmt::skip]
677 /// Converts an `ErrorKind` to a text description
678 pub fn description(&self) -> &str {
679 match *self {
680 ErrorKind::Assert => "assert",
681 ErrorKind::Token => "token",
682 ErrorKind::Tag => "tag",
683 ErrorKind::Alt => "alternative",
684 ErrorKind::Many => "many",
685 ErrorKind::Eof => "end of file",
686 ErrorKind::Slice => "slice",
687 ErrorKind::Complete => "complete",
688 ErrorKind::Not => "negation",
689 ErrorKind::Verify => "predicate verification",
690 ErrorKind::Fail => "fail",
691 }
692 }
693}
694
695/// Creates a parse error from a [`ErrorKind`]
696/// and the position in the input
697#[cfg(test)]
698macro_rules! error_position(
699 ($input:expr, $code:expr) => ({
700 $crate::error::ParseError::from_error_kind($input, $code)
701 });
702);
703
704#[cfg(test)]
705macro_rules! error_node_position(
706 ($input:expr, $code:expr, $next:expr) => ({
707 $crate::error::ParseError::append($next, $input, $code)
708 });
709);
710
711#[cfg(test)]
712#[cfg(feature = "alloc")]
713mod tests {
714 use super::*;
715
716 #[test]
717 fn convert_error_panic() {
718 let input = "";
719
720 let _result: IResult<_, _, VerboseError<&str>> = 'x'.parse_next(input);
721 }
722}
723