diff --git a/benches/contains_token.rs b/benches/contains_token.rs index 4be56132..4f07f402 100644 --- a/benches/contains_token.rs +++ b/benches/contains_token.rs @@ -1,7 +1,7 @@ use criterion::black_box; use winnow::combinator::alt; -use winnow::combinator::repeat0; +use winnow::combinator::repeat; use winnow::prelude::*; use winnow::token::take_till1; use winnow::token::take_while1; @@ -55,22 +55,22 @@ fn contains_token(c: &mut criterion::Criterion) { fn parser_str(input: &str) -> IResult<&str, usize> { let contains = "0123456789"; - repeat0(alt((take_while1(contains), take_till1(contains)))).parse_next(input) + repeat(0.., alt((take_while1(contains), take_till1(contains)))).parse_next(input) } fn parser_slice(input: &str) -> IResult<&str, usize> { let contains = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'][..]; - repeat0(alt((take_while1(contains), take_till1(contains)))).parse_next(input) + repeat(0.., alt((take_while1(contains), take_till1(contains)))).parse_next(input) } fn parser_array(input: &str) -> IResult<&str, usize> { let contains = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; - repeat0(alt((take_while1(contains), take_till1(contains)))).parse_next(input) + repeat(0.., alt((take_while1(contains), take_till1(contains)))).parse_next(input) } fn parser_tuple(input: &str) -> IResult<&str, usize> { let contains = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); - repeat0(alt((take_while1(contains), take_till1(contains)))).parse_next(input) + repeat(0.., alt((take_while1(contains), take_till1(contains)))).parse_next(input) } fn parser_closure_or(input: &str) -> IResult<&str, usize> { @@ -86,12 +86,12 @@ fn parser_closure_or(input: &str) -> IResult<&str, usize> { || c == '8' || c == '9' }; - repeat0(alt((take_while1(contains), take_till1(contains)))).parse_next(input) + repeat(0.., alt((take_while1(contains), take_till1(contains)))).parse_next(input) } fn parser_closure_matches(input: &str) -> IResult<&str, usize> { let contains = |c: char| matches!(c, '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'); - repeat0(alt((take_while1(contains), take_till1(contains)))).parse_next(input) + repeat(0.., alt((take_while1(contains), take_till1(contains)))).parse_next(input) } const CONTIGUOUS: &str = "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"; diff --git a/examples/arithmetic/parser_ast.rs b/examples/arithmetic/parser_ast.rs index 4cc5fb9c..fcf897e3 100644 --- a/examples/arithmetic/parser_ast.rs +++ b/examples/arithmetic/parser_ast.rs @@ -7,7 +7,7 @@ use winnow::prelude::*; use winnow::{ ascii::{digit1 as digit, multispace0 as multispace}, combinator::alt, - combinator::repeat0, + combinator::repeat, combinator::{delimited, preceded}, IResult, }; @@ -46,16 +46,19 @@ impl Display for Expr { pub fn expr(i: &str) -> IResult<&str, Expr> { let (i, initial) = term(i)?; - let (i, remainder) = repeat0(alt(( - |i| { - let (i, add) = preceded("+", term).parse_next(i)?; - Ok((i, (Oper::Add, add))) - }, - |i| { - let (i, sub) = preceded("-", term).parse_next(i)?; - Ok((i, (Oper::Sub, sub))) - }, - ))) + let (i, remainder) = repeat( + 0.., + alt(( + |i| { + let (i, add) = preceded("+", term).parse_next(i)?; + Ok((i, (Oper::Add, add))) + }, + |i| { + let (i, sub) = preceded("-", term).parse_next(i)?; + Ok((i, (Oper::Sub, sub))) + }, + )), + ) .parse_next(i)?; Ok((i, fold_exprs(initial, remainder))) @@ -63,16 +66,19 @@ pub fn expr(i: &str) -> IResult<&str, Expr> { fn term(i: &str) -> IResult<&str, Expr> { let (i, initial) = factor(i)?; - let (i, remainder) = repeat0(alt(( - |i| { - let (i, mul) = preceded("*", factor).parse_next(i)?; - Ok((i, (Oper::Mul, mul))) - }, - |i| { - let (i, div) = preceded("/", factor).parse_next(i)?; - Ok((i, (Oper::Div, div))) - }, - ))) + let (i, remainder) = repeat( + 0.., + alt(( + |i| { + let (i, mul) = preceded("*", factor).parse_next(i)?; + Ok((i, (Oper::Mul, mul))) + }, + |i| { + let (i, div) = preceded("/", factor).parse_next(i)?; + Ok((i, (Oper::Div, div))) + }, + )), + ) .parse_next(i)?; Ok((i, fold_exprs(initial, remainder))) diff --git a/examples/http/parser.rs b/examples/http/parser.rs index 3bac3ade..da8f81b2 100644 --- a/examples/http/parser.rs +++ b/examples/http/parser.rs @@ -1,4 +1,4 @@ -use winnow::{ascii::line_ending, combinator::repeat1, token::take_while1, IResult, Parser}; +use winnow::{ascii::line_ending, combinator::repeat, token::take_while1, IResult, Parser}; pub type Stream<'i> = &'i [u8]; @@ -44,7 +44,7 @@ pub fn parse(data: &[u8]) -> Option, Vec>)>> { fn request(input: Stream<'_>) -> IResult, (Request<'_>, Vec>)> { let (input, req) = request_line(input)?; - let (input, h) = repeat1(message_header).parse_next(input)?; + let (input, h) = repeat(1.., message_header).parse_next(input)?; let (input, _) = line_ending(input)?; Ok((input, (req, h))) @@ -86,7 +86,7 @@ fn message_header_value(input: Stream<'_>) -> IResult, &[u8]> { fn message_header(input: Stream<'_>) -> IResult, Header<'_>> { let (input, name) = take_while1(is_token).parse_next(input)?; let (input, _) = ':'.parse_next(input)?; - let (input, value) = repeat1(message_header_value).parse_next(input)?; + let (input, value) = repeat(1.., message_header_value).parse_next(input)?; Ok((input, Header { name, value })) } diff --git a/examples/http/parser_streaming.rs b/examples/http/parser_streaming.rs index 119cfc74..63c196d3 100644 --- a/examples/http/parser_streaming.rs +++ b/examples/http/parser_streaming.rs @@ -1,5 +1,5 @@ use winnow::{ - ascii::line_ending, combinator::repeat1, stream::Partial, token::take_while1, IResult, Parser, + ascii::line_ending, combinator::repeat, stream::Partial, token::take_while1, IResult, Parser, }; pub type Stream<'i> = Partial<&'i [u8]>; @@ -46,7 +46,7 @@ pub fn parse(data: &[u8]) -> Option, Vec>)>> { fn request(input: Stream<'_>) -> IResult, (Request<'_>, Vec>)> { let (input, req) = request_line(input)?; - let (input, h) = repeat1(message_header).parse_next(input)?; + let (input, h) = repeat(1.., message_header).parse_next(input)?; let (input, _) = line_ending(input)?; Ok((input, (req, h))) @@ -88,7 +88,7 @@ fn message_header_value(input: Stream<'_>) -> IResult, &[u8]> { fn message_header(input: Stream<'_>) -> IResult, Header<'_>> { let (input, name) = take_while1(is_token).parse_next(input)?; let (input, _) = ':'.parse_next(input)?; - let (input, value) = repeat1(message_header_value).parse_next(input)?; + let (input, value) = repeat(1.., message_header_value).parse_next(input)?; Ok((input, Header { name, value })) } diff --git a/examples/ini/bench.rs b/examples/ini/bench.rs index 5d57eec7..cffea3b8 100644 --- a/examples/ini/bench.rs +++ b/examples/ini/bench.rs @@ -1,4 +1,4 @@ -use winnow::combinator::repeat0; +use winnow::combinator::repeat; use winnow::prelude::*; mod parser; @@ -32,7 +32,7 @@ file=payroll.dat \0"; fn acc(i: parser::Stream<'_>) -> IResult, Vec<(&str, &str)>> { - repeat0(parser::key_value).parse_next(i) + repeat(0.., parser::key_value).parse_next(i) } let mut group = c.benchmark_group("ini keys and values"); diff --git a/examples/ini/parser.rs b/examples/ini/parser.rs index 190b0430..8c756d56 100644 --- a/examples/ini/parser.rs +++ b/examples/ini/parser.rs @@ -5,7 +5,7 @@ use winnow::prelude::*; use winnow::{ ascii::{alphanumeric1 as alphanumeric, multispace0 as multispace, space0 as space}, combinator::opt, - combinator::repeat0, + combinator::repeat, combinator::{delimited, separated_pair, terminated}, token::take_while0, }; @@ -13,11 +13,14 @@ use winnow::{ pub type Stream<'i> = &'i [u8]; pub fn categories(i: Stream<'_>) -> IResult, HashMap<&str, HashMap<&str, &str>>> { - repeat0(separated_pair( - category, - opt(multispace), - repeat0(terminated(key_value, opt(multispace))), - )) + repeat( + 0.., + separated_pair( + category, + opt(multispace), + repeat(0.., terminated(key_value, opt(multispace))), + ), + ) .parse_next(i) } diff --git a/examples/ini/parser_str.rs b/examples/ini/parser_str.rs index 2c280bef..30a7548f 100644 --- a/examples/ini/parser_str.rs +++ b/examples/ini/parser_str.rs @@ -4,7 +4,7 @@ use winnow::prelude::*; use winnow::{ ascii::{alphanumeric1 as alphanumeric, space0 as space}, combinator::opt, - combinator::repeat0, + combinator::repeat, combinator::{delimited, terminated}, token::{take_till0, take_while0, take_while1}, }; @@ -12,7 +12,7 @@ use winnow::{ pub type Stream<'i> = &'i str; pub fn categories(input: Stream<'_>) -> IResult, HashMap<&str, HashMap<&str, &str>>> { - repeat0(category_and_keys).parse_next(input) + repeat(0.., category_and_keys).parse_next(input) } fn category_and_keys(i: Stream<'_>) -> IResult, (&str, HashMap<&str, &str>)> { @@ -28,7 +28,7 @@ fn category(i: Stream<'_>) -> IResult, &str> { } fn keys_and_values(input: Stream<'_>) -> IResult, HashMap<&str, &str>> { - repeat0(key_value).parse_next(input) + repeat(0.., key_value).parse_next(input) } fn key_value(i: Stream<'_>) -> IResult, (&str, &str)> { diff --git a/examples/s_expression/parser.rs b/examples/s_expression/parser.rs index 1212b869..f9cb43a2 100644 --- a/examples/s_expression/parser.rs +++ b/examples/s_expression/parser.rs @@ -5,7 +5,7 @@ use winnow::{ ascii::{alpha1, digit1, multispace0, multispace1}, combinator::alt, - combinator::repeat0, + combinator::repeat, combinator::{cut_err, opt}, combinator::{delimited, preceded, terminated}, error::VerboseError, @@ -168,7 +168,7 @@ fn parse_keyword(i: &str) -> IResult<&str, Atom, VerboseError<&str>> { /// tuples are themselves a parser, used to sequence parsers together, so we can translate this /// directly and then map over it to transform the output into an `Expr::Application` fn parse_application(i: &str) -> IResult<&str, Expr, VerboseError<&str>> { - let application_inner = (parse_expr, repeat0(parse_expr)) + let application_inner = (parse_expr, repeat(0.., parse_expr)) .map(|(head, tail)| Expr::Application(Box::new(head), tail)); // finally, we wrap it in an s-expression s_exp(application_inner).parse_next(i) @@ -212,7 +212,7 @@ fn parse_quote(i: &str) -> IResult<&str, Expr, VerboseError<&str>> { // this should look very straight-forward after all we've done: // we find the `'` (quote) character, use cut_err to say that we're unambiguously // looking for an s-expression of 0 or more expressions, and then parse them - preceded("'", cut_err(s_exp(repeat0(parse_expr)))) + preceded("'", cut_err(s_exp(repeat(0.., parse_expr)))) .context("quote") .map(Expr::Quote) .parse_next(i) diff --git a/src/_topic/language.rs b/src/_topic/language.rs index 6a610fbe..b42f229d 100644 --- a/src/_topic/language.rs +++ b/src/_topic/language.rs @@ -146,9 +146,6 @@ //! string slice to an integer value is slightly simpler. You can also strip the `_` from the string //! slice that is returned, which is demonstrated in the second hexadecimal number parser. //! -//! If you wish to limit the number of digits in a valid integer literal, replace `repeat1` with -//! `repeat` in the recipes. -//! //! #### Hexadecimal //! //! The parser outputs the string slice of the digits without the leading `0x`/`0X`. @@ -157,7 +154,7 @@ //! use winnow::prelude::*; //! use winnow::{ //! combinator::alt, -//! combinator::{repeat0, repeat1}, +//! combinator::{repeat}, //! combinator::{preceded, terminated}, //! token::one_of, //! token::tag, @@ -166,8 +163,8 @@ //! fn hexadecimal(input: &str) -> IResult<&str, &str> { // <'a, E: ParseError<&'a str>> //! preceded( //! alt(("0x", "0X")), -//! repeat1( -//! terminated(one_of("0123456789abcdefABCDEF"), repeat0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789abcdefABCDEF"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() //! ).parse_next(input) //! } @@ -179,7 +176,7 @@ //! use winnow::prelude::*; //! use winnow::{ //! combinator::alt, -//! combinator::{repeat0, repeat1}, +//! combinator::{repeat}, //! combinator::{preceded, terminated}, //! token::one_of, //! token::tag, @@ -188,8 +185,8 @@ //! fn hexadecimal_value(input: &str) -> IResult<&str, i64> { //! preceded( //! alt(("0x", "0X")), -//! repeat1( -//! terminated(one_of("0123456789abcdefABCDEF"), repeat0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789abcdefABCDEF"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() //! ).try_map( //! |out: &str| i64::from_str_radix(&str::replace(&out, "_", ""), 16) @@ -203,7 +200,7 @@ //! use winnow::prelude::*; //! use winnow::{ //! combinator::alt, -//! combinator::{repeat0, repeat1}, +//! combinator::{repeat}, //! combinator::{preceded, terminated}, //! token::one_of, //! token::tag, @@ -212,8 +209,8 @@ //! fn octal(input: &str) -> IResult<&str, &str> { //! preceded( //! alt(("0o", "0O")), -//! repeat1( -//! terminated(one_of("01234567"), repeat0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("01234567"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() //! ).parse_next(input) //! } @@ -225,7 +222,7 @@ //! use winnow::prelude::*; //! use winnow::{ //! combinator::alt, -//! combinator::{repeat0, repeat1}, +//! combinator::{repeat}, //! combinator::{preceded, terminated}, //! token::one_of, //! token::tag, @@ -234,8 +231,8 @@ //! fn binary(input: &str) -> IResult<&str, &str> { //! preceded( //! alt(("0b", "0B")), -//! repeat1( -//! terminated(one_of("01"), repeat0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("01"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()).recognize() //! ).parse_next(input) //! } @@ -247,14 +244,14 @@ //! use winnow::prelude::*; //! use winnow::{ //! IResult, -//! combinator::{repeat0, repeat1}, +//! combinator::{repeat}, //! combinator::terminated, //! token::one_of, //! }; //! //! fn decimal(input: &str) -> IResult<&str, &str> { -//! repeat1( -//! terminated(one_of("0123456789"), repeat0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789"), repeat(0.., '_').map(|()| ())) //! ).map(|()| ()) //! .recognize() //! .parse_next(input) @@ -269,7 +266,7 @@ //! use winnow::prelude::*; //! use winnow::{ //! combinator::alt, -//! combinator::{repeat0, repeat1}, +//! combinator::{repeat}, //! combinator::opt, //! combinator::{preceded, terminated}, //! token::one_of, @@ -308,8 +305,8 @@ //! } //! //! fn decimal(input: &str) -> IResult<&str, &str> { -//! repeat1( -//! terminated(one_of("0123456789"), repeat0('_').map(|()| ())) +//! repeat(1.., +//! terminated(one_of("0123456789"), repeat(0.., '_').map(|()| ())) //! ). //! map(|()| ()) //! .recognize() diff --git a/src/_topic/partial.rs b/src/_topic/partial.rs index ecb55ab1..19895d35 100644 --- a/src/_topic/partial.rs +++ b/src/_topic/partial.rs @@ -21,7 +21,7 @@ //! Caveats: //! - `winnow` takes the approach of re-parsing from scratch. Chunks should be relatively small to //! prevent the re-parsing overhead from dominating. -//! - Parsers like [`repeat0`] do not know when an `eof` is from insufficient data or the end of the +//! - Parsers like [`repeat`] do not know when an `eof` is from insufficient data or the end of the //! stream, causing them to always report [`Incomplete`]. //! //! # Example @@ -39,7 +39,7 @@ #![allow(unused_imports)] // Used for intra-doc links use crate::binary::length_value; -use crate::combinator::repeat0; +use crate::combinator::repeat; use crate::error::ErrMode::Incomplete; use crate::error::Needed; use crate::stream::Partial; diff --git a/src/_tutorial/chapter_5.rs b/src/_tutorial/chapter_5.rs index 9c8374e7..4acde06d 100644 --- a/src/_tutorial/chapter_5.rs +++ b/src/_tutorial/chapter_5.rs @@ -3,7 +3,7 @@ //! In [`chapter_3`], we covered how to sequence different parsers into a tuple but sometimes you need to run a //! single parser multiple times, collecting the result into a [`Vec`]. //! -//! Let's take our `parse_digits` and collect a list of them with [`repeat0`]: +//! Let's take our `parse_digits` and collect a list of them with [`repeat`]: //! ```rust //! # use winnow::IResult; //! # use winnow::Parser; @@ -12,11 +12,11 @@ //! # use winnow::token::take; //! # use winnow::combinator::fail; //! use winnow::combinator::opt; -//! use winnow::combinator::repeat0; +//! use winnow::combinator::repeat; //! use winnow::combinator::terminated; //! //! fn parse_list(input: &str) -> IResult<&str, Vec> { -//! repeat0(terminated(parse_digits, opt(','))).parse_next(input) +//! repeat(0.., terminated(parse_digits, opt(','))).parse_next(input) //! } //! //! // ... @@ -132,7 +132,7 @@ //! } //! ``` //! -//! If you look closely at [`repeat0`], it isn't collecting directly into a [`Vec`] but +//! If you look closely at [`repeat`], it isn't collecting directly into a [`Vec`] but //! [`Accumulate`] to gather the results. This let's us make more complex parsers than we did in //! [`chapter_2`] by accumulating the results into a `()` and [`recognize`][Parser::recognize]-ing the captured input: //! ```rust @@ -204,7 +204,7 @@ #![allow(unused_imports)] use super::chapter_2; use super::chapter_3; -use crate::combinator::repeat0; +use crate::combinator::repeat; use crate::combinator::separated0; use crate::stream::Accumulate; use crate::Parser; diff --git a/src/combinator/mod.rs b/src/combinator/mod.rs index e47611bd..1ecb5fe9 100644 --- a/src/combinator/mod.rs +++ b/src/combinator/mod.rs @@ -40,7 +40,6 @@ //! | combinator | usage | input | output | comment | //! |---|---|---|---|---| //! | [`count`][crate::combinator::count] | `count(take(2), 3)` | `"abcdefgh"` | `Ok(("gh", vec!["ab", "cd", "ef"]))` |Applies the child parser a specified number of times| -//! | [`repeat0`][crate::combinator::repeat0] | `repeat0("ab")` | `"abababc"` | `Ok(("c", vec!["ab", "ab", "ab"]))` |Applies the parser 0 or more times and returns the list of results in a Vec. `repeat1` does the same operation but must return at least one element| //! | [`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| diff --git a/src/combinator/multi.rs b/src/combinator/multi.rs index 81db4419..8fdac1b7 100644 --- a/src/combinator/multi.rs +++ b/src/combinator/multi.rs @@ -28,6 +28,45 @@ use crate::Parser; /// /// # Example /// +/// Zero or more reptitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// repeat(0.., "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// # } +/// ``` +/// +/// One or more reptitions: +/// ```rust +/// # #[cfg(feature = "std")] { +/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; +/// # use winnow::prelude::*; +/// use winnow::combinator::repeat; +/// use winnow::token::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// repeat(1.., "abc").parse_next(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); +/// # } +/// ``` +/// +/// Arbitrary reptitions: /// ```rust /// # #[cfg(feature = "std")] { /// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; @@ -46,8 +85,14 @@ use crate::Parser; /// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); /// # } /// ``` -#[doc(alias = "repeated")] +#[doc(alias = "many0")] +#[doc(alias = "many0_count")] +#[doc(alias = "many1")] +#[doc(alias = "many1_count")] #[doc(alias = "many_m_n")] +#[doc(alias = "repeated")] +#[doc(alias = "skip_many")] +#[doc(alias = "skip_many1")] #[inline(always)] pub fn repeat(range: impl Into, mut f: F) -> impl Parser where @@ -63,53 +108,23 @@ where trace("repeat", move |i: I| { match (start_inclusive, end_inclusive) { (0, None) => repeat0_(&mut f, i), - (1, None) => repeat1(f.by_ref()).parse_next(i), + (1, None) => repeat1_(&mut f, i), (start, end) => repeat_m_n_(start, end.unwrap_or(usize::MAX), &mut f, i), } }) } -/// [`Accumulate`] the output of a parser into a container, like `Vec` -/// -/// This stops on [`ErrMode::Backtrack`]. To instead chain an error up, see -/// [`cut_err`][crate::combinator::cut_err]. -/// -/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. -/// -/// **Warning:** if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `repeat0` will -/// return an error, to prevent going into an infinite loop -/// -/// # Example -/// -/// ```rust -/// # #[cfg(feature = "std")] { -/// # use winnow::{error::ErrMode, error::ErrorKind, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::combinator::repeat0; -/// use winnow::token::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// repeat0("abc").parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); -/// assert_eq!(parser(""), Ok(("", vec![]))); -/// # } -/// ``` -#[doc(alias = "skip_many")] -#[doc(alias = "repeated")] -#[doc(alias = "many0_count")] -#[doc(alias = "many0")] -pub fn repeat0(mut f: F) -> impl Parser +/// Deprecated, replaced by [`repeat`] +#[deprecated(since = "0.4.6", note = "Replaced with `repeat`")] +#[inline(always)] +pub fn repeat0(f: F) -> impl Parser where I: Stream, C: Accumulate, F: Parser, E: ParseError, { - trace("repeat0", move |i: I| repeat0_(&mut f, i)) + repeat(0.., f) } fn repeat0_(f: &mut F, mut i: I) -> IResult @@ -138,51 +153,17 @@ where } } -/// [`Accumulate`] the output of a parser into a container, like `Vec` -/// -/// This stops on [`ErrMode::Backtrack`] if there is at least one result. To instead chain an error up, -/// see [`cut_err`][crate::combinator::cut_err]. -/// -/// # Arguments -/// * `f` The parser to apply. -/// -/// To recognize a series of tokens, [`Accumulate`] into a `()` and then [`Parser::recognize`]. -/// -/// **Warning:** If the parser passed to `repeat1` accepts empty inputs -/// (like `alpha0` or `digit0`), `repeat1` will return an error, -/// to prevent going into an infinite loop. -/// -/// # Example -/// -/// ```rust -/// # #[cfg(feature = "std")] { -/// # use winnow::{error::ErrMode, error::{Error, ErrorKind}, error::Needed}; -/// # use winnow::prelude::*; -/// use winnow::combinator::repeat1; -/// use winnow::token::tag; -/// -/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// repeat1("abc").parse_next(s) -/// } -/// -/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); -/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); -/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag)))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag)))); -/// # } -/// ``` -#[doc(alias = "skip_many1")] -#[doc(alias = "repeated")] -#[doc(alias = "many1_count")] -#[doc(alias = "many1")] -pub fn repeat1(mut f: F) -> impl Parser +/// Deprecated, replaced by [`repeat`] +#[deprecated(since = "0.4.6", note = "Replaced with `repeat`")] +#[inline(always)] +pub fn repeat1(f: F) -> impl Parser where I: Stream, C: Accumulate, F: Parser, E: ParseError, { - trace("repeat1", move |i: I| repeat1_(&mut f, i)) + repeat(1.., f) } fn repeat1_(f: &mut F, mut i: I) -> IResult @@ -539,7 +520,7 @@ where trace("separated_foldr1", move |i: I| { let (i, ol) = parser.parse_next(i)?; let (i, all): (_, crate::lib::std::vec::Vec<(O2, O)>) = - repeat0((sep.by_ref(), parser.by_ref())).parse_next(i)?; + repeat(0.., (sep.by_ref(), parser.by_ref())).parse_next(i)?; if let Some((s, or)) = all .into_iter() .rev() diff --git a/src/combinator/tests.rs b/src/combinator/tests.rs index 2adaf769..1c643893 100644 --- a/src/combinator/tests.rs +++ b/src/combinator/tests.rs @@ -817,7 +817,7 @@ fn separated1_test() { #[cfg(feature = "alloc")] fn repeat0_test() { fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - repeat0("abcd").parse_next(i) + repeat(0.., "abcd").parse_next(i) } assert_eq!( @@ -851,7 +851,7 @@ fn repeat0_test() { #[cfg_attr(debug_assertions, should_panic)] fn repeat0_empty_test() { fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - repeat0("").parse_next(i) + repeat(0.., "").parse_next(i) } assert_eq!( @@ -867,7 +867,7 @@ fn repeat0_empty_test() { #[cfg(feature = "alloc")] fn repeat1_test() { fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - repeat1("abcd").parse_next(i) + repeat(1.., "abcd").parse_next(i) } let a = &b"abcdef"[..]; @@ -931,13 +931,13 @@ fn infinite_many() { // should not go into an infinite loop fn multi0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - repeat0(tst).parse_next(i) + repeat(0.., tst).parse_next(i) } let a = &b"abcdef"[..]; assert_eq!(multi0(a), Ok((a, Vec::new()))); fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - repeat1(tst).parse_next(i) + repeat(1.., tst).parse_next(i) } let a = &b"abcdef"[..]; assert_eq!( @@ -1095,7 +1095,7 @@ fn fold_repeat0_test() { acc } fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - fold_repeat0("abcd", Vec::new, fold_into_vec).parse_next(i) + fold_repeat(0.., "abcd", Vec::new, fold_into_vec).parse_next(i) } assert_eq!( @@ -1133,7 +1133,7 @@ fn fold_repeat0_empty_test() { acc } fn multi_empty(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - fold_repeat0("", Vec::new, fold_into_vec).parse_next(i) + fold_repeat(0.., "", Vec::new, fold_into_vec).parse_next(i) } assert_eq!( @@ -1153,7 +1153,7 @@ fn fold_repeat1_test() { acc } fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - fold_repeat1("abcd", Vec::new, fold_into_vec).parse_next(i) + fold_repeat(1.., "abcd", Vec::new, fold_into_vec).parse_next(i) } let a = &b"abcdef"[..]; @@ -1229,7 +1229,7 @@ fn fold_repeat_test() { #[test] fn repeat0_count_test() { fn count0_nums(i: &[u8]) -> IResult<&[u8], usize> { - repeat0((digit, ",")).parse_next(i) + repeat(0.., (digit, ",")).parse_next(i) } assert_eq!(count0_nums(&b"123,junk"[..]), Ok((&b"junk"[..], 1))); @@ -1247,7 +1247,7 @@ fn repeat0_count_test() { #[test] fn repeat1_count_test() { fn count1_nums(i: &[u8]) -> IResult<&[u8], usize> { - repeat1((digit, ",")).parse_next(i) + repeat(1.., (digit, ",")).parse_next(i) } assert_eq!(count1_nums(&b"123,45,junk"[..]), Ok((&b"junk"[..], 2))); diff --git a/src/multi.rs b/src/multi.rs index a8f1b808..aecbb443 100644 --- a/src/multi.rs +++ b/src/multi.rs @@ -8,8 +8,8 @@ use crate::stream::Accumulate; use crate::stream::Stream; use crate::Parser; -/// Deprecated, replaced by [`combinator::repeat0`] -#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat0`")] +/// Deprecated, replaced by [`combinator::repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat`")] #[inline(always)] pub fn many0(f: F) -> impl Parser where @@ -18,11 +18,11 @@ where F: Parser, E: ParseError, { - combinator::repeat0(f) + combinator::repeat(0.., f) } -/// Deprecated, replaced by [`combinator::repeat1`] -#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat1`")] +/// Deprecated, replaced by [`combinator::repeat`] +#[deprecated(since = "0.4.2", note = "Replaced with `combinator::repeat`")] #[inline(always)] pub fn many1(f: F) -> impl Parser where @@ -31,7 +31,7 @@ where F: Parser, E: ParseError, { - combinator::repeat1(f) + combinator::repeat(1.., f) } /// Deprecated, replaced by [`combinator::repeat_till0`] diff --git a/src/token/mod.rs b/src/token/mod.rs index 8299eea9..60a96873 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -437,7 +437,7 @@ where /// /// *Partial version*: will return a `ErrMode::Incomplete(Needed::new(1))` if the pattern reaches the end of the input. /// -/// To recognize a series of tokens, use [`repeat0`][crate::combinator::repeat0] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. +/// To recognize a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. /// /// # Example /// @@ -497,7 +497,7 @@ where /// /// *Partial version* will return a `ErrMode::Incomplete(Needed::new(1))` or if the pattern reaches the end of the input. /// -/// To recognize a series of tokens, use [`repeat1`][crate::combinator::repeat1] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. +/// To recognize a series of tokens, use [`repeat`][crate::combinator::repeat] to [`Accumulate`][crate::stream::Accumulate] into a `()` and then [`Parser::recognize`][crate::Parser::recognize]. /// /// # Example /// diff --git a/tests/testsuite/fnmut.rs b/tests/testsuite/fnmut.rs index feb6d5e4..c0e70cb6 100644 --- a/tests/testsuite/fnmut.rs +++ b/tests/testsuite/fnmut.rs @@ -1,6 +1,6 @@ #![cfg(feature = "alloc")] -use winnow::combinator::repeat0; +use winnow::combinator::repeat; use winnow::Parser; #[test] @@ -9,7 +9,7 @@ fn parse() { let mut counter = 0; let res = { - let mut parser = repeat0::<_, _, Vec<_>, (), _>(|i| { + let mut parser = repeat::<_, _, Vec<_>, (), _>(0.., |i| { counter += 1; "abc".parse_next(i) }); @@ -26,7 +26,7 @@ fn accumulate() { let mut v = Vec::new(); let (_, count) = { - let mut parser = repeat0::<_, _, usize, (), _>(|i| { + let mut parser = repeat::<_, _, usize, (), _>(0.., |i| { let (i, o) = "abc".parse_next(i)?; v.push(o); Ok((i, ())) diff --git a/tests/testsuite/issues.rs b/tests/testsuite/issues.rs index d68f64c6..a7804502 100644 --- a/tests/testsuite/issues.rs +++ b/tests/testsuite/issues.rs @@ -28,12 +28,12 @@ mod parse_int { use winnow::{ ascii::{digit1 as digit, space1 as space}, combinator::opt, - combinator::repeat0, + combinator::repeat, IResult, }; fn parse_ints(input: Partial<&[u8]>) -> IResult, Vec> { - repeat0(spaces_or_int).parse_next(input) + repeat(0.., spaces_or_int).parse_next(input) } fn spaces_or_int(input: Partial<&[u8]>) -> IResult, i32> { @@ -187,8 +187,8 @@ fn issue_942() { pub fn parser<'a, E: ParseError<&'a str> + ContextError<&'a str, &'static str>>( i: &'a str, ) -> IResult<&'a str, usize, E> { - use winnow::combinator::repeat0; - repeat0('a'.context("char_a")).parse_next(i) + use winnow::combinator::repeat; + repeat(0.., 'a'.context("char_a")).parse_next(i) } assert_eq!(parser::<()>("aaa"), Ok(("", 3))); } diff --git a/tests/testsuite/multiline.rs b/tests/testsuite/multiline.rs index 9be54764..0472b25c 100644 --- a/tests/testsuite/multiline.rs +++ b/tests/testsuite/multiline.rs @@ -2,7 +2,7 @@ use winnow::{ ascii::{alphanumeric1 as alphanumeric, line_ending as eol}, - combinator::repeat0, + combinator::repeat, combinator::terminated, IResult, Parser, }; @@ -20,7 +20,7 @@ pub fn read_line(input: &str) -> IResult<&str, &str> { } pub fn read_lines(input: &str) -> IResult<&str, Vec<&str>> { - repeat0(read_line).parse_next(input) + repeat(0.., read_line).parse_next(input) } #[cfg(feature = "alloc")] diff --git a/tests/testsuite/overflow.rs b/tests/testsuite/overflow.rs index 987fc6b1..e30e4456 100644 --- a/tests/testsuite/overflow.rs +++ b/tests/testsuite/overflow.rs @@ -6,7 +6,7 @@ use winnow::binary::be_u64; #[cfg(feature = "alloc")] use winnow::binary::length_data; #[cfg(feature = "alloc")] -use winnow::combinator::repeat0; +use winnow::combinator::repeat; use winnow::error::{ErrMode, Needed}; use winnow::prelude::*; use winnow::token::take; @@ -32,7 +32,7 @@ fn overflow_incomplete_tuple() { #[cfg(feature = "alloc")] fn overflow_incomplete_length_bytes() { fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - repeat0(length_data(be_u64)).parse_next(i) + repeat(0.., length_data(be_u64)).parse_next(i) } // Trigger an overflow in length_data @@ -48,10 +48,10 @@ fn overflow_incomplete_length_bytes() { #[cfg(feature = "alloc")] fn overflow_incomplete_many0() { fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - repeat0(length_data(be_u64)).parse_next(i) + repeat(0.., length_data(be_u64)).parse_next(i) } - // Trigger an overflow in repeat0 + // Trigger an overflow in repeat assert_eq!( multi(Partial::new( &b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef"[..] @@ -63,13 +63,13 @@ fn overflow_incomplete_many0() { #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_many1() { - use winnow::combinator::repeat1; + use winnow::combinator::repeat; fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - repeat1(length_data(be_u64)).parse_next(i) + repeat(1.., length_data(be_u64)).parse_next(i) } - // Trigger an overflow in repeat1 + // Trigger an overflow in repeat assert_eq!( multi(Partial::new( &b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef"[..] @@ -154,7 +154,7 @@ fn overflow_incomplete_length_count() { #[cfg(feature = "alloc")] fn overflow_incomplete_length_data() { fn multi(i: Partial<&[u8]>) -> IResult, Vec<&[u8]>> { - repeat0(length_data(be_u64)).parse_next(i) + repeat(0.., length_data(be_u64)).parse_next(i) } assert_eq!( diff --git a/tests/testsuite/utf8.rs b/tests/testsuite/utf8.rs index 887aac89..9b5b7f18 100644 --- a/tests/testsuite/utf8.rs +++ b/tests/testsuite/utf8.rs @@ -3,7 +3,7 @@ mod test { use winnow::Parser; use winnow::Partial; #[cfg(feature = "alloc")] - use winnow::{combinator::alt, combinator::repeat1, token::tag_no_case}; + use winnow::{combinator::alt, combinator::repeat, token::tag_no_case}; use winnow::{ error::ErrMode, error::{self, Error, ErrorKind}, @@ -505,7 +505,7 @@ mod test { let b = "ababcd"; fn f(i: &str) -> IResult<&str, &str> { - repeat1::<_, _, (), _, _>(alt(("a", "b"))) + repeat::<_, _, (), _, _>(1.., alt(("a", "b"))) .recognize() .parse_next(i) }