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
+'''
+    }
 }