Simplify branching parsers

This commit is contained in:
Caleb Sander 2020-08-06 13:41:21 -04:00 committed by Geoffroy Couprie
parent 4d5e2484c2
commit 3a61f2453f
2 changed files with 96 additions and 103 deletions

View File

@ -566,6 +566,7 @@ macro_rules! succ (
(17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
(18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
(19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
(20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
);
#[doc(hidden)]

View File

@ -70,7 +70,7 @@ pub trait Permutation<I, O, E> {
/// # fn main() {
/// fn parser(input: &str) -> IResult<&str, (&str, &str)> {
/// permutation((alpha1, digit1))(input)
/// };
/// }
///
/// // permutation recognizes alphabetic characters then digit
/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123"))));
@ -79,9 +79,31 @@ pub trait Permutation<I, O, E> {
/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123"))));
///
/// // it will fail if one of the parsers failed
/// assert_eq!(parser("abc;"), Err(Err::Error(error_position!(";", ErrorKind::Permutation))));
/// assert_eq!(parser("abc;"), Err(Err::Error((";", ErrorKind::Digit))));
/// # }
/// ```
///
/// The parsers are applied greedily: if there are multiple unapplied parsers
/// that could parse the next slice of input, the first one is used.
/// ```rust
/// # use nom::{Err, error::ErrorKind, IResult};
/// use nom::branch::permutation;
/// use nom::character::complete::{anychar, char};
///
/// fn parser(input: &str) -> IResult<&str, (char, char)> {
/// permutation((anychar, char('a')))(input)
/// }
///
/// # fn main() {
/// // anychar parses 'b', then char('a') parses 'a'
/// assert_eq!(parser("ba"), Ok(("", ('b', 'a'))));
///
/// // anychar parses 'a', then char('a') fails on 'b',
/// // even though char('a') followed by anychar would succeed
/// assert_eq!(parser("ab"), Err(Err::Error(("b", ErrorKind::Char))));
/// # }
/// ```
///
pub fn permutation<I: Clone, O, E: ParseError<I>, List: Permutation<I, O, E>>(
mut l: List,
) -> impl FnMut(I) -> IResult<I, O, E> {
@ -111,10 +133,10 @@ macro_rules! alt_trait_impl(
> Alt<Input, Output, Error> for ( $($id),+ ) {
fn choice(&mut self, input: Input) -> IResult<Input, Output, Error> {
let mut err: Option<Error> = None;
alt_trait_inner!(0, self, input, err, $($id)+);
Err(Err::Error(Error::append(input, ErrorKind::Alt, err.unwrap())))
match self.0.parse(input.clone()) {
Err(Err::Error(e)) => alt_trait_inner!(1, self, input, e, $($id)+),
res => res,
}
}
}
);
@ -124,73 +146,65 @@ macro_rules! alt_trait_inner(
($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
match $self.$it.parse($input.clone()) {
Err(Err::Error(e)) => {
$err = Some(match $err.take() {
None => e,
Some(prev) => prev.or(e),
});
succ!($it, alt_trait_inner!($self, $input, $err, $($id)+))
},
res => return res,
let err = $err.or(e);
succ!($it, alt_trait_inner!($self, $input, err, $($id)+))
}
res => res,
}
);
($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
match $self.$it.parse($input.clone()) {
Err(Err::Error(e)) => {
$err = Some(match $err.take() {
None => e,
Some(prev) => prev.or(e),
});
},
res => return res,
}
Err(Err::Error(Error::append($input, ErrorKind::Alt, $err)))
);
);
alt_trait!(A B C D E F G H I J K L M N O P Q R S T U);
macro_rules! permutation_trait(
($name1:ident $ty1:ident, $name2:ident $ty2:ident) => (
permutation_trait_impl!($name1 $ty1, $name2 $ty2);
(
$name1:ident $ty1:ident $item1:ident
$name2:ident $ty2:ident $item2:ident
$($name3:ident $ty3:ident $item3:ident)*
) => (
permutation_trait!(__impl $name1 $ty1 $item1, $name2 $ty2 $item2; $($name3 $ty3 $item3)*);
);
($name1:ident $ty1:ident, $name2: ident $ty2:ident, $($name:ident $ty:ident),*) => (
permutation_trait!(__impl $name1 $ty1, $name2 $ty2; $($name $ty),*);
(
__impl $($name:ident $ty:ident $item:ident),+;
$name1:ident $ty1:ident $item1:ident $($name2:ident $ty2:ident $item2:ident)*
) => (
permutation_trait_impl!($($name $ty $item),+);
permutation_trait!(__impl $($name $ty $item),+ , $name1 $ty1 $item1; $($name2 $ty2 $item2)*);
);
(__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident, $($name2:ident $ty2:ident),*) => (
permutation_trait_impl!($($name $ty),+);
permutation_trait!(__impl $($name $ty),+ , $name1 $ty1; $($name2 $ty2),*);
);
(__impl $($name:ident $ty: ident),+; $name1:ident $ty1:ident) => (
permutation_trait_impl!($($name $ty),+);
permutation_trait_impl!($($name $ty),+, $name1 $ty1);
(__impl $($name:ident $ty:ident $item:ident),+;) => (
permutation_trait_impl!($($name $ty $item),+);
);
);
macro_rules! permutation_trait_impl(
($($name:ident $ty: ident),+) => (
($($name:ident $ty:ident $item:ident),+) => (
impl<
Input: Clone, $($ty),+ , Error: ParseError<Input>,
$($name: Parser<Input, $ty, Error>),+
> Permutation<Input, ( $($ty),+ ), Error> for ( $($name),+ ) {
fn permutation(&mut self, mut input: Input) -> IResult<Input, ( $($ty),+ ), Error> {
let mut res = permutation_init!((), $($name),+);
let mut res = ($(Option::<$ty>::None),+);
loop {
let mut all_done = true;
permutation_trait_inner!(0, self, input, res, all_done, $($name)+);
let mut err: Option<Error> = None;
permutation_trait_inner!(0, self, input, res, err, $($name)+);
//if we reach that part, it means none of the parsers were able to read anything
if !all_done {
//FIXME: should wrap the error returned by the child parser
return Err(Err::Error(error_position!(input, ErrorKind::Permutation)));
// If we reach here, every iterator has either been applied before,
// or errored on the remaining input
if let Some(err) = err {
// There are remaining parsers, and all errored on the remaining input
return Err(Err::Error(Error::append(input, ErrorKind::Permutation, err)));
}
break;
}
if let Some(unwrapped_res) = { permutation_trait_unwrap!(0, (), res, $($name),+) } {
Ok((input, unwrapped_res))
} else {
Err(Err::Error(error_position!(input, ErrorKind::Permutation)))
// All parsers were applied
match res {
($(Some($item)),+) => return Ok((input, ($($item),+))),
_ => unreachable!(),
}
}
}
}
@ -198,70 +212,48 @@ macro_rules! permutation_trait_impl(
);
macro_rules! permutation_trait_inner(
($it:tt, $self:expr, $input:ident, $res:expr, $all_done:expr, $head:ident $($id:ident)+) => ({
($it:tt, $self:expr, $input:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => (
if $res.$it.is_none() {
match $self.$it.parse($input.clone()) {
Ok((i,o)) => {
Ok((i, o)) => {
$input = i;
$res.$it = Some(o);
continue;
},
Err(Err::Error(_)) => {
$all_done = false;
},
Err(e) => {
return Err(e);
}
Err(Err::Error(e)) => {
$err = Some(match $err {
Some(err) => err.or(e),
None => e,
});
}
Err(e) => return Err(e),
};
}
succ!($it, permutation_trait_inner!($self, $input, $res, $all_done, $($id)+));
});
($it:tt, $self:expr, $input:ident, $res:expr, $all_done:expr, $head:ident) => ({
if $res.$it.is_none() {
match $self.$it.parse($input.clone()) {
Ok((i,o)) => {
$input = i;
$res.$it = Some(o);
continue;
},
Err(Err::Error(_)) => {
$all_done = false;
},
Err(e) => {
return Err(e);
}
};
}
});
succ!($it, permutation_trait_inner!($self, $input, $res, $err, $($id)*));
);
($it:tt, $self:expr, $input:ident, $res:expr, $err:expr,) => ();
);
macro_rules! permutation_trait_unwrap (
($it:tt, (), $res:ident, $e:ident, $($name:ident),+) => ({
let res = $res.$it;
if res.is_some() {
succ!($it, permutation_trait_unwrap!((res.unwrap()), $res, $($name),+))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $e:ident, $($name:ident),+) => ({
let res = $res.$it;
if res.is_some() {
succ!($it, permutation_trait_unwrap!(($($parsed),* , res.unwrap()), $res, $($name),+))
} else {
$crate::lib::std::option::Option::None
}
});
($it:tt, ($($parsed:expr),*), $res:ident, $name:ident) => ({
let res = $res.$it;
if res.is_some() {
$crate::lib::std::option::Option::Some(($($parsed),* , res.unwrap() ))
} else {
$crate::lib::std::option::Option::None
}
});
permutation_trait!(
FnA A a
FnB B b
FnC C c
FnD D d
FnE E e
FnF F f
FnG G g
FnH H h
FnI I i
FnJ J j
FnK K k
FnL L l
FnM M m
FnN N n
FnO O o
FnP P p
FnQ Q q
FnR R r
FnS S s
FnT T t
FnU U u
);
permutation_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L, FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);