You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2015/10/07 21:26:33 UTC

[13/37] incubator-groovy git commit: First prototype of an AST pattern matcher. * implemetation is *far from complete* * no unit test * implemented both match/find operations * moved the context aware visitor to the macro project

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContext.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContext.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContext.java
new file mode 100644
index 0000000..6020592
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContext.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.macro.matcher;
+
+import groovy.lang.Closure;
+import groovy.lang.DelegatesTo;
+import groovy.lang.MapWithDefault;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+public class TreeContext {
+    private static enum TreeContextKey {
+        expression_replacement
+    }
+    final TreeContext parent;
+    final ASTNode node;
+    final List<TreeContext> siblings = new LinkedList<TreeContext>();
+    final List<TreeContextAction> onPopHandlers = new LinkedList<TreeContextAction>();
+    final Map<Object, List<?>> userdata = MapWithDefault.newInstance(
+            new HashMap<Object, List<?>>(),
+            new Closure(this) {
+                public Object doCall(Object key) {
+                    return new LinkedList<Object>();
+                }
+            }
+    );
+
+    TreeContext(final TreeContext parent, final ASTNode node) {
+        this.parent = parent;
+        this.node = node;
+        if (parent!=null) {
+            parent.siblings.add(this);
+        }
+    }
+
+    public Map<?, ?> getUserdata() {
+        return userdata;
+    }
+
+    public TreeContext getParent() { return parent; }
+    public ASTNode getNode() { return node; }
+
+    public TreeContext fork(ASTNode node) {
+        return new TreeContext(this, node);
+    }
+
+    public boolean matches(ASTNodePredicate predicate) {
+        return predicate.matches(node);
+    }
+
+    public boolean matches(@DelegatesTo(value=ASTNode.class, strategy=Closure.DELEGATE_FIRST) Closure<Boolean> predicate) {
+        return MatcherUtils.cloneWithDelegate(predicate, node).call();
+    }
+
+    public List<TreeContext> getSiblings() {
+        return Collections.unmodifiableList(siblings);
+    }
+
+    public List<TreeContextAction> getOnPopHandlers() {
+        return Collections.unmodifiableList(onPopHandlers);
+    }
+
+    public void afterVisit(TreeContextAction action) {
+        onPopHandlers.add(action);
+    }
+
+    public void afterVisit(@DelegatesTo(value=TreeContext.class, strategy=Closure.DELEGATE_FIRST) Closure<?> action) {
+        Closure<?> clone = MatcherUtils.cloneWithDelegate(action, this);
+        afterVisit(DefaultGroovyMethods.asType(clone, TreeContextAction.class));
+    }
+
+    public void setReplacement(Expression replacement) {
+        userdata.put(TreeContextKey.expression_replacement, Collections.singletonList(replacement));
+    }
+
+    public Expression getReplacement() {
+        List<?> list = userdata.get(TreeContextKey.expression_replacement);
+        if (list.size()==1) {
+            return (Expression) list.get(0);
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("TreeContext{");
+        sb.append("node=").append(node!=null?node.getClass().getSimpleName():"undefined");
+        TreeContext p = parent;
+        if (p!=null) {
+            sb.append(", path=");
+        }
+        while (p!=null) {
+            sb.append(p.node!=null?p.node.getClass().getSimpleName():"undefined");
+            sb.append("<-");
+            p = p.parent;
+        }
+        //sb.append(", siblings=").append(siblings);
+        sb.append('}');
+        return sb.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContextAction.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContextAction.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContextAction.java
new file mode 100644
index 0000000..2c198d3
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/matcher/TreeContextAction.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.macro.matcher;
+
+public interface TreeContextAction {
+    void call(TreeContext context);
+}

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/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
new file mode 100644
index 0000000..ae82081
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroBuilder.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.macro.runtime;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.builder.AstBuilder;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+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.List;
+import java.util.Map;
+
+/**
+ *
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+public enum MacroBuilder {
+    INSTANCE;
+
+    public <T> T macro(String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
+        return macro(false, source, context, resultClass);
+    }
+
+    public <T> T macro(boolean asIs, String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
+        return macro(CompilePhase.CONVERSION, asIs, source, context, resultClass);
+    }
+
+    public <T> T macro(CompilePhase compilePhase, String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
+        return macro(compilePhase, false, source, context, resultClass);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T macro(CompilePhase compilePhase, boolean asIs, String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
+        final String label = "__synthesized__label__" + System.currentTimeMillis() + "__:";
+        final String labelledSource = label + source;
+        final int linesOffset = 1;
+        final int columnsOffset = label.length() + 1; // +1 because of {
+        
+        List<ASTNode> nodes = (new AstBuilder()).buildFromString(compilePhase, true, labelledSource);
+
+        for(ASTNode node : nodes) {
+            if (node instanceof BlockStatement) {
+
+                BlockStatement closureBlock = (BlockStatement) ((BlockStatement)node).getStatements().get(0);
+
+                (new ClassCodeExpressionTransformer() {
+                    public Expression transform(Expression expression) {
+                        if(!(expression instanceof MethodCallExpression)) {
+                            return super.transform(expression);
+                        }
+
+                        MethodCallExpression call = (MethodCallExpression) expression;
+
+                        if(!MacroInvocationTrap.isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
+                            return super.transform(expression);
+                        }
+
+                        MacroSubstitutionKey key = new MacroSubstitutionKey(call, linesOffset, columnsOffset);
+                        
+                        return context.get(key).call();
+                    }
+
+                    @Override
+                    protected SourceUnit getSourceUnit() {
+                        // Could be null if there are no errors
+                        return null;
+                    }
+                }).visitBlockStatement(closureBlock);
+
+                return (T) getMacroValue(closureBlock, asIs);
+            }
+        }
+        return null;
+    }
+
+    public static ASTNode getMacroValue(BlockStatement closureBlock, boolean asIs) {
+        if(!asIs && closureBlock.getStatements().size() == 1) {
+            Statement result = closureBlock.getStatements().get(0);
+            if(result instanceof ExpressionStatement) {
+                return ((ExpressionStatement) result).getExpression();
+            } else {
+                return result;
+            }
+        }
+        return closureBlock;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/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
new file mode 100644
index 0000000..5c41c04
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.macro.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/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java
new file mode 100644
index 0000000..e895867
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.macro.runtime;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ *
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+public class MacroSubstitutionKey {
+
+    private int startLine;
+    private int startColumn;
+    private int endLine;
+    private int endColumn;
+
+    public MacroSubstitutionKey(int startLine, int startColumn, int endLine, int endColumn) {
+        this.startLine = startLine;
+        this.startColumn = startColumn;
+        this.endLine = endLine;
+        this.endColumn = endColumn;
+    }
+    
+    public MacroSubstitutionKey(Expression expression, int linesOffset, int columnsOffset) {
+        this(
+                expression.getLineNumber() - linesOffset,
+                expression.getColumnNumber() - (expression.getLineNumber() == linesOffset ? columnsOffset : 0),
+                expression.getLastLineNumber() - linesOffset,
+                expression.getLastColumnNumber() - (expression.getLastLineNumber() == linesOffset ? columnsOffset : 0)
+        );
+    }
+    
+    public ConstructorCallExpression toConstructorCallExpression() {
+        return new ConstructorCallExpression(
+                ClassHelper.make(this.getClass()),
+                new ArgumentListExpression(new Expression[] {
+                        new ConstantExpression(startLine),
+                        new ConstantExpression(startColumn),
+                        new ConstantExpression(endLine),
+                        new ConstantExpression(endColumn)
+                })
+        );
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        MacroSubstitutionKey that = (MacroSubstitutionKey) o;
+
+        if (endColumn != that.endColumn) return false;
+        if (endLine != that.endLine) return false;
+        if (startColumn != that.startColumn) return false;
+        if (startLine != that.startLine) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = startLine;
+        result = 31 * result + startColumn;
+        result = 31 * result + endLine;
+        result = 31 * result + endColumn;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "SubstitutionKey{" +
+                "startLine=" + startLine +
+                ", startColumn=" + startColumn +
+                ", endLine=" + endLine +
+                ", endColumn=" + endColumn +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/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
new file mode 100644
index 0000000..127fb4b
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.macro.transform;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.MethodInvocationTrap;
+import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.macro.runtime.MacroBuilder;
+import org.codehaus.groovy.macro.runtime.MacroSubstitutionKey;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.codehaus.groovy.ast.expr.VariableExpression.THIS_EXPRESSION;
+
+/**
+ *
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+public class MacroInvocationTrap extends MethodInvocationTrap {
+
+    public MacroInvocationTrap(ReaderSource source, SourceUnit sourceUnit) {
+        super(source, sourceUnit);
+    }
+
+    @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;
+        }
+
+        final MapExpression mapExpression = new MapExpression();
+
+        (new CodeVisitorSupport() {
+            @Override
+            public void visitMethodCallExpression(MethodCallExpression call) {
+                super.visitMethodCallExpression(call);
+
+                if(isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
+                    ClosureExpression substitutionClosureExpression = getClosureArgument(call);
+
+                    if(substitutionClosureExpression == null) {
+                        return;
+                    }
+
+                    MacroSubstitutionKey key = new MacroSubstitutionKey(call, closureExpression.getLineNumber(), closureExpression.getColumnNumber());
+
+                    mapExpression.addMapEntryExpression(key.toConstructorCallExpression(), substitutionClosureExpression);
+                }
+            }
+        }).visitClosureExpression(closureExpression);
+
+        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(mapExpression);
+        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;
+    }
+
+    @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/incubator-groovy/blob/248e0fd9/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
new file mode 100644
index 0000000..65284b5
--- /dev/null
+++ b/subprojects/groovy-macro/src/main/groovy/org/codehaus/groovy/macro/transform/MacroTransformation.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.macro.transform;
+
+import org.codehaus.groovy.ast.*;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.transform.GroovyASTTransformation;
+
+/**
+ *
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+
+@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
+public class MacroTransformation extends MethodCallTransformation {
+
+    public static final String DOLLAR_VALUE = "$v";
+    public static final String MACRO_METHOD = "macro";
+
+    @Override
+    protected GroovyCodeVisitor getTransformer(ASTNode[] nodes, SourceUnit sourceUnit) {
+        return new MacroInvocationTrap(sourceUnit.getSource(), sourceUnit);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroBuilder.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroBuilder.java b/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroBuilder.java
deleted file mode 100644
index ae82081..0000000
--- a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroBuilder.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2003-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.macro.runtime;
-
-import groovy.lang.Closure;
-import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
-import org.codehaus.groovy.ast.builder.AstBuilder;
-import org.codehaus.groovy.ast.expr.Expression;
-import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.stmt.BlockStatement;
-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.List;
-import java.util.Map;
-
-/**
- *
- * @author Sergei Egorov <bs...@gmail.com>
- */
-public enum MacroBuilder {
-    INSTANCE;
-
-    public <T> T macro(String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
-        return macro(false, source, context, resultClass);
-    }
-
-    public <T> T macro(boolean asIs, String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
-        return macro(CompilePhase.CONVERSION, asIs, source, context, resultClass);
-    }
-
-    public <T> T macro(CompilePhase compilePhase, String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
-        return macro(compilePhase, false, source, context, resultClass);
-    }
-
-    @SuppressWarnings("unchecked")
-    public <T> T macro(CompilePhase compilePhase, boolean asIs, String source, final Map<MacroSubstitutionKey, Closure<Expression>> context, Class<T> resultClass) {
-        final String label = "__synthesized__label__" + System.currentTimeMillis() + "__:";
-        final String labelledSource = label + source;
-        final int linesOffset = 1;
-        final int columnsOffset = label.length() + 1; // +1 because of {
-        
-        List<ASTNode> nodes = (new AstBuilder()).buildFromString(compilePhase, true, labelledSource);
-
-        for(ASTNode node : nodes) {
-            if (node instanceof BlockStatement) {
-
-                BlockStatement closureBlock = (BlockStatement) ((BlockStatement)node).getStatements().get(0);
-
-                (new ClassCodeExpressionTransformer() {
-                    public Expression transform(Expression expression) {
-                        if(!(expression instanceof MethodCallExpression)) {
-                            return super.transform(expression);
-                        }
-
-                        MethodCallExpression call = (MethodCallExpression) expression;
-
-                        if(!MacroInvocationTrap.isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
-                            return super.transform(expression);
-                        }
-
-                        MacroSubstitutionKey key = new MacroSubstitutionKey(call, linesOffset, columnsOffset);
-                        
-                        return context.get(key).call();
-                    }
-
-                    @Override
-                    protected SourceUnit getSourceUnit() {
-                        // Could be null if there are no errors
-                        return null;
-                    }
-                }).visitBlockStatement(closureBlock);
-
-                return (T) getMacroValue(closureBlock, asIs);
-            }
-        }
-        return null;
-    }
-
-    public static ASTNode getMacroValue(BlockStatement closureBlock, boolean asIs) {
-        if(!asIs && closureBlock.getStatements().size() == 1) {
-            Statement result = closureBlock.getStatements().get(0);
-            if(result instanceof ExpressionStatement) {
-                return ((ExpressionStatement) result).getExpression();
-            } else {
-                return result;
-            }
-        }
-        return closureBlock;
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java b/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java
deleted file mode 100644
index 5c41c04..0000000
--- a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroGroovyMethods.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2003-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.macro.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/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java b/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java
deleted file mode 100644
index e895867..0000000
--- a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/runtime/MacroSubstitutionKey.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2003-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.macro.runtime;
-
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
-import org.codehaus.groovy.ast.expr.Expression;
-
-/**
- *
- * @author Sergei Egorov <bs...@gmail.com>
- */
-public class MacroSubstitutionKey {
-
-    private int startLine;
-    private int startColumn;
-    private int endLine;
-    private int endColumn;
-
-    public MacroSubstitutionKey(int startLine, int startColumn, int endLine, int endColumn) {
-        this.startLine = startLine;
-        this.startColumn = startColumn;
-        this.endLine = endLine;
-        this.endColumn = endColumn;
-    }
-    
-    public MacroSubstitutionKey(Expression expression, int linesOffset, int columnsOffset) {
-        this(
-                expression.getLineNumber() - linesOffset,
-                expression.getColumnNumber() - (expression.getLineNumber() == linesOffset ? columnsOffset : 0),
-                expression.getLastLineNumber() - linesOffset,
-                expression.getLastColumnNumber() - (expression.getLastLineNumber() == linesOffset ? columnsOffset : 0)
-        );
-    }
-    
-    public ConstructorCallExpression toConstructorCallExpression() {
-        return new ConstructorCallExpression(
-                ClassHelper.make(this.getClass()),
-                new ArgumentListExpression(new Expression[] {
-                        new ConstantExpression(startLine),
-                        new ConstantExpression(startColumn),
-                        new ConstantExpression(endLine),
-                        new ConstantExpression(endColumn)
-                })
-        );
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-
-        MacroSubstitutionKey that = (MacroSubstitutionKey) o;
-
-        if (endColumn != that.endColumn) return false;
-        if (endLine != that.endLine) return false;
-        if (startColumn != that.startColumn) return false;
-        if (startLine != that.startLine) return false;
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = startLine;
-        result = 31 * result + startColumn;
-        result = 31 * result + endLine;
-        result = 31 * result + endColumn;
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return "SubstitutionKey{" +
-                "startLine=" + startLine +
-                ", startColumn=" + startColumn +
-                ", endLine=" + endLine +
-                ", endColumn=" + endColumn +
-                '}';
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java b/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
deleted file mode 100644
index 127fb4b..0000000
--- a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroInvocationTrap.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2003-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.macro.transform;
-
-import org.codehaus.groovy.ast.ClassHelper;
-import org.codehaus.groovy.ast.CodeVisitorSupport;
-import org.codehaus.groovy.ast.MethodInvocationTrap;
-import org.codehaus.groovy.ast.expr.*;
-import org.codehaus.groovy.ast.stmt.BlockStatement;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.control.io.ReaderSource;
-import org.codehaus.groovy.macro.runtime.MacroBuilder;
-import org.codehaus.groovy.macro.runtime.MacroSubstitutionKey;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.codehaus.groovy.ast.expr.VariableExpression.THIS_EXPRESSION;
-
-/**
- *
- * @author Sergei Egorov <bs...@gmail.com>
- */
-public class MacroInvocationTrap extends MethodInvocationTrap {
-
-    public MacroInvocationTrap(ReaderSource source, SourceUnit sourceUnit) {
-        super(source, sourceUnit);
-    }
-
-    @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;
-        }
-
-        final MapExpression mapExpression = new MapExpression();
-
-        (new CodeVisitorSupport() {
-            @Override
-            public void visitMethodCallExpression(MethodCallExpression call) {
-                super.visitMethodCallExpression(call);
-
-                if(isBuildInvocation(call, MacroTransformation.DOLLAR_VALUE)) {
-                    ClosureExpression substitutionClosureExpression = getClosureArgument(call);
-
-                    if(substitutionClosureExpression == null) {
-                        return;
-                    }
-
-                    MacroSubstitutionKey key = new MacroSubstitutionKey(call, closureExpression.getLineNumber(), closureExpression.getColumnNumber());
-
-                    mapExpression.addMapEntryExpression(key.toConstructorCallExpression(), substitutionClosureExpression);
-                }
-            }
-        }).visitClosureExpression(closureExpression);
-
-        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(mapExpression);
-        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;
-    }
-
-    @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/incubator-groovy/blob/248e0fd9/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroTransformation.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroTransformation.java b/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroTransformation.java
deleted file mode 100644
index 65284b5..0000000
--- a/subprojects/groovy-macro/src/main/java/org/codehaus/groovy/macro/transform/MacroTransformation.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2003-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.macro.transform;
-
-import org.codehaus.groovy.ast.*;
-import org.codehaus.groovy.control.CompilePhase;
-import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.transform.GroovyASTTransformation;
-
-/**
- *
- * @author Sergei Egorov <bs...@gmail.com>
- */
-
-@GroovyASTTransformation(phase = CompilePhase.CONVERSION)
-public class MacroTransformation extends MethodCallTransformation {
-
-    public static final String DOLLAR_VALUE = "$v";
-    public static final String MACRO_METHOD = "macro";
-
-    @Override
-    protected GroovyCodeVisitor getTransformer(ASTNode[] nodes, SourceUnit sourceUnit) {
-        return new MacroInvocationTrap(sourceUnit.getSource(), sourceUnit);
-    }
-}
-