-
-
Notifications
You must be signed in to change notification settings - Fork 689
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
cucumber-expressions: Use a parser to parse Cucumber Expressions #771
Conversation
I've implemented the parser in Go and Java. I'm fairly proficient with both, before I continue with JavaScript and Ruby I'd like to have some feedback. |
Nevermind. Found the flaws. Cases not yet covered:
Ect. Currently can't catch these because this parser rewrites tokens collected by regex rather implementing a proper tokenizer + LR(1) parser. |
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.
Code is all good e.t.c. but
Personal pref, I don't like this (4 escaping \
), type of cuke exp. When you've got 4 escaping characters it's starting to get beyond the point that we should support (imo)
We support two escapes at most currently. But if the parser is implemented properly it doesn't matter. |
Okay. I've changed the implementation to a regular recursive descent parser. While not strictly necessary it makes the implementation much cleaner and behaves like all the other parsers people are used too (esp w.r.t escapes). Additionally I've changed the precedence order. Alternation is now the highest precedent operator. This means that any thing bordering a To make cucumber expressions easier to validate I've also extended the grammar to allow parameters to be nested in optionals and alternatives and optionals to be nested in alternatives. These are not valid cucumber expressions and will throw an error. For now I'm going to let this percolate a bit. I'll add some examples (for the docs) later on. |
@mpkorstanje thats great 👍
For your example ({int} blind\ rat(s)/mouse/mice) I would expect the following data:
Is this already possible? If not can you add it? |
Feel free to send a PR against the You'll probably want to add start and end indexes to |
...r-expressions/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java
Outdated
Show resolved
Hide resolved
...r-expressions/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java
Outdated
Show resolved
Hide resolved
And that is the go implementation of the recursive descent parser done. |
Great work @mpkorstanje! Looking forward to porting this to TypoeScript. Maybe this cleanup will make it easier to port to C# too? /cc @SabotageAndi @gasparnagy |
Can't believe I just wrote TypoeScript! |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in a week if no further activity occurs. |
…r name characters to reserved tokens
Design choices made: Make the parser complain about ambiguous structuresBecause cucumber expressions are an unknown language implicit behaviour will be harder to understand. For example given:
Or:
The latter makes sense but cucumber expressions don't support nesting alternatives in an optional. To make sure we can add this in the future and to make sure users understand that this is not a valid Cucumber expression the parser will complain about this. Note that But don't complain about shorthandThis however is perfectly fine:
|
…name characters to reserved tokens
…name characters to reserved tokens
…r name characters to reserved tokens
d06e728
to
df464a3
Compare
Implementation is done. Before releasing this it would be prudent to release the other unreleased fixes first. This release should result in a new major version because the semantics of Cucumber Expressions have subtly changed. The documentation here would need a small update w.r.t to escaping: https://cucumber.io/docs/cucumber/cucumber-expressions/ It would also be prudent if some one who's not me would try out some rather interesting Cucumber expressions and see if it all makes sense. |
end | ||
|
||
def escape(s) | ||
s.gsub(/%/, '%%') | ||
.gsub(/\(/, '\\(') | ||
.gsub(/\{/, '\\{') | ||
.gsub(/{/, '\\{') |
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.
Is {
not a reserved character?
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 is, but whether it needs to be escaped or not depends on the context. IDEA told me escaping was redundant here, and I trust it :-)
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.
What a tremendous piece of work this is @mpkorstanje. Thanks a million.
Really looking forward to integrating this into Cucumbers.
@mpkorstanje is there any example how to use the parser "standalone"? e.g. I have an expression as a string and like to parse it withe the parser to get the different parts? |
Not really. I'd rather not expose that as an API. I'd have to polish the AST even more before I'm confident I won't change it after the first bug we find. |
@mpkorstanje thanks for the feedback, I would be happy even with a "EXPERIMENTAL" marked API just to test and maybe give some feedback on this. I think this would is a really great addition to support tools in not firing their own (incomplete or differing) parsing algorithms. |
To make cucumber/common#771 possible we need both mono and berp. Currently mono isn't installed and berp is checked in as a binary executable. Both are less then ideal. Currently mono isn't supported on the same version of alpine as .NET Core SDK 2.2.2. To avoid messing around too much with APK which doesn't support mono yet I've changed the base image to `ubuntu:20.04`. This makes it easier to install mono. Additionally we can now also use the node version manager to manage the node and npm versions. They'll be installed without the need for global permissions. This solves another long standing build headace. The make file will now use `mono /var/lib/berp/1.1.1/tools/net471/Berp.exe -g gherkin.berp` which is less out of the box then it was before, but the exact installation instructions for berp and mono can be found in the `Dockerfile`.
To make cucumber/common#771 possible we need both mono and berp. Currently mono isn't installed and berp is checked in as a binary executable. Both are less then ideal. Currently mono isn't supported on the same version of alpine as .NET Core SDK 2.2.2. To avoid messing around too much with APK which doesn't support mono yet I've changed the base image to `ubuntu:20.04`. This makes it easier to install mono. Additionally we can now also use the node version manager to manage the node and npm versions. They'll be installed without the need for global permissions. This solves another long standing build headace. The make file will now use `mono /var/lib/berp/1.1.1/tools/net471/Berp.exe -g gherkin.berp` which is less out of the box then it was before, but the exact installation instructions for berp and mono can be found in the `Dockerfile`.
To make cucumber/common#771 possible we need both mono and berp. Currently mono isn't installed and berp is checked in as a binary executable. Both are less then ideal. Currently mono isn't supported on the same version of alpine as .NET Core SDK 2.2.2. To avoid messing around too much with APK which doesn't support mono yet I've changed the base image to `ubuntu:20.04`. This makes it easier to install mono. Additionally we can now also use the node version manager to manage the node and npm versions. They'll be installed without the need for global permissions. This solves another long standing build headace. The make file will now use `mono /var/lib/berp/1.1.1/tools/net471/Berp.exe -g gherkin.berp` which is less out of the box then it was before, but the exact installation instructions for berp and mono can be found in the `Dockerfile`.
To make cucumber/common#771 possible we need both mono and berp. Currently mono isn't installed and berp is checked in as a binary executable. Both are less then ideal. Currently mono isn't supported on the same version of alpine as .NET Core SDK 2.2.2. To avoid messing around too much with APK which doesn't support mono yet I've changed the base image to `ubuntu:20.04`. This makes it easier to install mono. Additionally we can now also use the node version manager to manage the node and npm versions. They'll be installed without the need for global permissions. This solves another long standing build headace. The make file will now use `mono /var/lib/berp/1.1.1/tools/net471/Berp.exe -g gherkin.berp` which is less out of the box then it was before, but the exact installation instructions for berp and mono can be found in the `Dockerfile`.
To make cucumber/common#771 possible we need both mono and berp. Currently mono isn't installed and berp is checked in as a binary executable. Both are less then ideal. Currently mono isn't supported on the same version of alpine as .NET Core SDK 2.2.2. To avoid messing around too much with APK which doesn't support mono yet I've changed the base image to `ubuntu:20.04`. This makes it easier to install mono. Additionally we can now also use the node version manager to manage the node and npm versions. They'll be installed without the need for global permissions. This solves another long standing build headace. The make file will now use `mono /var/lib/berp/1.1.1/tools/net471/Berp.exe -g gherkin.berp` which is less out of the box then it was before, but the exact installation instructions for berp and mono can be found in the `Dockerfile`.
To make cucumber/common#771 possible we need both mono and berp. Currently mono isn't installed and berp is checked in as a binary executable. Both are less then ideal. Currently mono isn't supported on the same version of alpine as .NET Core SDK 2.2.2. To avoid messing around too much with APK which doesn't support mono yet I've changed the base image to `ubuntu:20.04`. This makes it easier to install mono. Additionally we can now also use the node version manager to manage the node and npm versions. They'll be installed without the need for global permissions. This solves another long standing build headace. The make file will now use `mono /var/lib/berp/1.1.1/tools/net471/Berp.exe -g gherkin.berp` which is less out of the box then it was before, but the exact installation instructions for berp and mono can be found in the `Dockerfile`.
To make cucumber/common#771 possible we need both mono and berp. Currently mono isn't installed and berp is checked in as a binary executable. Both are less then ideal. Currently mono isn't supported on the same version of alpine as .NET Core SDK 2.2.2. To avoid messing around too much with APK which doesn't support mono yet I've changed the base image to `ubuntu:20.04`. This makes it easier to install mono. Additionally we can now also use the node version manager to manage the node and npm versions. They'll be installed without the need for global permissions. This solves another long standing build headace. The make file will now use `mono /var/lib/berp/1.1.1/tools/net471/Berp.exe -g gherkin.berp` which is less out of the box then it was before, but the exact installation instructions for berp and mono can be found in the `Dockerfile`.
Summary
A parser to parse Cucumber Expressions.
Cucumber Expressions currently uses a string rewriting algorithm
to turn Cucumber Expression Strings into regular expressions. This algorithm
has three major problems.
By using a parser to generate the AST of Cucumber expression and rewriting this
AST to a regular expression we can avoid all these problems. For example:
Matches:
Fixes: #767
Fixes: #601
Fixes: #726
Closes: #770
Details
Grammar
The AST is constructed from the following tokens:
Note:
parameter
is allowed to appear as part ofalternative
andoption
in the AST, such an AST is not a valid a Cucumber Expression.optional
is allowed to appear as part ofoption
in the AST,such an AST is not a valid a Cucumber Expression.
contain an optional are valid ASTs but invalid Cucumber Expressions.
unescaped equivalent after parsing.
Types of changes
Checklist: