#[cfg(test)]
mod tests;
use core::marker::PhantomData;
use crate::error::ErrorKind;
use crate::error::ParseError;
use crate::internal::{Err, Mode, Parser};
pub fn alt<List>(l: List) -> Choice<List> {
Choice { parser: l }
}
pub fn permutation<I: Clone, E: ParseError<I>, List>(list: List) -> Permutation<List, E> {
Permutation {
parser: list,
e: PhantomData,
}
}
macro_rules! alt_trait(
($first:ident $second:ident $($id: ident)+) => (
alt_trait!(__impl $first $second; $($id)+);
);
(__impl $($current:ident)*; $head:ident $($id: ident)+) => (
alt_trait_impl!($($current)*);
alt_trait!(__impl $($current)* $head; $($id)+);
);
(__impl $($current:ident)*; $head:ident) => (
alt_trait_impl!($($current)*);
alt_trait_impl!($($current)* $head);
);
);
pub struct Choice<T> {
parser: T,
}
macro_rules! alt_trait_impl(
($($id:ident)+) => (
impl<
Input: Clone, Output, Error: ParseError<Input>,
$($id: Parser<Input, Output = Output, Error = Error>),+
> Parser<Input> for Choice< ( $($id),+ )> {
type Output = Output;
type Error = Error;
#[inline(always)]
fn process<OM: crate::OutputMode>(
&mut self,
input: Input,
) -> crate::PResult<OM, Input, Self::Output, Self::Error> {
match self.parser.0.process::<OM>(input.clone()) {
Ok(res) => Ok(res),
Err(Err::Failure(e))=> Err(Err::Failure(e)),
Err(Err::Incomplete(i))=> Err(Err::Incomplete(i)),
Err(Err::Error(e)) => alt_trait_inner!(1, self, input, e, $($id)+),
}
}
}
);
);
macro_rules! alt_trait_inner(
($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
match $self.parser.$it.process::<OM>($input.clone()) {
Ok(res) => Ok(res),
Err(Err::Failure(e))=>Err(Err::Failure(e)),
Err(Err::Incomplete(i))=> Err(Err::Incomplete(i)),
Err(Err::Error(e)) => {
succ!($it, alt_trait_inner!($self, $input, <OM::Error as crate::Mode>::combine($err, e, |e1, e2| e1.or(e2)), $($id)+))
}
}
);
($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
Err(Err::Error(<OM::Error as crate::Mode>::map($err, |err| 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);
impl<Input, Output, Error: ParseError<Input>, A: Parser<Input, Output = Output, Error = Error>>
Parser<Input> for Choice<(A,)>
{
type Output = Output;
type Error = Error;
#[inline]
fn process<OM: crate::OutputMode>(
&mut self,
input: Input,
) -> crate::PResult<OM, Input, Self::Output, Self::Error> {
self.parser.0.process::<OM>(input)
}
}
impl<
const N: usize,
Input: Clone,
Output,
Error: ParseError<Input>,
A: Parser<Input, Output = Output, Error = Error>,
> Parser<Input> for Choice<[A; N]>
{
type Output = Output;
type Error = Error;
#[inline]
fn process<OM: crate::OutputMode>(
&mut self,
input: Input,
) -> crate::PResult<OM, Input, Self::Output, Self::Error> {
let mut error = None;
for branch in &mut self.parser {
match branch.process::<OM>(input.clone()) {
Err(Err::Error(e)) => match error {
None => error = Some(e),
Some(err) => error = Some(OM::Error::combine(err, e, |e1, e2| e1.or(e2))),
},
res => return res,
}
}
match error {
Some(e) => Err(Err::Error(OM::Error::map(e, |err| {
Error::append(input, ErrorKind::Alt, err)
}))),
None => Err(Err::Error(OM::Error::bind(|| {
Error::from_error_kind(input, ErrorKind::Alt)
}))),
}
}
}
impl<
Input: Clone,
Output,
Error: ParseError<Input>,
A: Parser<Input, Output = Output, Error = Error>,
> Parser<Input> for Choice<&mut [A]>
{
type Output = Output;
type Error = Error;
#[inline]
fn process<OM: crate::OutputMode>(
&mut self,
input: Input,
) -> crate::PResult<OM, Input, Self::Output, Self::Error> {
let mut error = None;
for branch in self.parser.iter_mut() {
match branch.process::<OM>(input.clone()) {
Err(Err::Error(e)) => match error {
None => error = Some(e),
Some(err) => error = Some(OM::Error::combine(err, e, |e1, e2| e1.or(e2))),
},
res => return res,
}
}
match error {
Some(e) => Err(Err::Error(OM::Error::map(e, |err| {
Error::append(input, ErrorKind::Alt, err)
}))),
None => Err(Err::Error(OM::Error::bind(|| {
Error::from_error_kind(input, ErrorKind::Alt)
}))),
}
}
}
macro_rules! permutation_trait(
(
$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)*);
);
(
__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 $item:ident),+;) => (
permutation_trait_impl!($($name $ty $item),+);
);
);
pub struct Permutation<T, Error> {
parser: T,
e: PhantomData<Error>,
}
macro_rules! permutation_trait_impl(
($($name:ident $ty:ident $item:ident),+) => (
impl<
Input, Error, $($ty),+ , $($name),+
> Parser<Input> for Permutation< ( $($name),+ ), Error>
where
Input: Clone,
Error: ParseError<Input>,
$($name: Parser<Input, Output = $ty, Error = Error>),+
{
type Output = ( $($ty),+ );
type Error = Error;
#[inline(always)]
fn process<OM: crate::OutputMode>(
&mut self,
mut input: Input,
) -> crate::PResult<OM, Input, Self::Output, Self::Error> {
let mut res = OM::Output::bind(|| ($(Option::<$ty>::None),+));
$(let mut $item = false;)+
loop {
let mut err: Option<<OM::Error as Mode>::Output<Error>> = None;
permutation_trait_inner!(0, self, input, res, err, $($item)+);
if let Some(err) = err {
return Err(Err::Error(OM::Error::map(err, |err| Error::append(input, ErrorKind::Permutation, err))));
}
return Ok((input,OM::Output::map(res, |res| {
match res {
($(Some($item)),+) => ($($item),+),
_ => unreachable!(),
}
})))
}
}
}
);
);
macro_rules! permutation_trait_inner(
($it:tt, $self:expr, $input:ident, $res:expr, $err:expr, $head:ident $($item:ident)*) => (
if !$head {
match $self.parser.$it.process::<OM>($input.clone()) {
Ok((i, o)) => {
$input = i;
$res = OM::Output::combine($res, o, |mut res, o | {res.$it = Some(o);res });
$head = true;
continue;
}
Err(Err::Error(e)) => {
$err = Some(match $err {
None => e,
Some(err) => OM::Error::combine(err, e, |err, e| err.or(e))
});
}
Err(e) => return Err(e),
};
}
succ!($it, permutation_trait_inner!($self, $input, $res, $err, $($item)*));
);
($it:tt, $self:expr, $input:ident, $res:expr, $err:expr,) => ();
);
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
);