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 2017/04/07 13:31:19 UTC
[36/50] [abbrv] groovy git commit: introduce macro methods and
re-implement macro as a macro method
introduce macro methods and re-implement macro as a macro method
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/b4e68bd5
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/b4e68bd5
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/b4e68bd5
Branch: refs/heads/parrot
Commit: b4e68bd554acbe8a9fc30a81a2291306d1e78968
Parents: a299cba
Author: Sergei Egorov <se...@zeroturnaround.com>
Authored: Thu Dec 29 20:42:50 2016 +0200
Committer: paulk <pa...@asert.com.au>
Committed: Tue Mar 28 16:02:21 2017 +1000
----------------------------------------------------------------------
.../groovy/ast/TransformingCodeVisitor.java | 340 ++++++++++++++++++
.../codehaus/groovy/control/ErrorCollector.java | 6 +-
.../org/codehaus/groovy/control/SourceUnit.java | 4 +
.../codehaus/groovy/syntax/SyntaxException.java | 5 +
.../macro/methods/MacroGroovyMethods.java | 214 +++++++++++
.../codehaus/groovy/macro/runtime/Macro.java | 36 ++
.../groovy/macro/runtime/MacroBuilder.java | 18 +-
.../groovy/macro/runtime/MacroContext.java | 56 +++
.../macro/runtime/MacroGroovyMethods.java | 53 ---
.../groovy/macro/runtime/MacroStub.java | 32 ++
.../transform/MacroClassTransformation.java | 114 ++++++
.../macro/transform/MacroInvocationTrap.java | 274 --------------
.../macro/transform/MacroMethodsCache.java | 143 ++++++++
.../macro/transform/MacroTransformation.java | 97 ++++-
.../macro/transform/TransformingMacroTrap.java | 343 ------------------
.../org.codehaus.groovy.runtime.ExtensionModule | 17 +
....codehaus.groovy.transform.ASTTransformation | 1 +
.../groovy/macro/ExampleMacroMethods.java | 34 ++
.../org/codehaus/groovy/macro/MacroTest.groovy | 15 +
.../groovy/macro/MacroTransformationTest.groovy | 70 ++++
.../groovy/macro/matcher/ASTMatcherTest.groovy | 357 ++++++++++++++++++-
.../org.codehaus.groovy.runtime.ExtensionModule | 17 +
22 files changed, 1534 insertions(+), 712 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/src/main/org/codehaus/groovy/ast/TransformingCodeVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/TransformingCodeVisitor.java b/src/main/org/codehaus/groovy/ast/TransformingCodeVisitor.java
new file mode 100644
index 0000000..53f02fd
--- /dev/null
+++ b/src/main/org/codehaus/groovy/ast/TransformingCodeVisitor.java
@@ -0,0 +1,340 @@
+/*
+ * 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.codehaus.groovy.ast;
+
+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;
+
+public class TransformingCodeVisitor extends CodeVisitorSupport {
+ private final ClassCodeExpressionTransformer trn;
+
+ public TransformingCodeVisitor(final ClassCodeExpressionTransformer trn) {
+ 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);
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/src/main/org/codehaus/groovy/control/ErrorCollector.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/control/ErrorCollector.java b/src/main/org/codehaus/groovy/control/ErrorCollector.java
index 4777d34..3376644 100644
--- a/src/main/org/codehaus/groovy/control/ErrorCollector.java
+++ b/src/main/org/codehaus/groovy/control/ErrorCollector.java
@@ -80,8 +80,10 @@ public class ErrorCollector {
}
}
}
-
-
+
+ public void addErrorAndContinue(SyntaxException error, SourceUnit source) throws CompilationFailedException {
+ addErrorAndContinue(Message.create(error, source));
+ }
/**
* Adds an error to the message set, but does not cause a failure. The message is not required to have a source
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/src/main/org/codehaus/groovy/control/SourceUnit.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/control/SourceUnit.java b/src/main/org/codehaus/groovy/control/SourceUnit.java
index 66950f4..b2c8a32 100644
--- a/src/main/org/codehaus/groovy/control/SourceUnit.java
+++ b/src/main/org/codehaus/groovy/control/SourceUnit.java
@@ -349,5 +349,9 @@ public class SourceUnit extends ProcessingUnit {
getErrorCollector().addError(se, this);
}
+ public void addErrorAndContinue(SyntaxException se) throws CompilationFailedException {
+ getErrorCollector().addErrorAndContinue(se, this);
+ }
+
public ReaderSource getSource() { return source; }
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/src/main/org/codehaus/groovy/syntax/SyntaxException.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/syntax/SyntaxException.java b/src/main/org/codehaus/groovy/syntax/SyntaxException.java
index 0348e8c..eb5b69f 100644
--- a/src/main/org/codehaus/groovy/syntax/SyntaxException.java
+++ b/src/main/org/codehaus/groovy/syntax/SyntaxException.java
@@ -19,6 +19,7 @@
package org.codehaus.groovy.syntax;
import org.codehaus.groovy.GroovyException;
+import org.codehaus.groovy.ast.ASTNode;
/** Base exception indicating a syntax error.
*
@@ -36,6 +37,10 @@ public class SyntaxException extends GroovyException {
private String sourceLocator;
+ public SyntaxException(String message, ASTNode node) {
+ this(message, node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber());
+ }
+
public SyntaxException(String message, int startLine, int startColumn) {
this(message, startLine, startColumn, startLine, startColumn+1);
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/methods/MacroGroovyMethods.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/methods/MacroGroovyMethods.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/methods/MacroGroovyMethods.java
new file mode 100644
index 0000000..d9f00e6
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/methods/MacroGroovyMethods.java
@@ -0,0 +1,214 @@
+/*
+ * 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.codehaus.groovy.macro.methods;
+
+import groovy.lang.Closure;
+import groovy.lang.DelegatesTo;
+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.InnerClassNode;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+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.stmt.Statement;
+import org.codehaus.groovy.ast.tools.ClosureUtils;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.macro.runtime.Macro;
+import org.codehaus.groovy.macro.runtime.MacroBuilder;
+import org.codehaus.groovy.macro.runtime.MacroContext;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+import java.util.Iterator;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
+
+public class MacroGroovyMethods {
+
+ public static final String DOLLAR_VALUE = "$v";
+
+ public static class MacroValuePlaceholder {
+ public static Object $v(Closure cl) {
+ // replaced with AST transformations
+ return null;
+ }
+ }
+
+ public static <T> T macro(Object self, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
+ throw new IllegalStateException("MacroGroovyMethods.macro(Closure) should never be called at runtime. Are you sure you are using it correctly?");
+ }
+
+ @Macro
+ public static Expression macro(MacroContext macroContext, ClosureExpression closureExpression) {
+ return macro(macroContext, new ConstantExpression(false, true), closureExpression);
+ }
+
+ public static <T> T macro(Object self, boolean asIs, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
+ throw new IllegalStateException("MacroGroovyMethods.macro(boolean, Closure) should never be called at runtime. Are you sure you are using it correctly?");
+ }
+
+ @Macro
+ public static Expression macro(MacroContext macroContext, ConstantExpression asIsConstantExpression, ClosureExpression closureExpression) {
+ return macro(macroContext, null, asIsConstantExpression, closureExpression);
+ }
+
+ public static <T> T macro(Object self, CompilePhase compilePhase, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
+ throw new IllegalStateException("MacroGroovyMethods.macro(CompilePhase, Closure) should never be called at runtime. Are you sure you are using it correctly?");
+ }
+
+ @Macro
+ public static Expression macro(MacroContext macroContext, PropertyExpression phaseExpression, ClosureExpression closureExpression) {
+ return macro(macroContext, phaseExpression, new ConstantExpression(false, true), closureExpression);
+ }
+
+ public static <T> T macro(Object self, CompilePhase compilePhase, boolean asIs, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
+ throw new IllegalStateException("MacroGroovyMethods.macro(CompilePhase, boolean, Closure) should never be called at runtime. Are you sure you are using it correctly?");
+ }
+
+ @Macro
+ public static Expression macro(MacroContext macroContext, PropertyExpression phaseExpression, ConstantExpression asIsConstantExpression, ClosureExpression closureExpression) {
+ if (closureExpression.getParameters() != null && closureExpression.getParameters().length > 0) {
+ macroContext.getSourceUnit().addError(new SyntaxException("Macro closure arguments are not allowed" + '\n', closureExpression));
+ return macroContext.getCall();
+ }
+
+ final String source;
+ try {
+ source = ClosureUtils.convertClosureToSource(macroContext.getSourceUnit().getSource(), closureExpression);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ BlockStatement closureBlock = (BlockStatement) closureExpression.getCode();
+
+ Boolean asIs = (Boolean) asIsConstantExpression.getValue();
+
+ TupleExpression macroArguments = getMacroArguments(macroContext.getSourceUnit(), macroContext.getCall());
+
+ if (macroArguments == null) {
+ // FIXME
+ return macroContext.getCall();
+ }
+
+ return callX(
+ propX(classX(ClassHelper.makeWithoutCaching(MacroBuilder.class, false)), "INSTANCE"),
+ "macro",
+ args(
+ phaseExpression != null ? phaseExpression : constX(null),
+ asIsConstantExpression,
+ constX(source),
+ buildSubstitutionMap(macroContext.getSourceUnit(), closureExpression),
+ classX(ClassHelper.makeWithoutCaching(MacroBuilder.getMacroValue(closureBlock, asIs).getClass(), false))
+ )
+ );
+ }
+
+ public static ListExpression buildSubstitutionMap(final SourceUnit source, final ASTNode expr) {
+ final ListExpression listExpression = new ListExpression();
+
+ 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 (DOLLAR_VALUE.equals(call.getMethodAsString())) {
+ ClosureExpression substitutionClosureExpression = getClosureArgument(source, call);
+
+ if (substitutionClosureExpression == null) {
+ return;
+ }
+
+ Statement code = substitutionClosureExpression.getCode();
+ if (code instanceof BlockStatement) {
+ ((BlockStatement) code).setVariableScope(null);
+ }
+
+ listExpression.addExpression(substitutionClosureExpression);
+ }
+ }
+ };
+ if (expr instanceof ClassNode) {
+ visitor.visitClass((ClassNode) expr);
+ } else {
+ expr.visit(visitor);
+ }
+ return listExpression;
+ }
+
+ protected static TupleExpression getMacroArguments(SourceUnit source, MethodCallExpression call) {
+ Expression macroCallArguments = call.getArguments();
+ if (macroCallArguments == null) {
+ source.addError(new SyntaxException("Call should have arguments" + '\n', call));
+ return null;
+ }
+
+ if (!(macroCallArguments instanceof TupleExpression)) {
+ source.addError(new SyntaxException("Call should have TupleExpression as arguments" + '\n', macroCallArguments));
+ return null;
+ }
+
+ TupleExpression tupleArguments = (TupleExpression) macroCallArguments;
+
+ if (tupleArguments.getExpressions() == null) {
+ source.addError(new SyntaxException("Call arguments should have expressions" + '\n', tupleArguments));
+ return null;
+ }
+
+ return tupleArguments;
+ }
+
+ protected static ClosureExpression getClosureArgument(SourceUnit source, MethodCallExpression call) {
+ TupleExpression tupleArguments = getMacroArguments(source, call);
+
+ if (tupleArguments == null || tupleArguments.getExpressions().size() < 1) {
+ source.addError(new SyntaxException("Call arguments should have at least one argument" + '\n', tupleArguments));
+ return null;
+ }
+
+ Expression result = tupleArguments.getExpression(tupleArguments.getExpressions().size() - 1);
+ if (!(result instanceof ClosureExpression)) {
+ source.addError(new SyntaxException("Last call argument should be a closure" + '\n', result));
+ return null;
+ }
+
+ return (ClosureExpression) result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/Macro.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/Macro.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/Macro.java
new file mode 100644
index 0000000..b6a8938
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/Macro.java
@@ -0,0 +1,36 @@
+/*
+ * 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.codehaus.groovy.macro.runtime;
+
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+@Incubating
+public @interface Macro {
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/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 d7cc5ce..ef857e9 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
@@ -30,15 +30,14 @@ import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.macro.transform.MacroInvocationTrap;
-import org.codehaus.groovy.macro.transform.MacroTransformation;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
+import static org.codehaus.groovy.macro.methods.MacroGroovyMethods.DOLLAR_VALUE;
+
/**
- *
* @author Sergei Egorov <bs...@gmail.com>
*/
public enum MacroBuilder {
@@ -49,7 +48,7 @@ public enum MacroBuilder {
}
public <T> T macro(boolean asIs, String source, final List<Closure<Expression>> context, Class<T> resultClass) {
- return macro(CompilePhase.CONVERSION, asIs, source, context, resultClass);
+ return macro(null, asIs, source, context, resultClass);
}
public <T> T macro(CompilePhase compilePhase, String source, final List<Closure<Expression>> context, Class<T> resultClass) {
@@ -61,12 +60,16 @@ public enum MacroBuilder {
@SuppressWarnings("unchecked")
public <T> T macro(CompilePhase compilePhase, boolean asIs, String source, final List<Closure<Expression>> context, Class<T> resultClass) {
boolean isClosure = source.startsWith("{");
- final String label = isClosure ?"__synthesized__label__" + COUNTER.incrementAndGet() + "__:":"";
+ final String label = isClosure ? "__synthesized__label__" + COUNTER.incrementAndGet() + "__:" : "";
final String labelledSource = label + source;
+ if (compilePhase == null) {
+ compilePhase = CompilePhase.CONVERSION;
+ }
+
List<ASTNode> nodes = (new AstBuilder()).buildFromString(compilePhase, true, labelledSource);
- for(ASTNode node : nodes) {
+ for (ASTNode node : nodes) {
if (node instanceof BlockStatement) {
List<Statement> statements = ((BlockStatement) node).getStatements();
@@ -75,7 +78,6 @@ public enum MacroBuilder {
performSubstitutions(context, closureBlock);
-
return (T) getMacroValue(closureBlock, asIs);
}
}
@@ -97,7 +99,7 @@ public enum MacroBuilder {
MethodCallExpression call = (MethodCallExpression) expression;
- if (!MacroInvocationTrap.isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
+ if (!DOLLAR_VALUE.equals(call.getMethodAsString())) {
return super.transform(expression);
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroContext.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroContext.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroContext.java
new file mode 100644
index 0000000..e181a2a
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroContext.java
@@ -0,0 +1,56 @@
+/*
+ * 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.codehaus.groovy.macro.runtime;
+
+import org.apache.groovy.lang.annotation.Incubating;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+
+/**
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+
+@Incubating
+public class MacroContext {
+
+ private final MethodCallExpression call;
+
+ private final SourceUnit sourceUnit;
+
+ private final CompilationUnit compilationUnit;
+
+ public MacroContext(CompilationUnit compilationUnit, SourceUnit sourceUnit, MethodCallExpression call) {
+ this.compilationUnit = compilationUnit;
+ this.sourceUnit = sourceUnit;
+ this.call = call;
+ }
+
+ public MethodCallExpression getCall() {
+ return call;
+ }
+
+ public SourceUnit getSourceUnit() {
+ return sourceUnit;
+ }
+
+ public CompilationUnit getCompilationUnit() {
+ return compilationUnit;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java
deleted file mode 100644
index 7e39589..0000000
--- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.codehaus.groovy.macro.runtime;
-
-import groovy.lang.Closure;
-import groovy.lang.DelegatesTo;
-import org.codehaus.groovy.control.CompilePhase;
-
-/**
- *
- * @author Sergei Egorov <bs...@gmail.com>
- */
-public class MacroGroovyMethods {
-
- public static class MacroValuePlaceholder {
- public static Object $v(Closure cl) {
- // replaced with AST transformations
- return null;
- }
- }
-
- public static <T> T macro(Object self, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
- return null;
- }
-
- public static <T> T macro(Object self, boolean asIs, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
- return null;
- }
-
- public static <T> T macro(Object self, CompilePhase compilePhase, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
- return null;
- }
-
- public static <T> T macro(Object self, CompilePhase compilePhase, boolean asIs, @DelegatesTo(MacroValuePlaceholder.class) Closure cl) {
- return null;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroStub.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroStub.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroStub.java
new file mode 100644
index 0000000..b0590b5
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroStub.java
@@ -0,0 +1,32 @@
+/*
+ * 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.codehaus.groovy.macro.runtime;
+
+/**
+ * Stub for macro calls.
+ *
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+public enum MacroStub {
+ INSTANCE;
+
+ public <T> T macroMethod(T obj) {
+ return obj;
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClassTransformation.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClassTransformation.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClassTransformation.java
new file mode 100644
index 0000000..292d59d
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroClassTransformation.java
@@ -0,0 +1,114 @@
+/*
+ * 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.codehaus.groovy.macro.transform;
+
+import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.macro.methods.MacroGroovyMethods;
+import org.codehaus.groovy.macro.runtime.MacroBuilder;
+import org.codehaus.groovy.transform.GroovyASTTransformation;
+
+import java.util.Iterator;
+import java.util.List;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
+
+@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
+public class MacroClassTransformation extends MethodCallTransformation {
+
+ private static final String MACRO_METHOD = "macro";
+ private static final ClassNode MACROCLASS_TYPE = ClassHelper.make(MacroClass.class);
+
+ @Override
+ protected GroovyCodeVisitor getTransformer(final ASTNode[] nodes, final SourceUnit sourceUnit) {
+ ClassCodeExpressionTransformer transformer = 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 TransformingCodeVisitor(transformer) {
+
+ @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())) {
+ try {
+ String source = convertInnerClassToSource(type);
+
+ MethodCallExpression macroCall = callX(
+ propX(classX(ClassHelper.makeWithoutCaching(MacroBuilder.class, false)), "INSTANCE"),
+ MACRO_METHOD,
+ args(
+ constX(source),
+ MacroGroovyMethods.buildSubstitutionMap(sourceUnit, type),
+ classX(ClassHelper.make(ClassNode.class))
+ )
+ );
+
+ macroCall.setSpreadSafe(false);
+ macroCall.setSafe(false);
+ macroCall.setImplicitThis(false);
+ call.putNodeMetaData(MacroTransformation.class, macroCall);
+ List<ClassNode> classes = sourceUnit.getAST().getClasses();
+ for (Iterator<ClassNode> iterator = classes.iterator(); iterator.hasNext(); ) {
+ final ClassNode aClass = iterator.next();
+ if (aClass == type || type == aClass.getOuterClass()) {
+ iterator.remove();
+ }
+ }
+ } catch (Exception e) {
+ // FIXME
+ e.printStackTrace();
+ }
+ return;
+ }
+ }
+ super.visitConstructorCallExpression(call);
+
+ }
+
+ private String convertInnerClassToSource(final ClassNode type) throws Exception {
+ String source = GeneralUtils.convertASTToSource(sourceUnit.getSource(), type);
+ // we need to remove the leading "{" and trailing "}"
+ source = source.substring(source.indexOf('{') + 1, source.lastIndexOf('}') - 1);
+ return source;
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/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
deleted file mode 100644
index 73c14db..0000000
--- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * 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.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.InnerClassNode;
-import org.codehaus.groovy.ast.MethodInvocationTrap;
-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.ListExpression;
-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.stmt.Statement;
-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 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;
- private final SourceUnit sourceUnit;
-
- public MacroInvocationTrap(ReaderSource source, SourceUnit sourceUnit) {
- super(source, sourceUnit);
- this.readerSource = source;
- this.sourceUnit = sourceUnit;
- }
-
- @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);
- List<ClassNode> classes = sourceUnit.getAST().getClasses();
- for (Iterator<ClassNode> iterator = classes.iterator(); iterator.hasNext(); ) {
- final ClassNode aClass = iterator.next();
- if (aClass==type || type==aClass.getOuterClass()) {
- iterator.remove();
- }
- }
- } 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) {
- return true;
- }
-
- if (closureExpression.getParameters() != null && closureExpression.getParameters().length > 0) {
- addError("Macro closure arguments are not allowed", closureExpression);
- return true;
- }
-
- String source = convertClosureToSource(closureExpression);
-
- BlockStatement closureBlock = (BlockStatement) closureExpression.getCode();
-
- Boolean asIs = false;
-
- TupleExpression macroArguments = getMacroArguments(macroCall);
-
- if (macroArguments == null) {
- return true;
- }
-
- List<Expression> macroArgumentsExpressions = macroArguments.getExpressions();
-
- if (macroArgumentsExpressions.size() == 2 || macroArgumentsExpressions.size() == 3) {
- Expression asIsArgumentExpression = macroArgumentsExpressions.get(macroArgumentsExpressions.size() - 2);
- if ((asIsArgumentExpression instanceof ConstantExpression)) {
- ConstantExpression asIsConstantExpression = (ConstantExpression) asIsArgumentExpression;
-
- if (!(asIsConstantExpression.getValue() instanceof Boolean)) {
- addError("AsIs argument value should be boolean", asIsConstantExpression);
- return true;
- }
-
- asIs = (Boolean) asIsConstantExpression.getValue();
- }
- }
-
- macroArgumentsExpressions.remove(macroArgumentsExpressions.size() - 1);
-
- macroArgumentsExpressions.add(new ConstantExpression(source));
- macroArgumentsExpressions.add(buildSubstitutionMap(closureExpression));
- macroArgumentsExpressions.add(new ClassExpression(ClassHelper.makeWithoutCaching(MacroBuilder.getMacroValue(closureBlock, asIs).getClass(), false)));
-
- macroCall.setObjectExpression(new PropertyExpression(new ClassExpression(ClassHelper.makeWithoutCaching(MacroBuilder.class, false)), "INSTANCE"));
- macroCall.setSpreadSafe(false);
- macroCall.setSafe(false);
- macroCall.setImplicitThis(false);
-
- return true;
- }
-
- private ListExpression buildSubstitutionMap(final ASTNode expr) {
- final ListExpression listExpression = new ListExpression();
-
- 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;
- }
-
- Statement code = substitutionClosureExpression.getCode();
- if (code instanceof BlockStatement) {
- ((BlockStatement) code).setVariableScope(null);
- }
-
- listExpression.addExpression(substitutionClosureExpression);
- }
- }
- };
- if (expr instanceof ClassNode) {
- visitor.visitClass((ClassNode) expr);
- } else {
- expr.visit(visitor);
- }
- return listExpression;
- }
-
- @Override
- protected boolean isBuildInvocation(MethodCallExpression call) {
- return isBuildInvocation(call, MacroTransformation.MACRO_METHOD);
- }
-
- 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 (!(call.getMethod() instanceof ConstantExpression)) {
- return false;
- }
-
- 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) {
- addError("Call should have arguments", call);
- return null;
- }
-
- if (!(macroCallArguments instanceof TupleExpression)) {
- addError("Call should have TupleExpression as arguments", macroCallArguments);
- return null;
- }
-
- TupleExpression tupleArguments = (TupleExpression) macroCallArguments;
-
- if (tupleArguments.getExpressions() == null) {
- 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) {
- addError("Call arguments should have at least one argument", tupleArguments);
- return null;
- }
-
- Expression result = tupleArguments.getExpression(tupleArguments.getExpressions().size() - 1);
- if (!(result instanceof ClosureExpression)) {
- addError("Last call argument should be a closure", result);
- return null;
- }
-
- return (ClosureExpression) result;
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java
new file mode 100644
index 0000000..d3e8ed4
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroMethodsCache.java
@@ -0,0 +1,143 @@
+/*
+ * 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.codehaus.groovy.macro.transform;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.macro.runtime.Macro;
+import org.codehaus.groovy.runtime.m12n.ExtensionModule;
+import org.codehaus.groovy.runtime.m12n.ExtensionModuleScanner;
+import org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule;
+import org.codehaus.groovy.transform.stc.ExtensionMethodNode;
+
+import java.util.*;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * TODO share some code with {@link org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.ExtensionMethodCache}
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+class MacroMethodsCache {
+
+ private static final ClassNode MACRO_ANNOTATION_CLASS_NODE = ClassHelper.make(Macro.class);
+
+ private static volatile Map<ClassLoader, Map<String, List<MethodNode>>> CACHE = new WeakHashMap<>();
+
+ private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+
+ public static Map<String, List<MethodNode>> get(ClassLoader classLoader) {
+ try {
+ lock.readLock().lock();
+ if (!CACHE.containsKey(classLoader)) {
+ lock.readLock().unlock();
+ lock.writeLock().lock();
+
+ try {
+ if (!CACHE.containsKey(classLoader)) {
+ WeakHashMap<ClassLoader, Map<String, List<MethodNode>>> newCache = new WeakHashMap<>(CACHE);
+
+ Map<String, List<MethodNode>> methods = getMacroMethodsFromClassLoader(classLoader);
+ newCache.put(classLoader, methods);
+
+ CACHE = Collections.unmodifiableMap(newCache);
+ }
+ } finally {
+ lock.readLock().lock();
+ lock.writeLock().unlock();
+ }
+ }
+
+ return CACHE.get(classLoader);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ protected static Map<String, List<MethodNode>> getMacroMethodsFromClassLoader(ClassLoader classLoader) {
+ final Map<String, List<MethodNode>> result = new HashMap<String, List<MethodNode>>();
+ ExtensionModuleScanner.ExtensionModuleListener listener = new ExtensionModuleScanner.ExtensionModuleListener() {
+ @Override
+ public void onModule(ExtensionModule module) {
+ if (!(module instanceof MetaInfExtensionModule)) {
+ return;
+ }
+
+ MetaInfExtensionModule extensionModule = (MetaInfExtensionModule) module;
+
+ scanExtClasses(result, extensionModule.getInstanceMethodsExtensionClasses(), false);
+ scanExtClasses(result, extensionModule.getStaticMethodsExtensionClasses(), true);
+ }
+ };
+
+ ExtensionModuleScanner macroModuleScanner = new ExtensionModuleScanner(listener, classLoader);
+
+ macroModuleScanner.scanClasspathModules();
+
+ for (Map.Entry<String, List<MethodNode>> entry : result.entrySet()) {
+ result.put(entry.getKey(), Collections.unmodifiableList(entry.getValue()));
+ }
+
+ return Collections.unmodifiableMap(result);
+ }
+
+ private static void scanExtClasses(Map<String, List<MethodNode>> accumulator, List<Class> classes, boolean isStatic) {
+ for (Class dgmLikeClass : classes) {
+ ClassNode cn = ClassHelper.makeWithoutCaching(dgmLikeClass, true);
+ for (MethodNode metaMethod : cn.getMethods()) {
+ Parameter[] types = metaMethod.getParameters();
+ if (!(metaMethod.isStatic() && metaMethod.isPublic())) {
+ continue;
+ }
+
+ if (types.length == 0) {
+ continue;
+ }
+
+ if (metaMethod.getAnnotations(MACRO_ANNOTATION_CLASS_NODE).isEmpty()) {
+ continue;
+ }
+
+ Parameter[] parameters = new Parameter[types.length - 1];
+ System.arraycopy(types, 1, parameters, 0, parameters.length);
+ ExtensionMethodNode node = new ExtensionMethodNode(
+ metaMethod,
+ metaMethod.getName(),
+ metaMethod.getModifiers(),
+ metaMethod.getReturnType(),
+ parameters,
+ ClassNode.EMPTY_ARRAY, null,
+ isStatic);
+ node.setGenericsTypes(metaMethod.getGenericsTypes());
+ ClassNode declaringClass = types[0].getType();
+ node.setDeclaringClass(declaringClass);
+
+ List<MethodNode> macroMethods = accumulator.get(metaMethod.getName());
+
+ if (macroMethods == null) {
+ macroMethods = new ArrayList<>();
+ accumulator.put(metaMethod.getName(), macroMethods);
+ }
+
+ macroMethods.add(node);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/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 06de16f..84e8d60 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
@@ -18,42 +18,113 @@
*/
package org.codehaus.groovy.macro.transform;
+import groovy.transform.CompilationUnitAware;
import org.codehaus.groovy.ast.*;
import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.classgen.asm.InvocationWriter;
+import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilePhase;
import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.macro.runtime.MacroContext;
+import org.codehaus.groovy.macro.runtime.MacroStub;
+import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.transform.GroovyASTTransformation;
+import org.codehaus.groovy.transform.stc.ExtensionMethodNode;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+
+import java.util.ArrayList;
+import java.util.List;
/**
- *
* @author Sergei Egorov <bs...@gmail.com>
*/
@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
-public class MacroTransformation extends MethodCallTransformation {
+public class MacroTransformation extends MethodCallTransformation implements CompilationUnitAware {
+
+ private static final ClassNode MACRO_CONTEXT_CLASS_NODE = ClassHelper.make(MacroContext.class);
+
+ private static final ClassNode MACRO_STUB_CLASS_NODE = ClassHelper.make(MacroStub.class);
+
+ private static final PropertyExpression MACRO_STUB_INSTANCE = new PropertyExpression(new ClassExpression(MACRO_STUB_CLASS_NODE), "INSTANCE");
+
+ private static final String MACRO_STUB_METHOD_NAME = "macroMethod";
+
+ protected CompilationUnit unit;
- public static final String DOLLAR_VALUE = "$v";
- public static final String MACRO_METHOD = "macro";
+ @Override
+ public void setCompilationUnit(CompilationUnit unit) {
+ this.unit = unit;
+ }
@Override
- protected GroovyCodeVisitor getTransformer(final ASTNode[] nodes, final SourceUnit sourceUnit) {
- final ClassCodeExpressionTransformer trn = new ClassCodeExpressionTransformer() {
+ protected GroovyCodeVisitor getTransformer(ASTNode[] nodes, final SourceUnit sourceUnit) {
+ // Macro methods should on a classpath of the compiler because we invoke them during the compilation
+ final ClassLoader classLoader = this.getClass().getClassLoader();
+ return new ClassCodeVisitorSupport() {
+
@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;
+ public void visitMethodCallExpression(MethodCallExpression call) {
+ super.visitMethodCallExpression(call);
+
+ List<MethodNode> methods = MacroMethodsCache.get(classLoader).get(call.getMethodAsString());
+
+ if (methods == null) {
+ // Not a macro call
+ return;
+ }
+
+ List<Expression> callArguments = InvocationWriter.makeArgumentList(call.getArguments()).getExpressions();
+
+ ClassNode[] argumentsList = new ClassNode[callArguments.size()];
+
+ for (int i = 0; i < callArguments.size(); i++) {
+ argumentsList[i] = ClassHelper.make(callArguments.get(i).getClass());
+ }
+
+ methods = StaticTypeCheckingSupport.chooseBestMethod(MACRO_CONTEXT_CLASS_NODE, methods, argumentsList);
+
+ for (MethodNode macroMethodNode : methods) {
+ if (!(macroMethodNode instanceof ExtensionMethodNode)) {
+ // TODO is it even possible?
+ continue;
+ }
+
+ MethodNode macroExtensionMethodNode = ((ExtensionMethodNode) macroMethodNode).getExtensionMethodNode();
+
+ final Class clazz;
+ try {
+ clazz = classLoader.loadClass(macroExtensionMethodNode.getDeclaringClass().getName());
+ } catch (ClassNotFoundException e) {
+ //TODO different reaction?
+ continue;
}
+
+ MacroContext macroContext = new MacroContext(unit, sourceUnit, call);
+
+ List<Object> macroArguments = new ArrayList<>();
+ macroArguments.add(macroContext);
+ macroArguments.addAll(callArguments);
+
+ Expression result = (Expression) InvokerHelper.invokeStaticMethod(clazz, macroMethodNode.getName(), macroArguments.toArray());
+
+ call.setObjectExpression(MACRO_STUB_INSTANCE);
+ call.setMethod(new ConstantExpression(MACRO_STUB_METHOD_NAME));
+
+ // TODO check that we reset everything here
+ call.setSpreadSafe(false);
+ call.setSafe(false);
+ call.setImplicitThis(false);
+ call.setArguments(result);
+
+ break;
}
- return super.transform(exp);
}
};
- return new TransformingMacroTrap(sourceUnit, trn);
}
}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/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
deleted file mode 100644
index f16e47a..0000000
--- a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/TransformingMacroTrap.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * 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.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);
- }
-}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule b/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
new file mode 100644
index 0000000..2d10063
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
@@ -0,0 +1,17 @@
+# 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.
+moduleName=macro-module
+moduleVersion=1.0
+extensionClasses=org.codehaus.groovy.macro.methods.MacroGroovyMethods
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.transform.ASTTransformation
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.transform.ASTTransformation b/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.transform.ASTTransformation
index c2ef479..e080e18 100644
--- a/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.transform.ASTTransformation
+++ b/subprojects/groovy-macro/src/main/resources/META-INF/services/org.codehaus.groovy.transform.ASTTransformation
@@ -15,3 +15,4 @@
#global transformation for macro support
org.codehaus.groovy.macro.transform.MacroTransformation
+org.codehaus.groovy.macro.transform.MacroClassTransformation
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/ExampleMacroMethods.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/ExampleMacroMethods.java b/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/ExampleMacroMethods.java
new file mode 100644
index 0000000..3b32ab8
--- /dev/null
+++ b/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/ExampleMacroMethods.java
@@ -0,0 +1,34 @@
+package org.codehaus.groovy.macro;
+
+import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.macro.runtime.Macro;
+import org.codehaus.groovy.macro.runtime.MacroContext;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.*;
+
+public class ExampleMacroMethods {
+
+ @Macro
+ public static Expression safe(MacroContext macroContext, MethodCallExpression callExpression) {
+ return ternaryX(
+ notNullX(callExpression.getObjectExpression()),
+ callExpression,
+ constX(null)
+ );
+ }
+
+ @Macro
+ public static ConstantExpression methodName(MacroContext macroContext, MethodCallExpression callExpression) {
+ return constX(callExpression.getMethodAsString());
+ }
+
+ @Macro
+ public static ConstantExpression methodName(MacroContext macroContext, MethodPointerExpression methodPointerExpression) {
+ return constX(methodPointerExpression.getMethodName().getText());
+ }
+
+ @Macro
+ public static ConstantExpression propertyName(MacroContext macroContext, PropertyExpression propertyExpression) {
+ return constX(propertyExpression.getPropertyAsString());
+ }
+}
http://git-wip-us.apache.org/repos/asf/groovy/blob/b4e68bd5/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/MacroTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/MacroTest.groovy b/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/MacroTest.groovy
index 1febbfa..69139b2 100644
--- a/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/MacroTest.groovy
+++ b/subprojects/groovy-macro/src/test/groovy/org/codehaus/groovy/macro/MacroTest.groovy
@@ -209,4 +209,19 @@ class MacroTest extends GroovyTestCase {
AstAssert.assertSyntaxTree([expected], [result])
'''
}
+
+ void testMacroClass() {
+ assertScript '''
+ import org.codehaus.groovy.ast.ClassNode
+ import org.codehaus.groovy.macro.transform.MacroClass
+
+ def ast1 = new MacroClass() {
+ class A { String str }
+ }
+
+ assert ast1.getClass() == ClassNode
+ assert ast1.name == "A"
+ assert ast1.getField("str") != null
+'''
+ }
}