Skip to content

Commit 29a4bf7

Browse files
committed
Used ANTLR lexer modes for java regex quotes \Q...\E.
1 parent 285fdb9 commit 29a4bf7

4 files changed

Lines changed: 33 additions & 19 deletions

File tree

core/src/main/antlr4/org/evomaster/core/parser/RegexJavaLexer.g4

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,6 @@ MINUS : '-';
9494
COMMA : ',';
9595
COLON : ':';
9696

97-
Q: 'Q';
98-
E: 'E';
99-
10097
BaseChar
10198
// practically all chars but the ones used for control and digits
10299
: ~[0-9:,^$\\.*+?()[\]{}|-]
@@ -134,3 +131,33 @@ fragment OctalDigit:
134131
NamedBackReference
135132
: SLASH 'k<' [a-zA-Z] [a-zA-Z0-9]* '>'
136133
;
134+
135+
// Special for Java: \Q...\E literal quoting.
136+
// Matching '\Q' switches the lexer into QUOTE_MODE (see below).
137+
QUOTE_OPEN
138+
: '\\' 'Q' -> pushMode(QUOTE_MODE)
139+
;
140+
141+
142+
143+
// --------------------------------------------------------------------------------
144+
// QUOTE_MODE: everything after \Q and before an optional \E is literal text.
145+
// By using lexer modes we skip having to explicitly allow all lexer tokens to appear
146+
// within quotes. This works by having a different set of tokens available when inside
147+
// a quote block, the default mode and the QUOTE_MODE each keep their own set of tokens.
148+
// QUOTE_MODE only has the lexer tokens defined below.
149+
// --------------------------------------------------------------------------------
150+
mode QUOTE_MODE;
151+
152+
// The only way out of a \Q...\E block. In Java the first literal "\E" sequence ends quoting.
153+
QUOTE_CLOSE
154+
: '\\' 'E' -> popMode
155+
;
156+
157+
// One or more characters that do not form a "\E" sequence, so either:
158+
// - a backslash immediately followed by something other than 'E',
159+
// - any single non-backslash character.
160+
// Note that this cannot consume the sequence QUOTE_CLOSE.
161+
QUOTE_CONTENT
162+
: ( '\\' ~[E] | ~[\\] )+
163+
;

core/src/main/antlr4/org/evomaster/core/parser/RegexJavaParser.g4

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,7 @@ atom
103103

104104
// Special for Java
105105
quote
106-
: SLASH Q quoteBlock SLASH E
107-
;
108-
109-
quoteBlock
110-
: quoteChar*
111-
;
112-
113-
quoteChar
114-
: classAtom
115-
| SLASH
116-
| BRACKET_close
117-
| Q
118-
| E
106+
: QUOTE_OPEN QUOTE_CONTENT? QUOTE_CLOSE? // both the content and closing the quote is optional in java regex.
119107
;
120108

121109
patternCharacter
@@ -125,7 +113,6 @@ patternCharacter
125113
| COMMA
126114
| MINUS
127115
| DecimalDigit
128-
| E | Q
129116
// These are also allowed as literals when no matching pair exists
130117
| BRACE_close
131118
| BRACKET_close

core/src/main/kotlin/org/evomaster/core/parser/GeneRegexJavaVisitor.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,8 +366,7 @@ class GeneRegexJavaVisitor(externalRegexFlags: RegexFlags = RegexFlags()) : Rege
366366

367367
if(ctx.quote() != null){
368368

369-
val block = ctx.quote().quoteBlock().quoteChar().map { it.text }
370-
.joinToString("")
369+
val block = ctx.quote().QUOTE_CONTENT()?.text ?: ""
371370

372371
val name = if(block.isBlank()) "blankBlock" else block
373372

core/src/test/kotlin/org/evomaster/core/parser/GeneRegexJavaVisitorTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class GeneRegexJavaVisitorTest : GeneRegexEcma262VisitorTest() {
5656
checkSameAsJava("^(\\Q6\\E(n|N)(u|U)(a|A)(q|Q)(w|W)(b|B)\\Q51\\E(y|Y)(w|W)\\Q1\\E(e|E)(r|R)(n|N))$")
5757
checkSameAsJava("^((z|Z)(l|L)(q|Q)\\Q9\\E(r|R)(e|E)(k|K)(q|Q)(b|B)\\Q6\\E(e|E)(q|Q)(u|U))$")
5858
checkSameAsJava("^(\\Q81\\E(x|X)(a|A)\\Q3\\E(p|P)(x|X)(d|D))$")
59+
checkSameAsJava("a{1}\\Qa{1}\\Qabcd")
5960
}
6061

6162
@Test

0 commit comments

Comments
 (0)