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 2017/05/10 22:27:03 UTC
[35/50] [abbrv] groovy git commit: rename antlr4 parser to remove
groovy- prefix since that is by convention for modules
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..67a68f8
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/SyntaxErrorTest.groovy
@@ -0,0 +1,181 @@
+/*
+ * 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 org.apache.groovy.parser.antlr4
+
+import org.apache.groovy.parser.antlr4.util.ASTComparatorCategory
+
+/**
+ * Some syntax error test cases for the new parser
+ *
+ * @author <a href="mailto:realbluesun@hotmail.com">Daniel.Sun</a>
+ * Created on 2016/09/02
+ */
+class SyntaxErrorTest extends GroovyTestCase {
+ public static final String RESOURCES_PATH = 'src/test/resources';
+
+ void setUp() {}
+
+ void tearDown() {}
+
+ void "test groovy core - List"() {
+ TestUtils.shouldFail('fail/List_01.groovy');
+ }
+
+ void "test groovy core - Expression"() {
+ TestUtils.shouldFail('fail/Expression_01.groovy');
+ TestUtils.shouldFail('fail/Expression_02.groovy');
+ TestUtils.shouldFail('fail/Expression_03.groovy');
+// shouldFail('fail/Expression_04.groovy', true);
+// shouldFail('fail/Expression_05.groovy', true);
+ TestUtils.shouldFail('fail/Expression_06.groovy');
+ TestUtils.shouldFail('fail/Expression_07.groovy');
+ TestUtils.shouldFail('fail/Expression_08.groovy');
+ TestUtils.shouldFail('fail/Expression_09.groovy');
+ }
+
+ void "test groovy core - Switch"() {
+ TestUtils.shouldFail('fail/Switch_01.groovy');
+ }
+
+ void "test groovy core - LocalVariableDeclaration"() {
+ TestUtils.shouldFail('fail/LocalVariableDeclaration_01.groovy');
+ }
+
+ void "test groovy core - Continue"() {
+ TestUtils.doRunAndShouldFail('fail/Continue_01x.groovy');
+ TestUtils.doRunAndShouldFail('fail/Continue_02x.groovy');
+ }
+
+ void "test groovy core - Break"() {
+ TestUtils.doRunAndShouldFail('fail/Break_01x.groovy');
+ TestUtils.doRunAndShouldFail('fail/Break_02x.groovy');
+ }
+
+ void "test groovy core - UnexpectedCharacter"() {
+ TestUtils.doRunAndShouldFail('fail/UnexpectedCharacter_01x.groovy');
+ }
+
+// void "test CompilerErrorTest_001.groovy"() {
+// unzipScriptAndShouldFail("scripts/CompilerErrorTest_001.groovy", [])
+// }
+
+// void "test CompilerErrorTest_002.groovy"() {
+// unzipScriptAndShouldFail("scripts/CompilerErrorTest_002.groovy", [])
+// }
+
+// void "test DifferencesFromJavaTest_002.groovy"() {
+// unzipScriptAndShouldFail("scripts/DifferencesFromJavaTest_002.groovy", [])
+// }
+
+// void "test Groovy5212Bug_001.groovy"() {
+// unzipScriptAndShouldFail("scripts/Groovy5212Bug_001.groovy", [])
+// }
+
+// void "test GStringEndTest_001.groovy"() {
+// unzipScriptAndShouldFail("scripts/GStringEndTest_001.groovy", [])
+// }
+
+ void "test groovy core - ParExpression"() {
+ TestUtils.doRunAndShouldFail('fail/ParExpression_01x.groovy');
+ TestUtils.doRunAndShouldFail('fail/ParExpression_02x.groovy');
+ TestUtils.doRunAndShouldFail('fail/ParExpression_03x.groovy');
+ }
+
+ void "test groovy core - Parentheses"() {
+ TestUtils.shouldFail('fail/Parentheses_01.groovy');
+ }
+
+ void "test groovy core - This"() {
+ TestUtils.doRunAndShouldFail('fail/This_01x.groovy');
+ }
+
+ void "test groovy core - Super"() {
+ TestUtils.doRunAndShouldFail('fail/Super_01x.groovy');
+ }
+
+ void "test groovy core - AbstractMethod"() {
+ TestUtils.doRunAndShouldFail('fail/AbstractMethod_01x.groovy');
+ TestUtils.doRunAndShouldFail('fail/AbstractMethod_02x.groovy');
+ TestUtils.doRunAndShouldFail('fail/AbstractMethod_03x.groovy');
+ TestUtils.doRunAndShouldFail('fail/AbstractMethod_04x.groovy');
+ TestUtils.doRunAndShouldFail('fail/AbstractMethod_05x.groovy');
+ TestUtils.doRunAndShouldFail('fail/AbstractMethod_06x.groovy');
+ }
+
+ void "test groovy core - BUGs"() {
+ TestUtils.doRunAndShouldFail('bugs/BUG-GROOVY-5318.groovy');
+ TestUtils.doRunAndShouldFail('bugs/BUG-GROOVY-8150.groovy');
+ }
+
+ void "test groovy core - DoWhile"() {
+ TestUtils.doRunAndShouldFail('fail/DoWhile_01x.groovy');
+ }
+
+ void "test groovy core - For"() {
+ TestUtils.shouldFail('fail/For_01.groovy');
+ TestUtils.shouldFail('fail/For_02.groovy');
+ }
+
+ void "test groovy core - Modifier"() {
+ TestUtils.doRunAndShouldFail('fail/Modifier_01x.groovy');
+ TestUtils.doRunAndShouldFail('fail/Modifier_02x.groovy');
+ TestUtils.doRunAndShouldFail('fail/Modifier_03x.groovy');
+ TestUtils.doRunAndShouldFail('fail/Modifier_04x.groovy');
+ TestUtils.doRunAndShouldFail('fail/Modifier_05x.groovy');
+ TestUtils.shouldFail('fail/Modifier_07.groovy');
+ }
+
+ void "test groovy core - ClassDeclaration"() {
+ TestUtils.doRunAndShouldFail('fail/ClassDeclaration_01x.groovy');
+ }
+
+ void "test groovy core - MethodDeclaration"() {
+ TestUtils.shouldFail('fail/MethodDeclaration_01.groovy');
+ }
+
+ void "test groovy core - ConstructorDeclaration"() {
+ TestUtils.shouldFail('fail/ConstructorDeclaration_01.groovy');
+ }
+
+ void "test groovy core - ClosureListExpression"() {
+ TestUtils.shouldFail('fail/ClosureListExpression_01.groovy');
+ TestUtils.shouldFail('fail/ClosureListExpression_02.groovy');
+ TestUtils.shouldFail('fail/ClosureListExpression_03.groovy');
+ TestUtils.shouldFail('fail/ClosureListExpression_04.groovy');
+ }
+
+ void "test groovy core - InterfaceDeclaration"() {
+ TestUtils.shouldFail('fail/InterfaceDeclaration_01.groovy');
+ }
+
+ void "test groovy core - void"() {
+ TestUtils.doRunAndShouldFail('fail/Void_01x.groovy');
+ TestUtils.doRunAndShouldFail('fail/Void_02x.groovy');
+ }
+
+
+ /**************************************/
+ static unzipScriptAndShouldFail(String entryName, List ignoreClazzList, Map<String, String> replacementsMap=[:], boolean toCheckNewParserOnly = false) {
+ ignoreClazzList.addAll(TestUtils.COMMON_IGNORE_CLASS_LIST)
+
+ TestUtils.unzipAndFail(SCRIPT_ZIP_PATH, entryName, TestUtils.addIgnore(ignoreClazzList, ASTComparatorCategory.LOCATION_IGNORE_LIST), replacementsMap, toCheckNewParserOnly)
+ }
+
+ public static final String SCRIPT_ZIP_PATH = "$TestUtils.RESOURCES_PATH/groovy-2.5.0/groovy-2.5.0-SNAPSHOT-20160921-allscripts.zip";
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/TestUtils.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/TestUtils.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/TestUtils.groovy
new file mode 100644
index 0000000..a82966f
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/TestUtils.groovy
@@ -0,0 +1,259 @@
+/*
+ * 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 org.apache.groovy.parser.antlr4
+
+import groovy.util.logging.Log
+import org.apache.groovy.parser.AbstractParser
+import org.apache.groovy.parser.Antlr2Parser
+import org.apache.groovy.parser.Antlr4Parser
+import org.apache.groovy.parser.antlr4.util.ASTComparatorCategory
+import org.apache.groovy.parser.antlr4.util.AstDumper
+import org.codehaus.groovy.ast.*
+import org.codehaus.groovy.ast.stmt.*
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.syntax.Token
+
+import java.util.zip.ZipEntry
+import java.util.zip.ZipFile
+
+/**
+ * Utilities for test
+ *
+ * @author <a href="mailto:realbluesun@hotmail.com">Daniel.Sun</a>
+ * Created on 2016/09/21
+ */
+
+@Log
+class TestUtils {
+ public static final String DEFAULT_RESOURCES_PATH = 'subprojects/parser-antlr4/src/test/resources';
+ public static final String RESOURCES_PATH = new File(DEFAULT_RESOURCES_PATH).exists() ? DEFAULT_RESOURCES_PATH : 'src/test/resources';
+
+ static doTest(String path) {
+ return doTest(path, ASTComparatorCategory.DEFAULT_CONFIGURATION)
+ }
+
+ static doTest(String path, List ignoreClazzList) {
+ return doTest(path, addIgnore(ignoreClazzList, ASTComparatorCategory.LOCATION_IGNORE_LIST))
+ }
+
+ static doTest(String path, conf) {
+ AbstractParser antlr4Parser = new Antlr4Parser()
+ AbstractParser antlr2Parser = new Antlr2Parser()
+
+ File file = new File("$RESOURCES_PATH/$path");
+ def (newAST, newElapsedTime) = profile { antlr4Parser.parse(file) }
+ def (oldAST, oldElapsedTime) = profile { antlr2Parser.parse(file) }
+
+
+ assertAST(newAST, oldAST, conf);
+
+ long diffInMillis = newElapsedTime - oldElapsedTime;
+
+ if (diffInMillis >= 500) {
+ log.warning "${path}\t\t\t\t\tdiff:${diffInMillis / 1000}s,\tnew:${newElapsedTime / 1000}s,\told:${oldElapsedTime / 1000}s."
+ }
+
+ return [newAST, oldAST]
+ }
+
+ /*
+ static unzipAndTest(String path, String entryName) {
+ unzipAndTest(path, entryName, ASTComparatorCategory.DEFAULT_CONFIGURATION)
+ }
+ */
+
+ /*
+ static unzipAndTest(String path, String entryName, List ignoreClazzList) {
+ unzipAndTest(path, entryName, addIgnore(ignoreClazzList, ASTComparatorCategory.LOCATION_IGNORE_LIST))
+ }
+ */
+
+ static unzipAndTest(String path, String entryName, conf, Map<String, String> replacementsMap=[:]) {
+ AbstractParser antlr4Parser = new Antlr4Parser()
+ AbstractParser antlr2Parser = new Antlr2Parser()
+
+ String name = "$path!$entryName";
+ String text = readZipEntry(path, entryName);
+
+ replacementsMap?.each {k, v ->
+ text = text.replace(k, v);
+ }
+
+ def (newAST, newElapsedTime) = profile { antlr4Parser.parse(name, text) }
+ def (oldAST, oldElapsedTime) = profile { antlr2Parser.parse(name, text) }
+
+
+ assertAST(newAST, oldAST, conf);
+
+ long diffInMillis = newElapsedTime - oldElapsedTime;
+
+ if (diffInMillis >= 500) {
+ log.warning "${path}!${entryName}\t\t\t\t\tdiff:${diffInMillis / 1000}s,\tnew:${newElapsedTime / 1000}s,\told:${oldElapsedTime / 1000}s."
+ }
+ }
+
+
+ static shouldFail(String path, boolean toCheckNewParserOnly = false) {
+ shouldFail(path, ASTComparatorCategory.DEFAULT_CONFIGURATION, toCheckNewParserOnly)
+ }
+
+ static shouldFail(String path, List ignoreClazzList, boolean toCheckNewParserOnly = false) {
+ shouldFail(path, addIgnore(ignoreClazzList, ASTComparatorCategory.LOCATION_IGNORE_LIST), toCheckNewParserOnly)
+ }
+
+ static shouldFail(String path, conf, boolean toCheckNewParserOnly = false) {
+ AbstractParser antlr4Parser = new Antlr4Parser()
+ AbstractParser antlr2Parser = new Antlr2Parser()
+
+ File file = new File("$RESOURCES_PATH/$path");
+ def (newAST, newElapsedTime) = profile { antlr4Parser.parse(file) }
+ def (oldAST, oldElapsedTime) = profile { antlr2Parser.parse(file) }
+
+ if (toCheckNewParserOnly) {
+ assert (newAST == null || newAST.context.errorCollector.hasErrors())
+ } else {
+ assert (newAST == null || newAST.context.errorCollector.hasErrors()) &&
+ (oldAST == null || oldAST.context.errorCollector.hasErrors())
+ }
+
+ long diffInMillis = newElapsedTime - oldElapsedTime;
+
+ if (diffInMillis >= 500) {
+ log.warning "${path}\t\t\t\t\tdiff:${diffInMillis / 1000}s,\tnew:${newElapsedTime / 1000}s,\told:${oldElapsedTime / 1000}s."
+ }
+ }
+
+ static unzipAndFail(String path, String entryName, conf, Map<String, String> replacementsMap=[:], boolean toCheckNewParserOnly = false) {
+ AbstractParser antlr4Parser = new Antlr4Parser()
+ AbstractParser antlr2Parser = new Antlr2Parser()
+
+ String name = "$path!$entryName";
+ String text = readZipEntry(path, entryName);
+
+ replacementsMap?.each {k, v ->
+ text = text.replace(k, v);
+ }
+
+ def (newAST, newElapsedTime) = profile { antlr4Parser.parse(name, text) }
+ def (oldAST, oldElapsedTime) = profile { antlr2Parser.parse(name, text) }
+
+ if (toCheckNewParserOnly) {
+ assert (newAST == null || newAST.context.errorCollector.hasErrors())
+ } else {
+ assert (newAST == null || newAST.context.errorCollector.hasErrors()) &&
+ (oldAST == null || oldAST.context.errorCollector.hasErrors())
+ }
+
+ long diffInMillis = newElapsedTime - oldElapsedTime;
+
+ if (diffInMillis >= 500) {
+ log.warning "${path}!${entryName}\t\t\t\t\tdiff:${diffInMillis / 1000}s,\tnew:${newElapsedTime / 1000}s,\told:${oldElapsedTime / 1000}s."
+ }
+ }
+
+
+ static assertAST(ast1, ast2, conf) {
+ assert null != ast1 && null != ast2
+
+ ASTComparatorCategory.apply(conf) {
+ assert ast1 == ast2
+ }
+
+ assert genSrc(ast1) == genSrc(ast2)
+ }
+
+ static genSrc(ModuleNode ast) {
+ return new AstDumper(ast).gen();
+ }
+
+ static profile(Closure c) {
+ long begin = System.currentTimeMillis()
+ def result = c.call()
+ long end = System.currentTimeMillis()
+
+ return [result, end - begin];
+ }
+
+ static addIgnore(Class aClass, ArrayList<String> ignore, Map<Class, List<String>> c = null) {
+ c = c ?: ASTComparatorCategory.DEFAULT_CONFIGURATION.clone() as Map<Class, List<String>>;
+ c[aClass].addAll(ignore)
+ return c
+ }
+
+ static addIgnore(Collection<Class> aClass, ArrayList<String> ignore, Map<Class, List<String>> c = null) {
+ c = c ?: ASTComparatorCategory.DEFAULT_CONFIGURATION.clone() as Map<Class, List<String>>;
+ aClass.each { c[it].addAll(ignore) }
+ return c
+ }
+
+ static readZipEntry(String path, String entryName) {
+ String result = "";
+
+ def zf = new ZipFile(new File(path));
+ try {
+ def is = new BufferedInputStream(zf.getInputStream(new ZipEntry(entryName)));
+ result = is.getText("UTF-8");
+ } catch (Exception e) {
+ log.severe(e.message);
+ } finally {
+ try {
+ zf.close();
+ } catch(Exception e) {
+ // IGNORED
+ }
+ }
+
+ return result;
+ }
+
+ static doRunAndShouldFail(String path) {
+ assert !executeScript(path);
+ }
+
+ static doRunAndTest(String path) {
+ assert executeScript(path);
+ }
+
+ static executeScript(String path) {
+ executeScript(createAntlr4Shell(), "$RESOURCES_PATH/$path")
+ }
+
+ static executeScript(gsh, String path) {
+ def file = new File(path);
+ def content = file.text;
+
+ try {
+ gsh.evaluate(content);
+// log.info("Evaluated $file")
+ return true;
+ } catch (Throwable t) {
+ log.severe("Failed $file: ${t.getMessage()}");
+ return false;
+ }
+ }
+
+ static createAntlr4Shell() {
+ CompilerConfiguration configuration = new CompilerConfiguration(CompilerConfiguration.DEFAULT)
+ configuration.pluginFactory = new Antlr4PluginFactory()
+
+ return new GroovyShell(configuration);
+ }
+
+ public static final List COMMON_IGNORE_CLASS_LIST = Collections.unmodifiableList([AssertStatement, BreakStatement, ConstructorNode, ContinueStatement, ExpressionStatement, FieldNode, ForStatement, GenericsType, IfStatement, MethodNode, PackageNode, Parameter, PropertyNode, ReturnStatement, ThrowStatement, Token, WhileStatement]);
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
new file mode 100644
index 0000000..47b9507
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
@@ -0,0 +1,526 @@
+/*
+ * 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 org.apache.groovy.parser.antlr4.util
+
+import groovy.util.logging.Log
+import org.codehaus.groovy.ast.*
+import org.codehaus.groovy.ast.expr.*
+import org.codehaus.groovy.ast.stmt.*
+import org.codehaus.groovy.syntax.Token
+
+import java.util.logging.Level
+
+@Log @SuppressWarnings("GroovyUnusedDeclaration")
+class ASTComparatorCategory {
+ static { log.level = Level.WARNING }
+ static List<String> LOCATION_IGNORE_LIST = ["columnNumber", "lineNumber", "lastColumnNumber", "lastLineNumber", "startLine"]
+ static private List<String> EXPRESSION_IGNORE_LIST = ["text"] + LOCATION_IGNORE_LIST
+
+ /**
+ * Keeps all checked object pairs and their comparison result.
+ * Will be cleared at {@link #apply(groovy.lang.Closure)} method }
+ */
+ static objects = [:] as Map<List<Object>, Boolean>
+ static String lastName
+
+ static Map<Class, List<String>> DEFAULT_CONFIGURATION = [
+ (ClassNode): (['module', "declaredMethodsMap", "plainNodeReference", "typeClass", "allInterfaces", "orAddStaticConstructorNode", "allDeclaredMethods", "unresolvedSuperClass", "innerClasses" ] + LOCATION_IGNORE_LIST) as List<String>,
+ (ConstructorNode): ['declaringClass'],
+ (DynamicVariable): [],
+ (EnumConstantClassNode): ["typeClass"],
+ (FieldNode): ["owner", "declaringClass", "initialValueExpression", "assignToken"],
+ (GenericsType): [],
+ (ImportNode): LOCATION_IGNORE_LIST,
+ (InnerClassNode): (['module', "declaredMethodsMap", "plainNodeReference", "typeClass", "allInterfaces", "orAddStaticConstructorNode", "allDeclaredMethods", "unresolvedSuperClass", "innerClasses" ] + LOCATION_IGNORE_LIST) as List<String>,
+ (InterfaceHelperClassNode): [],
+ (MethodNode): ["text", "declaringClass"],
+ (MixinNode): [],
+ (ModuleNode): ["context"],
+ (PackageNode): [],
+ (Parameter): [],
+ (PropertyNode): ['declaringClass', 'initialValueExpression', "assignToken"],
+ (Variable): [],
+ (VariableScope): ["clazzScope", "parent", "declaredVariablesIterator"],
+ (Token): ["root", "startColumn"],
+ (AnnotationNode): (["text"] + LOCATION_IGNORE_LIST) as List<String>,
+ (AssertStatement): ["text"],
+ (BlockStatement): ["columnNumber", "lineNumber", "lastColumnNumber", "lastLineNumber", "text"],
+ (BreakStatement): ["text"],
+ (CaseStatement): ["text"],
+ (CatchStatement): (["text"] + LOCATION_IGNORE_LIST) as List<String>,
+ (ContinueStatement): ["text"],
+ (DoWhileStatement): ["text"],
+ (EmptyStatement): ["text"],
+ (ExpressionStatement): ["text"],
+ (ForStatement): ["text"],
+ (IfStatement): ["text"],
+ (LoopingStatement): ["text"],
+ (ReturnStatement): ["text"],
+ (SwitchStatement): ["columnNumber", "lineNumber", "lastColumnNumber", "lastLineNumber", "text"],
+ (SynchronizedStatement): ["text"],
+ (ThrowStatement): ["text"],
+ (TryCatchStatement): (["text"] + LOCATION_IGNORE_LIST) as List<String>,
+ (WhileStatement): ["text"],
+ (AnnotationConstantExpression): EXPRESSION_IGNORE_LIST,
+ (ArgumentListExpression): EXPRESSION_IGNORE_LIST,
+ (ArrayExpression): EXPRESSION_IGNORE_LIST,
+ (AttributeExpression): EXPRESSION_IGNORE_LIST,
+ (BinaryExpression): EXPRESSION_IGNORE_LIST,
+ (BitwiseNegationExpression): EXPRESSION_IGNORE_LIST,
+ (BooleanExpression): EXPRESSION_IGNORE_LIST,
+ (CastExpression): EXPRESSION_IGNORE_LIST,
+ (ClassExpression): EXPRESSION_IGNORE_LIST,
+ (ClosureExpression): EXPRESSION_IGNORE_LIST,
+ (ClosureListExpression): EXPRESSION_IGNORE_LIST,
+ (ConstantExpression): EXPRESSION_IGNORE_LIST,
+ (ConstructorCallExpression): EXPRESSION_IGNORE_LIST,
+ (DeclarationExpression): ["text", "columnNumber", "lineNumber", "lastColumnNumber", "lastLineNumber"],
+ (ElvisOperatorExpression): EXPRESSION_IGNORE_LIST,
+ (EmptyExpression): EXPRESSION_IGNORE_LIST,
+ (ExpressionTransformer): EXPRESSION_IGNORE_LIST,
+ (FieldExpression): EXPRESSION_IGNORE_LIST,
+ (GStringExpression): EXPRESSION_IGNORE_LIST,
+ (ListExpression): EXPRESSION_IGNORE_LIST,
+ (MapEntryExpression): EXPRESSION_IGNORE_LIST,
+ (MapExpression): EXPRESSION_IGNORE_LIST,
+ (MethodCall): EXPRESSION_IGNORE_LIST,
+ (MethodCallExpression): EXPRESSION_IGNORE_LIST,
+ (MethodPointerExpression): EXPRESSION_IGNORE_LIST,
+ (NamedArgumentListExpression): EXPRESSION_IGNORE_LIST,
+ (NotExpression): EXPRESSION_IGNORE_LIST,
+ (PostfixExpression): EXPRESSION_IGNORE_LIST,
+ (PrefixExpression): EXPRESSION_IGNORE_LIST,
+ (PropertyExpression): EXPRESSION_IGNORE_LIST,
+ (RangeExpression): EXPRESSION_IGNORE_LIST,
+ (SpreadExpression): EXPRESSION_IGNORE_LIST,
+ (SpreadMapExpression): EXPRESSION_IGNORE_LIST,
+ (StaticMethodCallExpression): EXPRESSION_IGNORE_LIST,
+ (TernaryExpression): EXPRESSION_IGNORE_LIST,
+ (TupleExpression): EXPRESSION_IGNORE_LIST,
+ (UnaryMinusExpression): EXPRESSION_IGNORE_LIST,
+ (UnaryPlusExpression): EXPRESSION_IGNORE_LIST,
+ (VariableExpression): EXPRESSION_IGNORE_LIST,
+ ];
+
+ static Map<Class, List<String>> COLLECTION_PROPERTY_CONFIGURATION = [
+ (ModuleNode): ["classes", "name"]
+ ]
+
+ static Map<Class, List<String>> configuration = DEFAULT_CONFIGURATION;
+
+ static void apply(config = DEFAULT_CONFIGURATION, Closure cl) {
+ configuration = config
+ objects.clear()
+ use(ASTComparatorCategory, cl)
+ configuration = DEFAULT_CONFIGURATION
+ }
+
+ /**
+ * Main method that makes the magic. Compares all properties for object a and object b.
+ * There is a lot of problems in this code, like omitted class checking and so on. Just belive, it will be used properly.
+ * @param a
+ * @param b
+ * @return
+ */
+ static reflexiveEquals(a, b, ignore = []) {
+
+ if (a.getClass() != b.getClass()) {
+ log.warning(" !!!! DIFFERENCE WAS FOUND! ${a.getClass()} != ${b.getClass()}")
+ return false;
+ }
+
+ def objects = [a, b]
+ Boolean res = this.objects[objects]
+ if (res != null) {
+ log.info("Skipping [$a, $b] comparison as they are ${ res ? "" : "un" }equal.")
+ return res;
+ }
+ else if (this.objects.containsKey(objects)) {
+ log.info("Skipping as they are processed at higher levels.")
+ return true
+ }
+
+ this.objects[objects] = null
+ log.info("Equals was called for ${ a.getClass() } ${ a.hashCode() }, $lastName")
+ if (a.is(b))
+ return true
+
+ def difference = a.metaClass.properties.find { MetaBeanProperty p ->
+ if (!p.getter)
+ return false
+
+ def name = p.name
+ lastName = "$name :::: ${ a.getClass() } ${ a.hashCode() }"
+
+
+ for (Map.Entry<Class, List<String>> me : COLLECTION_PROPERTY_CONFIGURATION) {
+ if (!(me.key.isCase(a) && me.key.isCase(b))) {
+ continue;
+ }
+
+ String propName = me.value[0];
+
+ if (name != propName) {
+ continue;
+ }
+
+ def aValue = a."${propName}"; // FIXME when the propName is "classes", a classNode will be added to moduleNode.classes
+ def bValue = b."${propName}";
+
+ String orderName = me.value[1];
+
+ return new LinkedList(aValue?.getClass()?.isArray() ? Arrays.asList(aValue) : (aValue ?: [])).sort {c1, c2 -> c1."${orderName}" <=> c2."${orderName}"} !=
+ new LinkedList(bValue?.getClass()?.isArray() ? Arrays.asList(bValue) : (bValue ?: [])).sort {c1, c2 -> c1."${orderName}" <=> c2."${orderName}"}
+ }
+
+
+ !(name in ignore) && (name != 'nodeMetaData' && name != 'metaDataMap') && a."$name" != b."$name"
+ }
+
+ if (difference)
+ log.warning(" !!!! DIFFERENCE WAS FOUND! [${a.metaClass.hasProperty(a, 'text') ? a.text : '<NO TEXT>'}][${a.class}][${difference.name}]:: ${ a."$difference.name" } != ${ b."$difference.name" }")
+ else
+ log.info(" ==== Exit ${ a.getClass() } ${ a.hashCode() } ====== ")
+
+ res = difference == null
+ this.objects[objects] = res
+ this.objects[objects.reverse(false)] = res
+ res
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Just a bunch of copypasted methods. Maybe will wrote AST transformation for them.
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ static equals(ClassNode a, ClassNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ConstructorNode a, ConstructorNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(DynamicVariable a, DynamicVariable b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(EnumConstantClassNode a, EnumConstantClassNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(FieldNode a, FieldNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(GenericsType a, GenericsType b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ImportNode a, ImportNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(InnerClassNode a, InnerClassNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(InterfaceHelperClassNode a, InterfaceHelperClassNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(MethodNode a, MethodNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(MixinNode a, MixinNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ModuleNode a, ModuleNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(PackageNode a, PackageNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(Parameter a, Parameter b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(PropertyNode a, PropertyNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(Variable a, Variable b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(VariableScope a, VariableScope b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(Token a, Token b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(CompileUnit a, CompileUnit b) {
+ true
+ }
+
+ static equals(AnnotationNode a, AnnotationNode b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Statements
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ static equals(AssertStatement a, AssertStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(BlockStatement a, BlockStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(BreakStatement a, BreakStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(CaseStatement a, CaseStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(CatchStatement a, CatchStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ContinueStatement a, ContinueStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(DoWhileStatement a, DoWhileStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(EmptyStatement a, EmptyStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ExpressionStatement a, ExpressionStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ForStatement a, ForStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(IfStatement a, IfStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(LoopingStatement a, LoopingStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ReturnStatement a, ReturnStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(SwitchStatement a, SwitchStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(SynchronizedStatement a, SynchronizedStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ThrowStatement a, ThrowStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(TryCatchStatement a, TryCatchStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(WhileStatement a, WhileStatement b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ /////////////////////////////////////////////////////////////////////////////////////////////
+ // Expressions
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+ static equals(AnnotationConstantExpression a, AnnotationConstantExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ArgumentListExpression a, ArgumentListExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ArrayExpression a, ArrayExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(AttributeExpression a, AttributeExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(BinaryExpression a, BinaryExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(BitwiseNegationExpression a, BitwiseNegationExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(BooleanExpression a, BooleanExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(CastExpression a, CastExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ClassExpression a, ClassExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ClosureExpression a, ClosureExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ClosureListExpression a, ClosureListExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ConstantExpression a, ConstantExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ConstructorCallExpression a, ConstructorCallExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(DeclarationExpression a, DeclarationExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ElvisOperatorExpression a, ElvisOperatorExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(EmptyExpression a, EmptyExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ExpressionTransformer a, ExpressionTransformer b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(FieldExpression a, FieldExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(GStringExpression a, GStringExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(ListExpression a, ListExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(MapEntryExpression a, MapEntryExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(MapExpression a, MapExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(MethodCall a, MethodCall b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(MethodCallExpression a, MethodCallExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(MethodPointerExpression a, MethodPointerExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(NamedArgumentListExpression a, NamedArgumentListExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(NotExpression a, NotExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(PostfixExpression a, PostfixExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(PrefixExpression a, PrefixExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(PropertyExpression a, PropertyExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(RangeExpression a, RangeExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(SpreadExpression a, SpreadExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(SpreadMapExpression a, SpreadMapExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(StaticMethodCallExpression a, StaticMethodCallExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(TernaryExpression a, TernaryExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(TupleExpression a, TupleExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(UnaryMinusExpression a, UnaryMinusExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(UnaryPlusExpression a, UnaryPlusExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+
+ static equals(VariableExpression a, VariableExpression b) {
+ reflexiveEquals(a, b, configuration[a.class])
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
new file mode 100644
index 0000000..72a64e5
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
@@ -0,0 +1,1025 @@
+/*
+ * 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 org.apache.groovy.parser.antlr4.util
+
+import org.codehaus.groovy.ast.*
+import org.codehaus.groovy.ast.expr.*
+import org.codehaus.groovy.ast.stmt.*
+import org.codehaus.groovy.classgen.BytecodeExpression
+import org.codehaus.groovy.classgen.GeneratorContext
+import org.codehaus.groovy.classgen.Verifier
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.control.io.ReaderSource
+
+import java.lang.reflect.Modifier
+
+/**
+ * Generate the groovy source according to the AST.
+ * It is useful to verify the equality of new and old parser.
+ *
+ * @author <a href="mailto:realbluesun@hotmail.com">Daniel.Sun</a>
+ * Created on 2016/08/16
+ */
+class AstDumper {
+ private ModuleNode ast;
+
+ public AstDumper(ModuleNode ast) {
+ this.ast = ast;
+ }
+
+ /**
+ * Generate the groovy source code according the AST
+ *
+ * @return the groovy source code
+ */
+ public String gen() {
+ StringWriter out = new StringWriter();
+
+ try {
+ AstNodeToScriptVisitor visitor = new AstNodeToScriptVisitor(out, true, true);
+
+ new LinkedList<ClassNode>(this.ast?.classes ?: []).sort { c1, c2 -> c1.name <=> c2.name }?.each {
+ visitor.call(new SourceUnit((String) null, (ReaderSource) null, null, null, null) {
+ @Override
+ public ModuleNode getAST() {
+ return AstDumper.this.ast;
+ }
+ }, null, it)
+ }
+
+ return out.toString().replaceAll(/([\w_$]+)@[0-9a-z]+/, '$1@<hashcode>');
+ } finally {
+ out.close();
+ }
+ }
+}
+
+/**
+ * *****************************************************
+ * In order to solve the "Egg & Chicken" problem,
+ * we have to copy the source code(instead of invoking it): subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstNodeToScriptAdapter.groovy
+ * *****************************************************
+ *
+ *
+ * An adapter from ASTNode tree to source code.
+ *
+ * @author Hamlet D'Arcy
+ */
+class AstNodeToScriptVisitor extends CompilationUnit.PrimaryClassNodeOperation implements GroovyCodeVisitor, GroovyClassVisitor {
+
+ private final Writer _out
+ Stack<String> classNameStack = new Stack<String>()
+ String _indent = ''
+ boolean readyToIndent = true
+ boolean showScriptFreeForm
+ boolean showScriptClass
+ boolean scriptHasBeenVisited
+
+ def AstNodeToScriptVisitor(Writer writer, boolean showScriptFreeForm = true, boolean showScriptClass = true) {
+ this._out = writer
+ this.showScriptFreeForm = showScriptFreeForm
+ this.showScriptClass = showScriptClass
+ this.scriptHasBeenVisited = false
+ }
+
+ void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+
+ visitPackage(source?.getAST()?.getPackage())
+
+ visitAllImports(source)
+
+ if (showScriptFreeForm && !scriptHasBeenVisited) {
+ scriptHasBeenVisited = true
+ source?.getAST()?.getStatementBlock()?.visit(this)
+ }
+ if (showScriptClass || !classNode.isScript()) {
+ visitClass classNode
+ }
+ }
+
+ private def visitAllImports(SourceUnit source) {
+ boolean staticImportsPresent = false
+ boolean importsPresent = false
+
+ source?.getAST()?.getStaticImports()?.values()?.each {
+ visitImport(it)
+ staticImportsPresent = true
+ }
+ source?.getAST()?.getStaticStarImports()?.values()?.each {
+ visitImport(it)
+ staticImportsPresent = true
+ }
+
+ if (staticImportsPresent) {
+ printDoubleBreak()
+ }
+
+ source?.getAST()?.getImports()?.each {
+ visitImport(it)
+ importsPresent = true
+ }
+ source?.getAST()?.getStarImports()?.each {
+ visitImport(it)
+ importsPresent = true
+ }
+ if (importsPresent) {
+ printDoubleBreak()
+ }
+ }
+
+
+ void print(parameter) {
+ def output = parameter.toString()
+
+ if (readyToIndent) {
+ _out.print _indent
+ readyToIndent = false
+ while (output.startsWith(' ')) {
+ output = output[1..-1] // trim left
+ }
+ }
+ if (_out.toString().endsWith(' ')) {
+ if (output.startsWith(' ')) {
+ output = output[1..-1]
+ }
+ }
+ _out.print output
+ }
+
+ def println(parameter) {
+ throw new UnsupportedOperationException('Wrong API')
+ }
+
+ def indented(Closure block) {
+ String startingIndent = _indent
+ _indent = _indent + ' '
+ block()
+ _indent = startingIndent
+ }
+
+ def printLineBreak() {
+ if (!_out.toString().endsWith('\n')) {
+ _out.print '\n'
+ }
+ readyToIndent = true
+ }
+
+ def printDoubleBreak() {
+ if (_out.toString().endsWith('\n\n')) {
+ // do nothing
+ } else if (_out.toString().endsWith('\n')) {
+ _out.print '\n'
+ } else {
+ _out.print '\n'
+ _out.print '\n'
+ }
+ readyToIndent = true
+ }
+
+ void visitPackage(PackageNode packageNode) {
+
+ if (packageNode) {
+
+ packageNode.annotations?.each {
+ visitAnnotationNode(it)
+ printLineBreak()
+ }
+
+ if (packageNode.text.endsWith('.')) {
+ print packageNode.text[0..-2]
+ } else {
+ print packageNode.text
+ }
+ printDoubleBreak()
+ }
+ }
+
+ void visitImport(ImportNode node) {
+ if (node) {
+ node.annotations?.each {
+ visitAnnotationNode(it)
+ printLineBreak()
+ }
+ print node.text
+ printLineBreak()
+ }
+ }
+
+ @Override
+ void visitClass(ClassNode node) {
+
+ classNameStack.push(node.name)
+
+ node?.annotations?.each {
+ visitAnnotationNode(it)
+ printLineBreak()
+ }
+
+ visitModifiers(node.modifiers)
+ print "class $node.name"
+ visitGenerics node?.genericsTypes
+ boolean first = true
+ node.unresolvedInterfaces?.each {
+ if (!first) {
+ print ', '
+ } else {
+ print ' implements '
+ }
+ first = false
+ visitType it
+ }
+ print ' extends '
+ visitType node.unresolvedSuperClass
+ print ' { '
+ printDoubleBreak()
+
+ indented {
+ node?.properties?.each { visitProperty(it) }
+ printLineBreak()
+ node?.fields?.each { visitField(it) }
+ printDoubleBreak()
+ node?.declaredConstructors?.each { visitConstructor(it) }
+ printLineBreak()
+ node?.methods?.each { visitMethod(it) }
+ }
+ print '}'
+ printLineBreak()
+ classNameStack.pop()
+ }
+
+ private void visitGenerics(GenericsType[] generics) {
+
+ if (generics) {
+ print '<'
+ boolean first = true
+ generics.each { GenericsType it ->
+ if (!first) {
+ print ', '
+ }
+ first = false
+ print it.name
+ if (it.upperBounds) {
+ print ' extends '
+ boolean innerFirst = true
+ it.upperBounds.each { ClassNode upperBound ->
+ if (!innerFirst) {
+ print ' & '
+ }
+ innerFirst = false
+ visitType upperBound
+ }
+ }
+ if (it.lowerBound) {
+ print ' super '
+ visitType it.lowerBound
+ }
+ }
+ print '>'
+ }
+ }
+
+ @Override
+ void visitConstructor(ConstructorNode node) {
+ visitMethod(node)
+ }
+
+ private String visitParameters(parameters) {
+ boolean first = true
+
+ parameters.each { Parameter it ->
+ if (!first) {
+ print ', '
+ }
+ first = false
+
+ it.annotations?.each {
+ visitAnnotationNode(it)
+ print(' ')
+ }
+
+ visitModifiers(it.modifiers)
+ visitType it.type
+ print ' ' + it.name
+ if (it.initialExpression && !(it.initialExpression instanceof EmptyExpression)) {
+ print ' = '
+ it.initialExpression.visit this
+ }
+ }
+ }
+
+ @Override
+ void visitMethod(MethodNode node) {
+ node?.annotations?.each {
+ visitAnnotationNode(it)
+ printLineBreak()
+ }
+
+ visitModifiers(node.modifiers)
+ if (node.name == '<init>') {
+ print "${classNameStack.peek()}("
+ visitParameters(node.parameters)
+ print ') {'
+ printLineBreak()
+ } else if (node.name == '<clinit>') {
+ print '{ ' // will already have 'static' from modifiers
+ printLineBreak()
+ } else {
+ visitType node.returnType
+ print " $node.name("
+ visitParameters(node.parameters)
+ print ')'
+ if (node.exceptions) {
+ boolean first = true
+ print ' throws '
+ node.exceptions.each {
+ if (!first) {
+ print ', '
+ }
+ first = false
+ visitType it
+ }
+ }
+ print ' {'
+ printLineBreak()
+ }
+
+ indented {
+ node?.code?.visit(this)
+ }
+ printLineBreak()
+ print '}'
+ printDoubleBreak()
+ }
+
+ private def visitModifiers(int modifiers) {
+ if (Modifier.isAbstract(modifiers)) {
+ print 'abstract '
+ }
+ if (Modifier.isFinal(modifiers)) {
+ print 'final '
+ }
+ if (Modifier.isInterface(modifiers)) {
+ print 'interface '
+ }
+ if (Modifier.isNative(modifiers)) {
+ print 'native '
+ }
+ if (Modifier.isPrivate(modifiers)) {
+ print 'private '
+ }
+ if (Modifier.isProtected(modifiers)) {
+ print 'protected '
+ }
+ if (Modifier.isPublic(modifiers)) {
+ print 'public '
+ }
+ if (Modifier.isStatic(modifiers)) {
+ print 'static '
+ }
+ if (Modifier.isSynchronized(modifiers)) {
+ print 'synchronized '
+ }
+ if (Modifier.isTransient(modifiers)) {
+ print 'transient '
+ }
+ if (Modifier.isVolatile(modifiers)) {
+ print 'volatile '
+ }
+ }
+
+ @Override
+ void visitField(FieldNode node) {
+ node?.annotations?.each {
+ visitAnnotationNode(it)
+ printLineBreak()
+ }
+ visitModifiers(node.modifiers)
+ visitType node.type
+ print " $node.name "
+ // do not print initial expression, as this is executed as part of the constructor, unless on static constant
+ Expression exp = node.initialValueExpression
+ if (exp instanceof ConstantExpression) exp = Verifier.transformToPrimitiveConstantIfPossible(exp)
+ ClassNode type = exp?.type
+ if (Modifier.isStatic(node.modifiers) && Modifier.isFinal(node.getModifiers())
+ && exp instanceof ConstantExpression
+ && type == node.type
+ && ClassHelper.isStaticConstantInitializerType(type)) {
+ // GROOVY-5150: final constants may be initialized directly
+ print ' = '
+ if (ClassHelper.STRING_TYPE == type) {
+ print "'"+node.initialValueExpression.text.replaceAll("'", "\\\\'")+"'"
+ } else if (ClassHelper.char_TYPE == type) {
+ print "'${node.initialValueExpression.text}'"
+ } else {
+ print node.initialValueExpression.text
+ }
+ }
+ printLineBreak()
+ }
+
+ void visitAnnotationNode(AnnotationNode node) {
+ print '@' + node?.classNode?.name
+ if (node?.members) {
+ print '('
+ boolean first = true
+ node.members.each { String name, Expression value ->
+ if (first) {
+ first = false
+ } else {
+ print ', '
+ }
+ print name + ' = '
+ value.visit(this)
+ }
+ print ')'
+ }
+
+ }
+
+ @Override
+ void visitProperty(PropertyNode node) {
+ // is a FieldNode, avoid double dispatch
+ }
+
+ @Override
+ void visitBlockStatement(BlockStatement block) {
+ block?.statements?.each {
+ it.visit(this)
+ printLineBreak()
+ }
+ if (!_out.toString().endsWith('\n')) {
+ printLineBreak()
+ }
+ }
+
+ @Override
+ void visitForLoop(ForStatement statement) {
+
+ print 'for ('
+ if (statement?.variable != ForStatement.FOR_LOOP_DUMMY) {
+ visitParameters([statement.variable])
+ print ' : '
+ }
+
+ if (statement?.collectionExpression instanceof ListExpression) {
+ statement?.collectionExpression?.visit this
+ } else {
+ statement?.collectionExpression?.visit this
+ }
+ print ') {'
+ printLineBreak()
+ indented {
+ statement?.loopBlock?.visit this
+ }
+ print '}'
+ printLineBreak()
+ }
+
+ @Override
+ void visitIfElse(IfStatement ifElse) {
+ print 'if ('
+ ifElse?.booleanExpression?.visit this
+ print ') {'
+ printLineBreak()
+ indented {
+ ifElse?.ifBlock?.visit this
+ }
+ printLineBreak()
+ if (ifElse?.elseBlock && !(ifElse.elseBlock instanceof EmptyStatement)) {
+ print '} else {'
+ printLineBreak()
+ indented {
+ ifElse?.elseBlock?.visit this
+ }
+ printLineBreak()
+ }
+ print '}'
+ printLineBreak()
+ }
+
+ @Override
+ void visitExpressionStatement(ExpressionStatement statement) {
+ statement.expression.visit this
+ }
+
+ @Override
+ void visitReturnStatement(ReturnStatement statement) {
+ printLineBreak()
+ print 'return '
+ statement.getExpression().visit(this)
+ printLineBreak()
+ }
+
+ @Override
+ void visitSwitch(SwitchStatement statement) {
+ print 'switch ('
+ statement?.expression?.visit this
+ print ') {'
+ printLineBreak()
+ indented {
+ statement?.caseStatements?.each {
+ visitCaseStatement it
+ }
+ if (statement?.defaultStatement) {
+ print 'default: '
+ printLineBreak()
+ statement?.defaultStatement?.visit this
+ }
+ }
+ print '}'
+ printLineBreak()
+ }
+
+ @Override
+ void visitCaseStatement(CaseStatement statement) {
+ print 'case '
+ statement?.expression?.visit this
+ print ':'
+ printLineBreak()
+ indented {
+ statement?.code?.visit this
+ }
+ }
+
+ @Override
+ void visitBreakStatement(BreakStatement statement) {
+ print 'break'
+ printLineBreak()
+ }
+
+ @Override
+ void visitContinueStatement(ContinueStatement statement) {
+ print 'continue'
+ printLineBreak()
+ }
+
+ @Override
+ void visitMethodCallExpression(MethodCallExpression expression) {
+
+ Expression objectExp = expression.getObjectExpression()
+ if (objectExp instanceof VariableExpression) {
+ visitVariableExpression(objectExp, false)
+ } else {
+ objectExp.visit(this)
+ }
+ if (expression.spreadSafe) {
+ print '*'
+ }
+ if (expression.safe) {
+ print '?'
+ }
+ print '.'
+ Expression method = expression.getMethod()
+ if (method instanceof ConstantExpression) {
+ visitConstantExpression(method, true)
+ } else {
+ method.visit(this)
+ }
+ expression.getArguments().visit(this)
+ }
+
+ @Override
+ void visitStaticMethodCallExpression(StaticMethodCallExpression expression) {
+ print expression?.ownerType?.name + '.' + expression?.method
+ if (expression?.arguments instanceof VariableExpression || expression?.arguments instanceof MethodCallExpression) {
+ print '('
+ expression?.arguments?.visit this
+ print ')'
+ } else {
+ expression?.arguments?.visit this
+ }
+ }
+
+ @Override
+ void visitConstructorCallExpression(ConstructorCallExpression expression) {
+ if (expression?.isSuperCall()) {
+ print 'super'
+ } else if (expression?.isThisCall()) {
+ print 'this '
+ } else {
+ print 'new '
+ visitType expression?.type
+ }
+ expression?.arguments?.visit this
+ }
+
+ @Override
+ void visitBinaryExpression(BinaryExpression expression) {
+ expression?.leftExpression?.visit this
+ print " $expression.operation.text "
+ expression.rightExpression.visit this
+
+ if (expression?.operation?.text == '[') {
+ print ']'
+ }
+ }
+
+ @Override
+ void visitPostfixExpression(PostfixExpression expression) {
+ print '('
+ expression?.expression?.visit this
+ print ')'
+ print expression?.operation?.text
+ }
+
+ @Override
+ void visitPrefixExpression(PrefixExpression expression) {
+ print expression?.operation?.text
+ print '('
+ expression?.expression?.visit this
+ print ')'
+ }
+
+
+ @Override
+ void visitClosureExpression(ClosureExpression expression) {
+ print '{ '
+ if (expression?.parameters) {
+ visitParameters(expression?.parameters)
+ print ' ->'
+ }
+ printLineBreak()
+ indented {
+ expression?.code?.visit this
+ }
+ print '}'
+ }
+
+ @Override
+ void visitTupleExpression(TupleExpression expression) {
+ print '('
+ visitExpressionsAndCommaSeparate(expression?.expressions)
+ print ')'
+ }
+
+ @Override
+ void visitRangeExpression(RangeExpression expression) {
+ print '('
+ expression?.from?.visit this
+ print '..'
+ expression?.to?.visit this
+ print ')'
+ }
+
+ @Override
+ void visitPropertyExpression(PropertyExpression expression) {
+ expression?.objectExpression?.visit this
+ if (expression?.spreadSafe) {
+ print '*'
+ } else if (expression?.isSafe()) {
+ print '?'
+ }
+ print '.'
+ if (expression?.property instanceof ConstantExpression) {
+ visitConstantExpression(expression?.property, true)
+ } else {
+ expression?.property?.visit this
+ }
+ }
+
+ @Override
+ void visitAttributeExpression(AttributeExpression attributeExpression) {
+ visitPropertyExpression attributeExpression
+ }
+
+ @Override
+ void visitFieldExpression(FieldExpression expression) {
+ print expression?.field?.name
+ }
+
+ void visitConstantExpression(ConstantExpression expression, boolean unwrapQuotes = false) {
+ if (expression.value instanceof String && !unwrapQuotes) {
+ // string reverse escaping is very naive
+ def escaped = ((String) expression.value).replaceAll('\n', '\\\\n').replaceAll("'", "\\\\'")
+ print "'$escaped'"
+ } else {
+ print expression.value
+ }
+ }
+
+ @Override
+ void visitClassExpression(ClassExpression expression) {
+ print expression.text
+ }
+
+ void visitVariableExpression(VariableExpression expression, boolean spacePad = true) {
+
+ if (spacePad) {
+ print ' ' + expression.name + ' '
+ } else {
+ print expression.name
+ }
+ }
+
+ @Override
+ void visitDeclarationExpression(DeclarationExpression expression) {
+ // handle multiple assignment expressions
+ if (expression?.leftExpression instanceof ArgumentListExpression) {
+ print 'def '
+ visitArgumentlistExpression expression?.leftExpression, true
+ print " $expression.operation.text "
+ expression.rightExpression.visit this
+
+ if (expression?.operation?.text == '[') {
+ print ']'
+ }
+ } else {
+ visitType expression?.leftExpression?.type
+ visitBinaryExpression expression // is a BinaryExpression
+ }
+ }
+
+ @Override
+ void visitGStringExpression(GStringExpression expression) {
+ print '"' + expression.text + '"'
+ }
+
+ @Override
+ void visitSpreadExpression(SpreadExpression expression) {
+ print '*'
+ expression?.expression?.visit this
+ }
+
+ @Override
+ void visitNotExpression(NotExpression expression) {
+ print '!('
+ expression?.expression?.visit this
+ print ')'
+ }
+
+ @Override
+ void visitUnaryMinusExpression(UnaryMinusExpression expression) {
+ print '-('
+ expression?.expression?.visit this
+ print ')'
+ }
+
+ @Override
+ void visitUnaryPlusExpression(UnaryPlusExpression expression) {
+ print '+('
+ expression?.expression?.visit this
+ print ')'
+ }
+
+ @Override
+ void visitCastExpression(CastExpression expression) {
+ print '(('
+ expression?.expression?.visit this
+ print ') as '
+ visitType(expression?.type)
+ print ')'
+
+ }
+
+ /**
+ * Prints out the type, safely handling arrays.
+ * @param classNode
+ * classnode
+ */
+ void visitType(ClassNode classNode) {
+ def name = classNode.name
+ if (name =~ /^\[+L/ && name.endsWith(';')) {
+ int numDimensions = name.indexOf('L')
+ print "${classNode.name[(numDimensions + 1)..-2]}" + ('[]' * numDimensions)
+ } else {
+ print name
+ }
+ visitGenerics classNode?.genericsTypes
+ }
+
+ void visitArgumentlistExpression(ArgumentListExpression expression, boolean showTypes = false) {
+ print '('
+ int count = expression?.expressions?.size()
+ expression.expressions.each {
+ if (showTypes) {
+ visitType it.type
+ print ' '
+ }
+ if (it instanceof VariableExpression) {
+ visitVariableExpression it, false
+ } else if (it instanceof ConstantExpression) {
+ visitConstantExpression it, false
+ } else {
+ it.visit this
+ }
+ count--
+ if (count) print ', '
+ }
+ print ')'
+ }
+
+ @Override
+ void visitBytecodeExpression(BytecodeExpression expression) {
+ print '/*BytecodeExpression*/'
+ printLineBreak()
+ }
+
+
+
+ @Override
+ void visitMapExpression(MapExpression expression) {
+ print '['
+ if (expression?.mapEntryExpressions?.size() == 0) {
+ print ':'
+ } else {
+ visitExpressionsAndCommaSeparate(expression?.mapEntryExpressions)
+ }
+ print ']'
+ }
+
+ @Override
+ void visitMapEntryExpression(MapEntryExpression expression) {
+ if (expression?.keyExpression instanceof SpreadMapExpression) {
+ print '*' // is this correct?
+ } else {
+ expression?.keyExpression?.visit this
+ }
+ print ': '
+ expression?.valueExpression?.visit this
+ }
+
+ @Override
+ void visitListExpression(ListExpression expression) {
+ print '['
+ visitExpressionsAndCommaSeparate(expression?.expressions)
+ print ']'
+ }
+
+ @Override
+ void visitTryCatchFinally(TryCatchStatement statement) {
+ print 'try {'
+ printLineBreak()
+ indented {
+ statement?.tryStatement?.visit this
+ }
+ printLineBreak()
+ print '} '
+ printLineBreak()
+ statement?.catchStatements?.each { CatchStatement catchStatement ->
+ visitCatchStatement(catchStatement)
+ }
+ print 'finally { '
+ printLineBreak()
+ indented {
+ statement?.finallyStatement?.visit this
+ }
+ print '} '
+ printLineBreak()
+ }
+
+ @Override
+ void visitThrowStatement(ThrowStatement statement) {
+ print 'throw '
+ statement?.expression?.visit this
+ printLineBreak()
+ }
+
+ @Override
+ void visitSynchronizedStatement(SynchronizedStatement statement) {
+ print 'synchronized ('
+ statement?.expression?.visit this
+ print ') {'
+ printLineBreak()
+ indented {
+ statement?.code?.visit this
+ }
+ print '}'
+ }
+
+ @Override
+ void visitTernaryExpression(TernaryExpression expression) {
+ expression?.booleanExpression?.visit this
+ print ' ? '
+ expression?.trueExpression?.visit this
+ print ' : '
+ expression?.falseExpression?.visit this
+ }
+
+ @Override
+ void visitShortTernaryExpression(ElvisOperatorExpression expression) {
+ visitTernaryExpression(expression)
+ }
+
+ @Override
+ void visitBooleanExpression(BooleanExpression expression) {
+ expression?.expression?.visit this
+ }
+
+ @Override
+ void visitWhileLoop(WhileStatement statement) {
+ print 'while ('
+ statement?.booleanExpression?.visit this
+ print ') {'
+ printLineBreak()
+ indented {
+ statement?.loopBlock?.visit this
+ }
+ printLineBreak()
+ print '}'
+ printLineBreak()
+ }
+
+ @Override
+ void visitDoWhileLoop(DoWhileStatement statement) {
+ print 'do {'
+ printLineBreak()
+ indented {
+ statement?.loopBlock?.visit this
+ }
+ print '} while ('
+ statement?.booleanExpression?.visit this
+ print ')'
+ printLineBreak()
+ }
+
+ @Override
+ void visitCatchStatement(CatchStatement statement) {
+ print 'catch ('
+ visitParameters([statement.variable])
+ print ') {'
+ printLineBreak()
+ indented {
+ statement.code?.visit this
+ }
+ print '} '
+ printLineBreak()
+ }
+
+ @Override
+ void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
+ print '~('
+ expression?.expression?.visit this
+ print ') '
+ }
+
+ @Override
+ void visitAssertStatement(AssertStatement statement) {
+ print 'assert '
+ statement?.booleanExpression?.visit this
+ print ' : '
+ statement?.messageExpression?.visit this
+ }
+
+ @Override
+ void visitClosureListExpression(ClosureListExpression expression) {
+ boolean first = true
+ expression?.expressions?.each {
+ if (!first) {
+ print ';'
+ }
+ first = false
+ it.visit this
+ }
+ }
+
+ @Override
+ void visitMethodPointerExpression(MethodPointerExpression expression) {
+ expression?.expression?.visit this
+ print '.&'
+ expression?.methodName?.visit this
+ }
+
+ @Override
+ void visitArrayExpression(ArrayExpression expression) {
+ print 'new '
+ visitType expression?.elementType
+ print '['
+ visitExpressionsAndCommaSeparate(expression?.sizeExpression)
+ print ']'
+ }
+
+ private void visitExpressionsAndCommaSeparate(List<? super Expression> expressions) {
+ boolean first = true
+ expressions?.each {
+ if (!first) {
+ print ', '
+ }
+ first = false
+ it.visit this
+ }
+ }
+
+ @Override
+ void visitSpreadMapExpression(SpreadMapExpression expression) {
+ print '*:'
+ expression?.expression?.visit this
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-2324.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-2324.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-2324.groovy
new file mode 100644
index 0000000..30e2f30
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-2324.groovy
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+class Foo {}
+
+Foo bar
+bar = new Foo()
+assert bar instanceof Foo
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4438.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4438.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4438.groovy
new file mode 100644
index 0000000..41ee327
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4438.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+enum Outer {
+ A, B
+ enum Inner{X, Y}
+}
+assert Outer.A instanceof Outer
+assert Outer.B instanceof Outer
+assert Outer.Inner.X instanceof Outer.Inner
+assert Outer.Inner.Y instanceof Outer.Inner
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4757.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4757.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4757.groovy
new file mode 100644
index 0000000..1a7d2e5
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4757.groovy
@@ -0,0 +1,27 @@
+/*
+ * 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 bugs
+
+class Foo {
+ <T extends Object> T foo(T t) {
+ return t
+ }
+}
+
+assert 'abc' == new Foo().foo('abc')
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4762.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4762.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4762.groovy
new file mode 100644
index 0000000..235f6a5
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-4762.groovy
@@ -0,0 +1,27 @@
+/*
+ * 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 bugs
+
+def get123() {2}
+def foo(i) {this}
+
+def a = foo(2).'123'
+def b = foo 2 123
+
+assert a == b
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5318.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5318.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5318.groovy
new file mode 100644
index 0000000..13cb623
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5318.groovy
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+def a= new java.util<Integer>.ArrayList<ArrayList<Integer>>()
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5652.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5652.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5652.groovy
new file mode 100644
index 0000000..e7c6b3f
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-5652.groovy
@@ -0,0 +1,24 @@
+/*
+ * 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 bugs
+
+def list = [[1,2],[3,4]] as List<List<Integer>>
+println list
+println 'bye'
+assert [[1,2],[3,4]] == list
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-6038.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-6038.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-6038.groovy
new file mode 100644
index 0000000..f41c5e9
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-6038.groovy
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+import java.lang.annotation.*
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@interface Upper {
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ @interface Inner {
+ String testInner()
+ }
+}
+
+class X {
+ @Upper.Inner(testInner='abc')
+ def m() {}
+}
+
+def m = X.class.declaredMethods.find { it.name == 'm' }
+assert m.declaredAnnotations[0].testInner() == 'abc'
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8150.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8150.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8150.groovy
new file mode 100644
index 0000000..ac0cc9d
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8150.groovy
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+def a
+def b = [1]
+((a)) = b
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8161.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8161.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8161.groovy
new file mode 100644
index 0000000..0b54cda
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8161.groovy
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+for (foo in []) {;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/bugs/GROOVY-3898.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/GROOVY-3898.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/GROOVY-3898.groovy
new file mode 100644
index 0000000..146b5e6
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/GROOVY-3898.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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 bugs
+
+int result = 1
+for((i, j) = [0,0]; i < 3; {i++; j++}()){
+ result = result * i + j
+}
+assert 4 == result
+
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy b/subprojects/parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy
new file mode 100644
index 0000000..88f3a3d
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+import org.codehaus.groovy.transform.GroovyASTTransformationClass
+
+import java.lang.annotation.Documented
+import java.lang.annotation.ElementType
+import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
+import java.lang.annotation.Target
+
+@Canonical(
+ includes = ['a', 'b'], excludes = ['c']
+)
+@Documented
+@Retention(RetentionPolicy.SOURCE)
+@Target(ElementType.FIELD)
+@GroovyASTTransformationClass('Lulz')
+@interface FunnyAnnotation {
+ public static final String SOME_CONSTANT2 = 'SOME_CONSTANT2';
+ String SOME_CONSTANT = 'SOME_CONSTANT';
+
+ /* This is a comment
+ */
+ String name() default ""
+
+ /**
+ * This has a default, too
+ */
+ boolean synchronize() default false
+
+ boolean synchronize2() default
+ false
+}
+
+@interface a {
+
+}
+
+@interface b {
+ String name()
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/core/Annotation_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/core/Annotation_01.groovy b/subprojects/parser-antlr4/src/test/resources/core/Annotation_01.groovy
new file mode 100644
index 0000000..c86b156
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/core/Annotation_01.groovy
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@Export package core
http://git-wip-us.apache.org/repos/asf/groovy/blob/2c01e99f/subprojects/parser-antlr4/src/test/resources/core/Annotation_02.groovy
----------------------------------------------------------------------
diff --git a/subprojects/parser-antlr4/src/test/resources/core/Annotation_02.groovy b/subprojects/parser-antlr4/src/test/resources/core/Annotation_02.groovy
new file mode 100644
index 0000000..8d624ae
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/core/Annotation_02.groovy
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+@Export
+package core