From 3bdd5ec5a9a553b4592eca0e69afa95d1f30e1da Mon Sep 17 00:00:00 2001 From: Griffin Smith Date: Wed, 28 Sep 2022 16:53:07 -0400 Subject: [PATCH] feat(comb): Allow arrays as input to `alt` Now that min-const-generics is stabilized, it's possible to (backwards-compatibly) write a version of `alt` that uses a const array as input instead of being limited to only tuples - this allows us to lift the 21-element limitation on tuples passed to `alt`. Upstream: rust-bakery/nom#1556 --- src/combinator/branch.rs | 20 ++++++++++++++++++++ src/combinator/tests.rs | 23 +++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/combinator/branch.rs b/src/combinator/branch.rs index 2a712ec1..e0df48f3 100644 --- a/src/combinator/branch.rs +++ b/src/combinator/branch.rs @@ -112,6 +112,26 @@ pub fn permutation, List: Permutation>( trace("permutation", move |i: &mut I| l.permutation(i)) } +impl, P: Parser> Alt for [P; N] { + fn choice(&mut self, input: &mut I) -> PResult { + let mut error = None; + + let start = input.checkpoint(); + for branch in self { + input.reset(start.clone()); + match branch.parse_next(input) { + Err(ErrMode::Backtrack(e)) => error = Some(e), + res => return res, + } + } + + match error { + Some(e) => Err(ErrMode::Backtrack(e.append(input, ErrorKind::Alt))), + None => Err(ErrMode::assert(input, "`alt` needs at least one parser")), + } + } +} + macro_rules! alt_trait( ($first:ident $second:ident $($id: ident)+) => ( alt_trait!(__impl $first $second; $($id)+); diff --git a/src/combinator/tests.rs b/src/combinator/tests.rs index 62dc420e..9d2b49d8 100644 --- a/src/combinator/tests.rs +++ b/src/combinator/tests.rs @@ -13,6 +13,7 @@ use crate::stream::Stream; use crate::token::take; use crate::unpeek; use crate::IResult; +use crate::PResult; use crate::Parser; use crate::Partial; @@ -648,6 +649,28 @@ fn alt_incomplete() { ); } +#[test] +fn alt_array() { + fn alt1<'i>(i: &mut &'i [u8]) -> PResult<&'i [u8]> { + alt(["a", "bc", "def"]).parse_next(i) + } + + let i = &b"a"[..]; + assert_eq!(alt1.parse_peek(i), Ok((&b""[..], (&b"a"[..])))); + + let i = &b"bc"[..]; + assert_eq!(alt1.parse_peek(i), Ok((&b""[..], (&b"bc"[..])))); + + let i = &b"defg"[..]; + assert_eq!(alt1.parse_peek(i), Ok((&b"g"[..], (&b"def"[..])))); + + let i = &b"z"[..]; + assert_eq!( + alt1.parse_peek(i), + Err(ErrMode::Backtrack(error_position!(&i, ErrorKind::Tag))) + ); +} + #[test] fn permutation_test() { #[allow(clippy::type_complexity)]