diff options
Diffstat (limited to 'vendor/winnow/src/combinator/branch.rs')
-rw-r--r-- | vendor/winnow/src/combinator/branch.rs | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/vendor/winnow/src/combinator/branch.rs b/vendor/winnow/src/combinator/branch.rs new file mode 100644 index 000000000..042b27d53 --- /dev/null +++ b/vendor/winnow/src/combinator/branch.rs @@ -0,0 +1,268 @@ +use crate::error::{ErrMode, ErrorKind, ParseError}; +use crate::stream::Stream; +use crate::trace::trace; +use crate::*; + +#[doc(inline)] +pub use crate::dispatch; + +/// Helper trait for the [alt()] combinator. +/// +/// This trait is implemented for tuples of up to 21 elements +pub trait Alt<I, O, E> { + /// Tests each parser in the tuple and returns the result of the first one that succeeds + fn choice(&mut self, input: I) -> IResult<I, O, E>; +} + +/// Pick the first successful parser +/// +/// For tight control over the error, add a final case using [`fail`][crate::combinator::fail]. +/// Alternatively, with a [custom error type][crate::_topic::error], it is possible to track all +/// errors or return the error of the parser that went the farthest in the input data. +/// +/// When the alternative cases have unique prefixes, [`dispatch`] can offer better performance. +/// +/// # Example +/// +/// ```rust +/// # use winnow::{error::ErrMode, error::Error,error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::ascii::{alpha1, digit1}; +/// use winnow::combinator::alt; +/// # fn main() { +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alt((alpha1, digit1)).parse_next(input) +/// }; +/// +/// // the first parser, alpha1, recognizes the input +/// assert_eq!(parser("abc"), Ok(("", "abc"))); +/// +/// // the first parser returns an error, so alt tries the second one +/// assert_eq!(parser("123456"), Ok(("", "123456"))); +/// +/// // both parsers failed, and with the default error type, alt will return the last error +/// assert_eq!(parser(" "), Err(ErrMode::Backtrack(Error::new(" ", ErrorKind::Slice)))); +/// # } +/// ``` +#[doc(alias = "choice")] +pub fn alt<I: Stream, O, E: ParseError<I>, List: Alt<I, O, E>>( + mut l: List, +) -> impl Parser<I, O, E> { + trace("alt", move |i: I| l.choice(i)) +} + +/// Helper trait for the [permutation()] combinator. +/// +/// This trait is implemented for tuples of up to 21 elements +pub trait Permutation<I, O, E> { + /// Tries to apply all parsers in the tuple in various orders until all of them succeed + fn permutation(&mut self, input: I) -> IResult<I, O, E>; +} + +/// Applies a list of parsers in any order. +/// +/// Permutation will succeed if all of the child parsers succeeded. +/// It takes as argument a tuple of parsers, and returns a +/// tuple of the parser results. +/// +/// ```rust +/// # use winnow::{error::ErrMode,error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::ascii::{alpha1, digit1}; +/// use winnow::combinator::permutation; +/// # fn main() { +/// fn parser(input: &str) -> IResult<&str, (&str, &str)> { +/// permutation((alpha1, digit1)).parse_next(input) +/// } +/// +/// // permutation recognizes alphabetic characters then digit +/// assert_eq!(parser("abc123"), Ok(("", ("abc", "123")))); +/// +/// // but also in inverse order +/// assert_eq!(parser("123abc"), Ok(("", ("abc", "123")))); +/// +/// // it will fail if one of the parsers failed +/// assert_eq!(parser("abc;"), Err(ErrMode::Backtrack(Error::new(";", ErrorKind::Slice)))); +/// # } +/// ``` +/// +/// 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 winnow::{error::ErrMode, error::{Error, ErrorKind}}; +/// # use winnow::prelude::*; +/// use winnow::combinator::permutation; +/// use winnow::token::any; +/// +/// fn parser(input: &str) -> IResult<&str, (char, char)> { +/// permutation((any, 'a')).parse_next(input) +/// } +/// +/// // any parses 'b', then char('a') parses 'a' +/// assert_eq!(parser("ba"), Ok(("", ('b', 'a')))); +/// +/// // any parses 'a', then char('a') fails on 'b', +/// // even though char('a') followed by any would succeed +/// assert_eq!(parser("ab"), Err(ErrMode::Backtrack(Error::new("b", ErrorKind::Verify)))); +/// ``` +/// +pub fn permutation<I: Stream, O, E: ParseError<I>, List: Permutation<I, O, E>>( + mut l: List, +) -> impl Parser<I, O, E> { + trace("permutation", move |i: I| l.permutation(i)) +} + +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); + ); +); + +macro_rules! alt_trait_impl( + ($($id:ident)+) => ( + impl< + I: Clone, Output, Error: ParseError<I>, + $($id: Parser<I, Output, Error>),+ + > Alt<I, Output, Error> for ( $($id),+ ) { + + fn choice(&mut self, input: I) -> IResult<I, Output, Error> { + match self.0.parse_next(input.clone()) { + Err(ErrMode::Backtrack(e)) => alt_trait_inner!(1, self, input, e, $($id)+), + res => res, + } + } + } + ); +); + +macro_rules! alt_trait_inner( + ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => ( + match $self.$it.parse_next($input.clone()) { + Err(ErrMode::Backtrack(e)) => { + 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) => ( + Err(ErrMode::Backtrack($err.append($input, ErrorKind::Alt))) + ); +); + +alt_trait!(Alt2 Alt3 Alt4 Alt5 Alt6 Alt7 Alt8 Alt9 Alt10 Alt11 Alt12 Alt13 Alt14 Alt15 Alt16 Alt17 Alt18 Alt19 Alt20 Alt21 Alt22); + +// Manually implement Alt for (A,), the 1-tuple type +impl<I, O, E: ParseError<I>, A: Parser<I, O, E>> Alt<I, O, E> for (A,) { + fn choice(&mut self, input: I) -> IResult<I, O, E> { + self.0.parse_next(input) + } +} + +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),+); + ); +); + +macro_rules! permutation_trait_impl( + ($($name:ident $ty:ident $item:ident),+) => ( + impl< + I: Clone, $($ty),+ , Error: ParseError<I>, + $($name: Parser<I, $ty, Error>),+ + > Permutation<I, ( $($ty),+ ), Error> for ( $($name),+ ) { + + fn permutation(&mut self, mut input: I) -> IResult<I, ( $($ty),+ ), Error> { + let mut res = ($(Option::<$ty>::None),+); + + loop { + let mut err: Option<Error> = None; + permutation_trait_inner!(0, self, input, res, err, $($name)+); + + // 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(ErrMode::Backtrack(err.append(input, ErrorKind::Alt))); + } + + // All parsers were applied + match res { + ($(Some($item)),+) => return Ok((input, ($($item),+))), + _ => unreachable!(), + } + } + } + } + ); +); + +macro_rules! permutation_trait_inner( + ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr, $head:ident $($id:ident)*) => ( + if $res.$it.is_none() { + match $self.$it.parse_next($input.clone()) { + Ok((i, o)) => { + $input = i; + $res.$it = Some(o); + continue; + } + Err(ErrMode::Backtrack(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, $err, $($id)*)); + ); + ($it:tt, $self:expr, $input:ident, $res:expr, $err:expr,) => (); +); + +permutation_trait!( + P1 O1 o1 + P2 O2 o2 + P3 O3 o3 + P4 O4 o4 + P5 O5 o5 + P6 O6 o6 + P7 O7 o7 + P8 O8 o8 + P9 O9 o9 + P10 O10 o10 + P11 O11 o11 + P12 O12 o12 + P13 O13 o13 + P14 O14 o14 + P15 O15 o15 + P16 O16 o16 + P17 O17 o17 + P18 O18 o18 + P19 O19 o19 + P20 O20 o20 + P21 O21 o21 +); |