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 2016/12/21 16:36:30 UTC
[10/39] groovy git commit: Keep same name rule with
groovy-parser-antlr2
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/TestUtils.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/TestUtils.groovy b/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/TestUtils.groovy
new file mode 100644
index 0000000..5ba538b
--- /dev/null
+++ b/subprojects/groovy-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/groovy-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/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy b/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/ASTComparatorCategory.groovy
new file mode 100644
index 0000000..47b9507
--- /dev/null
+++ b/subprojects/groovy-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/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy b/subprojects/groovy-parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/util/AstDumper.groovy
new file mode 100644
index 0000000..72a64e5
--- /dev/null
+++ b/subprojects/groovy-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/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy
new file mode 100644
index 0000000..3c5662b
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/AnnotationDeclaration_01.groovy
@@ -0,0 +1,39 @@
+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/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_01.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_01.groovy
new file mode 100644
index 0000000..6dbf1f7
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_01.groovy
@@ -0,0 +1 @@
+@Export package core
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_02.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_02.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_02.groovy
new file mode 100644
index 0000000..d673313
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_02.groovy
@@ -0,0 +1,2 @@
+@Export
+package core
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_03.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_03.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_03.groovy
new file mode 100644
index 0000000..644de35
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_03.groovy
@@ -0,0 +1,3 @@
+@Export
+@Version
+package core
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_04.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_04.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_04.groovy
new file mode 100644
index 0000000..5edeef2
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_04.groovy
@@ -0,0 +1,2 @@
+@Export @Version
+package core
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_05.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_05.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_05.groovy
new file mode 100644
index 0000000..545d6d5
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_05.groovy
@@ -0,0 +1 @@
+@Test1 import java.util.Map
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_06.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_06.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_06.groovy
new file mode 100644
index 0000000..068d6c3
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_06.groovy
@@ -0,0 +1,2 @@
+@Test1
+import java.util.Map
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_07.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_07.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_07.groovy
new file mode 100644
index 0000000..bb777ca
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_07.groovy
@@ -0,0 +1,2 @@
+@Test1 @Test2
+import java.util.Map
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_08.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_08.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_08.groovy
new file mode 100644
index 0000000..60d51eb
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_08.groovy
@@ -0,0 +1,10 @@
+@Test1 @Test2 @Test3
+import java.util.Map
+@Test1 @Test2 @Test3
+import java.util.*
+@Test1 @Test2 @Test3
+import static java.lang.Math
+@Test1 @Test2 @Test3
+import static java.lang.Math.*
+@Test1 @Test2 @Test3
+import static java.lang.Math.pow
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_09.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_09.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_09.groovy
new file mode 100644
index 0000000..98f565a
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_09.groovy
@@ -0,0 +1,14 @@
+@Test1(12)
+@Test1(@Test1)
+@Test2(v=6)
+@Test3(v1=6, v2=8, v3=10)
+@Test4([1, 2, 3])
+@Test5(v=[1, 2, 3])
+@Test6(v1=[1, 2, 3], v2=[1], v3=6)
+package core
+
+@Grapes([
+ @Grab('xx:yy:1.0'), // xx
+ @Grab('zz:yy:1.0') /* zz */
+])
+import xx.yy.ZZ;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_10x.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_10x.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_10x.groovy
new file mode 100644
index 0000000..22cd289
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Annotation_10x.groovy
@@ -0,0 +1,20 @@
+import java.lang.annotation.RetentionPolicy
+import java.lang.annotation.Retention
+
+def closureClass = NestedAnnotationWithDefault.getAnnotation(AnnWithNestedAnnWithDefault).elem().elem()
+def closure = closureClass.newInstance(null, null)
+assert closure.call() == 3
+
+
+@AnnWithNestedAnnWithDefault(elem = @AnnWithDefaultValue())
+class NestedAnnotationWithDefault {}
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface AnnWithDefaultValue {
+ Class elem() default { 1 + 2 }
+}
+
+@Retention(RetentionPolicy.RUNTIME)
+@interface AnnWithNestedAnnWithDefault {
+ AnnWithDefaultValue elem()
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_01.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_01.groovy
new file mode 100644
index 0000000..f9a50e0
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_01.groovy
@@ -0,0 +1,28 @@
+assert true
+assert true;
+assert true : ':(';
+assert true , ':(';
+assert true :
+ ':('
+assert true ,
+ ':(';
+
+assert true: \
+ 'hello, world'
+
+assert true, \
+ 'hello, world'
+
+assert 1 \
+ + 2 * \
+ 3 : \
+ 'hello, world'
+
+assert 1 \
+ + 2 * \
+\
+ 3 : \
+\
+\
+'hello, world'
+
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_02x.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_02x.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_02x.groovy
new file mode 100644
index 0000000..887f0b9
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_02x.groovy
@@ -0,0 +1,37 @@
+import org.codehaus.groovy.runtime.powerassert.PowerAssertionError
+
+testBinaryExpression()
+
+/***********************************/
+void testBinaryExpression() {
+ isRendered """
+assert a * b
+ | | |
+ 0 0 1
+ """, {
+ def a = 0
+ def b = 1
+ assert a * b
+ }
+
+ isRendered """
+assert a[b]
+ |||
+ ||0
+ |false
+ [false]
+ """, {
+ def a = [false]
+ def b = 0
+ assert a[b]
+ }
+}
+
+static isRendered(String expectedRendering, Closure failingAssertion) {
+ try {
+ failingAssertion.call();
+ assert false, "assertion should have failed but didn't"
+ } catch (PowerAssertionError e) {
+ assert expectedRendering.trim() == e.message.trim()
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_03x.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_03x.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_03x.groovy
new file mode 100644
index 0000000..75d305a
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Assert_03x.groovy
@@ -0,0 +1,26 @@
+import org.codehaus.groovy.runtime.powerassert.PowerAssertionError
+
+testPostfixExpression()
+
+/***********************************/
+
+void testPostfixExpression() {
+ isRendered """
+assert x++ == null
+ || |
+ |0 false
+ 0
+ """, {
+ def x = 0
+ assert x++ == null
+ }
+}
+
+static isRendered(String expectedRendering, Closure failingAssertion) {
+ try {
+ failingAssertion.call();
+ assert false, "assertion should have failed but didn't"
+ } catch (PowerAssertionError e) {
+ assert expectedRendering.trim() == e.message.trim()
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_01.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_01.groovy
new file mode 100644
index 0000000..13d0b8e
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_01.groovy
@@ -0,0 +1,47 @@
+package core
+
+class A {}
+class B<T> {}
+class C<T extends A> {}
+class D<T extends A & B> {}
+class E<T extends A & B & C> {}
+class F<T extends A & B & C> extends A {}
+class F2 extends A<T> {}
+class G1<T extends A & B & C> extends A implements X {}
+class G2<T extends A & B & C> extends A<T> implements X<T> {}
+class G3 extends A<T> implements X<T> {}
+class G4 extends A implements X<T> {}
+class G5 extends A implements X {}
+class H<T extends A & B & C> extends A implements X, Y {}
+class I<T extends A & B & C> extends A implements X, Y, Z {}
+public class J<T extends A & B & C> extends A implements X, Y, Z {}
+@Test2 public class K<T extends A & B & C> extends A implements X, Y, Z {}
+@Test2 @Test3 public class L<T extends A & B & C> extends A implements X, Y, Z {}
+
+@Test2
+@Test3
+@Test4(value={
+ def a = someMethod()
+ assert a.result() == 'abc'
+})
+@Test5(b=2, a=1)
+@Test6(a=2, b=1)
+public
+class M
+<
+ T extends
+A &
+B &
+C
+>
+ extends
+ A
+ implements
+ X,
+ Y,
+ Z
+{
+
+}
+
+class a {}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_02.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_02.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_02.groovy
new file mode 100644
index 0000000..b8a1b40
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_02.groovy
@@ -0,0 +1,42 @@
+class AA {
+ {
+ println 123
+ }
+}
+
+class BB {
+ static {
+ println '123'
+ }
+}
+
+class CC {
+ static
+ {
+ println '123'
+ }
+}
+
+class DD {
+ static {
+ println '123'
+ }
+
+ {
+ println 'abc'
+ }
+
+ static {
+ println '234'
+ }
+
+ {
+ println 'bcd'
+ }
+}
+
+class EE {{}}
+class FF {static {}}
+class GG {static {};{}}
+
+class Iterator implements java.util.Iterator {}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_03.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_03.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_03.groovy
new file mode 100644
index 0000000..32c5c41
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_03.groovy
@@ -0,0 +1,51 @@
+import java.sql.SQLException
+
+class AAA {
+ private volatile XX xx;
+ private transient YY yy;
+
+ public AAA() {
+
+ }
+
+ public AAA(String name) {
+
+ }
+
+ @Test2
+ public AAA(String name, int age) throws Exception {
+
+ }
+
+ AAA(String name, int age, String title) throws Exception {
+
+ }
+
+ private AAA(String name, int age, String title, double income) throws Exception {
+
+ }
+
+ @Test2
+ public synchronized String sayHello(String name) {
+ return "Hello, $name";
+ }
+
+ @Test2
+ public <T> T sayHello2(T name) throws IOException, SQLException {
+ return "Hello, $name";
+ }
+
+ public static privateStaticMethod(){}
+
+ public void m(final int param) {}
+ public void m2(def param) {}
+ public void m3(final int param1, long param2, final String param3) {}
+
+ def "hello world"(p1, p2) {
+ println "$p1, $p2"
+ }
+
+ def run() {
+ this."hello world"('ab', 'bc')
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_04.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_04.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_04.groovy
new file mode 100644
index 0000000..7750cb4
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_04.groovy
@@ -0,0 +1,22 @@
+public class Person {
+ public static final SOME_CONSTANT = 'SOME_CONSTANT';
+ private String name = 'Daniel';
+ private int age;
+ @Test2
+ private String country = 'China',
+ location = 'Shanghai';
+
+ private String field, field2 = 'field2';
+ String someProperty;
+ String someProperty2 = 'someProperty2';
+ String someProperty3 = 'someProperty3',
+ someProperty4 = 'someProperty4';
+ String someProperty5, someProperty6 = 'someProperty6';
+ final String someProperty7 = 'someProperty7';
+ static final String someProperty8 = 'someProperty8';
+
+ @Test3
+ static final String someProperty9 = 'someProperty9';
+
+ protected static def protectedStaticDefField;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_05.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_05.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_05.groovy
new file mode 100644
index 0000000..7f66f72
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_05.groovy
@@ -0,0 +1,20 @@
+public class A extends B {
+ private int age;
+
+ public A() {
+ super()
+ }
+
+ public A(int age) {
+ this()
+ }
+
+ public A(String name) {
+ super(name);
+ }
+
+ public A(String name, int age) {
+ this(name);
+ this.age = age;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_06.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_06.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_06.groovy
new file mode 100644
index 0000000..95e013c
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_06.groovy
@@ -0,0 +1,83 @@
+public class OuterA {
+ class InnerB {}
+}
+
+class OuterClazz {
+ enum InnerEnum implements SomeInterface {
+ A, B
+ }
+}
+
+
+class AA {
+ class Inner {
+ public def innerMethod() {}
+ }
+ private class PrivateInner {}
+ protected final class ProtectedFinalInner {
+ ProtectedFinalInner() {
+
+ }
+
+ ProtectedFinalInner(Integer a) {
+ new A() {
+ public int method() {
+ 1
+ }
+ }
+ }
+ }
+
+ public int method() {
+ 0
+ }
+}
+
+
+
+interface A {
+ static enum B {
+ static interface C {
+ }
+ }
+}
+
+interface A2 {
+ static class B2 {
+ static enum C2 {
+ }
+ }
+}
+
+enum A4 {
+ static interface B4 {
+ static class C4 {
+ }
+ }
+}
+
+
+class A3 {
+ static class B3 {
+ static enum C3 {
+ }
+ }
+}
+
+class A5 {
+ static class B5 {
+ static class C5 {
+ }
+ }
+}
+
+interface A1 {
+ static interface B1 {
+ static enum C1 {
+ }
+ }
+}
+
+
+
+
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_07.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_07.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_07.groovy
new file mode 100644
index 0000000..37cd5ee
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/ClassDeclaration_07.groovy
@@ -0,0 +1,27 @@
+new A() {}
+new A(1, '2') {
+ public void prt() {
+ new B() {}
+ new C() {
+ {
+ new D() {
+ {
+ new E() {}
+ new F() {}
+ }
+ }
+ }
+ }
+ }
+}
+
+class OuterAA {
+ public void method() {
+ new InnerBB() {}
+ new InnerCC() {{
+ new InnerDD() {}
+ new InnerEE() {}
+ }}
+ new InnerFF() {}
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_01.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_01.groovy
new file mode 100644
index 0000000..bb83ebe
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_01.groovy
@@ -0,0 +1 @@
+{->}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_02.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_02.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_02.groovy
new file mode 100644
index 0000000..3e7bc88
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_02.groovy
@@ -0,0 +1 @@
+{->12}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_03.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_03.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_03.groovy
new file mode 100644
index 0000000..61d7b27
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_03.groovy
@@ -0,0 +1 @@
+{-> {->12}}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_04.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_04.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_04.groovy
new file mode 100644
index 0000000..9c3a357
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_04.groovy
@@ -0,0 +1,3 @@
+{->
+ 12
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_05.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_05.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_05.groovy
new file mode 100644
index 0000000..47686c3
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_05.groovy
@@ -0,0 +1,3 @@
+{int a ->
+ a
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_06.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_06.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_06.groovy
new file mode 100644
index 0000000..dde2725
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_06.groovy
@@ -0,0 +1,9 @@
+{int a,
+ long b, float[] c,
+ double[][] d, String e, Object[] f,
+ Object[][] g, Object[][][] h,
+ Object[]... i
+ ->
+
+ a
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_07.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_07.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_07.groovy
new file mode 100644
index 0000000..9567574
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_07.groovy
@@ -0,0 +1,3 @@
+{Object... i ->
+ i
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_08.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_08.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_08.groovy
new file mode 100644
index 0000000..3e1811d
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_08.groovy
@@ -0,0 +1,16 @@
+{ List<String> i, List<List<String>> j, List<List<List<String>>> k,
+ List<?> l, List<? extends Map> m, List<? super Map> n,
+ List<? extends Map<String, Object>> o, List<? super Map<String, Object>> p,
+ List<String>[] q, List<? extends Map<String, Object>>[][] r,
+
+ List<
+ ? super
+ Map,
+ ? extends
+ Set,
+ List
+ > s,
+
+ List<? extends Map<String, Object>>[][]... t ->
+ i
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_09.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_09.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_09.groovy
new file mode 100644
index 0000000..8bbcee8
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_09.groovy
@@ -0,0 +1,16 @@
+{ String i,
+ final String j, final def String k,
+ @Test2 final def String l,
+ @Test2
+ final
+
+ def
+ String m,
+ final n,
+ def
+ o,
+ p, q,
+ r, s,
+ @Test2 final def String... z ->
+ i
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_10.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_10.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_10.groovy
new file mode 100644
index 0000000..010952c
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Closure_10.groovy
@@ -0,0 +1,4 @@
+{ java.lang.Integer t, Integer u, int v, int[] w, int[][] x,
+ String y = 'y', long... z = 123 ->
+ i
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/groovy/blob/fc23a2ed/subprojects/groovy-parser-antlr4/src/test/resources/core/Command_01.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-parser-antlr4/src/test/resources/core/Command_01.groovy b/subprojects/groovy-parser-antlr4/src/test/resources/core/Command_01.groovy
new file mode 100644
index 0000000..a6188c4
--- /dev/null
+++ b/subprojects/groovy-parser-antlr4/src/test/resources/core/Command_01.groovy
@@ -0,0 +1,14 @@
+a 1
+a 1, 2
+a x: 1, y: 2
+a.b 1, 2
+z.a b(1), c(2)
+a.b x: 1, y: 2
+z.a x: b(1), y: c(2)
+a b(1), c(2)
+a x: b(1), y: c(2)
+z.a x: b(1, 3), y: c(2, 4)
+a b(1, 3), c(2, 4)
+obj.<Integer, Double>a b(1, 3), c(2, 4), d(3, 5)
+println a
+println a = 1
\ No newline at end of file