You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/02/23 09:33:23 UTC

[groovy] branch danielsun/tweak-classdecl-rule created (now fc1f360)

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

sunlan pushed a change to branch danielsun/tweak-classdecl-rule
in repository https://gitbox.apache.org/repos/asf/groovy.git.


      at fc1f360  Tweak rule `classDeclaration`

This branch includes the following new commits:

     new fc1f360  Tweak rule `classDeclaration`

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[groovy] 01/01: Tweak rule `classDeclaration`

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch danielsun/tweak-classdecl-rule
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit fc1f36041c95bba4dac6dfdededa9de8362ab190
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Feb 23 17:33:07 2020 +0800

    Tweak rule `classDeclaration`
---
 src/antlr/GroovyParser.g4                          |  35 +------
 .../apache/groovy/parser/antlr4/AstBuilder.java    |  53 +++++++++-
 .../groovy/parser/antlr4/SyntaxErrorTest.groovy    | 107 +++++++++++++++++++++
 3 files changed, 160 insertions(+), 35 deletions(-)

diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index f075237..ef6cd79 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -221,36 +221,11 @@ locals[ int t ]
         |   AT INTERFACE { $t = 3; }
         |   TRAIT { $t = 4; }
         )
-        identifier nls
-
-        (
-            { 3 != $t }?
-            (typeParameters nls)?
-            (
-                { 2 != $t }?
-                EXTENDS nls
-                    (
-                        // Only interface can extend more than one super class
-                        {1 == $t}? scs=typeList
-                    |
-                        sc=type
-                    )
-                nls
-            |
-                /* enum should not have type parameters and extends */
-            )
-
-            (
-                {1 != $t}?
-                IMPLEMENTS nls is=typeList nls
-            |
-                /* interface should not implement other interfaces */
-            )
-        |
-            /* annotation should not have implements and extends*/
-        )
-
-        classBody[$t]
+        identifier
+        (nls typeParameters)?
+        (nls EXTENDS nls scs=typeList)?
+        (nls IMPLEMENTS nls is=typeList)?
+        nls classBody[$t]
     ;
 
 // t    see the comment of classDeclaration
diff --git a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 9b2780e..82baee7 100644
--- a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -1082,6 +1082,39 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             throw createParsingFailedException("var cannot be used for type declarations", ctx.identifier());
         }
 
+        boolean isAnnotation = asBoolean(ctx.AT());
+        if (isAnnotation) {
+            if (asBoolean(ctx.typeParameters())) {
+                throw createParsingFailedException("annotation declaration cannot have type parameters", ctx.typeParameters());
+            }
+
+            if (asBoolean(ctx.EXTENDS())) {
+                throw createParsingFailedException("No extends clause allowed for annotation declaration", ctx.EXTENDS());
+            }
+
+            if (asBoolean(ctx.IMPLEMENTS())) {
+                throw createParsingFailedException("No implements clause allowed for annotation declaration", ctx.IMPLEMENTS());
+            }
+        }
+
+        boolean isEnum = asBoolean(ctx.ENUM());
+        if (isEnum) {
+            if (asBoolean(ctx.typeParameters())) {
+                throw createParsingFailedException("enum declaration cannot have type parameters", ctx.typeParameters());
+            }
+
+            if (asBoolean(ctx.EXTENDS())) {
+                throw createParsingFailedException("No extends clause allowed for enum declaration", ctx.EXTENDS());
+            }
+        }
+
+        boolean isInterface = (asBoolean(ctx.INTERFACE()) && !isAnnotation);
+        if (isInterface) {
+            if (asBoolean(ctx.IMPLEMENTS())) {
+                throw createParsingFailedException("No implements clause allowed for interface declaration", ctx.IMPLEMENTS());
+            }
+        }
+
         List<ModifierNode> modifierNodeList = ctx.getNodeMetaData(TYPE_DECLARATION_MODIFIERS);
         Objects.requireNonNull(modifierNodeList, "modifierNodeList should not be null");
         ModifierManager modifierManager = new ModifierManager(this, modifierNodeList);
@@ -1091,7 +1124,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         modifiers &= ~Opcodes.ACC_SYNTHETIC;
 
         ClassNode classNode, outerClass = classNodeStack.peek();
