summaryrefslogtreecommitdiffstats
path: root/vendor/winnow/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/winnow/src/error.rs')
-rw-r--r--vendor/winnow/src/error.rs721
1 files changed, 721 insertions, 0 deletions
diff --git a/vendor/winnow/src/error.rs b/vendor/winnow/src/error.rs
new file mode 100644
index 000000000..b49b0560a
--- /dev/null
+++ b/vendor/winnow/src/error.rs
@@ -0,0 +1,721 @@
+//! # Error management
+//!
+//! Errors are designed with multiple needs in mind:
+//! - Accumulate more [context][Parser::context] as the error goes up the parser chain
+//! - Distinguish between [recoverable errors,
+//! unrecoverable errors, and more data is needed][ErrMode]
+//! - Have a very low overhead, as errors are often discarded by the calling parser (examples: `many0`, `alt`)
+//! - Can be modified according to the user's needs, because some languages need a lot more information
+//! - Help thread-through the [stream][crate::stream]
+//!
+//! To abstract these needs away from the user, generally `winnow` parsers use the [`IResult`]
+//! alias, rather than [`Result`][std::result::Result]. [`finish`][FinishIResult::finish] is
+//! provided for top-level parsers to integrate with your application's error reporting.
+//!
+//! Error types include:
+//! - `()`
+//! - [`Error`]
+//! - [`VerboseError`]
+//! - [Custom errors][crate::_topic::error]
+
+#[cfg(feature = "alloc")]
+use crate::lib::std::borrow::ToOwned;
+use crate::lib::std::fmt;
+use core::num::NonZeroUsize;
+
+use crate::stream::Stream;
+use crate::stream::StreamIsPartial;
+#[allow(unused_imports)] // Here for intra-doc links
+use crate::Parser;
+
+/// Holds the result of [`Parser`]
+///
+/// - `Ok((I, O))` is the remaining [input][crate::stream] and the parsed value
+/// - [`Err(ErrMode<E>)`][ErrMode] is the error along with how to respond to it
+///
+/// By default, the error type (`E`) is [`Error`]
+///
+/// At the top-level of your parser, you can use the [`FinishIResult::finish`] method to convert
+/// it to a more common result type
+pub type IResult<I, O, E = Error<I>> = Result<(I, O), ErrMode<E>>;
+
+/// Extension trait to convert a parser's [`IResult`] to a more manageable type
+#[deprecated(since = "0.4.0", note = "Replaced with `Parser::parse`")]
+pub trait FinishIResult<I, O, E> {
+ /// Converts the parser's [`IResult`] to a type that is more consumable by callers.
+ ///
+ /// Errors if the parser is not at the [end of input][crate::combinator::eof]. See
+ /// [`FinishIResult::finish_err`] if the remaining input is needed.
+ ///
+ /// # Panic
+ ///
+ /// If the result is `Err(ErrMode::Incomplete(_))`, this method will panic.
+ /// - **Complete parsers:** It will not be an issue, `Incomplete` is never used
+ /// - **Partial parsers:** `Incomplete` will be returned if there's not enough data
+ /// for the parser to decide, and you should gather more data before parsing again.
+ /// Once the parser returns either `Ok(_)`, `Err(ErrMode::Backtrack(_))` or `Err(ErrMode::Cut(_))`,
+ /// you can get out of the parsing loop and call `finish_err()` on the parser's result
+ ///
+ /// # Example
+ ///
+ #[cfg_attr(not(feature = "std"), doc = "```ignore")]
+ #[cfg_attr(feature = "std", doc = "```")]
+ /// use winnow::prelude::*;
+ /// use winnow::character::hex_uint;
+ /// use winnow::error::Error;
+ ///
+ /// struct Hex(u64);
+ ///
+ /// fn parse(value: &str) -> Result<Hex, Error<String>> {
+ /// hex_uint.map(Hex).parse_next(value).finish().map_err(Error::into_owned)
+ /// }
+ /// ```
+ #[deprecated(since = "0.4.0", note = "Replaced with `Parser::parse`")]
+ fn finish(self) -> Result<O, E>;
+
+ /// Converts the parser's [`IResult`] to a type that is more consumable by errors.
+ ///
+ /// It keeps the same `Ok` branch, and merges `ErrMode::Backtrack` and `ErrMode::Cut` into the `Err`
+ /// side.
+ ///
+ /// # Panic
+ ///
+ /// If the result is `Err(ErrMode::Incomplete(_))`, this method will panic as [`ErrMode::Incomplete`]
+ /// should only be set when the input is [`StreamIsPartial<false>`] which this isn't implemented
+ /// for.
+ #[deprecated(since = "0.4.0", note = "Replaced with `Parser::parse`")]
+ fn finish_err(self) -> Result<(I, O), E>;
+}
+
+#[allow(deprecated)]
+impl<I, O, E> FinishIResult<I, O, E> for IResult<I, O, E>
+where
+ I: Stream,
+ // Force users to deal with `Incomplete` when `StreamIsPartial<true>`
+ I: StreamIsPartial,
+ I: Clone,
+ E: ParseError<I>,
+{
+ fn finish(self) -> Result<O, E> {
+ debug_assert!(
+ !I::is_partial_supported(),
+ "partial streams need to handle `ErrMode::Incomplete`"
+ );
+
+ let (i, o) = self.finish_err()?;
+ crate::combinator::eof(i).finish_err()?;
+ Ok(o)
+ }
+
+ fn finish_err(self) -> Result<(I, O), E> {
+ debug_assert!(
+ !I::is_partial_supported(),
+ "partial streams need to handle `ErrMode::Incomplete`"
+ );
+
+ match self {
+ Ok(res) => Ok(res),
+ Err(ErrMode::Backtrack(e)) | Err(ErrMode::Cut(e)) => Err(e),
+ Err(ErrMode::Incomplete(_)) => {
+ panic!("complete parsers should not report `Err(ErrMode::Incomplete(_))`")
+ }
+ }
+ }
+}
+
+/// Contains information on needed data if a parser returned `Incomplete`
+///
+/// **Note:** This is only possible for `Stream` that are [partial][`StreamIsPartial`],
+/// like [`Partial`][crate::Partial].
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
+pub enum Needed {
+ /// Needs more data, but we do not know how much
+ Unknown,
+ /// Contains the required data size in bytes
+ Size(NonZeroUsize),
+}
+
+impl Needed {
+ /// Creates `Needed` instance, returns `Needed::Unknown` if the argument is zero
+ pub fn new(s: usize) -> Self {
+ match NonZeroUsize::new(s) {
+ Some(sz) => Needed::Size(sz),
+ None => Needed::Unknown,
+ }
+ }
+
+ /// Indicates if we know how many bytes we need
+ pub fn is_known(&self) -> bool {
+ *self != Needed::Unknown
+ }
+
+ /// Maps a `Needed` to `Needed` by applying a function to a contained `Size` value.
+ #[inline]
+ pub fn map<F: Fn(NonZeroUsize) -> usize>(self, f: F) -> Needed {
+ match self {
+ Needed::Unknown => Needed::Unknown,
+ Needed::Size(n) => Needed::new(f(n)),
+ }
+ }
+}
+
+/// The `Err` enum indicates the parser was not successful
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
+pub enum ErrMode<E> {
+ /// There was not enough data to determine the appropriate action
+ ///
+ /// More data needs to be buffered before retrying the parse.
+ ///
+ /// This must only be set when the [`Stream`] is [partial][`StreamIsPartial`], like with
+ /// [`Partial`][crate::Partial]
+ ///
+ /// Convert this into an `Backtrack` with [`Parser::complete_err`]
+ Incomplete(Needed),
+ /// The parser failed with a recoverable error (the default).
+ ///
+ /// For example, a parser for json values might include a
+ /// [`dec_uint`][crate::character::dec_uint] as one case in an [`alt`][crate::branch::alt]
+ /// combiantor. If it fails, the next case should be tried.
+ Backtrack(E),
+ /// The parser had an unrecoverable error.
+ ///
+ /// The parser was on the right branch, so directly report it to the user rather than trying
+ /// other branches. You can use [`cut_err()`][crate::combinator::cut_err] combinator to switch
+ /// from `ErrMode::Backtrack` to `ErrMode::Cut`.
+ ///
+ /// For example, one case in an [`alt`][crate::branch::alt] combinator found a unique prefix
+ /// and you want any further errors parsing the case to be reported to the user.
+ Cut(E),
+}
+
+impl<E> ErrMode<E> {
+ /// Tests if the result is Incomplete
+ pub fn is_incomplete(&self) -> bool {
+ matches!(self, ErrMode::Incomplete(_))
+ }
+
+ /// Prevent backtracking, bubbling the error up to the top
+ pub fn cut(self) -> Self {
+ match self {
+ ErrMode::Backtrack(e) => ErrMode::Cut(e),
+ rest => rest,
+ }
+ }
+
+ /// Enable backtracking support
+ pub fn backtrack(self) -> Self {
+ match self {
+ ErrMode::Cut(e) => ErrMode::Backtrack(e),
+ rest => rest,
+ }
+ }
+
+ /// Applies the given function to the inner error
+ pub fn map<E2, F>(self, f: F) -> ErrMode<E2>
+ where
+ F: FnOnce(E) -> E2,
+ {
+ match self {
+ ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
+ ErrMode::Cut(t) => ErrMode::Cut(f(t)),
+ ErrMode::Backtrack(t) => ErrMode::Backtrack(f(t)),
+ }
+ }
+
+ /// Automatically converts between errors if the underlying type supports it
+ pub fn convert<F>(self) -> ErrMode<F>
+ where
+ E: ErrorConvert<F>,
+ {
+ self.map(ErrorConvert::convert)
+ }
+}
+
+impl<I, E: ParseError<I>> ParseError<I> for ErrMode<E> {
+ fn from_error_kind(input: I, kind: ErrorKind) -> Self {
+ ErrMode::Backtrack(E::from_error_kind(input, kind))
+ }
+
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn assert(input: I, message: &'static str) -> Self
+ where
+ I: crate::lib::std::fmt::Debug,
+ {
+ ErrMode::Backtrack(E::assert(input, message))
+ }
+
+ fn append(self, input: I, kind: ErrorKind) -> Self {
+ match self {
+ ErrMode::Backtrack(e) => ErrMode::Backtrack(e.append(input, kind)),
+ e => e,
+ }
+ }
+
+ fn or(self, other: Self) -> Self {
+ match (self, other) {
+ (ErrMode::Backtrack(e), ErrMode::Backtrack(o)) => ErrMode::Backtrack(e.or(o)),
+ (ErrMode::Incomplete(e), _) | (_, ErrMode::Incomplete(e)) => ErrMode::Incomplete(e),
+ (ErrMode::Cut(e), _) | (_, ErrMode::Cut(e)) => ErrMode::Cut(e),
+ }
+ }
+}
+
+impl<I, EXT, E> FromExternalError<I, EXT> for ErrMode<E>
+where
+ E: FromExternalError<I, EXT>,
+{
+ fn from_external_error(input: I, kind: ErrorKind, e: EXT) -> Self {
+ ErrMode::Backtrack(E::from_external_error(input, kind, e))
+ }
+}
+
+impl<T> ErrMode<Error<T>> {
+ /// Maps `ErrMode<Error<T>>` to `ErrMode<Error<U>>` with the given `F: T -> U`
+ pub fn map_input<U, F>(self, f: F) -> ErrMode<Error<U>>
+ where
+ F: FnOnce(T) -> U,
+ {
+ match self {
+ ErrMode::Incomplete(n) => ErrMode::Incomplete(n),
+ ErrMode::Cut(Error { input, kind }) => ErrMode::Cut(Error {
+ input: f(input),
+ kind,
+ }),
+ ErrMode::Backtrack(Error { input, kind }) => ErrMode::Backtrack(Error {
+ input: f(input),
+ kind,
+ }),
+ }
+ }
+}
+
+impl<E: Eq> Eq for ErrMode<E> {}
+
+impl<E> fmt::Display for ErrMode<E>
+where
+ E: fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ErrMode::Incomplete(Needed::Size(u)) => write!(f, "Parsing requires {} bytes/chars", u),
+ ErrMode::Incomplete(Needed::Unknown) => write!(f, "Parsing requires more data"),
+ ErrMode::Cut(c) => write!(f, "Parsing Failure: {:?}", c),
+ ErrMode::Backtrack(c) => write!(f, "Parsing Error: {:?}", c),
+ }
+ }
+}
+
+/// The basic [`Parser`] trait for errors
+///
+/// It provides methods to create an error from some combinators,
+/// and combine existing errors in combinators like `alt`.
+pub trait ParseError<I>: Sized {
+ /// Creates an error from the input position and an [`ErrorKind`]
+ fn from_error_kind(input: I, kind: ErrorKind) -> Self;
+
+ /// Process a parser assertion
+ #[cfg_attr(debug_assertions, track_caller)]
+ fn assert(input: I, _message: &'static str) -> Self
+ where
+ I: crate::lib::std::fmt::Debug,
+ {
+ #[cfg(debug_assertions)]
+ panic!("assert `{}` failed at {:#?}", _message, input);
+ #[cfg(not(debug_assertions))]
+ Self::from_error_kind(input, ErrorKind::Assert)
+ }
+
+ /// Like [`ParseError::from_error_kind`] but merges it with the existing error.
+ ///
+ /// This is useful when backtracking through a parse tree, accumulating error context on the
+ /// way.
+ fn append(self, input: I, kind: ErrorKind) -> Self;
+
+ /// Combines errors from two different parse branches.
+ ///
+ /// For example, this would be used by [`alt`][crate::branch::alt] to report the error from
+ /// each case.
+ fn or(self, other: Self) -> Self {
+ other
+ }
+}
+
+/// Used by [`Parser::context`] to add custom data to error while backtracking
+///
+/// May be implemented multiple times for different kinds of context.
+pub trait ContextError<I, C = &'static str>: Sized {
+ /// Append to an existing error custom data
+ ///
+ /// This is used mainly by [`Parser::context`], to add user friendly information
+ /// to errors when backtracking through a parse tree
+ fn add_context(self, _input: I, _ctx: C) -> Self {
+ self
+ }
+}
+
+/// Create a new error with an external error, from [`std::str::FromStr`]
+///
+/// This trait is required by the [`Parser::map_res`] combinator.
+pub trait FromExternalError<I, E> {
+ /// Like [`ParseError::from_error_kind`] but also include an external error.
+ fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self;
+}
+
+/// Equivalent of `From` implementation to avoid orphan rules in bits parsers
+pub trait ErrorConvert<E> {
+ /// Transform to another error type
+ fn convert(self) -> E;
+}
+
+/// Default error type, only contains the error' location and kind
+///
+/// This is a low-overhead error that only provides basic information. For less overhead, see
+/// `()`. Fore more information, see [`VerboseError`].
+///:w
+/// **Note:** [context][Parser::context] and inner errors (like from [`Parser::map_res`]) will be
+/// dropped.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct Error<I> {
+ /// The input stream, pointing to the location where the error occurred
+ pub input: I,
+ /// A rudimentary error kind
+ pub kind: ErrorKind,
+}
+
+impl<I> Error<I> {
+ /// Creates a new basic error
+ pub fn new(input: I, kind: ErrorKind) -> Error<I> {
+ Error { input, kind }
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<'i, I: ToOwned + ?Sized> Error<&'i I> {
+ /// Obtaining ownership
+ pub fn into_owned(self) -> Error<<I as ToOwned>::Owned> {
+ Error {
+ input: self.input.to_owned(),
+ kind: self.kind,
+ }
+ }
+}
+
+impl<I> ParseError<I> for Error<I> {
+ fn from_error_kind(input: I, kind: ErrorKind) -> Self {
+ Error { input, kind }
+ }
+
+ fn append(self, _: I, _: ErrorKind) -> Self {
+ self
+ }
+}
+
+impl<I, C> ContextError<I, C> for Error<I> {}
+
+impl<I, E> FromExternalError<I, E> for Error<I> {
+ /// Create a new error from an input position and an external error
+ fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
+ Error { input, kind }
+ }
+}
+
+impl<I> ErrorConvert<Error<(I, usize)>> for Error<I> {
+ fn convert(self) -> Error<(I, usize)> {
+ Error {
+ input: (self.input, 0),
+ kind: self.kind,
+ }
+ }
+}
+
+impl<I> ErrorConvert<Error<I>> for Error<(I, usize)> {
+ fn convert(self) -> Error<I> {
+ Error {
+ input: self.input.0,
+ kind: self.kind,
+ }
+ }
+}
+
+/// The Display implementation allows the `std::error::Error` implementation
+impl<I: fmt::Display> fmt::Display for Error<I> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "error {:?} at: {}", self.kind, self.input)
+ }
+}
+
+#[cfg(feature = "std")]
+impl<I: fmt::Debug + fmt::Display + Sync + Send + 'static> std::error::Error for Error<I> {}
+
+impl<I> ParseError<I> for () {
+ fn from_error_kind(_: I, _: ErrorKind) -> Self {}
+
+ fn append(self, _: I, _: ErrorKind) -> Self {}
+}
+
+impl<I, C> ContextError<I, C> for () {}
+
+impl<I, E> FromExternalError<I, E> for () {
+ fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {}
+}
+
+impl ErrorConvert<()> for () {
+ fn convert(self) {}
+}
+
+/// Accumulates error information while backtracking
+///
+/// For less overhead (and information), see [`Error`].
+///
+/// [`convert_error`] provides an example of how to render this for end-users.
+///
+/// **Note:** This will only capture the last failed branch for combinators like
+/// [`alt`][crate::branch::alt].
+#[cfg(feature = "alloc")]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct VerboseError<I> {
+ /// Accumulated error information
+ pub errors: crate::lib::std::vec::Vec<(I, VerboseErrorKind)>,
+}
+
+#[cfg(feature = "alloc")]
+impl<'i, I: ToOwned + ?Sized> VerboseError<&'i I> {
+ /// Obtaining ownership
+ pub fn into_owned(self) -> VerboseError<<I as ToOwned>::Owned> {
+ #[allow(clippy::redundant_clone)] // false positive
+ VerboseError {
+ errors: self
+ .errors
+ .into_iter()
+ .map(|(i, k)| (i.to_owned(), k))
+ .collect(),
+ }
+ }
+}
+
+#[cfg(feature = "alloc")]
+#[derive(Clone, Debug, Eq, PartialEq)]
+/// Error context for `VerboseError`
+pub enum VerboseErrorKind {
+ /// Static string added by the `context` function
+ Context(&'static str),
+ /// Error kind given by various parsers
+ Winnow(ErrorKind),
+}
+
+#[cfg(feature = "alloc")]
+impl<I> ParseError<I> for VerboseError<I> {
+ fn from_error_kind(input: I, kind: ErrorKind) -> Self {
+ VerboseError {
+ errors: vec![(input, VerboseErrorKind::Winnow(kind))],
+ }
+ }
+
+ fn append(mut self, input: I, kind: ErrorKind) -> Self {
+ self.errors.push((input, VerboseErrorKind::Winnow(kind)));
+ self
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<I> ContextError<I, &'static str> for VerboseError<I> {
+ fn add_context(mut self, input: I, ctx: &'static str) -> Self {
+ self.errors.push((input, VerboseErrorKind::Context(ctx)));
+ self
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<I, E> FromExternalError<I, E> for VerboseError<I> {
+ /// Create a new error from an input position and an external error
+ fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
+ Self::from_error_kind(input, kind)
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<I> ErrorConvert<VerboseError<I>> for VerboseError<(I, usize)> {
+ fn convert(self) -> VerboseError<I> {
+ VerboseError {
+ errors: self.errors.into_iter().map(|(i, e)| (i.0, e)).collect(),
+ }
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<I> ErrorConvert<VerboseError<(I, usize)>> for VerboseError<I> {
+ fn convert(self) -> VerboseError<(I, usize)> {
+ VerboseError {
+ errors: self.errors.into_iter().map(|(i, e)| ((i, 0), e)).collect(),
+ }
+ }
+}
+
+#[cfg(feature = "alloc")]
+impl<I: fmt::Display> fmt::Display for VerboseError<I> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ writeln!(f, "Parse error:")?;
+ for (input, error) in &self.errors {
+ match error {
+ VerboseErrorKind::Winnow(e) => writeln!(f, "{:?} at: {}", e, input)?,
+ VerboseErrorKind::Context(s) => writeln!(f, "in section '{}', at: {}", s, input)?,
+ }
+ }
+
+ Ok(())
+ }
+}
+
+#[cfg(feature = "std")]
+impl<I: fmt::Debug + fmt::Display + Sync + Send + 'static> std::error::Error for VerboseError<I> {}
+
+/// Transforms a `VerboseError` into a trace with input position information
+#[cfg(feature = "alloc")]
+pub fn convert_error<I: core::ops::Deref<Target = str>>(
+ input: I,
+ e: VerboseError<I>,
+) -> crate::lib::std::string::String {
+ use crate::lib::std::fmt::Write;
+ use crate::stream::Offset;
+
+ let mut result = crate::lib::std::string::String::new();
+
+ for (i, (substring, kind)) in e.errors.iter().enumerate() {
+ let offset = input.offset_to(substring);
+
+ if input.is_empty() {
+ match kind {
+ VerboseErrorKind::Context(s) => {
+ write!(&mut result, "{}: in {}, got empty input\n\n", i, s)
+ }
+ VerboseErrorKind::Winnow(e) => {
+ write!(&mut result, "{}: in {:?}, got empty input\n\n", i, e)
+ }
+ }
+ } else {
+ let prefix = &input.as_bytes()[..offset];
+
+ // Count the number of newlines in the first `offset` bytes of input
+ let line_number = prefix.iter().filter(|&&b| b == b'\n').count() + 1;
+
+ // Find the line that includes the subslice:
+ // Find the *last* newline before the substring starts
+ let line_begin = prefix
+ .iter()
+ .rev()
+ .position(|&b| b == b'\n')
+ .map(|pos| offset - pos)
+ .unwrap_or(0);
+
+ // Find the full line after that newline
+ let line = input[line_begin..]
+ .lines()
+ .next()
+ .unwrap_or(&input[line_begin..])
+ .trim_end();
+
+ // The (1-indexed) column number is the offset of our substring into that line
+ let column_number = line.offset_to(substring) + 1;
+
+ match kind {
+ VerboseErrorKind::Context(s) => write!(
+ &mut result,
+ "{i}: at line {line_number}, in {context}:\n\
+ {line}\n\
+ {caret:>column$}\n\n",
+ i = i,
+ line_number = line_number,
+ context = s,
+ line = line,
+ caret = '^',
+ column = column_number,
+ ),
+ VerboseErrorKind::Winnow(e) => write!(
+ &mut result,
+ "{i}: at line {line_number}, in {kind:?}:\n\
+ {line}\n\
+ {caret:>column$}\n\n",
+ i = i,
+ line_number = line_number,
+ kind = e,
+ line = line,
+ caret = '^',
+ column = column_number,
+ ),
+ }
+ }
+ // Because `write!` to a `String` is infallible, this `unwrap` is fine.
+ .unwrap();
+ }
+
+ result
+}
+
+/// Provide some minor debug context for errors
+#[rustfmt::skip]
+#[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)]
+#[allow(missing_docs)]
+pub enum ErrorKind {
+ Assert,
+ Token,
+ Tag,
+ Alt,
+ Many,
+ Eof,
+ Slice,
+ Complete,
+ Not,
+ Verify,
+ Fail,
+}
+
+impl ErrorKind {
+ #[rustfmt::skip]
+ /// Converts an `ErrorKind` to a text description
+ pub fn description(&self) -> &str {
+ match *self {
+ ErrorKind::Assert => "assert",
+ ErrorKind::Token => "token",
+ ErrorKind::Tag => "tag",
+ ErrorKind::Alt => "alternative",
+ ErrorKind::Many => "many",
+ ErrorKind::Eof => "end of file",
+ ErrorKind::Slice => "slice",
+ ErrorKind::Complete => "complete",
+ ErrorKind::Not => "negation",
+ ErrorKind::Verify => "predicate verification",
+ ErrorKind::Fail => "fail",
+ }
+ }
+}
+
+/// Creates a parse error from a [`ErrorKind`]
+/// and the position in the input
+#[cfg(test)]
+macro_rules! error_position(
+ ($input:expr, $code:expr) => ({
+ $crate::error::ParseError::from_error_kind($input, $code)
+ });
+);
+
+#[cfg(test)]
+macro_rules! error_node_position(
+ ($input:expr, $code:expr, $next:expr) => ({
+ $crate::error::ParseError::append($next, $input, $code)
+ });
+);
+
+#[cfg(test)]
+#[cfg(feature = "alloc")]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn convert_error_panic() {
+ let input = "";
+
+ let _result: IResult<_, _, VerboseError<&str>> = 'x'.parse_next(input);
+ }
+}