Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify role of 'cut' #1603

Merged
merged 2 commits into from Dec 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 47 additions & 6 deletions src/combinator/mod.rs
Expand Up @@ -218,7 +218,9 @@ where
}
}

/// Optional parser: Will return `None` if not successful.
/// Optional parser, will return `None` on [`Err::Error`].
///
/// To chain an error up, see [`cut`].
///
/// ```rust
/// # use nom::{Err,error::ErrorKind, IResult};
Expand Down Expand Up @@ -575,18 +577,55 @@ where
}
}

/// transforms an error to failure
/// Transforms an [`Err::Error`] (recoverable) to [`Err::Failure`] (unrecoverable)
///
/// This commits the parse result, preventing alternative branch paths like with
/// [`nom::branch::alt`][crate::branch::alt].
///
/// # Example
///
/// Without `cut`:
/// ```rust
/// # use nom::{Err,error::ErrorKind, IResult};
/// # use nom::character::complete::{one_of, digit1};
/// # use nom::combinator::rest;
/// # use nom::branch::alt;
/// # use nom::sequence::preceded;
/// # fn main() {
///
/// fn parser(input: &str) -> IResult<&str, &str> {
/// alt((
/// preceded(one_of("+-"), digit1),
/// rest
/// ))(input)
/// }
///
/// assert_eq!(parser("+10 ab"), Ok((" ab", "10")));
/// assert_eq!(parser("ab"), Ok(("", "ab")));
/// assert_eq!(parser("+"), Ok(("", "+")));
/// # }
/// ```
///
/// With `cut`:
/// ```rust
/// # use nom::{Err,error::ErrorKind, IResult, error::Error};
/// # use nom::character::complete::{one_of, digit1};
/// # use nom::combinator::rest;
/// # use nom::branch::alt;
/// # use nom::sequence::preceded;
/// use nom::combinator::cut;
/// use nom::character::complete::alpha1;
/// # fn main() {
///
/// let mut parser = cut(alpha1);
/// fn parser(input: &str) -> IResult<&str, &str> {
/// alt((
/// preceded(one_of("+-"), cut(digit1)),
/// rest
/// ))(input)
/// }
///
/// assert_eq!(parser("abcd;"), Ok((";", "abcd")));
/// assert_eq!(parser("123;"), Err(Err::Failure(("123;", ErrorKind::Alpha))));
/// assert_eq!(parser("+10 ab"), Ok((" ab", "10")));
/// assert_eq!(parser("ab"), Ok(("", "ab")));
/// assert_eq!(parser("+"), Err(Err::Failure(Error { input: "", code: ErrorKind::Digit })));
/// # }
/// ```
pub fn cut<I, O, E: ParseError<I>, F>(mut parser: F) -> impl FnMut(I) -> IResult<I, O, E>
Expand Down Expand Up @@ -643,6 +682,8 @@ 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 [`Err::Error`], iteration will stop. To instead chain an error up, see [`cut`].
Geal marked this conversation as resolved.
Show resolved Hide resolved
///
/// ```rust
/// use nom::{combinator::iterator, IResult, bytes::complete::tag, character::complete::alpha1, sequence::terminated};
/// use std::collections::HashMap;
Expand Down
132 changes: 92 additions & 40 deletions src/multi/mod.rs
Expand Up @@ -23,15 +23,16 @@ use core::num::NonZeroUsize;
#[cfg(feature = "alloc")]
const MAX_INITIAL_CAPACITY_BYTES: usize = 65536;

/// Repeats the embedded parser until it fails
/// and returns the results in a `Vec`.
/// Repeats the embedded parser, gathering the results in a `Vec`.
///
/// This stops on [`Err::Error`]. To instead chain an error up, see
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
///
/// *Note*: if the parser passed to `many0` accepts empty inputs
/// (like `alpha0` or `digit0`), `many0` will return an error,
/// to prevent going into an infinite loop
/// *Note*: if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will
/// return an error, to prevent going into an infinite loop
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
Expand Down Expand Up @@ -76,10 +77,10 @@ where
}
}

/// Runs the embedded parser until it fails and
/// returns the results in a `Vec`. Fails if
/// the embedded parser does not produce at least
/// one result.
/// Runs the embedded parser, gathering the results in a `Vec`.
///
/// This stops on [`Err::Error`] if there is at least one result. To instead chain an error up,
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// see [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
Expand Down Expand Up @@ -138,9 +139,12 @@ where
}
}

/// Applies the parser `f` until the parser `g` produces
/// a result. Returns a pair consisting of the results of
/// `f` in a `Vec` and the result of `g`.
/// Applies the parser `f` until the parser `g` produces a result.
///
/// Returns a tuple of the results of `f` in a `Vec` and the result of `g`.
///
/// `f` keeps going so long as `g` produces [`Err::Error`]. To instead chain an error up, see [`cut`][crate::combinator::cut].
///
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
/// use nom::multi::many_till;
Expand Down Expand Up @@ -195,8 +199,11 @@ where
}
}

