summaryrefslogtreecommitdiffstats
path: root/vendor/winnow/src/combinator
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/winnow/src/combinator')
-rw-r--r--vendor/winnow/src/combinator/core.rs2
-rw-r--r--vendor/winnow/src/combinator/mod.rs95
-rw-r--r--vendor/winnow/src/combinator/multi.rs590
-rw-r--r--vendor/winnow/src/combinator/parser.rs2
-rw-r--r--vendor/winnow/src/combinator/tests.rs53
5 files changed, 548 insertions, 194 deletions
diff --git a/vendor/winnow/src/combinator/core.rs b/vendor/winnow/src/combinator/core.rs
index d784b4e9e..2a92d64b7 100644
--- a/vendor/winnow/src/combinator/core.rs
+++ b/vendor/winnow/src/combinator/core.rs
@@ -331,7 +331,7 @@ where
/// Call the iterator's [`ParserIterator::finish`] method to get the remaining input if successful,
/// or the error value if we encountered an error.
///
-/// On [`ErrMode::Backtrack`], iteration will stop. To instead chain an error up, see [`cut_err`].
+/// On [`ErrMode::Backtrack`], iteration will stop. To instead chain an error up, see [`cut_err`].
///
/// # Example
///
diff --git a/vendor/winnow/src/combinator/mod.rs b/vendor/winnow/src/combinator/mod.rs
index ec68e48e2..542b156a2 100644
--- a/vendor/winnow/src/combinator/mod.rs
+++ b/vendor/winnow/src/combinator/mod.rs
@@ -6,72 +6,71 @@
//!
//! Those are used to recognize the lowest level elements of your grammar, like, "here is a dot", or "here is an big endian integer".
//!
-//! | combinator | usage | input | output | comment |
-//! |---|---|---|---|---|
-//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `Ok(("bc", 'a'))` |Matches one of the provided characters (works with non ASCII characters too)|
-//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"xyab"` | `Ok(("yab", 'x'))` |Matches anything but the provided characters|
-//! | [`tag`][crate::token::tag] | `"hello"` | `"hello world"` | `Ok((" world", "hello"))` |Recognizes a specific suite of characters or bytes|
-//! | [`tag_no_case`][crate::token::tag_no_case] | `tag_no_case("hello")` | `"HeLLo World"` | `Ok((" World", "HeLLo"))` |Case insensitive comparison. Note that case insensitive comparison is not well defined for unicode, and that you might have bad surprises|
-//! | [`take`][crate::token::take] | `take(4)` | `"hello"` | `Ok(("o", "hell"))` |Takes a specific number of bytes or characters|
-//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `Ok(("123", "abc"))` |Returns the longest list of bytes for which the provided pattern matches.|
-//! | [`take_till0`][crate::token::take_till0] | `take_till0(is_alphabetic)` | `"123abc"` | `Ok(("abc", "123"))` |Returns the longest list of bytes or characters until the provided pattern matches. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while`: `take_till(f)` is equivalent to `take_while(0.., \|c\| !f(c))`|
-//! | [`take_until0`][crate::token::take_until0] | `take_until0("world")` | `"Hello world"` | `Ok(("world", "Hello "))` |Returns the longest list of bytes or characters until the provided tag is found. `take_until1` does the same, but must return at least one character|
+//! | combinator | usage | input | new input | output | comment |
+//! |---|---|---|---|---|---|
+//! | [`one_of`][crate::token::one_of] | `one_of(['a', 'b', 'c'])` | `"abc"` | `"bc"` | `Ok('a')` |Matches one of the provided characters (works with non ASCII characters too)|
+//! | [`none_of`][crate::token::none_of] | `none_of(['a', 'b', 'c'])` | `"xyab"` | `"yab"` | `Ok('x')` |Matches anything but the provided characters|
+//! | [`tag`][crate::token::tag] | `"hello"` | `"hello world"` | `" world"` | `Ok("hello")` |Recognizes a specific suite of characters or bytes (see also [`Caseless`][crate::ascii::Caseless])|
+//! | [`take`][crate::token::take] | `take(4)` | `"hello"` | `"o"` | `Ok("hell")` |Takes a specific number of bytes or characters|
+//! | [`take_while`][crate::token::take_while] | `take_while(0.., is_alphabetic)` | `"abc123"` | `"123"` | `Ok("abc")` |Returns the longest list of bytes for which the provided pattern matches.|
+//! | [`take_till0`][crate::token::take_till0] | `take_till0(is_alphabetic)` | `"123abc"` | `"abc"` | `Ok("123")` |Returns the longest list of bytes or characters until the provided pattern matches. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while`: `take_till(f)` is equivalent to `take_while(0.., \|c\| !f(c))`|
+//! | [`take_until0`][crate::token::take_until0] | `take_until0("world")` | `"Hello world"` | `"world"` | `Ok("Hello ")` |Returns the longest list of bytes or characters until the provided tag is found. `take_until1` does the same, but must return at least one character|
//!
//! ## Choice combinators
//!
-//! | combinator | usage | input | output | comment |
-//! |---|---|---|---|---|
-//! | [`alt`][crate::combinator::alt] | `alt(("ab", "cd"))` | `"cdef"` | `Ok(("ef", "cd"))` |Try a list of parsers and return the result of the first successful one|
-//! | [`dispatch`][crate::combinator::dispatch] | \- | \- | \- | `match` for parsers |
-//! | [`permutation`][crate::combinator::permutation] | `permutation(("ab", "cd", "12"))` | `"cd12abc"` | `Ok(("c", ("ab", "cd", "12"))` |Succeeds when all its child parser have succeeded, whatever the order|
+//! | combinator | usage | input | new input | output | comment |
+//! |---|---|---|---|---|---|
+//! | [`alt`] | `alt(("ab", "cd"))` | `"cdef"` | `"ef"` | `Ok("cd")` |Try a list of parsers and return the result of the first successful one|
+//! | [`dispatch`] | \- | \- | \- | \- | `match` for parsers |
+//! | [`permutation`] | `permutation(("ab", "cd", "12"))` | `"cd12abc"` | `"c"` | `Ok(("ab", "cd", "12"))` |Succeeds when all its child parser have succeeded, whatever the order|
//!
//! ## Sequence combinators
//!
-//! | combinator | usage | input | output | comment |
-//! |---|---|---|---|---|
-//! | [`(...)` (tuples)][crate::Parser] | `("ab", "XY", take(1))` | `"abXYZ!"` | `Ok(("!", ("ab", "XY", "Z")))` |Chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple|
-//! | [`delimited`] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `Ok(("cd", "ab"))` ||
-//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "XY"))` ||
-//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `Ok(("Z", "ab"))` ||
-//! | [`separated_pair`] | `separated_pair("hello", char(','), "world")` | `"hello,world!"` | `Ok(("!", ("hello", "world")))` ||
+//! | combinator | usage | input | new input | output | comment |
+//! |---|---|---|---|---|---|
+//! | [`(...)` (tuples)][crate::Parser] | `("ab", "XY", take(1))` | `"abXYZ!"` | `"!"` | `Ok(("ab", "XY", "Z"))` |Chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple|
+//! | [`delimited`] | `delimited(char('('), take(2), char(')'))` | `"(ab)cd"` | `"cd"` | `Ok("ab")` ||
+//! | [`preceded`] | `preceded("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("XY")` ||
+//! | [`terminated`] | `terminated("ab", "XY")` | `"abXYZ"` | `"Z"` | `Ok("ab")` ||
+//! | [`separated_pair`] | `separated_pair("hello", char(','), "world")` | `"hello,world!"` | `"!"` | `Ok(("hello", "world"))` ||
//!
//! ## Applying a parser multiple times
//!
-//! | combinator | usage | input | output | comment |
-//! |---|---|---|---|---|
-//! | [`repeat`][crate::combinator::repeat] | `repeat(1..=3, "ab")` | `"ababc"` | `Ok(("c", vec!["ab", "ab"]))` |Applies the parser between m and n times (n included) and returns the list of results in a Vec|
-//! | [`repeat_till0`][crate::combinator::repeat_till0] | `repeat_till0(tag( "ab" ), tag( "ef" ))` | `"ababefg"` | `Ok(("g", (vec!["ab", "ab"], "ef")))` |Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second|
-//! | [`separated0`][crate::combinator::separated0] | `separated0("ab", ",")` | `"ab,ab,ab."` | `Ok((".", vec!["ab", "ab", "ab"]))` |`separated1` works like `separated0` but must returns at least one element|
-//! | [`fold_repeat`][crate::combinator::fold_repeat] | `fold_repeat(1..=2, be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `Ok(([3], 3))` |Applies the parser between m and n times (n included) and folds the list of return value|
+//! | combinator | usage | input | new input | output | comment |
+//! |---|---|---|---|---|---|
+//! | [`repeat`] | `repeat(1..=3, "ab")` | `"ababc"` | `"c"` | `Ok(vec!["ab", "ab"])` |Applies the parser between m and n times (n included) and returns the list of results in a Vec|
+//! | [`repeat_till0`] | `repeat_till0(tag( "ab" ), tag( "ef" ))` | `"ababefg"` | `"g"` | `Ok((vec!["ab", "ab"], "ef"))` |Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second|
+//! | [`separated`] | `separated(1..=3, "ab", ",")` | `"ab,ab,ab."` | `"."` | `Ok(vec!["ab", "ab", "ab"])` |Applies the parser and separator between m and n times (n included) and returns the list of results in a Vec|
+//! | [`fold_repeat`] | `fold_repeat(1..=2, be_u8, \|\| 0, \|acc, item\| acc + item)` | `[1, 2, 3]` | `[3]` | `Ok(3)` |Applies the parser between m and n times (n included) and folds the list of return value|
//!
//! ## Partial related
//!
-//! - [`eof`][eof]: Returns its input if it is at the end of input data
+//! - [`eof`]: Returns its input if it is at the end of input data
//! - [`Parser::complete_err`]: Replaces an `Incomplete` returned by the child parser with an `Backtrack`
//!
//! ## Modifiers
//!
-//! - [`cond`][cond]: Conditional combinator. Wraps another parser and calls it if the condition is met
-//! - [`Parser::flat_map`][crate::Parser::flat_map]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input
-//! - [`Parser::value`][crate::Parser::value]: method to replace the result of a parser
-//! - [`Parser::map`][crate::Parser::map]: method to map a function on the result of a parser
-//! - [`Parser::and_then`][crate::Parser::and_then]: Applies a second parser over the output of the first one
-//! - [`Parser::verify_map`][Parser::verify_map]: Maps a function returning an `Option` on the output of a parser
-//! - [`Parser::try_map`][Parser::try_map]: Maps a function returning a `Result` on the output of a parser
-//! - [`Parser::parse_to`][crate::Parser::parse_to]: Apply [`std::str::FromStr`] to the output of the parser
-//! - [`not`][not]: Returns a result only if the embedded parser returns `Backtrack` or `Incomplete`. Does not consume the input
-//! - [`opt`][opt]: Make the underlying parser optional
-//! - [`peek`][peek]: Returns a result without consuming the input
-//! - [`Parser::recognize`][Parser::recognize]: If the child parser was successful, return the consumed input as the produced value
-//! - [`Parser::with_recognized`][Parser::with_recognized]: If the child parser was successful, return a tuple of the consumed input and the produced output.
-//! - [`Parser::span`][Parser::span]: If the child parser was successful, return the location of the consumed input as the produced value
-//! - [`Parser::with_span`][Parser::with_span]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output.
+//! - [`cond`]: Conditional combinator. Wraps another parser and calls it if the condition is met
+//! - [`Parser::flat_map`]: method to map a new parser from the output of the first parser, then apply that parser over the rest of the input
+//! - [`Parser::value`]: method to replace the result of a parser
+//! - [`Parser::map`]: method to map a function on the result of a parser
+//! - [`Parser::and_then`]: Applies a second parser over the output of the first one
+//! - [`Parser::verify_map`]: Maps a function returning an `Option` on the output of a parser
+//! - [`Parser::try_map`]: Maps a function returning a `Result` on the output of a parser
+//! - [`Parser::parse_to`]: Apply [`std::str::FromStr`] to the output of the parser
+//! - [`not`]: Returns a result only if the embedded parser returns `Backtrack` or `Incomplete`. Does not consume the input
+//! - [`opt`]: Make the underlying parser optional
+//! - [`peek`]: Returns a result without consuming the input
+//! - [`Parser::recognize`]: If the child parser was successful, return the consumed input as the produced value
+//! - [`Parser::with_recognized`]: If the child parser was successful, return a tuple of the consumed input and the produced output.
+//! - [`Parser::span`]: If the child parser was successful, return the location of the consumed input as the produced value
+//! - [`Parser::with_span`]: If the child parser was successful, return a tuple of the location of the consumed input and the produced output.
//! - [`Parser::verify`]: Returns the result of the child parser if it satisfies a verification function
//!
//! ## Error management and debugging
//!
//! - [`cut_err`]: Commit the parse result, disallowing alternative parsers from being attempted
-//! - [`backtrack_err`]: Attemmpts a parse, allowing alternative parsers to be attempted despite
+//! - [`backtrack_err`]: Attempts a parse, allowing alternative parsers to be attempted despite
//! use of `cut_err`
//! - [`Parser::context`]: Add context to the error if the parser fails
//! - [`trace`][crate::trace::trace]: Print the parse state with the `debug` feature flag
@@ -79,8 +78,8 @@
//!
//! ## Remaining combinators
//!
-//! - [`success`][success]: Returns a value without consuming any input, always succeeds
-//! - [`fail`][fail]: Inversion of `success`. Always fails.
+//! - [`success`]: Returns a value without consuming any input, always succeeds
+//! - [`fail`]: Inversion of `success`. Always fails.
//! - [`Parser::by_ref`]: Allow moving `&mut impl Parser` into other parsers
//!
//! ## Text parsing
@@ -91,7 +90,7 @@
//! - [`line_ending`][crate::ascii::line_ending]: Recognizes an end of line (both `\n` and `\r\n`)
//! - [`newline`][crate::ascii::newline]: Matches a newline character `\n`
//! - [`not_line_ending`][crate::ascii::not_line_ending]: Recognizes a string of any char except `\r` or `\n`
-//! - [`rest`][rest]: Return the remaining input
+//! - [`rest`]: Return the remaining input
//!
//! - [`alpha0`][crate::ascii::alpha0]: Recognizes zero or more lowercase and uppercase alphabetic characters: `[a-zA-Z]`. [`alpha1`][crate::ascii::alpha1] does the same but returns at least one character
//! - [`alphanumeric0`][crate::ascii::alphanumeric0]: Recognizes zero or more numerical and alphabetic characters: `[0-9a-zA-Z]`. [`alphanumeric1`][crate::ascii::alphanumeric1] does the same but returns at least one character
diff --git a/vendor/winnow/src/combinator/multi.rs b/vendor/winnow/src/combinator/multi.rs
index 1fdb7535b..d06362878 100644
--- a/vendor/winnow/src/combinator/multi.rs
+++ b/vendor/winnow/src/combinator/multi.rs
@@ -12,7 +12,7 @@ use crate::Parser;
/// [`Accumulate`] the output of a parser into a container, like `Vec`
///
-/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
@@ -28,7 +28,7 @@ use crate::Parser;
///
/// # Example
///
-/// Zero or more reptitions:
+/// Zero or more repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed};
@@ -47,7 +47,7 @@ use crate::Parser;
/// # }
/// ```
///
-/// One or more reptitions:
+/// One or more repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
@@ -66,7 +66,7 @@ use crate::Parser;
/// # }
/// ```
///
-/// Fixed number of repeitions:
+/// Fixed number of repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
@@ -86,7 +86,7 @@ use crate::Parser;
/// # }
/// ```
///
-/// Arbitrary reptitions:
+/// Arbitrary repetitions:
/// ```rust
/// # #[cfg(feature = "std")] {
/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed};
@@ -201,6 +201,73 @@ where
}
}
+fn repeat_n_<I, O, C, E, F>(count: usize, f: &mut F, i: &mut I) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ F: Parser<I, O, E>,
+ E: ParserError<I>,
+{
+ let mut res = C::initial(Some(count));
+
+ for _ in 0..count {
+ match f.parse_next(i) {
+ Ok(o) => {
+ res.accumulate(o);
+ }
+ Err(e) => {
+ return Err(e.append(i, ErrorKind::Many));
+ }
+ }
+ }
+
+ Ok(res)
+}
+
+fn repeat_m_n_<I, O, C, E, F>(min: usize, max: usize, parse: &mut F, input: &mut I) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ F: Parser<I, O, E>,
+ E: ParserError<I>,
+{
+ if min > max {
+ return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many)));
+ }
+
+ let mut res = C::initial(Some(min));
+ for count in 0..max {
+ let start = input.checkpoint();
+ let len = input.eof_offset();
+ match parse.parse_next(input) {
+ Ok(value) => {
+ // infinite loop check: the parser must always consume
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`repeat` parsers must always consume",
+ ));
+ }
+
+ res.accumulate(value);
+ }
+ Err(ErrMode::Backtrack(e)) => {
+ if count < min {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ } else {
+ input.reset(start);
+ return Ok(res);
+ }
+ }
+ Err(e) => {
+ return Err(e);
+ }
+ }
+ }
+
+ Ok(res)
+}
+
/// [`Accumulate`] the output of parser `f` into a container, like `Vec`, until the parser `g`
/// produces a result.
///
@@ -269,9 +336,144 @@ where
})
}
-/// [`Accumulate`] the output of a parser, interleaed with `sep`
+/// [`Accumulate`] the output of a parser, interleaved with `sep`
///
-/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// [`cut_err`][crate::combinator::cut_err].
+///
+/// # Arguments
+/// * `range` The minimum and maximum number of iterations.
+/// * `parser` The parser that parses the elements of the list.
+/// * `sep` The parser that parses the separator between list elements.
+///
+/// **Warning:** If the separator parser accepts empty inputs
+/// (like `alpha0` or `digit0`), `separated` will return an error,
+/// to prevent going into an infinite loop.
+///
+/// # Example
+///
+/// Zero or more repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(0.., "abc", "|").parse_peek(s)
+/// }
+///
+/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"])));
+/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"])));
+/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"])));
+/// assert_eq!(parser(""), Ok(("", vec![])));
+/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![])));
+/// # }
+/// ```
+///
+/// One or more repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(1.., "abc", "|").parse_peek(s)
+/// }
+///
+/// assert_eq!(parser("abc|abc|abc"), Ok(("", vec!["abc", "abc", "abc"])));
+/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"])));
+/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"])));
+/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
+/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Tag))));
+/// # }
+/// ```
+///
+/// Fixed number of repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(2, "abc", "|").parse_peek(s)
+/// }
+///
+/// assert_eq!(parser("abc|abc|abc"), Ok(("|abc", vec!["abc", "abc"])));
+/// assert_eq!(parser("abc123abc"), Err(ErrMode::Backtrack(InputError::new("123abc", ErrorKind::Tag))));
+/// assert_eq!(parser("abc|def"), Err(ErrMode::Backtrack(InputError::new("def", ErrorKind::Tag))));
+/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Tag))));
+/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Tag))));
+/// # }
+/// ```
+///
+/// Arbitrary repetitions:
+/// ```rust
+/// # #[cfg(feature = "std")] {
+/// # use winnow::{error::ErrMode, error::{InputError, ErrorKind}, error::Needed};
+/// # use winnow::prelude::*;
+/// use winnow::combinator::separated;
+/// use winnow::token::tag;
+///
+/// fn parser(s: &str) -> IResult<&str, Vec<&str>> {
+/// separated(0..=2, "abc", "|").parse_peek(s)
+/// }
+///
+/// assert_eq!(parser("abc|abc|abc"), Ok(("|abc", vec!["abc", "abc"])));
+/// assert_eq!(parser("abc123abc"), Ok(("123abc", vec!["abc"])));
+/// assert_eq!(parser("abc|def"), Ok(("|def", vec!["abc"])));
+/// assert_eq!(parser(""), Ok(("", vec![])));
+/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![])));
+/// # }
+/// ```
+#[doc(alias = "sep_by")]
+#[doc(alias = "sep_by1")]
+#[doc(alias = "separated_list0")]
+#[doc(alias = "separated_list1")]
+#[doc(alias = "separated_m_n")]
+#[inline(always)]
+pub fn separated<I, O, C, O2, E, P, S>(
+ range: impl Into<Range>,
+ mut parser: P,
+ mut separator: S,
+) -> impl Parser<I, C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let Range {
+ start_inclusive,
+ end_inclusive,
+ } = range.into();
+ trace("separated", move |input: &mut I| {
+ match (start_inclusive, end_inclusive) {
+ (0, None) => separated0_(&mut parser, &mut separator, input),
+ (1, None) => separated1_(&mut parser, &mut separator, input),
+ (start, end) if Some(start) == end => {
+ separated_n_(start, &mut parser, &mut separator, input)
+ }
+ (start, end) => separated_m_n_(
+ start,
+ end.unwrap_or(usize::MAX),
+ &mut parser,
+ &mut separator,
+ input,
+ ),
+ }
+ })
+}
+
+/// [`Accumulate`] the output of a parser, interleaved with `sep`
+///
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
@@ -300,6 +502,7 @@ where
/// ```
#[doc(alias = "sep_by")]
#[doc(alias = "separated_list0")]
+#[deprecated(since = "0.5.19", note = "Replaced with `combinator::separated`")]
pub fn separated0<I, O, C, O2, E, P, S>(mut parser: P, mut sep: S) -> impl Parser<I, C, E>
where
I: Stream,
@@ -309,56 +512,74 @@ where
E: ParserError<I>,
{
trace("separated0", move |i: &mut I| {
- let mut res = C::initial(None);
+ separated0_(&mut parser, &mut sep, i)
+ })
+}
- let start = i.checkpoint();
- match parser.parse_next(i) {
+fn separated0_<I, O, C, O2, E, P, S>(
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let mut acc = C::initial(None);
+
+ let start = input.checkpoint();
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
+
+ loop {
+ let start = input.checkpoint();
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
+ input.reset(start);
+ return Ok(acc);
}
Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
- }
- }
-
- loop {
- let start = i.checkpoint();
- let len = i.eof_offset();
- match sep.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
}
- Err(e) => return Err(e),
- Ok(_) => {
- // infinite loop check: the parser must always consume
- if i.eof_offset() == len {
- return Err(ErrMode::assert(i, "sep parsers must always consume"));
- }
- match parser.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
- }
- Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
- }
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
}
}
}
}
- })
+ }
}
-/// [`Accumulate`] the output of a parser, interleaed with `sep`
+/// [`Accumulate`] the output of a parser, interleaved with `sep`
///
/// Fails if the element parser does not produce at least one element.$
///
-/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
@@ -387,6 +608,7 @@ where
/// ```
#[doc(alias = "sep_by1")]
#[doc(alias = "separated_list1")]
+#[deprecated(since = "0.5.19", note = "Replaced with `combinator::separated`")]
pub fn separated1<I, O, C, O2, E, P, S>(mut parser: P, mut sep: S) -> impl Parser<I, C, E>
where
I: Stream,
@@ -396,50 +618,209 @@ where
E: ParserError<I>,
{
trace("separated1", move |i: &mut I| {
- let mut res = C::initial(None);
+ separated1_(&mut parser, &mut sep, i)
+ })
+}
+
+fn separated1_<I, O, C, O2, E, P, S>(
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let mut acc = C::initial(None);
+
+ // Parse the first element
+ match parser.parse_next(input) {
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
- // Parse the first element
- match parser.parse_next(i) {
+ loop {
+ let start = input.checkpoint();
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
+ }
+
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(_)) => {
+ input.reset(start);
+ return Ok(acc);
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
}
}
+ }
+}
- loop {
- let start = i.checkpoint();
- let len = i.eof_offset();
- match sep.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
+fn separated_n_<I, O, C, O2, E, P, S>(
+ count: usize,
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ let mut acc = C::initial(Some(count));
+
+ if count == 0 {
+ return Ok(acc);
+ }
+
+ match parser.parse_next(input) {
+ Err(e) => {
+ return Err(e.append(input, ErrorKind::Many));
+ }
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
+
+ for _ in 1..count {
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
+ Err(e) => {
+ return Err(e.append(input, ErrorKind::Many));
+ }
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
}
- Err(e) => return Err(e),
- Ok(_) => {
- // infinite loop check: the parser must always consume
- if i.eof_offset() == len {
- return Err(ErrMode::assert(i, "sep parsers must always consume"));
+
+ match parser.parse_next(input) {
+ Err(e) => {
+ return Err(e.append(input, ErrorKind::Many));
+ }
+ Ok(o) => {
+ acc.accumulate(o);
}
+ }
+ }
+ }
+ }
- match parser.parse_next(i) {
- Err(ErrMode::Backtrack(_)) => {
- i.reset(start);
- return Ok(res);
- }
- Err(e) => return Err(e),
- Ok(o) => {
- res.accumulate(o);
+ Ok(acc)
+}
+
+fn separated_m_n_<I, O, C, O2, E, P, S>(
+ min: usize,
+ max: usize,
+ parser: &mut P,
+ separator: &mut S,
+ input: &mut I,
+) -> PResult<C, E>
+where
+ I: Stream,
+ C: Accumulate<O>,
+ P: Parser<I, O, E>,
+ S: Parser<I, O2, E>,
+ E: ParserError<I>,
+{
+ if min > max {
+ return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many)));
+ }
+
+ let mut acc = C::initial(Some(min));
+
+ let start = input.checkpoint();
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(e)) => {
+ if min == 0 {
+ input.reset(start);
+ return Ok(acc);
+ } else {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ }
+ }
+ Err(e) => return Err(e),
+ Ok(o) => {
+ acc.accumulate(o);
+ }
+ }
+
+ for index in 1..max {
+ let start = input.checkpoint();
+ let len = input.eof_offset();
+ match separator.parse_next(input) {
+ Err(ErrMode::Backtrack(e)) => {
+ if index < min {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ } else {
+ input.reset(start);
+ return Ok(acc);
+ }
+ }
+ Err(e) => {
+ return Err(e);
+ }
+ Ok(_) => {
+ // infinite loop check
+ if input.eof_offset() == len {
+ return Err(ErrMode::assert(
+ input,
+ "`separated` separator parser must always consume",
+ ));
+ }
+
+ match parser.parse_next(input) {
+ Err(ErrMode::Backtrack(e)) => {
+ if index < min {
+ return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
+ } else {
+ input.reset(start);
+ return Ok(acc);
}
}
+ Err(e) => {
+ return Err(e);
+ }
+ Ok(o) => {
+ acc.accumulate(o);
+ }
}
}
}
- })
+ }
+
+ Ok(acc)
}
/// Alternates between two parsers, merging the results (left associative)
///
-/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Example
@@ -506,7 +887,7 @@ where
/// Alternates between two parsers, merging the results (right associative)
///
-/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops when either parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Example
@@ -556,73 +937,6 @@ where
})
}
-fn repeat_m_n_<I, O, C, E, F>(min: usize, max: usize, parse: &mut F, input: &mut I) -> PResult<C, E>
-where
- I: Stream,
- C: Accumulate<O>,
- F: Parser<I, O, E>,
- E: ParserError<I>,
-{
- if min > max {
- return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::Many)));
- }
-
- let mut res = C::initial(Some(min));
- for count in 0..max {
- let start = input.checkpoint();
- let len = input.eof_offset();
- match parse.parse_next(input) {
- Ok(value) => {
- // infinite loop check: the parser must always consume
- if input.eof_offset() == len {
- return Err(ErrMode::assert(
- input,
- "`repeat` parsers must always consume",
- ));
- }
-
- res.accumulate(value);
- }
- Err(ErrMode::Backtrack(e)) => {
- if count < min {
- return Err(ErrMode::Backtrack(e.append(input, ErrorKind::Many)));
- } else {
- input.reset(start);
- return Ok(res);
- }
- }
- Err(e) => {
- return Err(e);
- }
- }
- }
-
- Ok(res)
-}
-
-fn repeat_n_<I, O, C, E, F>(count: usize, f: &mut F, i: &mut I) -> PResult<C, E>
-where
- I: Stream,
- C: Accumulate<O>,
- F: Parser<I, O, E>,
- E: ParserError<I>,
-{
- let mut res = C::initial(Some(count));
-
- for _ in 0..count {
- match f.parse_next(i) {
- Ok(o) => {
- res.accumulate(o);
- }
- Err(e) => {
- return Err(e.append(i, ErrorKind::Many));
- }
- }
- }
-
- Ok(res)
-}
-
/// Repeats the embedded parser, filling the given slice with results.
///
/// This parser fails if the input runs out before the given slice is full.
@@ -675,7 +989,7 @@ where
/// Repeats the embedded parser `m..=n` times, calling `g` to gather the results
///
-/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
+/// This stops before `n` when the parser returns [`ErrMode::Backtrack`]. To instead chain an error up, see
/// [`cut_err`][crate::combinator::cut_err].
///
/// # Arguments
diff --git a/vendor/winnow/src/combinator/parser.rs b/vendor/winnow/src/combinator/parser.rs
index fb11adc15..c95f1f6f3 100644
--- a/vendor/winnow/src/combinator/parser.rs
+++ b/vendor/winnow/src/combinator/parser.rs
@@ -7,7 +7,7 @@ use crate::trace::trace;
use crate::trace::trace_result;
use crate::*;
-/// Implementation of [`Parser::by_ref`][Parser::by_ref]
+/// Implementation of [`Parser::by_ref`]
#[cfg_attr(nightly, warn(rustdoc::missing_doc_code_examples))]
pub struct ByRef<'p, P> {
p: &'p mut P,
diff --git a/vendor/winnow/src/combinator/tests.rs b/vendor/winnow/src/combinator/tests.rs
index 9d2b49d80..27fa53456 100644
--- a/vendor/winnow/src/combinator/tests.rs
+++ b/vendor/winnow/src/combinator/tests.rs
@@ -717,13 +717,13 @@ fn permutation_test() {
#[cfg(feature = "alloc")]
fn separated0_test() {
fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("abcd", ",").parse_peek(i)
+ separated(0.., "abcd", ",").parse_peek(i)
}
fn multi_empty(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("", ",").parse_peek(i)
+ separated(0.., "", ",").parse_peek(i)
}
fn multi_longsep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("abcd", "..").parse_peek(i)
+ separated(0.., "abcd", "..").parse_peek(i)
}
let a = &b"abcdef"[..];
@@ -773,7 +773,7 @@ fn separated0_test() {
#[cfg_attr(debug_assertions, should_panic)]
fn separated0_empty_sep_test() {
fn empty_sep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated0("abc", "").parse_peek(i)
+ separated(0.., "abc", "").parse_peek(i)
}
let i = &b"abcabc"[..];
@@ -792,10 +792,10 @@ fn separated0_empty_sep_test() {
#[cfg(feature = "alloc")]
fn separated1_test() {
fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated1("abcd", ",").parse_peek(i)
+ separated(1.., "abcd", ",").parse_peek(i)
}
fn multi_longsep(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
- separated1("abcd", "..").parse_peek(i)
+ separated(1.., "abcd", "..").parse_peek(i)
}
let a = &b"abcdef"[..];
@@ -840,6 +840,47 @@ fn separated1_test() {
#[test]
#[cfg(feature = "alloc")]
+fn separated_test() {
+ fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
+ separated(2..=4, "abcd", ",").parse_peek(i)
+ }
+
+ let a = &b"abcd,ef"[..];
+ let b = &b"abcd,abcd,efgh"[..];
+ let c = &b"abcd,abcd,abcd,abcd,efgh"[..];
+ let d = &b"abcd,abcd,abcd,abcd,abcd,efgh"[..];
+ let e = &b"abcd,ab"[..];
+
+ assert_eq!(
+ multi(Partial::new(a)),
+ Err(ErrMode::Backtrack(error_position!(
+ &Partial::new(&b"ef"[..]),
+ ErrorKind::Tag
+ )))
+ );
+ let res1 = vec![&b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(
+ multi(Partial::new(b)),
+ Ok((Partial::new(&b",efgh"[..]), res1))
+ );
+ let res2 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(
+ multi(Partial::new(c)),
+ Ok((Partial::new(&b",efgh"[..]), res2))
+ );
+ let res3 = vec![&b"abcd"[..], &b"abcd"[..], &b"abcd"[..], &b"abcd"[..]];
+ assert_eq!(
+ multi(Partial::new(d)),
+ Ok((Partial::new(&b",abcd,efgh"[..]), res3))
+ );
+ assert_eq!(
+ multi(Partial::new(e)),
+ Err(ErrMode::Incomplete(Needed::new(2)))
+ );
+}
+
+#[test]
+#[cfg(feature = "alloc")]
fn repeat0_test() {
fn multi(i: Partial<&[u8]>) -> IResult<Partial<&[u8]>, Vec<&[u8]>> {
repeat(0.., "abcd").parse_peek(i)