You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2015/10/07 21:26:35 UTC
[15/37] incubator-groovy git commit: Add support for generating
classes through a MacroClass block * instead of using def ast = macro { class
A {} },
use def ast=new MacroClass() { class A{} } * substitutions broken due to
incorrect scoping of the
Add support for generating classes through a MacroClass block
* instead of using def ast = macro { class A {} }, use def ast=new MacroClass() { class A{} }
* substitutions broken due to incorrect scoping of the closure expression representing the substitution
Project: http://git-wip-us.apache.org/repos/asf/incubator-groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-groovy/commit/09758c34
Tree: http://git-wip-us.apache.org/repos/asf/incubator-groovy/tree/09758c34
Diff: http://git-wip-us.apache.org/repos/asf/incubator-groovy/diff/09758c34
Branch: refs/heads/master
Commit: 09758c34899f09285c8333e20f4e855ab28de2e6
Parents: 248e0fd
Author: Cedric Champeau <ce...@gmail.com>
Authored: Thu Oct 16 12:09:25 2014 +0200
Committer: Sergei Egorov <bs...@gmail.com>
Committed: Mon Sep 28 14:33:03 2015 +0300
----------------------------------------------------------------------
.../codehaus/groovy/ast/tools/ClosureUtils.java | 24 +-
.../codehaus/groovy/ast/tools/GeneralUtils.java | 39 +++
.../groovy/macro/runtime/MacroBuilder.java | 69 ++--
.../groovy/macro/transform/MacroClass.java | 19 ++
.../macro/transform/MacroInvocationTrap.java | 160 ++++++---
.../macro/transform/MacroTransformation.java | 22 +-
.../macro/transform/TransformingMacroTrap.java | 340 +++++++++++++++++++
7 files changed, 585 insertions(+), 88 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/09758c34/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java b/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java
index c13c31c..06d4995 100644
--- a/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java
+++ b/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java
@@ -37,32 +37,10 @@ public class ClosureUtils {
* @throws java.lang.Exception when closure can't be read from source
*/
public static String convertClosureToSource(ReaderSource readerSource, ClosureExpression expression) throws Exception {
- if (expression == null) throw new IllegalArgumentException("Null: expression");
-
- StringBuilder result = new StringBuilder();
- for (int x = expression.getLineNumber(); x <= expression.getLastLineNumber(); x++) {
- String line = readerSource.getLine(x, null);
- if (line == null) {
- throw new Exception(
- "Error calculating source code for expression. Trying to read line " + x + " from " + readerSource.getClass()
- );
- }
- if (x == expression.getLastLineNumber()) {
- line = line.substring(0, expression.getLastColumnNumber() - 1);
- }
- if (x == expression.getLineNumber()) {
- line = line.substring(expression.getColumnNumber() - 1);
- }
- //restoring line breaks is important b/c of lack of semicolons
- result.append(line).append('\n');
- }
-
-
- String source = result.toString().trim();
+ String source = GeneralUtils.convertASTToSource(readerSource, expression);
if (!source.startsWith("{")) {
throw new Exception("Error converting ClosureExpression into source code. Closures must start with {. Found: " + source);
}
-
return source;
}
http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/09758c34/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java b/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java
index ce4b19e..9d8508f 100644
--- a/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java
+++ b/src/main/org/codehaus/groovy/ast/tools/GeneralUtils.java
@@ -18,6 +18,7 @@
*/
package org.codehaus.groovy.ast.tools;
+import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
@@ -53,6 +54,7 @@ import org.codehaus.groovy.ast.stmt.IfStatement;
import org.codehaus.groovy.ast.stmt.ReturnStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.io.ReaderSource;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.MetaClassHelper;
import org.codehaus.groovy.syntax.Token;
@@ -680,4 +682,41 @@ public class GeneralUtils {
}
return propX(receiver, pNode.getName());
}
+
+ /**
+ * Converts an expression into the String source. Only some specific expressions like closure expression
+ * support this.
+ *
+ * @param readerSource a source
+ * @param expression an expression. Can't be null
+ * @return the source the closure was created from
+ * @throws java.lang.IllegalArgumentException when expression is null
+ * @throws java.lang.Exception when closure can't be read from source
+ */
+ public static String convertASTToSource(ReaderSource readerSource, ASTNode expression) throws Exception {
+ if (expression == null) throw new IllegalArgumentException("Null: expression");
+
+ StringBuilder result = new StringBuilder();
+ for (int x = expression.getLineNumber(); x <= expression.getLastLineNumber(); x++) {
+ String line = readerSource.getLine(x, null);
+ if (line == null) {
+ throw new Exception(
+ "Error calculating source code for expression. Trying to read line " + x + " from " + readerSource.getClass()
+ );
+ }
+ if (x == expression.getLastLineNumber()) {
+ line = line.substring(0, expression.getLastColumnNumber() - 1);
+ }
+ if (x == expression.getLineNumber()) {
+ line = line.substring(expression.getColumnNumber() - 1);
+ }
+ //restoring line breaks is important b/c of lack of semicolons
+ result.append(line).append('\n');
+ }
+
+
+ String source = result.toString().trim();
+
+ return source;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/09758c34/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroBuilder.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroBuilder.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroBuilder.java
index ae82081..1edbcba 100644
--- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroBuilder.java
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroBuilder.java
@@ -18,6 +18,7 @@ package org.codehaus.groovy.macro.runtime;
import groovy.lang.Closure;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.builder.AstBuilder;
import org.codehaus.groovy.ast.expr.Expression;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
@@ -53,46 +54,64 @@ public enum MacroBuilder {
@SuppressWarnings("unchecked")
public <T> T macro(CompilePhase compilePhase, boolean asIs, String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
- final String label = "__synthesized__label__" + System.currentTimeMillis() + "__:";
+ boolean isClosure = source.startsWith("{");
+ final String label = isClosure ?"__synthesized__label__" + System.currentTimeMillis() + "__:":"";
final String labelledSource = label + source;
final int linesOffset = 1;
- final int columnsOffset = label.length() + 1; // +1 because of {
-
+ final int columnsOffset = label.length() + (isClosure?1:0); // +1 because of {
+
List<ASTNode> nodes = (new AstBuilder()).buildFromString(compilePhase, true, labelledSource);
for(ASTNode node : nodes) {
if (node instanceof BlockStatement) {
- BlockStatement closureBlock = (BlockStatement) ((BlockStatement)node).getStatements().get(0);
+ List<Statement> statements = ((BlockStatement) node).getStatements();
+ if (!statements.isEmpty()) {
+ BlockStatement closureBlock = (BlockStatement) statements.get(0);
- (new ClassCodeExpressionTransformer() {
- public Expression transform(Expression expression) {
- if(!(expression instanceof MethodCallExpression)) {
- return super.transform(expression);
- }
+ performSubstitutions(linesOffset, columnsOffset, context, closureBlock);
- MethodCallExpression call = (MethodCallExpression) expression;
- if(!MacroInvocationTrap.isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
- return super.transform(expression);
- }
+ return (T) getMacroValue(closureBlock, asIs);
+ }
+ }
+ if (node instanceof ClassNode) {
+ performSubstitutions(linesOffset, columnsOffset, context, node);
+ return (T) node;
+ }
+ }
+ return null;
+ }
- MacroSubstitutionKey key = new MacroSubstitutionKey(call, linesOffset, columnsOffset);
-
- return context.get(key).call();
- }
+ private void performSubstitutions(final int linesOffset, final int columnsOffset, final Map<MacroSubstitutionKey, Closure<Expression>> context, final ASTNode astNode) {
+ ClassCodeExpressionTransformer trn = new ClassCodeExpressionTransformer() {
+ public Expression transform(Expression expression) {
+ if (!(expression instanceof MethodCallExpression)) {
+ return super.transform(expression);
+ }
- @Override
- protected SourceUnit getSourceUnit() {
- // Could be null if there are no errors
- return null;
- }
- }).visitBlockStatement(closureBlock);
+ MethodCallExpression call = (MethodCallExpression) expression;
- return (T) getMacroValue(closureBlock, asIs);
+ if (!MacroInvocationTrap.isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
+ return super.transform(expression);
+ }
+
+ MacroSubstitutionKey key = new MacroSubstitutionKey(call, linesOffset, columnsOffset);
+
+ return context.get(key).call();
}
+
+ @Override
+ protected SourceUnit getSourceUnit() {
+ // Could be null if there are no errors
+ return null;
+ }
+ };
+ if (astNode instanceof BlockStatement) {
+ trn.visitBlockStatement((BlockStatement) astNode);
+ } else if (astNode instanceof ClassNode) {
+ trn.visitClass((ClassNode) astNode);
}
- return null;
}
public static ASTNode getMacroValue(BlockStatement closureBlock, boolean asIs) {
http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/09758c34/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClass.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClass.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClass.java
new file mode 100644
index 0000000..46dc062
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClass.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed 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.codehaus.groovy.macro.transform;
+
+public abstract class MacroClass {
+}
http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/09758c34/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
index 127fb4b..5a7c275 100644
--- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
@@ -15,64 +15,104 @@
*/
package org.codehaus.groovy.macro.transform;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.InnerClassNode;
import org.codehaus.groovy.ast.MethodInvocationTrap;
-import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MapExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.control.io.ReaderSource;
import org.codehaus.groovy.macro.runtime.MacroBuilder;
import org.codehaus.groovy.macro.runtime.MacroSubstitutionKey;
-import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import static org.codehaus.groovy.ast.expr.VariableExpression.THIS_EXPRESSION;
/**
- *
* @author Sergei Egorov <bs...@gmail.com>
*/
public class MacroInvocationTrap extends MethodInvocationTrap {
+ private final static ClassNode MACROCLASS_TYPE = ClassHelper.make(MacroClass.class);
+ private final ReaderSource readerSource;
+
public MacroInvocationTrap(ReaderSource source, SourceUnit sourceUnit) {
super(source, sourceUnit);
+ this.readerSource = source;
+ }
+
+ @Override
+ public void visitConstructorCallExpression(final ConstructorCallExpression call) {
+ ClassNode type = call.getType();
+ if (type instanceof InnerClassNode) {
+ if (((InnerClassNode) type).isAnonymous() &&
+ MACROCLASS_TYPE.getNameWithoutPackage().equals(type.getSuperClass().getNameWithoutPackage())) {
+ //System.out.println("call = " + call.getText());
+ try {
+ String source = convertInnerClassToSource(type);
+ List<Expression> macroArgumentsExpressions = new LinkedList<Expression>();
+ macroArgumentsExpressions.add(new ConstantExpression(source));
+ macroArgumentsExpressions.add(buildSubstitutionMap(type));
+ macroArgumentsExpressions.add(new ClassExpression(ClassHelper.make(ClassNode.class)));
+
+ MethodCallExpression macroCall = new MethodCallExpression(
+ new PropertyExpression(new ClassExpression(ClassHelper.makeWithoutCaching(MacroBuilder.class, false)), "INSTANCE"),
+ MacroTransformation.MACRO_METHOD,
+ new ArgumentListExpression(macroArgumentsExpressions)
+ );
+
+ macroCall.setSpreadSafe(false);
+ macroCall.setSafe(false);
+ macroCall.setImplicitThis(false);
+ call.putNodeMetaData(MacroTransformation.class, macroCall);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+ }
+ super.visitConstructorCallExpression(call);
+
+ }
+
+ private String convertInnerClassToSource(final ClassNode type) throws Exception {
+ String source = GeneralUtils.convertASTToSource(readerSource, type);
+ // we need to remove the leading "{" and trailing "}"
+ source = source.substring(source.indexOf('{')+1, source.lastIndexOf('}')-1);
+ return source;
}
@Override
protected boolean handleTargetMethodCallExpression(MethodCallExpression macroCall) {
final ClosureExpression closureExpression = getClosureArgument(macroCall);
- if(closureExpression == null) {
+ if (closureExpression == null) {
return true;
}
- if(closureExpression.getParameters() != null && closureExpression.getParameters().length > 0) {
+ if (closureExpression.getParameters() != null && closureExpression.getParameters().length > 0) {
addError("Macro closure arguments are not allowed", closureExpression);
return true;
}
- final MapExpression mapExpression = new MapExpression();
-
- (new CodeVisitorSupport() {
- @Override
- public void visitMethodCallExpression(MethodCallExpression call) {
- super.visitMethodCallExpression(call);
-
- if(isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
- ClosureExpression substitutionClosureExpression = getClosureArgument(call);
-
- if(substitutionClosureExpression == null) {
- return;
- }
-
- MacroSubstitutionKey key = new MacroSubstitutionKey(call, closureExpression.getLineNumber(), closureExpression.getColumnNumber());
-
- mapExpression.addMapEntryExpression(key.toConstructorCallExpression(), substitutionClosureExpression);
- }
- }
- }).visitClosureExpression(closureExpression);
+ final MapExpression mapExpression = buildSubstitutionMap(closureExpression);
String source = convertClosureToSource(closureExpression);
@@ -82,18 +122,18 @@ public class MacroInvocationTrap extends MethodInvocationTrap {
TupleExpression macroArguments = getMacroArguments(macroCall);
- if(macroArguments == null) {
+ if (macroArguments == null) {
return true;
}
List<Expression> macroArgumentsExpressions = macroArguments.getExpressions();
- if(macroArgumentsExpressions.size() == 2 || macroArgumentsExpressions.size() == 3) {
+ if (macroArgumentsExpressions.size() == 2 || macroArgumentsExpressions.size() == 3) {
Expression asIsArgumentExpression = macroArgumentsExpressions.get(macroArgumentsExpressions.size() - 2);
- if((asIsArgumentExpression instanceof ConstantExpression)) {
+ if ((asIsArgumentExpression instanceof ConstantExpression)) {
ConstantExpression asIsConstantExpression = (ConstantExpression) asIsArgumentExpression;
- if(!(asIsConstantExpression.getValue() instanceof Boolean)) {
+ if (!(asIsConstantExpression.getValue() instanceof Boolean)) {
addError("AsIs argument value should be boolean", asIsConstantExpression);
return true;
}
@@ -112,10 +152,54 @@ public class MacroInvocationTrap extends MethodInvocationTrap {
macroCall.setSpreadSafe(false);
macroCall.setSafe(false);
macroCall.setImplicitThis(false);
-
+
return true;
}
+ private MapExpression buildSubstitutionMap(final ASTNode expr) {
+ final MapExpression mapExpression = new MapExpression();
+
+ ClassCodeVisitorSupport visitor = new ClassCodeVisitorSupport() {
+ @Override
+ protected SourceUnit getSourceUnit() {
+ return null;
+ }
+
+ @Override
+ public void visitClass(final ClassNode node) {
+ super.visitClass(node);
+ Iterator<InnerClassNode> it = node.getInnerClasses();
+ while (it.hasNext()) {
+ InnerClassNode next = it.next();
+ visitClass(next);
+ }
+ }
+
+ @Override
+ public void visitMethodCallExpression(MethodCallExpression call) {
+ super.visitMethodCallExpression(call);
+
+ if (isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
+ ClosureExpression substitutionClosureExpression = getClosureArgument(call);
+
+ if (substitutionClosureExpression == null) {
+ return;
+ }
+
+ MacroSubstitutionKey key = new MacroSubstitutionKey(call, expr.getLineNumber(), expr.getColumnNumber());
+
+ mapExpression.addMapEntryExpression(key.toConstructorCallExpression(), substitutionClosureExpression);
+ }
+ }
+ };
+ if (expr instanceof ClassNode) {
+ visitor.visitClass((ClassNode) expr);
+ } else {
+ expr.visit(visitor);
+ }
+ return mapExpression;
+ }
+
@Override
protected boolean isBuildInvocation(MethodCallExpression call) {
return isBuildInvocation(call, MacroTransformation.MACRO_METHOD);
@@ -123,20 +207,20 @@ public class MacroInvocationTrap extends MethodInvocationTrap {
public static boolean isBuildInvocation(MethodCallExpression call, String methodName) {
if (call == null) throw new IllegalArgumentException("Null: call");
- if(methodName == null) throw new IllegalArgumentException("Null: methodName");
+ if (methodName == null) throw new IllegalArgumentException("Null: methodName");
- if(!(call.getMethod() instanceof ConstantExpression)) {
+ if (!(call.getMethod() instanceof ConstantExpression)) {
return false;
}
- if(!(methodName.equals(call.getMethodAsString()))) {
+ if (!(methodName.equals(call.getMethodAsString()))) {
return false;
}
// is method object correct type?
return call.getObjectExpression() == THIS_EXPRESSION;
}
-
+
protected TupleExpression getMacroArguments(MethodCallExpression call) {
Expression macroCallArguments = call.getArguments();
if (macroCallArguments == null) {
@@ -144,7 +228,7 @@ public class MacroInvocationTrap extends MethodInvocationTrap {
return null;
}
- if(!(macroCallArguments instanceof TupleExpression)) {
+ if (!(macroCallArguments instanceof TupleExpression)) {
addError("Call should have TupleExpression as arguments", macroCallArguments);
return null;
}
@@ -155,14 +239,14 @@ public class MacroInvocationTrap extends MethodInvocationTrap {
addError("Call arguments should have expressions", tupleArguments);
return null;
}
-
+
return tupleArguments;
}
-
+
protected ClosureExpression getClosureArgument(MethodCallExpression call) {
TupleExpression tupleArguments = getMacroArguments(call);
- if(tupleArguments.getExpressions().size() < 1) {
+ if (tupleArguments.getExpressions().size() < 1) {
addError("Call arguments should have at least one argument", tupleArguments);
return null;
}
http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/09758c34/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroTransformation.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroTransformation.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroTransformation.java
index 65284b5..7920e2e 100644
--- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroTransformation.java
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroTransformation.java
@@ -16,6 +16,7 @@
package org.codehaus.groovy.macro.transform;
import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.ast.expr.*;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.transform.GroovyASTTransformation;
@@ -32,8 +33,25 @@ public class MacroTransformation extends MethodCallTransformation {
public static final String MACRO_METHOD = "macro";
@Override
- protected GroovyCodeVisitor getTransformer(ASTNode[] nodes, SourceUnit sourceUnit) {
- return new MacroInvocationTrap(sourceUnit.getSource(), sourceUnit);
+ protected GroovyCodeVisitor getTransformer(final ASTNode[] nodes, final SourceUnit sourceUnit) {
+ final ClassCodeExpressionTransformer trn = new ClassCodeExpressionTransformer() {
+ @Override
+ protected SourceUnit getSourceUnit() {
+ return sourceUnit;
+ }
+
+ @Override
+ public Expression transform(final Expression exp) {
+ if (exp instanceof ConstructorCallExpression) {
+ MethodCallExpression call = exp.getNodeMetaData(MacroTransformation.class);
+ if (call!=null) {
+ return call;
+ }
+ }
+ return super.transform(exp);
+ }
+ };
+ return new TransformingMacroTrap(sourceUnit, trn);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/09758c34/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/TransformingMacroTrap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/TransformingMacroTrap.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/TransformingMacroTrap.java
new file mode 100644
index 0000000..35ddf55
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/TransformingMacroTrap.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed 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.codehaus.groovy.macro.transform;
+
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.codehaus.groovy.control.SourceUnit;
+
+class TransformingMacroTrap extends MacroInvocationTrap {
+ private final ClassCodeExpressionTransformer trn;
+
+ public TransformingMacroTrap(final SourceUnit sourceUnit, final ClassCodeExpressionTransformer trn) {
+ super(sourceUnit.getSource(), sourceUnit);
+ this.trn = trn;
+ }
+
+ @Override
+ public void visitBlockStatement(final BlockStatement block) {
+ super.visitBlockStatement(block);
+ trn.visitBlockStatement(block);
+ }
+
+ @Override
+ public void visitForLoop(final ForStatement forLoop) {
+ super.visitForLoop(forLoop);
+ trn.visitForLoop(forLoop);
+ }
+
+ @Override
+ public void visitWhileLoop(final WhileStatement loop) {
+ super.visitWhileLoop(loop);
+ trn.visitWhileLoop(loop);
+ }
+
+ @Override
+ public void visitDoWhileLoop(final DoWhileStatement loop) {
+ super.visitDoWhileLoop(loop);
+ trn.visitDoWhileLoop(loop);
+ }
+
+ @Override
+ public void visitIfElse(final IfStatement ifElse) {
+ super.visitIfElse(ifElse);
+ trn.visitIfElse(ifElse);
+ }
+
+ @Override
+ public void visitExpressionStatement(final ExpressionStatement statement) {
+ super.visitExpressionStatement(statement);
+ trn.visitExpressionStatement(statement);
+ }
+
+ @Override
+ public void visitReturnStatement(final ReturnStatement statement) {
+ super.visitReturnStatement(statement);
+ trn.visitReturnStatement(statement);
+ }
+
+ @Override
+ public void visitAssertStatement(final AssertStatement statement) {
+ super.visitAssertStatement(statement);
+ trn.visitAssertStatement(statement);
+ }
+
+ @Override
+ public void visitTryCatchFinally(final TryCatchStatement statement) {
+ super.visitTryCatchFinally(statement);
+ trn.visitTryCatchFinally(statement);
+ }
+
+ @Override
+ public void visitSwitch(final SwitchStatement statement) {
+ super.visitSwitch(statement);
+ trn.visitSwitch(statement);
+ }
+
+ @Override
+ public void visitCaseStatement(final CaseStatement statement) {
+ super.visitCaseStatement(statement);
+ trn.visitCaseStatement(statement);
+ }
+
+ @Override
+ public void visitBreakStatement(final BreakStatement statement) {
+ super.visitBreakStatement(statement);
+ trn.visitBreakStatement(statement);
+ }
+
+ @Override
+ public void visitContinueStatement(final ContinueStatement statement) {
+ super.visitContinueStatement(statement);
+ trn.visitContinueStatement(statement);
+ }
+
+ @Override
+ public void visitSynchronizedStatement(final SynchronizedStatement statement) {
+ super.visitSynchronizedStatement(statement);
+ trn.visitSynchronizedStatement(statement);
+ }
+
+ @Override
+ public void visitThrowStatement(final ThrowStatement statement) {
+ super.visitThrowStatement(statement);
+ trn.visitThrowStatement(statement);
+ }
+
+ @Override
+ public void visitStaticMethodCallExpression(final StaticMethodCallExpression call) {
+ super.visitStaticMethodCallExpression(call);
+ trn.visitStaticMethodCallExpression(call);
+ }
+
+ @Override
+ public void visitBinaryExpression(final BinaryExpression expression) {
+ super.visitBinaryExpression(expression);
+ trn.visitBinaryExpression(expression);
+ }
+
+ @Override
+ public void visitTernaryExpression(final TernaryExpression expression) {
+ super.visitTernaryExpression(expression);
+ trn.visitTernaryExpression(expression);
+ }
+
+ @Override
+ public void visitShortTernaryExpression(final ElvisOperatorExpression expression) {
+ super.visitShortTernaryExpression(expression);
+ trn.visitShortTernaryExpression(expression);
+ }
+
+ @Override
+ public void visitPostfixExpression(final PostfixExpression expression) {
+ super.visitPostfixExpression(expression);
+ trn.visitPostfixExpression(expression);
+ }
+
+ @Override
+ public void visitPrefixExpression(final PrefixExpression expression) {
+ super.visitPrefixExpression(expression);
+ trn.visitPrefixExpression(expression);
+ }
+
+ @Override
+ public void visitBooleanExpression(final BooleanExpression expression) {
+ super.visitBooleanExpression(expression);
+ trn.visitBooleanExpression(expression);
+ }
+
+ @Override
+ public void visitNotExpression(final NotExpression expression) {
+ super.visitNotExpression(expression);
+ trn.visitNotExpression(expression);
+ }
+
+ @Override
+ public void visitClosureExpression(final ClosureExpression expression) {
+ super.visitClosureExpression(expression);
+ trn.visitClosureExpression(expression);
+ }
+
+ @Override
+ public void visitTupleExpression(final TupleExpression expression) {
+ super.visitTupleExpression(expression);
+ trn.visitTupleExpression(expression);
+ }
+
+ @Override
+ public void visitListExpression(final ListExpression expression) {
+ super.visitListExpression(expression);
+ trn.visitListExpression(expression);
+ }
+
+ @Override
+ public void visitArrayExpression(final ArrayExpression expression) {
+ super.visitArrayExpression(expression);
+ trn.visitArrayExpression(expression);
+ }
+
+ @Override
+ public void visitMapExpression(final MapExpression expression) {
+ super.visitMapExpression(expression);
+ trn.visitMapExpression(expression);
+ }
+
+ @Override
+ public void visitMapEntryExpression(final MapEntryExpression expression) {
+ super.visitMapEntryExpression(expression);
+ trn.visitMapEntryExpression(expression);
+ }
+
+ @Override
+ public void visitRangeExpression(final RangeExpression expression) {
+ super.visitRangeExpression(expression);
+ trn.visitRangeExpression(expression);
+ }
+
+ @Override
+ public void visitSpreadExpression(final SpreadExpression expression) {
+ super.visitSpreadExpression(expression);
+ trn.visitSpreadExpression(expression);
+ }
+
+ @Override
+ public void visitSpreadMapExpression(final SpreadMapExpression expression) {
+ super.visitSpreadMapExpression(expression);
+ trn.visitSpreadMapExpression(expression);
+ }
+
+ @Override
+ public void visitMethodPointerExpression(final MethodPointerExpression expression) {
+ super.visitMethodPointerExpression(expression);
+ trn.visitMethodPointerExpression(expression);
+ }
+
+ @Override
+ public void visitUnaryMinusExpression(final UnaryMinusExpression expression) {
+ super.visitUnaryMinusExpression(expression);
+ trn.visitUnaryMinusExpression(expression);
+ }
+
+ @Override
+ public void visitUnaryPlusExpression(final UnaryPlusExpression expression) {
+ super.visitUnaryPlusExpression(expression);
+ trn.visitUnaryPlusExpression(expression);
+ }
+
+ @Override
+ public void visitBitwiseNegationExpression(final BitwiseNegationExpression expression) {
+ super.visitBitwiseNegationExpression(expression);
+ trn.visitBitwiseNegationExpression(expression);
+ }
+
+ @Override
+ public void visitCastExpression(final CastExpression expression) {
+ super.visitCastExpression(expression);
+ trn.visitCastExpression(expression);
+ }
+
+ @Override
+ public void visitConstantExpression(final ConstantExpression expression) {
+ super.visitConstantExpression(expression);
+ trn.visitConstantExpression(expression);
+ }
+
+ @Override
+ public void visitClassExpression(final ClassExpression expression) {
+ super.visitClassExpression(expression);
+ trn.visitClassExpression(expression);
+ }
+
+ @Override
+ public void visitVariableExpression(final VariableExpression expression) {
+ super.visitVariableExpression(expression);
+ trn.visitVariableExpression(expression);
+ }
+
+ @Override
+ public void visitDeclarationExpression(final DeclarationExpression expression) {
+ super.visitDeclarationExpression(expression);
+ trn.visitDeclarationExpression(expression);
+ }
+
+ @Override
+ public void visitPropertyExpression(final PropertyExpression expression) {
+ super.visitPropertyExpression(expression);
+ trn.visitPropertyExpression(expression);
+ }
+
+ @Override
+ public void visitAttributeExpression(final AttributeExpression expression) {
+ super.visitAttributeExpression(expression);
+ trn.visitAttributeExpression(expression);
+ }
+
+ @Override
+ public void visitFieldExpression(final FieldExpression expression) {
+ super.visitFieldExpression(expression);
+ trn.visitFieldExpression(expression);
+ }
+
+ @Override
+ public void visitGStringExpression(final GStringExpression expression) {
+ super.visitGStringExpression(expression);
+ trn.visitGStringExpression(expression);
+ }
+
+ @Override
+ public void visitCatchStatement(final CatchStatement statement) {
+ super.visitCatchStatement(statement);
+ trn.visitCatchStatement(statement);
+ }
+
+ @Override
+ public void visitArgumentlistExpression(final ArgumentListExpression ale) {
+ super.visitArgumentlistExpression(ale);
+ trn.visitArgumentlistExpression(ale);
+ }
+
+ @Override
+ public void visitClosureListExpression(final ClosureListExpression cle) {
+ super.visitClosureListExpression(cle);
+ trn.visitClosureListExpression(cle);
+ }
+
+ @Override
+ public void visitBytecodeExpression(final BytecodeExpression cle) {
+ super.visitBytecodeExpression(cle);
+ trn.visitBytecodeExpression(cle);
+ }
+}