You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2019/07/02 14:17:16 UTC

[groovy] 01/02: GROOVY-9184 (clone of GROOVY-4438): enumConstants: reduce ambiguity within loop (closes #940)

This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit c159feba2126d746a23cc57dbc50467b9331777a
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Jun 1 10:50:20 2019 -0500

    GROOVY-9184 (clone of GROOVY-4438): enumConstants: reduce ambiguity within loop (closes #940)
---
 src/main/antlr2/org/codehaus/groovy/antlr/groovy.g |  10 +-
 src/test/groovy/bugs/Groovy4438.groovy             |  50 ++++++
 .../groovy/antlr/EnumSourceParsingTest.java        | 179 +++++++++++++--------
 3 files changed, 166 insertions(+), 73 deletions(-)

diff --git a/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g b/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g
index 105059a..4458bc7 100644
--- a/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g
+++ b/src/main/antlr2/org/codehaus/groovy/antlr/groovy.g
@@ -1191,13 +1191,13 @@ enumConstantsStart
 enumConstants
     :
         enumConstant
-        (    options {generateAmbigWarnings=false;} :
-            (nls (SEMI! | RCURLY | classField)) => { break; /* leave ()* loop */ }
-        |   nls! COMMA!
-            (
+        ( options {generateAmbigWarnings=false;} :
+            (nls ( options {generateAmbigWarnings=false;} : SEMI! | RCURLY | declarationStart | constructorStart)) => {break;}
+        |
+            nls! COMMA! (
                 (nls annotationsOpt IDENT) => nls! enumConstant
             |
-                (nls (SEMI! | RCURLY | classField)) => { break; /* leave ()* loop */ }
+                (nls (RCURLY | classField)) => {break;}
             )
         )*
     ;
diff --git a/src/test/groovy/bugs/Groovy4438.groovy b/src/test/groovy/bugs/Groovy4438.groovy
new file mode 100644
index 0000000..9e3e3fc
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy4438.groovy
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package groovy.bugs
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+import static org.codehaus.groovy.control.ParserPluginFactory.antlr2
+
+@CompileStatic
+@RunWith(JUnit4)
+final class Groovy4438 {
+
+    @Test(timeout=1500L)
+    void testEnumWithinEnum() {
+        def config = new CompilerConfiguration(pluginFactory: antlr2())
+
+        new GroovyShell(config).evaluate('''\
+            enum Outer {
+                A, B
+                enum Inner {
+                    X, Y
+                }
+            }
+            assert Outer.A.name() == 'A'
+            assert Outer.A.ordinal() == 0
+            assert Outer.Inner.Y.name() == 'Y'
+            assert Outer.Inner.Y.ordinal() == 1
+        ''')
+    }
+}
diff --git a/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java b/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java
index ad0d23e..8a6d2a3 100644
--- a/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java
+++ b/src/test/org/codehaus/groovy/antlr/EnumSourceParsingTest.java
@@ -20,108 +20,151 @@ package org.codehaus.groovy.antlr;
 
 import java.io.StringReader;
 
-
 /**
  * Parser tests for Enum definitions.
  */
-public class EnumSourceParsingTest extends SourceParserTest {
+public final class EnumSourceParsingTest extends SourceParserTest {
+
     public void testParseEnumConstants() {
-        StringReader reader = new StringReader(
-                "enum One {\n"
-                        + "  ONE, TWO, THREE\n"
-                        + "}");
-        parse("testParseEnumConstants", reader);
+        parse(getMethodName(), new StringReader(
+            "enum E {\n" +
+            "    ONE, TWO, THREE\n" +
+            "}"));
     }
 
-    public void testParseEnumMultiLine() {
-      StringReader reader = new StringReader(
-          "enum ParseCode\n" +
-          "{\n" +
-          "    COMPLETE,\n" +
-          "    INCOMPLETE,\n" +
-          "    ERROR\n" +
-          "}");
-      parse("testParseEnumMultiLine", reader);
+    public void testParseEnumConstantsMultiLine() {
+        parse(getMethodName(), new StringReader(
+            "enum E {\n" +
+            "    ONE,\n" +
+            "    TWO,\n" +
+            "    THREE,\n" +
+            "}"));
+    }
+
+    public void testParseEnumConstantsMultiLine2() {
+        parse(getMethodName(), new StringReader(
+            "enum ParseCode\n" +
+            "{\n" +
+            "    COMPLETE,\n" +
+            "    INCOMPLETE,\n" +
+            "    ERROR\n" +
+            "}"));
     }
-    
+
     public void testParseEnumImplementsMultiLine() {
-        StringReader reader = new StringReader(
+        parse(getMethodName(), new StringReader(
             "enum ParseCode implements I\n" +
             "{\n" +
             "    COMPLETE,\n" +
             "    INCOMPLETE,\n" +
             "    ERROR\n" +
-            "}");
-        parse("testParseEnumImplementsMultiLine", reader);
+            "}"));
     }
-    
+
     public void testParseEnumImplementsMultiLine2() {
-        StringReader reader = new StringReader(
+        parse(getMethodName(), new StringReader(
             "enum ParseCode\n" +
             "implements I\n" +
             "{\n" +
             "    COMPLETE,\n" +
             "    INCOMPLETE,\n" +
             "    ERROR\n" +
-            "}");
-        parse("testParseEnumImplementsMultiLine2", reader);
+            "}"));
     }
-    
+
     public void testParseEnumConstantsOneLiner() {
-        StringReader reader = new StringReader(
-                "enum One { ONE, TWO, THREE }");
-        parse("testParseEnumConstantsOneLiner", reader);
+        parse(getMethodName(), new StringReader(
+            "enum One { ONE, TWO, THREE }"));
     }
 
     public void testParseEnumImplements() {
-        StringReader reader = new StringReader(
-                "enum Two implements I1 {\n"
-                        + "ONE, TWO, THREE\n"
-                        + "}");
-        parse("testParseEnumImplements", reader);
+        parse(getMethodName(), new StringReader(
+            "enum Two implements I1 {\n" +
+            "ONE, TWO, THREE\n" +
+            "}"));
     }
 
     public void testParseEnumWithValues() {
-        StringReader reader = new StringReader(
-                "enum Three1 {\n"
-                        + "    ONE(1), TWO(2)\n\n"
-                        + "    Three1(val) {\n"
-                        + "        value = val\n"
-                        + "    }\n\n"
-                        + "    private final int value"
-                        + "}");
-        parse("testParseEnumWithValues", reader);
-
-        reader = new StringReader(
-                "enum Three1 {\n"
-                        + "    @Annotation ONE(1), TWO(2)\n\n"
-                        + "    Three1(val) {\n"
-                        + "        value = val\n"
-                        + "    }\n\n"
-                        + "    private final int value"
-                        + "}");
-        parse("testParseEnumWithValues2", reader);
+        parse(getMethodName(), new StringReader(
+            "enum Three1 {\n" +
+            "    ONE(1), TWO(2)\n\n" +
+            "    Three1(val) {\n" +
+            "        value = val\n" +
+            "    }\n\n" +
+            "    private final int value" +
+            "}"));
+    }
+
+    public void testParseEnumWithValues2() {
+        parse(getMethodName(), new StringReader(
+            "enum Three1 {\n" +
+            "    @Annotation ONE(1), TWO(2)\n\n" +
+            "    Three1(val) {\n" +
+            "        value = val\n" +
+            "    }\n\n" +
+            "    private final int value" +
+            "}"));
+    }
+
+    public void testParseEnumWithValues3() {
+        parse(getMethodName(), new StringReader(
+            "enum NonFinal {\n" +
+            "    One(1), Two(2)\n" +
+            "    Object value\n" + // different parsing without leading keyword
+            "    NonFinal(value) {\n" +
+            "        this.value = value\n" +
+            "    }\n" +
+            "}\n"));
+    }
+
+    public void testParseEnumWithValues4() {
+        parse(getMethodName(), new StringReader(
+            "enum Color {\n" +
+            "    RED,\n" +
+            "    BLACK\n" +
+            "}\n" +
+            "enum Suit {\n" +
+            "    CLUBS(Color.BLACK),\n" +
+            "    DIAMONDS(Color.RED),\n" +
+            "    HEARTS(Color.RED),\n" +
+            "    SPADES(Color.BLACK),\n" +
+            "    \n" +
+            "    final Color color\n" +
+            "    Suit(Color color) {\n" +
+            "        this.color = color\n" +
+            "    }\n" +
+            "}\n"));
     }
 
     public void testParseEnumWithMethodDefinitions() {
-        StringReader reader = new StringReader(
-                "enum Four {\n"
-                        + "    ONE, TWO, THREE\n\n"
-                        + "    def someMethod() { }\n"
-                        + "    public m2(args) { }\n"
-                        + "    int m3(String arg) { }\n"
-                        + "}");
-        parse("testParseEnumWithMethodDefinitions", reader);
+        parse(getMethodName(), new StringReader(
+            "enum Four {\n" +
+            "    ONE, TWO, THREE\n\n" +
+            "    def someMethod() { }\n" +
+            "    public m2(args) { }\n" +
+            "    int m3(String arg) { }\n" +
+            "}"));
+    }
+
+    public void testParseEnumWithAnnotatedMethodDefinition() {
+        parse(getMethodName(), new StringReader(
+            "enum Orientation {\n" +
+            "    LANDSCAPE, PORTRAIT\n" +
+            "    \n" +
+            "    @Override\n" +
+            "    String toString() {\n" +
+            "        name().toLowerCase().capitalize()\n" +
+            "    }\n" +
+            "}\n"));
     }
 
     public void testParseCompleteEnum() {
-        StringReader reader = new StringReader(
-                "enum Five {\n"
-                        + "    ONE { double eval(int v) { return (double) v } }, \n"
-                        + "    TWO {\n"
-                        + "        double eval(int v) { return (double) v + 1 }\n"
-                        + "    }, THREE\n"
-                        + "}");
-        parse("testParseCompleteEnum", reader);
+        parse(getMethodName(), new StringReader(
+            "enum Five {\n" +
+            "    ONE { double eval(int v) { return (double) v } }, \n" +
+            "    TWO {\n" +
+            "        double eval(int v) { return (double) v + 1 }\n" +
+            "    }, THREE\n" +
+            "}"));
     }
 }