-        if (asBoolean(ctx.ENUM())) {
+
+        if (isEnum) {
             classNode = EnumHelper.makeEnumNode(
                     asBoolean(outerClass) ? className : packageName + className,
                     modifiers,
@@ -1117,7 +1151,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         configureAST(classNode, ctx);
         classNode.setSyntheticPublic(syntheticPublic);
         classNode.setGenericsTypes(this.visitTypeParameters(ctx.typeParameters()));
-        boolean isInterface = (asBoolean(ctx.INTERFACE()) && !asBoolean(ctx.AT()));
         boolean isInterfaceWithDefaultMethods = (isInterface && this.containsDefaultMethods(ctx));
 
         if (isInterfaceWithDefaultMethods || asBoolean(ctx.TRAIT())) {
@@ -1131,7 +1164,17 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         classNode.putNodeMetaData(CLASS_NAME, className);
 
         if (asBoolean(ctx.CLASS()) || asBoolean(ctx.TRAIT()) || isInterfaceWithDefaultMethods) {
-            classNode.setSuperClass(this.visitType(ctx.sc));
+            ClassNode superClass;
+            if (asBoolean(ctx.scs)) {
+                ClassNode[] scs = this.visitTypeList(ctx.scs);
+                if (scs.length > 1) {
+                    throw createParsingFailedException("Cannot extend multiple classes", ctx.EXTENDS());
+                }
+                superClass = scs[0];
+            } else {
+                superClass = ClassHelper.OBJECT_TYPE;
+            }
+            classNode.setSuperClass(superClass);
             classNode.setInterfaces(this.visitTypeList(ctx.is));
             this.initUsingGenerics(classNode);
 
@@ -1142,12 +1185,12 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             this.initUsingGenerics(classNode);
             this.hackMixins(classNode);
 
-        } else if (asBoolean(ctx.ENUM())) {
+        } else if (isEnum) {
             classNode.setModifiers(classNode.getModifiers() | Opcodes.ACC_ENUM | Opcodes.ACC_FINAL);
             classNode.setInterfaces(this.visitTypeList(ctx.is));
             this.initUsingGenerics(classNode);
 
-        } else if (asBoolean(ctx.AT())) {
+        } else if (isAnnotation) {
             classNode.setModifiers(classNode.getModifiers() | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_ANNOTATION);
             classNode.addInterface(ClassHelper.Annotation_TYPE);
             this.hackMixins(classNode);
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
index 98d2a1c..fc7cebd 100644
--- a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
@@ -284,6 +284,113 @@ test.groovy: 2: Missing ')' @ line 2, column 22.
 '''
     }
 
+
+    void "test groovy core - AnnotationDeclaration 1"() {
+        def err = expectFail '''\
+@interface A<T> {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: annotation declaration cannot have type parameters @ line 1, column 13.
+   @interface A<T> {}
+               ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - AnnotationDeclaration 2"() {
+        def err = expectFail '''\
+@interface A extends Object {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No extends clause allowed for annotation declaration @ line 1, column 14.
+   @interface A extends Object {}
+                ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - AnnotationDeclaration 3"() {
+        def err = expectFail '''\
+@interface A implements Serializable {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No implements clause allowed for annotation declaration @ line 1, column 14.
+   @interface A implements Serializable {}
+                ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - EnumDeclaration 1"() {
+        def err = expectFail '''\
+enum E<T> {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: enum declaration cannot have type parameters @ line 1, column 7.
+   enum E<T> {}
+         ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - EnumDeclaration 2"() {
+        def err = expectFail '''\
+enum E extends Object {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No extends clause allowed for enum declaration @ line 1, column 8.
+   enum E extends Object {}
+          ^
+
+1 error
+'''
+    }
+
+    void "test groovy core - InterfaceDeclaration 1"() {
+        def err = expectFail '''\
+interface I implements Serializable {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: No implements clause allowed for interface declaration @ line 1, column 13.
+   interface I implements Serializable {}
+               ^
+
+1 error
+'''
+    }
+
+    void "test test groovy core - ClassDeclaration 1"() {
+        def err = expectFail '''\
+class C extends Object, Number {}
+        '''
+
+        assert err == '''\
+startup failed:
+test.groovy: 1: Cannot extend multiple classes @ line 1, column 9.
+   class C extends Object, Number {}
+           ^
+
+1 error
+'''
+    }
+
+
     //--------------------------------------------------------------------------
     def expectFail(String code) {
         try {