You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2019/11/03 18:32:29 UTC
[groovy] 01/01: GROOVY-8507,
GROOVY-9301: support comma on last enum value in more cases
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch GROOVY-8507
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 5ac71d7a5bee39efe7ac0e1dd408705c82a97b3d
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Nov 3 12:15:26 2019 -0600
GROOVY-8507, GROOVY-9301: support comma on last enum value in more cases
and reduce ambiguity within (antlr2) enumConstants loop
---
src/main/antlr2/org/codehaus/groovy/antlr/groovy.g | 15 +-
.../groovy/antlr/EnumSourceParsingTest.java | 284 +++++++++++++++++----
2 files changed, 240 insertions(+), 59 deletions(-)
diff --git a/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g b/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g
index 3f29054..41d5e29 100644
--- a/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g
+++ b/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g
@@ -1128,26 +1128,33 @@ enumBlock {Token first = LT(1);}
{#enumBlock = #(create(OBJBLOCK,"OBJBLOCK",first,LT(1)), #enumBlock);}
;
-/** Guard for enumConstants. */
+/** Guard for enumConstants. */
enumConstantsStart
: annotationsOpt IDENT (LCURLY | LPAREN | nls (SEMI | COMMA | declarationStart | RCURLY))
;
-/** Comma-separated list of one or more enum constant definitions. */
+/** Comma-separated list of one or more enum constant definitions. */
enumConstants
:
enumConstant
( options {generateAmbigWarnings=false;} :
- (nls ( options {generateAmbigWarnings=false;} : SEMI! | RCURLY | declarationStart | constructorStart)) => {break;}
+ (nls (SEMI | enumConstantsEnd)) => {break;} // GROOVY-4438, GROOVY-9184
|
nls! COMMA! (
+ (nls enumConstantsEnd) => {break;} // GROOVY-8507, GROOVY-9301
+ |
(nls annotationsOpt IDENT) => nls! enumConstant
|
- (nls (SEMI! | RCURLY | classField)) => {break;}
+ (nls classField) => {break;}
)
)*
;
+enumConstantsEnd
+ options {generateAmbigWarnings=false;}
+ : RCURLY | declarationStart | constructorStart | typeDefinitionStart
+ ;
+
// An annotation field
annotationField! {Token first = LT(1);}
: mods:modifiersOpt!
diff --git a/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java b/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java
index 8a6d2a3..fd24cb4 100644
--- a/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java
+++ b/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java
@@ -28,93 +28,116 @@ public final class EnumSourceParsingTest extends SourceParserTest {
public void testParseEnumConstants() {
parse(getMethodName(), new StringReader(
"enum E {\n" +
- " ONE, TWO, THREE\n" +
- "}"));
+ " X, Y, Z\n" +
+ "}\n")
+ );
}
public void testParseEnumConstantsMultiLine() {
parse(getMethodName(), new StringReader(
"enum E {\n" +
- " ONE,\n" +
- " TWO,\n" +
- " THREE,\n" +
- "}"));
+ " X,\n" +
+ " Y,\n" +
+ " Z,\n" +
+ "}\n")
+ );
}
public void testParseEnumConstantsMultiLine2() {
parse(getMethodName(), new StringReader(
- "enum ParseCode\n" +
+ "enum E\n" +
"{\n" +
- " COMPLETE,\n" +
- " INCOMPLETE,\n" +
- " ERROR\n" +
- "}"));
+ " X,\n" +
+ " Y,\n" +
+ " Z\n" +
+ "}\n")
+ );
}
public void testParseEnumImplementsMultiLine() {
parse(getMethodName(), new StringReader(
- "enum ParseCode implements I\n" +
+ "enum E implements I\n" +
"{\n" +
- " COMPLETE,\n" +
- " INCOMPLETE,\n" +
- " ERROR\n" +
- "}"));
+ " X,\n" +
+ " Y,\n" +
+ " Z\n" +
+ "}\n")
+ );
}
public void testParseEnumImplementsMultiLine2() {
parse(getMethodName(), new StringReader(
- "enum ParseCode\n" +
+ "enum E\n" +
"implements I\n" +
"{\n" +
- " COMPLETE,\n" +
- " INCOMPLETE,\n" +
- " ERROR\n" +
- "}"));
+ " X,\n" +
+ " Y,\n" +
+ " Z\n" +
+ "}\n")
+ );
}
public void testParseEnumConstantsOneLiner() {
parse(getMethodName(), new StringReader(
- "enum One { ONE, TWO, THREE }"));
+ "enum E { X, Y, Z }\n")
+ );
}
public void testParseEnumImplements() {
parse(getMethodName(), new StringReader(
- "enum Two implements I1 {\n" +
- "ONE, TWO, THREE\n" +
- "}"));
+ "enum E implements I {\n" +
+ " X, Y, Z\n" +
+ "}\n")
+ );
}
public void testParseEnumWithValues() {
parse(getMethodName(), new StringReader(
- "enum Three1 {\n" +
- " ONE(1), TWO(2)\n\n" +
- " Three1(val) {\n" +
- " value = val\n" +
+ "enum E {\n" +
+ " X(1), Y(2)\n\n" +
+ " E(value) {\n" +
+ " this.value = value\n" +
" }\n\n" +
- " private final int value" +
- "}"));
+ " private final int value\n" +
+ "}\n")
+ );
}
public void testParseEnumWithValues2() {
parse(getMethodName(), new StringReader(
- "enum Three1 {\n" +
- " @Annotation ONE(1), TWO(2)\n\n" +
- " Three1(val) {\n" +
- " value = val\n" +
+ "enum E {\n" +
+ " @Annotation X(1), Y(2)\n\n" +
+ " E(value) {\n" +
+ " this.value = value\n" +
" }\n\n" +
- " private final int value" +
- "}"));
+ " private final int value\n" +
+ "}\n")
+ );
}
public void testParseEnumWithValues3() {
parse(getMethodName(), new StringReader(
- "enum NonFinal {\n" +
- " One(1), Two(2)\n" +
+ "enum E {\n" +
+ " X(1), Y(2)\n" +
" Object value\n" + // different parsing without leading keyword
- " NonFinal(value) {\n" +
+ " E(value) {\n" +
+ " this.value = value\n" +
+ " }\n" +
+ "}\n")
+ );
+ }
+
+ // GROOVY-9301
+ public void testParseEnumWithValues3a() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X(1), Y(2),\n" + // trailing comma
+ " Object value\n" +
+ " E(value) {\n" +
" this.value = value\n" +
" }\n" +
- "}\n"));
+ "}\n")
+ );
}
public void testParseEnumWithValues4() {
@@ -127,26 +150,55 @@ public final class EnumSourceParsingTest extends SourceParserTest {
" CLUBS(Color.BLACK),\n" +
" DIAMONDS(Color.RED),\n" +
" HEARTS(Color.RED),\n" +
- " SPADES(Color.BLACK),\n" +
+ " SPADES(Color.BLACK),\n" + // trailing comma
" \n" +
" final Color color\n" +
" Suit(Color color) {\n" +
" this.color = color\n" +
" }\n" +
- "}\n"));
+ "}\n")
+ );
}
- public void testParseEnumWithMethodDefinitions() {
+ public void testParseEnumWithMethodDefinitions1() {
parse(getMethodName(), new StringReader(
- "enum Four {\n" +
- " ONE, TWO, THREE\n\n" +
- " def someMethod() { }\n" +
+ "enum E {\n" +
+ " X, Y, Z\n\n" +
+ " def m1() { }\n" +
" public m2(args) { }\n" +
" int m3(String arg) { }\n" +
- "}"));
+ "}\n")
+ );
+ }
+
+ public void testParseEnumWithMethodDefinitions2() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n\n" +
+ " def <T> T m() { }\n" +
+ "}\n")
+ );
+ }
+
+ public void testParseEnumWithMethodDefinitions2a() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n\n" +
+ " final <T> T m() { }\n" +
+ "}\n")
+ );
}
- public void testParseEnumWithAnnotatedMethodDefinition() {
+ public void testParseEnumWithMethodDefinitions2b() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n\n" +
+ " public <T> T m() { }\n" +
+ "}\n")
+ );
+ }
+
+ public void testParseEnumWithAnnotatedMethodDefinition1() {
parse(getMethodName(), new StringReader(
"enum Orientation {\n" +
" LANDSCAPE, PORTRAIT\n" +
@@ -155,16 +207,138 @@ public final class EnumSourceParsingTest extends SourceParserTest {
" String toString() {\n" +
" name().toLowerCase().capitalize()\n" +
" }\n" +
- "}\n"));
+ "}\n")
+ );
+ }
+
+ // GROOVY-9301
+ public void testParseEnumWithAnnotatedMethodDefinition2() {
+ parse(getMethodName(), new StringReader(
+ "enum Orientation {\n" +
+ " LANDSCAPE, PORTRAIT,\n" + // trailing comma
+ " \n" +
+ " @Override\n" +
+ " String toString() {\n" +
+ " name().toLowerCase().capitalize()\n" +
+ " }\n" +
+ "}\n")
+ );
+ }
+
+ // GROOVY-9301
+ public void testParseEnumWithAnnotatedMethodDefinition3() {
+ parse(getMethodName(), new StringReader(
+ "enum Orientation {\n" +
+ " LANDSCAPE, PORTRAIT,\n" + // trailing comma
+ " \n" +
+ " @Deprecated <T> T whatever() {\n" +
+ " }\n" +
+ "}\n")
+ );
}
public void testParseCompleteEnum() {
parse(getMethodName(), new StringReader(
- "enum Five {\n" +
- " ONE { double eval(int v) { return (double) v } }, \n" +
- " TWO {\n" +
+ "enum E {\n" +
+ " X { double eval(int v) { return (double) v } }, \n" +
+ " Y {\n" +
" double eval(int v) { return (double) v + 1 }\n" +
- " }, THREE\n" +
- "}"));
+ " }, Z\n" +
+ "}")
+ );
+ }
+
+ public void testParseEnumWithInnerClass1() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n" +
+ " class C { }\n" +
+ "}\n")
+ );
+ }
+
+ // GROOVY-8507
+ public void testParseEnumWithInnerClass1a() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z,\n" + // trailing comma
+ " class C { }\n" +
+ "}\n")
+ );
+ }
+
+ public void testParseEnumWithInnerClass2() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n" +
+ " enum E2 { A, B, C }\n" +
+ "}\n")
+ );
+ }
+
+ // GROOVY-8507
+ public void testParseEnumWithInnerClass2a() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z,\n" + // trailing comma
+ " enum Another { A, B, C }\n" +
+ "}\n")
+ );
+ }
+
+ public void testParseEnumWithInnerClass3() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n" +
+ " interface I { }\n" +
+ "}\n")
+ );
+ }
+
+ // GROOVY-8507
+ public void testParseEnumWithInnerClass3a() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z,\n" + // trailing comma
+ " interface I { }\n" +
+ "}\n")
+ );
+ }
+
+ public void _FIXME_testParseEnumWithInnerClass4() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n" +
+ " @interface A { }\n" +
+ "}\n")
+ );
+ }
+
+ public void _FIXME_testParseEnumWithInnerClass4a() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z,\n" + // trailing comma
+ " @interface A { }\n" +
+ "}\n")
+ );
+ }
+
+ public void testParseEnumWithInnerClass5() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z\n" +
+ " trait T { }\n" +
+ "}\n")
+ );
+ }
+
+ // GROOVY-8507
+ public void testParseEnumWithInnerClass5a() {
+ parse(getMethodName(), new StringReader(
+ "enum E {\n" +
+ " X, Y, Z,\n" + // trailing comma
+ " trait T { }\n" +
+ "}\n")
+ );
}
}