use crate::internal::{Err, Mode, OutputMode, PResult, Parser};
use crate::lib::std::fmt;
#[cfg(feature = "alloc")]
use crate::alloc::borrow::ToOwned;
#[cfg(feature = "std")]
use crate::internal::IResult;
pub trait ParseError<I>: Sized {
fn from_error_kind(input: I, kind: ErrorKind) -> Self;
fn append(input: I, kind: ErrorKind, other: Self) -> Self;
fn from_char(input: I, _: char) -> Self {
Self::from_error_kind(input, ErrorKind::Char)
}
fn or(self, other: Self) -> Self {
other
}
}
pub trait ContextError<I>: Sized {
fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self {
other
}
}
pub trait FromExternalError<I, E> {
fn from_external_error(input: I, kind: ErrorKind, e: E) -> Self;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Error<I> {
pub input: I,
pub code: ErrorKind,
}
impl<I> Error<I> {
pub fn new(input: I, code: ErrorKind) -> Error<I> {
Error { input, code }
}
}
impl<I> ParseError<I> for Error<I> {
fn from_error_kind(input: I, kind: ErrorKind) -> Self {
Error { input, code: kind }
}
fn append(_: I, _: ErrorKind, other: Self) -> Self {
other
}
}
impl<I> ContextError<I> for Error<I> {}
impl<I, E> FromExternalError<I, E> for Error<I> {
fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
Error { input, code: kind }
}
}
impl<I: fmt::Display> fmt::Display for Error<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "error {:?} at: {}", self.code, self.input)
}
}
#[cfg(feature = "alloc")]
impl<I: ToOwned + ?Sized> Error<&I> {
pub fn cloned(self) -> Error<I::Owned> {
Error {
input: self.input.to_owned(),
code: self.code,
}
}
}
#[cfg(feature = "alloc")]
impl<I: ToOwned + ?Sized> Error<&mut I> {
pub fn cloned(self) -> Error<I::Owned> {
Error {
input: self.input.to_owned(),
code: self.code,
}
}
}
impl<I: Copy> Error<&I> {
pub fn copied(self) -> Error<I> {
Error {
input: *self.input,
code: self.code,
}
}
}
impl<I: Copy> Error<&mut I> {
pub fn copied(self) -> Error<I> {
Error {
input: *self.input,
code: self.code,
}
}
}
#[cfg(feature = "std")]
impl<I: fmt::Debug + fmt::Display> std::error::Error for Error<I> {}
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
impl From<Error<&[u8]>> for Error<crate::lib::std::vec::Vec<u8>> {
fn from(value: Error<&[u8]>) -> Self {
Error {
input: value.input.to_owned(),
code: value.code,
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))]
impl From<Error<&str>> for Error<crate::lib::std::string::String> {
fn from(value: Error<&str>) -> Self {
Error {
input: value.input.to_owned(),
code: value.code,
}
}
}
impl<I> ParseError<I> for (I, ErrorKind) {
fn from_error_kind(input: I, kind: ErrorKind) -> Self {
(input, kind)
}
fn append(_: I, _: ErrorKind, other: Self) -> Self {
other
}
}
impl<I> ContextError<I> for (I, ErrorKind) {}
impl<I, E> FromExternalError<I, E> for (I, ErrorKind) {
fn from_external_error(input: I, kind: ErrorKind, _e: E) -> Self {
(input, kind)
}
}
impl<I> ParseError<I> for () {
fn from_error_kind(_: I, _: ErrorKind) -> Self {}
fn append(_: I, _: ErrorKind, _: Self) -> Self {}
}
impl<I> ContextError<I> for () {}
impl<I, E> FromExternalError<I, E> for () {
fn from_external_error(_input: I, _kind: ErrorKind, _e: E) -> Self {}
}
pub fn make_error<I, E: ParseError<I>>(input: I, kind: ErrorKind) -> E {
E::from_error_kind(input, kind)
}
pub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) -> E {
E::append(input, kind, other)
}
pub fn context<F>(context: &'static str, parser: F) -> Context<F> {
Context { context, parser }
}
pub struct Context<F> {
context: &'static str,
parser: F,
}
impl<I, F> Parser<I> for Context<F>
where
I: Clone,
F: Parser<I>,
<F as Parser<I>>::Error: ContextError<I>,
{
type Output = <F as Parser<I>>::Output;
type Error = <F as Parser<I>>::Error;
fn process<OM: OutputMode>(&mut self, input: I) -> PResult<OM, I, Self::Output, Self::Error> {
match self.parser.process::<OM>(input.clone()) {
Err(Err::Error(e)) => Err(Err::Error(OM::Error::map(e, |e| {
<F as Parser<I>>::Error::add_context(input, self.context, e)
}))),
Err(Err::Failure(e)) => Err(Err::Failure(<F as Parser<I>>::Error::add_context(
input,
self.context,
e,
))),
x => x,
}
}
}
#[rustfmt::skip]
#[derive(Debug,PartialEq,Eq,Hash,Clone,Copy)]
#[allow(deprecated,missing_docs)]
pub enum ErrorKind {
Tag,
MapRes,
MapOpt,
Alt,
IsNot,
IsA,
SeparatedList,
SeparatedNonEmptyList,
Many0,
Many1,
ManyTill,
Count,
TakeUntil,
LengthValue,
TagClosure,
Alpha,
Digit,
HexDigit,
OctDigit,
BinDigit,
AlphaNumeric,
Space,
MultiSpace,
LengthValueFn,
Eof,
Switch,
TagBits,
OneOf,
NoneOf,
Char,
CrLf,
RegexpMatch,
RegexpMatches,
RegexpFind,
RegexpCapture,
RegexpCaptures,
TakeWhile1,
Complete,
Fix,
Escaped,
EscapedTransform,
NonEmpty,
ManyMN,
Not,
Permutation,
Verify,
TakeTill1,
TakeWhileMN,
TooLarge,
Many0Count,
Many1Count,
Float,
Satisfy,
Fail,
Many,
Fold,
Precedence,
}
#[rustfmt::skip]
#[allow(deprecated)]
pub fn error_to_u32(e: &ErrorKind) -> u32 {
match *e {
ErrorKind::Tag => 1,
ErrorKind::MapRes => 2,
ErrorKind::MapOpt => 3,
ErrorKind::Alt => 4,
ErrorKind::IsNot => 5,
ErrorKind::IsA => 6,
ErrorKind::SeparatedList => 7,
ErrorKind::SeparatedNonEmptyList => 8,
ErrorKind::Many1 => 9,
ErrorKind::Count => 10,
ErrorKind::TakeUntil => 12,
ErrorKind::LengthValue => 15,
ErrorKind::TagClosure => 16,
ErrorKind::Alpha => 17,
ErrorKind::Digit => 18,
ErrorKind::AlphaNumeric => 19,
ErrorKind::Space => 20,
ErrorKind::MultiSpace => 21,
ErrorKind::LengthValueFn => 22,
ErrorKind::Eof => 23,
ErrorKind::Switch => 27,
ErrorKind::TagBits => 28,
ErrorKind::OneOf => 29,
ErrorKind::NoneOf => 30,
ErrorKind::Char => 40,
ErrorKind::CrLf => 41,
ErrorKind::RegexpMatch => 42,
ErrorKind::RegexpMatches => 43,
ErrorKind::RegexpFind => 44,
ErrorKind::RegexpCapture => 45,
ErrorKind::RegexpCaptures => 46,
ErrorKind::TakeWhile1 => 47,
ErrorKind::Complete => 48,
ErrorKind::Fix => 49,
ErrorKind::Escaped => 50,
ErrorKind::EscapedTransform => 51,
ErrorKind::NonEmpty => 56,
ErrorKind::ManyMN => 57,
ErrorKind::HexDigit => 59,
ErrorKind::OctDigit => 61,
ErrorKind::Many0 => 62,
ErrorKind::Not => 63,
ErrorKind::Permutation => 64,
ErrorKind::ManyTill => 65,
ErrorKind::Verify => 66,
ErrorKind::TakeTill1 => 67,
ErrorKind::TakeWhileMN => 69,
ErrorKind::TooLarge => 70,
ErrorKind::Many0Count => 71,
ErrorKind::Many1Count => 72,
ErrorKind::Float => 73,
ErrorKind::Satisfy => 74,
ErrorKind::Fail => 75,
ErrorKind::Many => 76,
ErrorKind::Fold => 77,
ErrorKind::BinDigit => 78,
ErrorKind::Precedence => 79,
}
}
impl ErrorKind {
#[rustfmt::skip]
#[allow(deprecated)]
pub fn description(&self) -> &str {
match *self {
ErrorKind::Tag => "Tag",
ErrorKind::MapRes => "Map on Result",
ErrorKind::MapOpt => "Map on Option",
ErrorKind::Alt => "Alternative",
ErrorKind::IsNot => "IsNot",
ErrorKind::IsA => "IsA",
ErrorKind::SeparatedList => "Separated list",
ErrorKind::SeparatedNonEmptyList => "Separated non empty list",
ErrorKind::Many0 => "Many0",
ErrorKind::Many1 => "Many1",
ErrorKind::Count => "Count",
ErrorKind::TakeUntil => "Take until",
ErrorKind::LengthValue => "Length followed by value",
ErrorKind::TagClosure => "Tag closure",
ErrorKind::Alpha => "Alphabetic",
ErrorKind::Digit => "Digit",
ErrorKind::AlphaNumeric => "AlphaNumeric",
ErrorKind::Space => "Space",
ErrorKind::MultiSpace => "Multiple spaces",
ErrorKind::LengthValueFn => "LengthValueFn",
ErrorKind::Eof => "End of file",
ErrorKind::Switch => "Switch",
ErrorKind::TagBits => "Tag on bitstream",
ErrorKind::OneOf => "OneOf",
ErrorKind::NoneOf => "NoneOf",
ErrorKind::Char => "Char",
ErrorKind::CrLf => "CrLf",
ErrorKind::RegexpMatch => "RegexpMatch",
ErrorKind::RegexpMatches => "RegexpMatches",
ErrorKind::RegexpFind => "RegexpFind",
ErrorKind::RegexpCapture => "RegexpCapture",
ErrorKind::RegexpCaptures => "RegexpCaptures",
ErrorKind::TakeWhile1 => "TakeWhile1",
ErrorKind::Complete => "Complete",
ErrorKind::Fix => "Fix",
ErrorKind::Escaped => "Escaped",
ErrorKind::EscapedTransform => "EscapedTransform",
ErrorKind::NonEmpty => "NonEmpty",
ErrorKind::ManyMN => "Many(m, n)",
ErrorKind::HexDigit => "Hexadecimal Digit",
ErrorKind::OctDigit => "Octal digit",
ErrorKind::BinDigit => "Binary digit",
ErrorKind::Not => "Negation",
ErrorKind::Permutation => "Permutation",
ErrorKind::ManyTill => "ManyTill",
ErrorKind::Verify => "predicate verification",
ErrorKind::TakeTill1 => "TakeTill1",
ErrorKind::TakeWhileMN => "TakeWhileMN",
ErrorKind::TooLarge => "Needed data size is too large",
ErrorKind::Many0Count => "Count occurrence of >=0 patterns",
ErrorKind::Many1Count => "Count occurrence of >=1 patterns",
ErrorKind::Float => "Float",
ErrorKind::Satisfy => "Satisfy",
ErrorKind::Fail => "Fail",
ErrorKind::Many => "Many",
ErrorKind::Fold => "Fold",
ErrorKind::Precedence => "Precedence",
}
}
}
#[allow(unused_variables)]
#[macro_export(local_inner_macros)]
macro_rules! error_position(
($input:expr, $code:expr $(,)?) => ({
$crate::error::make_error($input, $code)
});
);
#[allow(unused_variables)]
#[macro_export(local_inner_macros)]
macro_rules! error_node_position(
($input:expr, $code:expr, $next:expr $(,)?) => ({
$crate::error::append_error($input, $code, $next)
});
);
#[cfg(feature = "std")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
pub fn 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>,
{
use crate::HexDisplay;
move |i: &'a [u8]| match f(i) {
Err(e) => {
println!("{}: Error({:?}) at:\n{}", context, e, i.to_hex(8));
Err(e)
}
a => a,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn context_test() {
use crate::{character::char, combinator::cut, internal::Needed};
#[derive(Debug, PartialEq)]
struct Error<I> {
input: I,
ctx: Option<&'static str>,
}
impl<I> ParseError<I> for Error<I> {
fn from_error_kind(input: I, _kind: ErrorKind) -> Self {
Self { input, ctx: None }
}
fn append(input: I, _kind: ErrorKind, other: Self) -> Self {
Self {
input,
ctx: other.ctx,
}
}
}
impl<I> ContextError<I> for Error<I> {
fn add_context(input: I, ctx: &'static str, _other: Self) -> Self {
Self {
input,
ctx: Some(ctx),
}
}
}
assert_eq!(
context("ctx", char::<_, Error<_>>('a')).parse("abcd"),
Ok(("bcd", 'a'))
);
assert_eq!(
context("ctx", char::<_, Error<_>>('a')).parse(""),
Err(Err::Incomplete(Needed::new(1)))
);
assert_eq!(
context("ctx", char::<_, Error<_>>('a')).parse_complete(""),
Err(Err::Error(Error {
input: "",
ctx: Some("ctx")
}))
);
assert_eq!(
context("ctx", cut(char::<_, Error<_>>('a'))).parse("bcd"),
Err(Err::Failure(Error {
input: "bcd",
ctx: Some("ctx")
}))
);
}
#[cfg(feature = "alloc")]
#[test]
fn clone_error() {
use crate::lib::std::string::String;
let err = Error {
code: ErrorKind::Eof,
input: "test",
};
let _err: Error<String> = err.cloned();
}
#[test]
fn copy_error() {
let err = Error {
code: ErrorKind::Eof,
input: &0_u8,
};
let _err: Error<u8> = err.copied();
}
}