-
Notifications
You must be signed in to change notification settings - Fork 96
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
Choice #16
Choice #16
Conversation
It's worth reiterating that both body code for the fn parse_state are* the same. |
type Output = O; | ||
fn parse_state(&mut self, input: State<I>) -> ParseResult<O, I> { | ||
if self.0.len() == 0 { // err: slice empty of parsers | ||
return Err(Consumed::Empty(ParseError { position: input.position.clone(), errors: vec![] })) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the ParseError::new function instead. Since the fields are all public it is possible to construct like this but I defined the new function in part to make sure that there is always an error (no empty errors vector).
In this case something like Error::Message("parser choice used with no parsers")
Added a few comments on your PR. I'm still not sold on the idea of including a choice parser though. While it may be useful in parsec, I think that being forced to box every parser makes it much less useful. If you or someone else can show a compelling use case for using choice over doing |
Instead of having choice_slice and choice_vec, maybe it is possible to only have fn choice<I>(ps: I) -> Choice<I> where I: Iterator + Clone, Iterator::Item: Parser By having a Clone bound on iterator I'm thinking that every time the parser is called, the iterator can be cloned and iterated. |
Here's my case to use ChoiceSlice: https://github.com/jxv/irc/commit/5d4d82aa2362b5282db5d674b3de3ad3565f461c#diff-9c0b8390b3d65627e2d9c5ad4536cc35R242 I haven't actually got it to compile using the |
This gives crashes the compiler: fn choice<I>(ps: I) -> Choice<I> where I: Iterator + Clone, Iterator::Item: Parser Either I'm doing something wrong or there's a legit bug. |
Your problem with the compile times is this issue rust-lang/rust#21231. Specializing the I noticed you have a bug though in the parser, since it is LL(1) parsers that are created you need to use the |
Anything that crashes the compiler is a bug and the code is actually wrong. It should be:
EDIT: This seems to be the issue in rust rust-lang/rust#21867 |
So, okay. It's bug (or two). Also, thanks for the Other than the compiler bug with the choice traits, is there anything else which can be improved? |
A couple of things left I think. I'd argue that ChoiceSlice should hold EDIT: I should mention that the Clone bound is probably fine for the most part since parsers should be really cheap to clone but since no other parser requires it I feel it is a little inconsistent. I think you got the ChoiceSlice right though it was a little hard to follow the code. I think it may be easier to visualize if you think of the parser as returning three different values you need to deal with.
I think you got all of these right but a test or two for the parser would be really useful. Only thing that is 'wrong' is that you don't exit early when a consumed error occurs (which is probably why you didn't notice that you needed try in your parsers). Arguably you should only construct the "choice is empty" error if the slice is actually empty, it should avoid an unnecessary allocation. This ended up a longer response than I expected but choice is probably one of the trickier parsers to get right. I should probably add some function which helps deal with these cases correctly though, since I know I had to write some extra boilerplate similar to this for a few other parsers (there is the |
Yeah, I think my misunderstanding of the relationship between In regards to the |
How would you use I have experimented a bit with having parsers take themselves as &self but I didn't feel like it was a good idea since it would force all parsers to take functions as |
I was thinking that ref-counting might have* reduced the overhead from cloning. But yeah, you'd lose the ability to mutate. |
Looks fine to me, haven't done many tests which are more thorough than that. It might be good to have one call to parse which returns |
If you feel like you have nothing more to add to this I can merge this after a rebase (I can do the rebase if you want to, just remember to pull in the new master afterwards and work from that). |
Yes, you can rebase and merge. |
Rebased and merged in 3bc8739 |
This is really a review request, not a PR.