This document describes the grammar and production rules of Cucumber Expressions.
A Cucumber Expression has the following EBNF grammar:
cucumber-expression = (alternation
| optional
| parameter
| text)*
text = (- text-to-escape) | ('\', text-to-escape)
text-to-escape = '(' | '{' | '/' | '\'
alternation = single-alternation, ('/', single_alternation)+
single-alternation = ((text-in-alternative+, optional*)
| (optional+, text-in-alternative+))+
text-in-alternative = (- alternative-to-escape) | ('\', alternative-to-escape)
alternative-to-escape = ' ' | '(' | '{' | '/' | '\'
optional = '(', text-in-optional+, ')'
text-in-optional = (- optional-to-escape) | ('\', optional-to-escape)
optional-to-escape = '(' | ')' | '{' | '/' | '\'
parameter = '{', name*, '}'
name = (- name-to-escape) | ('\', name-to-escape)
name-to-escape = '{' | '}' | '(' | '/' | '\'
Implementations provided in this repository are using the following grammar, which is superset of Cucumber Expressions
. Only after creating superset AST comes validation for better error handling.
Note, that this is only suggestion for implementation and as long as you are compliant with formal spec, you should be alright.
cucumber-expression = ( alternation | optional | parameter | text )*
alternation = (?<=left-boundary), alternative*, ( "/" + alternative* )+, (?=right-boundary)
left-boundary = whitespace | "}" | "^"
right-boundary = whitespace | "{" | "$"
alternative = optional | parameter | text
optional = "(", option*, ")"
option = optional | parameter | text
parameter = "{", name*, "}"
name = whitespace | .
text = whitespace | ")" | "}" | .
The AST is constructed from the following tokens:
escape = "\"
token = whitespace | "(" | ")" | "{" | "}" | "/" | .
. = any non-reserved codepoint
Note:
- While
parameter
is allowed to appear as part ofalternative
andoption
in the AST, such an AST is not a valid Cucumber Expression. - While
optional
is allowed to appear as part ofoption
in the AST, such an AST is not a valid Cucumber Expression. - ASTs with empty alternatives or alternatives that only contain an optional are valid ASTs but invalid Cucumber Expressions.
- All escaped tokens (tokens starting with a backslash) are rewritten to their unescaped equivalent after parsing.
The AST can be rewritten into a regular expression by the following production rules:
cucumber-expression -> "^" + rewrite(node[0]) + ... + rewrite(node[n-1]) + "$"
alternation -> "(?:" + rewrite(node[0]) + "|" + ... + "|" + rewerite(node[n-1]) + ")"
alternative -> rewrite(node[0]) + ... + rewrite(node[n-1])
optional -> "(?:" + rewrite(node[0]) + ... + rewrite(node[n-1]) + ")?"
parameter -> {
parameter_name := node[0].text + ... + node[n-1].text
parameter_pattern := parameter_type_registry[parameter_name]
"((?:" + parameter_pattern[0] + ")|(?:" ... + ")|(?:" + parameter_pattern[n-1] + "))"
}
text -> {
escape_regex := escape "^", "$", "[", "]", "(", ")" "\", "{", "}", ".", "|", "?", "*", "+"
escape_regex(token.text)
}