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
Unary prefix/suffix operator support for PrecClimber #344
Conversation
04c6aa2
to
ba220d2
Compare
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.
Thanks a lot for your contribution! Really interesting work. I've taken a first look over the PR and there are a few issues that need to be resolved in order to get closer to merging this:
- we need to find a way to support this in
2.1+
; the way I see it,3.0
is too far right now away in order lock into a particular implementation, so we need to find a way to deprecate the old types without breaking compatibility - prefix and postfix/suffix operators should potentially have their own precedence; this would require changing the algorithm
- we should probably add another type in order not to restrain verification only in debug builds
pest/src/prec_climber.rs
Outdated
} | ||
} | ||
|
||
/// Defines `rule` as a suffix unary operator. |
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.
I'm more in favour of postfix
rather than suffix
.
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.
done
pest/src/prec_climber.rs
Outdated
/// Below is a [`PrecClimber`] that is able to climb an `expr` in the above grammar. The order | ||
/// of precedence corresponds to the order in which [`op`] is called. Thus, `mul` will | ||
/// have higher precedence than `add`. Operators can also be chained with `|` to give them equal | ||
/// precedence. In the current version, prefix operators precede suffix, and suffix |
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.
The issue here is that users might find confusing how, even though infix, prefix and postfix operators are mixed together, order matters only when Op
s are infix. In other words, there is a redundant ordering complication here that has potential to be confusing.
In my opinion, the best course of action is to either logically separate prefix/postfix ops, such that they cannot be mixed in with infix operators, or extend the algorithm to deal with prefix/postfix operator precedence as well.
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.
The algorithm should now be able to deal with prefix/postfix operator precedence
pest/src/prec_climber.rs
Outdated
/// _ => unreachable!(), | ||
/// }) | ||
/// .map_suffix(|lhs, op| match op.as_rule() { | ||
/// Rule::fac => (1..=lhs).product(), |
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.
Kind of a papercut, but I believe this syntax will probably raise the minimum required Rust version. Might be a good idea to leave these kind of refactorings for when we tackle the 2018 edition refactor.
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.
I changed it to (1..lhs+1)
pest/src/prec_climber.rs
Outdated
/// | ||
/// [`map_primary`]: struct.PrecClimber.html#method.map_primary | ||
/// [`PrecClimber`]: struct.PrecClimber.html | ||
pub struct PrecClimberMap<'climber, 'pest, R, F, T> | ||
where |
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.
This doesn't look like the style specified in rustfmt.toml
, but I might be mistaken. Is this formatted with rustfmt
? Trailing commas style also seems to be different.
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.
it should now be properly formatted
pest/src/prec_climber.rs
Outdated
pairs: P | ||
) -> T { | ||
|
||
#[cfg(debug_assertions)] |
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.
Maybe it would be worthwhile to introduce a third type that this one would get compiled to. This would both offer a nice API, i.e. return a None
if missing map_*
s, and relive the user from possible headaches in release builds.
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.
I changed so that the code panics either when:
- The stream of tokens does not match the expected pattern.
- No map function is specified for a certain kind of operator.
pest/src/prec_climber.rs
Outdated
} | ||
|
||
/// Maps primary expressions with a closure `primary`. | ||
pub fn map_primary<'climber, 'pest, X, T>(&'climber self, primary: X) |
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.
'i
in pest stands for input
. 'pest
lifetime is too ambiguous.
pub fn map_primary<'climber, 'pest, X, T>(&'climber self, primary: X) | |
pub fn map_primary<'climber, 'i, X, T>(&'climber self, primary: X) |
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.
done
725007f
to
fce43c4
Compare
fce43c4
to
960195d
Compare
@@ -187,14 +190,15 @@ fn expression() { | |||
} | |||
|
|||
#[test] | |||
fn prec_climb() { |
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.
I see tests for PrecClimber
removed and replaced, but PrecClimber
is still in the codebase. I don't think these should be removed until PrecClimber
itself is.
This would be a great feature to have! Personally I think the right way to incorporate this is to keep the public APIs involving |
I understand that this is a little bit old now and would probably requite a bit of fixing up, but is there any movement on this? I think it would be quite handy to enable prefix/suffix operators like this. |
@lberezy, there hasn't been that much work here ever since, but I'm happy to merge this if it gets push forward. |
Hi again, I refactored this into its own crate https://crates.io/crates/pratt. Feel free to copy it, add it as a dependency, or just point to it from to pest. You may close this PR if you want. |
Closes pest-parser#461 based on pest-parser#344 Co-authored-by: Klas Segeljakt <klasseg@kth.se>
@segeljakt @lberezy @dragostis I opened a new PR based on this one: #710 -- I had to make a few small changes in order to support |
Adds a new
PrattParser
, which works similar toPrecClimber
but extends it with unary (prefix and suffix) operator handling.To try it out, checkout this PR and run
cargo run --example=calc
in the terminal.Given a grammar:
You can now define a
PrattParser
:And use it like:
Some things to consider:
prefix
/suffix
/infix
) could be misinterpreted as binary operators withprefix
/suffix
/infix
notation. Does it work, or should I name things more explicitly, e.g.,unary_prefix
/unary_suffix
/binary_infix
?