Skip to content

Commit

Permalink
Merge pull request #39 from epage/cut
Browse files Browse the repository at this point in the history
docs(combinator): Clarify role of 'cut'
  • Loading branch information
epage authored Dec 14, 2022
2 parents d274f94 + 8cc0997 commit 055823b
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 46 deletions.
55 changes: 49 additions & 6 deletions src/combinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,9 @@ impl<'a, I, O1, O2, E, F: Parser<I, O1, E>, G: Fn(O1) -> H, H: Parser<I, O2, E>>
}
}

/// 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 @@ -894,18 +896,57 @@ 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::one_of;
/// # use nom::character::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::one_of;
/// # use nom::character::digit1;
/// # use nom::combinator::rest;
/// # use nom::branch::alt;
/// # use nom::sequence::preceded;
/// use nom::combinator::cut;
/// use nom::character::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 @@ -1006,6 +1047,8 @@ impl<
/// 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`].
///
/// ```rust
/// use nom::{combinator::iterator, IResult, bytes::tag, character::alpha1, sequence::terminated};
/// use std::collections::HashMap;
Expand Down
132 changes: 92 additions & 40 deletions src/multi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ use crate::{Err, IResult, Parser};
/// of elements regardless of the capacity cap.
const MAX_INITIAL_CAPACITY: 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
/// [`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 @@ -74,10 +75,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,
/// see [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
Expand Down Expand Up @@ -135,9 +136,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 @@ -191,8 +195,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
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `sep` Parses the separator between list elements.
/// * `f` Parses the elements of the list.
Expand Down Expand Up @@ -260,9 +267,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
/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `sep` Parses the separator between list elements.
/// * `f` Parses the elements of the list.
Expand Down Expand Up @@ -329,13 +340,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
/// [`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 @@ -397,10 +415,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
/// [`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 @@ -447,12 +472,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,
/// 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 @@ -504,8 +535,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 @@ -555,8 +586,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 @@ -606,13 +639,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
/// [`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 @@ -674,15 +714,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,
/// 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 @@ -752,17 +798,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
/// [`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

0 comments on commit 055823b

Please sign in to comment.