Add the Set combinator that applies a set of parser without order#850
Conversation
|
Thanks for the PR! I do think there's a lot of potential use for this combinator, and I think the deferred progress trick is especially neat! I am a little worried about the way in which it can subtly hide O(n^2) parsing behaviour. I assume that the goal is to replace something like enum Item { A(A), B(B), C(C) }
choose((
a.map(Item::A),
b.map(Item::B),
c.map(Item::C),
))
.repeated_exactly::<3>()
.try_map(|items| {
let (mut a, mut b, mut c) = (None, None, None);
for x in items {
match x {
Item::A(x) => a.replace(x).map(|_| Err(Error::custom("A was repeated"))).unwrap_or(Ok(()))?,
Item::B(x) => b.replace(x).map(|_| Err(Error::custom("B was repeated"))).unwrap_or(Ok(()))?,
Item::C(x) => c.replace(x).map(|_| Err(Error::custom("C was repeated"))).unwrap_or(Ok(()))?,
}
}
Ok((a.unwrap(), b.unwrap(), c.unwrap()))
})with set((a, b, c))Definitely a big win, although expanding it out to even a dozen elements could easily produce hundreds of parser invocations. I'm not sure whether there's a good way to deal with that other than to recommend careful use in the docs. |
|
I'm definitely happy to see this merged, although:
|
|
Thank you for your quick answer. It does more than replacing the snippet you wrote, because it allows a, b and c in The quadratic behavior is unavoidable, I think. Its impact can be reduced if the user knows a usual ordering of items. But yes, it must be documented. You're right about other suggestions, I think I will also provide implementations for vecs and arrays in addition to the current tuple one. |
|
Great. By the way, if you do a rebase then CI should pass. I really need to get round to pinning the rustc version. |
|
Done, please tell me what you think |
|
Looks great. One concern I have is that this parser always Other than that, I'd be happy to merge this! |
|
I tried making it generic over mode earlier, but I couldn't find How, let me try again. I found how to do it in the tuple case, but for the array case, I need the In the Vec case, I couldn't find how to map a |
|
Found it, and added some clippy fixes linked to MSRV |
|
Ideal, thanks so much! Your work is really appreciated, this is a great addition. |
Add a
Setcombinator that takes a tuple of parsers and applies all of them in any order.This permits parsing languages where arguments can be provided in any order.
set((A, B))parses A then B or B then A depending on which comes first.Parsers that match without making progress are applied last to make sure they have no better alternative, which allows optional parsers like
A.or_not().