diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/nom/src/branch | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nom/src/branch')
-rw-r--r-- | third_party/rust/nom/src/branch/mod.rs | 291 | ||||
-rw-r--r-- | third_party/rust/nom/src/branch/tests.rs | 142 |
2 files changed, 433 insertions, 0 deletions
diff --git a/third_party/rust/nom/src/branch/mod.rs b/third_party/rust/nom/src/branch/mod.rs new file mode 100644 index 0000000000..9df5a2941a --- /dev/null +++ b/third_party/rust/nom/src/branch/mod.rs @@ -0,0 +1,291 @@ +//! Choice combinators + +macro_rules! succ ( + (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*)); + (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*)); + (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*)); + (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*)); + (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*)); + (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*)); + (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*)); + (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*)); + (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*)); + (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*)); + (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*)); + (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*)); + (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*)); + (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*)); + (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*)); + (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*)); + (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*)); + (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)*)); +); + +#[cfg(test)] +mod tests; + +use crate::error::ErrorKind; +use crate::error::ParseError; +use crate::internal::{Err, IResult, Parser}; + +/// 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>; +} + +/// Tests a list of parsers one by one until one succeeds. +/// +/// It takes as argument a tuple of parsers. There is a maximum of 21 +/// parsers. If you need more, it is possible to nest them in other `alt` calls, +/// like this: `alt(parser_a, alt(parser_b, parser_c))` +/// +/// ```rust +/// # use nom::error_position; +/// # use nom::{Err,error::ErrorKind, Needed, IResult}; +/// use nom::character::complete::{alpha1, digit1}; +/// use nom::branch::alt; +/// # fn main() { +/// fn parser(input: &str) -> IResult<&str, &str> { +/// alt((alpha1, digit1))(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(Err::Error(error_position!(" ", ErrorKind::Digit)))); +/// # } +/// ``` +/// +/// With a custom error type, it is possible to have alt return the error of the parser +/// that went the farthest in the input data +pub fn alt<I: Clone, O, E: ParseError<I>, List: Alt<I, O, E>>( + mut l: List, +) -> impl FnMut(I) -> IResult<I, O, E> { + 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 nom::{Err,error::{Error, ErrorKind}, Needed, IResult}; +/// use nom::character::complete::{alpha1, digit1}; +/// use nom::branch::permutation; +/// # 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")))); +/// +/// // 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(Err::Error(Error::new(";", 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::{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) +/// } +/// +/// // 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(Error::new("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> { + 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< + Input: Clone, Output, Error: ParseError<Input>, + $($id: Parser<Input, Output, Error>),+ + > Alt<Input, Output, Error> for ( $($id),+ ) { + + fn choice(&mut self, input: Input) -> IResult<Input, Output, Error> { + match self.0.parse(input.clone()) { + Err(Err::Error(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($input.clone()) { + Err(Err::Error(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(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); + +// Manually implement Alt for (A,), the 1-tuple type +impl<Input, Output, Error: ParseError<Input>, A: Parser<Input, Output, Error>> + Alt<Input, Output, Error> for (A,) +{ + fn choice(&mut self, input: Input) -> IResult<Input, Output, Error> { + self.0.parse(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< + 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 = ($(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(Err::Error(Error::append(input, ErrorKind::Permutation, err))); + } + + // 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($input.clone()) { + Ok((i, o)) => { + $input = i; + $res.$it = Some(o); + continue; + } + 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, $err, $($id)*)); + ); + ($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 +); diff --git a/third_party/rust/nom/src/branch/tests.rs b/third_party/rust/nom/src/branch/tests.rs new file mode 100644 index 0000000000..ecd44407e9 --- /dev/null +++ b/third_party/rust/nom/src/branch/tests.rs @@ -0,0 +1,142 @@ +use crate::branch::{alt, permutation}; +use crate::bytes::streaming::tag; +use crate::error::ErrorKind; +use crate::internal::{Err, IResult, Needed}; +#[cfg(feature = "alloc")] +use crate::{ + error::ParseError, + lib::std::{ + fmt::Debug, + string::{String, ToString}, + }, +}; + +#[cfg(feature = "alloc")] +#[derive(Debug, Clone, PartialEq)] +pub struct ErrorStr(String); + +#[cfg(feature = "alloc")] +impl From<u32> for ErrorStr { + fn from(i: u32) -> Self { + ErrorStr(format!("custom error code: {}", i)) + } +} + +#[cfg(feature = "alloc")] +impl<'a> From<&'a str> for ErrorStr { + fn from(i: &'a str) -> Self { + ErrorStr(format!("custom error message: {}", i)) + } +} + +#[cfg(feature = "alloc")] +impl<I: Debug> ParseError<I> for ErrorStr { + fn from_error_kind(input: I, kind: ErrorKind) -> Self { + ErrorStr(format!("custom error message: ({:?}, {:?})", input, kind)) + } + + fn append(input: I, kind: ErrorKind, other: Self) -> Self { + ErrorStr(format!( + "custom error message: ({:?}, {:?}) - {:?}", + input, kind, other + )) + } +} + +#[cfg(feature = "alloc")] +#[test] +fn alt_test() { + fn work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + Ok((&b""[..], input)) + } + + #[allow(unused_variables)] + fn dont_work(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + Err(Err::Error(ErrorStr("abcd".to_string()))) + } + + fn work2(input: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + Ok((input, &b""[..])) + } + + fn alt1(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + alt((dont_work, dont_work))(i) + } + fn alt2(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + alt((dont_work, work))(i) + } + fn alt3(i: &[u8]) -> IResult<&[u8], &[u8], ErrorStr> { + alt((dont_work, dont_work, work2, dont_work))(i) + } + //named!(alt1, alt!(dont_work | dont_work)); + //named!(alt2, alt!(dont_work | work)); + //named!(alt3, alt!(dont_work | dont_work | work2 | dont_work)); + + let a = &b"abcd"[..]; + assert_eq!( + alt1(a), + Err(Err::Error(error_node_position!( + a, + ErrorKind::Alt, + ErrorStr("abcd".to_string()) + ))) + ); + assert_eq!(alt2(a), Ok((&b""[..], a))); + assert_eq!(alt3(a), Ok((a, &b""[..]))); + + fn alt4(i: &[u8]) -> IResult<&[u8], &[u8]> { + alt((tag("abcd"), tag("efgh")))(i) + } + let b = &b"efgh"[..]; + assert_eq!(alt4(a), Ok((&b""[..], a))); + assert_eq!(alt4(b), Ok((&b""[..], b))); +} + +#[test] +fn alt_incomplete() { + fn alt1(i: &[u8]) -> IResult<&[u8], &[u8]> { + alt((tag("a"), tag("bc"), tag("def")))(i) + } + + let a = &b""[..]; + assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(1)))); + let a = &b"b"[..]; + assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(1)))); + let a = &b"bcd"[..]; + assert_eq!(alt1(a), Ok((&b"d"[..], &b"bc"[..]))); + let a = &b"cde"[..]; + assert_eq!(alt1(a), Err(Err::Error(error_position!(a, ErrorKind::Tag)))); + let a = &b"de"[..]; + assert_eq!(alt1(a), Err(Err::Incomplete(Needed::new(1)))); + let a = &b"defg"[..]; + assert_eq!(alt1(a), Ok((&b"g"[..], &b"def"[..]))); +} + +#[test] +fn permutation_test() { + fn perm(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8], &[u8])> { + permutation((tag("abcd"), tag("efg"), tag("hi")))(i) + } + + let expected = (&b"abcd"[..], &b"efg"[..], &b"hi"[..]); + + let a = &b"abcdefghijk"[..]; + assert_eq!(perm(a), Ok((&b"jk"[..], expected))); + let b = &b"efgabcdhijk"[..]; + assert_eq!(perm(b), Ok((&b"jk"[..], expected))); + let c = &b"hiefgabcdjk"[..]; + assert_eq!(perm(c), Ok((&b"jk"[..], expected))); + + let d = &b"efgxyzabcdefghi"[..]; + assert_eq!( + perm(d), + Err(Err::Error(error_node_position!( + &b"efgxyzabcdefghi"[..], + ErrorKind::Permutation, + error_position!(&b"xyzabcdefghi"[..], ErrorKind::Tag) + ))) + ); + + let e = &b"efgabc"[..]; + assert_eq!(perm(e), Err(Err::Incomplete(Needed::new(1)))); +} |