Skip to content

Commit

Permalink
Add opt_partial() combinator
Browse files Browse the repository at this point in the history
  • Loading branch information
ebkalderon committed Oct 13, 2019
1 parent 89ec4b5 commit a1e4c50
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion nix-parser/src/parser/partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::iter::FromIterator;

use codespan::Span;
use nom::bytes::complete::take;
use nom::combinator::opt;
use nom::sequence::{preceded, terminated};
use nom::InputLength;

Expand Down Expand Up @@ -232,7 +233,7 @@ where
}
}

/// Combinator which behaves like `nom::combinator::map()`, except it is a shorthand for:
/// Combinator which behaves like `nom::combinator::map`, except it is a shorthand for:
///
/// ```rust,ignore
/// map(partial, |partial| partial.map(&f))
Expand Down Expand Up @@ -320,6 +321,39 @@ where
}
}

/// Combinator which returns `None` if the given partial parser fails.
///
/// This combinator behaves like `nom::combinator::opt`, except it also transposes the result from
/// `Option<Partial<O>>` to `Partial<Option<O>>`. This transposition allows you to utilize the
/// behavior of `opt` while remaining compatible with other partial combinators like
/// `pair_partial()` and `map_partial()`.
///
/// # Examples
///
/// `opt_partial()` is especially handy when combined with `pair_partial()` to create partial
/// parsers with predicates that trigger based on some non-partial condition. For example, compare
/// this regular `nom` parser with its partial equivalent:
///
/// ```rust,ignore
/// // Regular version
/// pair(f, opt(preceded(sep, g)))
///
/// // Partial version
/// pair_partial(f, opt_partial(preceded(sep, g)))
/// ```
pub fn opt_partial<'a, O, F>(f: F) -> impl Fn(Tokens<'a>) -> IResult<Partial<Option<O>>>
where
F: Fn(Tokens<'a>) -> IResult<Partial<O>>,
{
move |input| {
let (remaining, value) = opt(&f)(input)?;
match value {
Some(partial) => Ok((remaining, partial.map(Some))),
None => Ok((remaining, Partial::new(Some(None)))),
}
}
}

/// Combinator which gets the result from the first partial parser, then gets the result from the
/// second partial parser, and produces a partial value containing a tuple of the two results.
///
Expand Down

0 comments on commit a1e4c50

Please sign in to comment.