blob: 04bddd4309bf8d33306a7dcd915376d7fb69db9e [file] [log] [blame]
//! Error management
//!
//! there are two ways to handle errors in nom. The first one,
//! activated by default, uses the `nom::ErrorKind<E=u32>` enum
//! in the error branch of `IResult`. This enum can hold either
//! a parser specific error code, or a custom error type you
//! specify.
//!
//! If you need more advanced error management, you can activate
//! the "verbose-errors" compilation feature, which will give you
//! the error system available in nom 1.0. The verbose errors
//! accumulate error codes and positions as you backtrack through
//! the parser tree. From there, you can precisely identify which
//! parts of the input triggered the error case.
//!
//! Please note that the verbose error management is a bit slower
//! than the simple one.
use util::ErrorKind;
use internal::{IResult, IError};
use internal::IResult::*;
pub type Err<E=u32> = ErrorKind<E>;
impl<I,O,E> IResult<I,O,E> {
/// Maps a `IResult<I, O, E>` to `IResult<I, O, N>` by appling a function
/// to a contained `Error` value, leaving `Done` and `Incomplete` value
/// untouched.
#[inline]
pub fn map_err<N, F>(self, f: F) -> IResult<I, O, N>
where F: FnOnce(Err<E>) -> Err<N> {
match self {
Error(e) => Error(f(e)),
Incomplete(n) => Incomplete(n),
Done(i, o) => Done(i, o),
}
}
/// Unwrap the contained `Error(E)` value, or panic if the `IResult` is not
/// `Error`.
pub fn unwrap_err(self) -> Err<E> {
match self {
Error(e) => e,
Done(_, _) => panic!("unwrap_err() called on an IResult that is Done"),
Incomplete(_) => panic!("unwrap_err() called on an IResult that is Incomplete"),
}
}
/// Convert the IResult to a std::result::Result
pub fn to_full_result(self) -> Result<O, IError<E>> {
match self {
Done(_, o) => Ok(o),
Incomplete(n) => Err(IError::Incomplete(n)),
Error(e) => Err(IError::Error(e))
}
}
/// Convert the IResult to a std::result::Result, or panic if the `IResult` is `Incomplete`
pub fn to_result(self) -> Result<O, Err<E>> {
match self {
Done(_, o) => Ok(o),
Error(e) => Err(e),
Incomplete(_) => panic!("to_result() called on an IResult that is Incomplete")
}
}
}
#[cfg(feature = "std")]
use std::any::Any;
#[cfg(feature = "std")]
use std::{error,fmt};
#[cfg(feature = "std")]
impl<E: fmt::Debug+Any> error::Error for Err<E> {
fn description(&self) -> &str {
self.description()
}
}
#[cfg(feature = "std")]
impl<E: fmt::Debug> fmt::Display for Err<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
/// translate parser result from IResult<I,O,u32> to IResult<I,O,E> with a custom type
///
/// ```
/// # #[macro_use] extern crate nom;
/// # use std::collections;
/// # use nom::IResult::Error;
/// # use nom::ErrorKind;
/// # fn main() {
/// // will add a Custom(42) error to the error chain
/// named!(err_test, add_return_error!(ErrorKind::Custom(42), tag!("abcd")));
/// // Convert to IREsult<&[u8], &[u8], &str>
/// named!(parser<&[u8], &[u8], &str>, add_return_error!(ErrorKind::Custom("custom error message"), fix_error!(&str, err_test)));
///
/// let a = &b"efghblah"[..];
/// let res_a = parser(a);
/// assert_eq!(res_a, Error(error_node_position!( ErrorKind::Custom("custom error message"), a, Position(ErrorKind::Fix, a))));
/// # }
/// ```
#[macro_export]
macro_rules! fix_error (
($i:expr, $t:ty, $submac:ident!( $($args:tt)* )) => (
{
match $submac!($i, $($args)*) {
$crate::IResult::Incomplete(x) => $crate::IResult::Incomplete(x),
$crate::IResult::Done(i, o) => $crate::IResult::Done(i, o),
$crate::IResult::Error(_) => {
let e: $crate::ErrorKind<$t> = $crate::ErrorKind::Fix;
$crate::IResult::Error(e)
}
}
}
);
($i:expr, $t:ty, $f:expr) => (
fix_error!($i, $t, call!($f));
);
);
/// `flat_map!(R -> IResult<R,S>, S -> IResult<S,T>) => R -> IResult<R, T>`
///
/// combines a parser R -> IResult<R,S> and
/// a parser S -> IResult<S,T> to return another
/// parser R -> IResult<R,T>
#[macro_export]
macro_rules! flat_map(
($i:expr, $submac:ident!( $($args:tt)* ), $submac2:ident!( $($args2:tt)* )) => (
{
match $submac!($i, $($args)*) {
$crate::IResult::Error(e) => $crate::IResult::Error(e),
$crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
$crate::IResult::Incomplete($crate::Needed::Size(i)) => $crate::IResult::Incomplete($crate::Needed::Size(i)),
$crate::IResult::Done(i, o) => match $submac2!(o, $($args2)*) {
$crate::IResult::Error(e) => $crate::IResult::Error(e),
$crate::IResult::Incomplete($crate::Needed::Unknown) => $crate::IResult::Incomplete($crate::Needed::Unknown),
$crate::IResult::Incomplete($crate::Needed::Size(ref i2)) => $crate::IResult::Incomplete($crate::Needed::Size(*i2)),
$crate::IResult::Done(_, o2) => $crate::IResult::Done(i, o2)
}
}
}
);
($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
flat_map!($i, $submac!($($args)*), call!($g));
);
($i:expr, $f:expr, $g:expr) => (
flat_map!($i, call!($f), call!($g));
);
($i:expr, $f:expr, $submac:ident!( $($args:tt)* )) => (
flat_map!($i, call!($f), $submac!($($args)*));
);
);