/// Alternates between two parsers to produce
/// a list of elements.
/// Alternates between two parsers to produce a list of elements.
///
/// This stops when either parser returns [`Err::Error`]. To instead chain an error up, see
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `sep` Parses the separator between list elements.
/// * `f` Parses the elements of the list.
Expand Down Expand Up @@ -265,9 +272,13 @@ where
}
}

/// Alternates between two parsers to produce
/// a list of elements. Fails if the element
/// parser does not produce at least one element.
/// Alternates between two parsers to produce a list of elements until [`Err::Error`].
///
/// Fails if the element parser does not produce at least one element.$
///
/// This stops when either parser returns [`Err::Error`]. To instead chain an error up, see
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `sep` Parses the separator between list elements.
/// * `f` Parses the elements of the list.
Expand Down Expand Up @@ -335,13 +346,20 @@ where
}
}

/// Repeats the embedded parser `n` times or until it fails
/// and returns the results in a `Vec`. Fails if the
/// embedded parser does not succeed at least `m` times.
/// Repeats the embedded parser `m..=n` times
///
/// This stops before `n` when the parser returns [`Err::Error`]. To instead chain an error up, see
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `m` The minimum number of iterations.
/// * `n` The maximum number of iterations.
/// * `f` The parser to apply.
///
/// *Note*: If the parser passed to `many1` accepts empty inputs
/// (like `alpha0` or `digit0`), `many1` will return an error,
/// to prevent going into an infinite loop.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::many_m_n;
Expand Down Expand Up @@ -405,10 +423,17 @@ where
}
}

/// Repeats the embedded parser until it fails
/// and returns the number of successful iterations.
/// Repeats the embedded parser, counting the results
///
/// This stops on [`Err::Error`]. To instead chain an error up, see
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
///
/// *Note*: if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will
/// return an error, to prevent going into an infinite loop
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::many0_count;
Expand Down Expand Up @@ -455,12 +480,18 @@ where
}
}

/// Repeats the embedded parser until it fails
/// and returns the number of successful iterations.
/// Fails if the embedded parser does not succeed
/// at least once.
/// Runs the embedded parser, counting the results.
///
/// This stops on [`Err::Error`] if there is at least one result. To instead chain an error up,
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// see [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
///
/// *Note*: If the parser passed to `many1` accepts empty inputs
/// (like `alpha0` or `digit0`), `many1` will return an error,
/// to prevent going into an infinite loop.
///
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
/// use nom::multi::many1_count;
Expand Down Expand Up @@ -512,8 +543,8 @@ where
}
}

/// Runs the embedded parser a specified number
/// of times. Returns the results in a `Vec`.
/// Runs the embedded parser `count` times, gathering the results in a `Vec`
///
/// # Arguments
/// * `f` The parser to apply.
/// * `count` How often to apply the parser.
Expand Down Expand Up @@ -565,8 +596,10 @@ where
}
}

/// Runs the embedded parser repeatedly, filling the given slice with results. This parser fails if
/// the input runs out before the given slice is full.
/// Runs the embedded parser repeatedly, filling the given slice with results.
///
/// This parser fails if the input runs out before the given slice is full.
///
/// # Arguments
/// * `f` The parser to apply.
/// * `buf` The slice to fill
Expand Down Expand Up @@ -616,13 +649,20 @@ where
}
}

/// Applies a parser until it fails and accumulates
/// the results using a given function and initial value.
/// Repeats the embedded parser, calling `g` to gather the results.
///
/// This stops on [`Err::Error`]. To instead chain an error up, see
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
///
/// *Note*: if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will
/// return an error, to prevent going into an infinite loop
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::fold_many0;
Expand Down Expand Up @@ -684,15 +724,21 @@ where
}
}

/// Applies a parser until it fails and accumulates
/// the results using a given function and initial value.
/// Fails if the embedded parser does not succeed at least
/// once.
/// Repeats the embedded parser, calling `g` to gather the results.
///
/// This stops on [`Err::Error`] if there is at least one result. To instead chain an error up,
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// see [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
///
/// *Note*: If the parser passed to `many1` accepts empty inputs
/// (like `alpha0` or `digit0`), `many1` will return an error,
/// to prevent going into an infinite loop.
///
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
/// use nom::multi::fold_many1;
Expand Down Expand Up @@ -762,17 +808,23 @@ where
}
}

/// Applies a parser `n` times or until it fails and accumulates
/// the results using a given function and initial value.
/// Fails if the embedded parser does not succeed at least `m`
/// times.
/// Repeats the embedded parser `m..=n` times, calling `g` to gather the results
///
/// This stops before `n` when the parser returns [`Err::Error`]. To instead chain an error up, see
Geal marked this conversation as resolved.
Show resolved Hide resolved
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `m` The minimum number of iterations.
/// * `n` The maximum number of iterations.
/// * `f` The parser to apply.
/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
///
/// *Note*: If the parser passed to `many1` accepts empty inputs
/// (like `alpha0` or `digit0`), `many1` will return an error,
/// to prevent going into an infinite loop.
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::fold_many_m_n;
Expand Down