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 2017/12/17 14:01:46 UTC

[35/62] [abbrv] [partial] groovy git commit: Move Java source set into `src/main/java`

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
new file mode 100644
index 0000000..a0f4b52
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
@@ -0,0 +1,488 @@
+/*
+ *  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 groovy.lang.Binding;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+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.classgen.GeneratorContext;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.transform.BaseScriptASTTransformation;
+import org.objectweb.asm.Opcodes;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a module, which consists typically of a class declaration
+ * but could include some imports, some statements and multiple classes
+ * intermixed with statements like scripts in Python or Ruby
+ *
+ * @author Jochen Theodorou
+ * @author Paul King
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ModuleNode extends ASTNode implements Opcodes {
+
+    private final BlockStatement statementBlock = new BlockStatement();
+    List<ClassNode> classes = new LinkedList<ClassNode>();
+    private final List<MethodNode> methods = new ArrayList<MethodNode>();
+    private final Map<String, ImportNode> imports = new HashMap<String, ImportNode>();
+    private final List<ImportNode> starImports = new ArrayList<ImportNode>();
+    private final Map<String, ImportNode> staticImports = new LinkedHashMap<String, ImportNode>();
+    private final Map<String, ImportNode> staticStarImports = new LinkedHashMap<String, ImportNode>();
+    private CompileUnit unit;
+    private PackageNode packageNode;
+    private String description;
+    private boolean createClassForStatements = true;
+    private transient SourceUnit context;
+    private boolean importsResolved = false;
+    private ClassNode scriptDummy;
+    private String mainClassName = null;
+    private final Parameter[] SCRIPT_CONTEXT_CTOR = {new Parameter(ClassHelper.BINDING_TYPE, "context")};
+
+    public ModuleNode (SourceUnit context ) {
+        this.context = context;
+    }
+
+    public ModuleNode (CompileUnit unit) {
+        this.unit = unit;
+    }
+
+    public BlockStatement getStatementBlock() {
+        return statementBlock;
+    }
+
+    public List<MethodNode> getMethods() {
+        return methods;
+    }
+
+    public List<ClassNode> getClasses() {
+        if (createClassForStatements && (!statementBlock.isEmpty() || !methods.isEmpty() || isPackageInfo())) {
+            ClassNode mainClass = createStatementsClass();
+            mainClassName = mainClass.getName(); 
+            createClassForStatements = false;
+            classes.add(0, mainClass);
+            mainClass.setModule(this);
+            addToCompileUnit(mainClass);
+        }
+        return classes;
+    }
+
+    private boolean isPackageInfo() {
+        return context != null && context.getName() != null && context.getName().endsWith("package-info.groovy");
+    }
+
+    public List<ImportNode> getImports() {
+        return new ArrayList<ImportNode>(imports.values());
+    }
+
+    public List<ImportNode> getStarImports() {
+        return starImports;
+    }
+
+    /**
+     * @param alias the name of interest
+     * @return the class node for the given alias or null if none is available
+     */
+    public ClassNode getImportType(String alias) {
+        ImportNode importNode = imports.get(alias);
+        return importNode == null ? null : importNode.getType();
+    }
+
+    /**
+     * @param alias the name of interest
+     * @return the import node for the given alias or null if none is available
+     */
+    public ImportNode getImport(String alias) {
+        return imports.get(alias);
+    }
+
+    public void addImport(String alias, ClassNode type) {
+        addImport(alias, type, new ArrayList<AnnotationNode>());
+    }
+
+    public void addImport(String alias, ClassNode type, List<AnnotationNode> annotations) {
+        ImportNode importNode = new ImportNode(type, alias);
+        imports.put(alias, importNode);
+        importNode.addAnnotations(annotations);
+        storeLastAddedImportNode(importNode);
+    }
+
+    public void addStarImport(String packageName) {
+        addStarImport(packageName, new ArrayList<AnnotationNode>());
+    }
+
+    public void addStarImport(String packageName, List<AnnotationNode> annotations) {
+        ImportNode importNode = new ImportNode(packageName);
+        importNode.addAnnotations(annotations);
+        starImports.add(importNode);
+        storeLastAddedImportNode(importNode);
+    }
+
+    public void addStatement(Statement node) {
+        statementBlock.addStatement(node);
+    }
+
+    public void addClass(ClassNode node) {
+        if(classes.isEmpty()) mainClassName = node.getName();
+        classes.add(node);
+        node.setModule(this);
+        addToCompileUnit(node);
+    }
+
+    private void addToCompileUnit(ClassNode node) {
+        // register the new class with the compile unit
+        if (unit != null) {
+            unit.addClass(node);
+        }
+    }
+
+    public void addMethod(MethodNode node) {
+        methods.add(node);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+    }
+
+    public String getPackageName() {
+        return packageNode == null ? null : packageNode.getName();
+    }
+
+    public PackageNode getPackage() {
+        return packageNode;
+    }
+
+    // TODO don't allow override?
+    public void setPackage(PackageNode packageNode) {
+        this.packageNode = packageNode;
+    }
+
+    // TODO don't allow override?
+    public void setPackageName(String packageName) {
+        this.packageNode = new PackageNode(packageName);
+    }
+
+    public boolean hasPackageName(){
+        return packageNode != null && packageNode.getName() != null;
+    }
+
+    public boolean hasPackage(){
+        return this.packageNode != null;
+    }
+
+    public SourceUnit getContext() {
+        return context;
+    }
+
+    /**
+     * @return the underlying character stream description
+     */
+    public String getDescription() {
+        if( context != null )
+        {
+            return context.getName();
+        }
+        else
+        {
+            return this.description;
+        }
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public CompileUnit getUnit() {
+        return unit;
+    }
+
+    void setUnit(CompileUnit unit) {
+        this.unit = unit;
+    }
+
+    public ClassNode getScriptClassDummy() {
+        if (scriptDummy!=null) {
+            setScriptBaseClassFromConfig(scriptDummy);
+            return scriptDummy;
+        }
+        
+        String name = getPackageName();
+        if (name == null) {
+            name = "";
+        }
+        // now let's use the file name to determine the class name
+        if (getDescription() == null) {
+            throw new RuntimeException("Cannot generate main(String[]) class for statements when we have no file description");
+        }
+        name += GeneratorContext.encodeAsValidClassName(extractClassFromFileDescription());
+
+        ClassNode classNode;
+        if (isPackageInfo()) {
+            classNode = new ClassNode(name, ACC_ABSTRACT | ACC_INTERFACE, ClassHelper.OBJECT_TYPE);
+        } else {
+            classNode = new ClassNode(name, ACC_PUBLIC, ClassHelper.SCRIPT_TYPE);
+            setScriptBaseClassFromConfig(classNode);
+            classNode.setScript(true);
+            classNode.setScriptBody(true);
+        }
+
+        scriptDummy = classNode;
+        return classNode;
+    }
+
+    private void setScriptBaseClassFromConfig(ClassNode cn) {
+        String baseClassName = null;
+        if (unit != null) {
+            baseClassName = unit.getConfig().getScriptBaseClass();
+        } else if (context != null) {
+            baseClassName = context.getConfiguration().getScriptBaseClass();
+        }
+        if (baseClassName != null) {
+            if (!cn.getSuperClass().getName().equals(baseClassName)) {
+                cn.setSuperClass(ClassHelper.make(baseClassName));
+                AnnotationNode annotationNode = new AnnotationNode(BaseScriptASTTransformation.MY_TYPE);
+                cn.addAnnotation(annotationNode);
+            }
+        }
+    }
+    
+    protected ClassNode createStatementsClass() {
+        ClassNode classNode = getScriptClassDummy();
+        if (classNode.getName().endsWith("package-info")) {
+            return classNode;
+        }
+        
+        handleMainMethodIfPresent(methods);
+
+        // return new Foo(new ShellContext(args)).run()
+        classNode.addMethod(
+            new MethodNode(
+                "main",
+                ACC_PUBLIC | ACC_STATIC,
+                ClassHelper.VOID_TYPE,
+                new Parameter[] { new Parameter(ClassHelper.STRING_TYPE.makeArray(), "args")},
+                ClassNode.EMPTY_ARRAY,
+                new ExpressionStatement(
+                    new MethodCallExpression(
+                        new ClassExpression(ClassHelper.make(InvokerHelper.class)),
+                        "runScript",
+                        new ArgumentListExpression(
+                                new ClassExpression(classNode),
+                                new VariableExpression("args"))))));
+
+        MethodNode methodNode = new MethodNode("run", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementBlock);
+        methodNode.setIsScriptBody();
+        classNode.addMethod(methodNode);
+
+        classNode.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement());
+
+        Statement stmt;
+        // A script's contextual constructor should call it's super class' contextual constructor, if it has one.
+        // In practice this will always be true because currently this visitor is run before the AST transformations
+        // (like @BaseScript) that could change this.  But this is cautious and anticipates possible compiler changes.
+        if (classNode.getSuperClass().getDeclaredConstructor(SCRIPT_CONTEXT_CTOR) != null) {
+            stmt = new ExpressionStatement(
+                    new ConstructorCallExpression(ClassNode.SUPER,
+                            new ArgumentListExpression(
+                                    new VariableExpression("context"))));
+        } else {
+            // Fallback for non-standard base "script" classes with no context (Binding) constructor.
+            stmt = new ExpressionStatement(
+                    new MethodCallExpression(
+                            new VariableExpression("super"),
+                            "setBinding",
+                            new ArgumentListExpression(
+                                    new VariableExpression("context"))));
+        }
+
+        classNode.addConstructor(
+            ACC_PUBLIC,
+            new Parameter[] { new Parameter(ClassHelper.make(Binding.class), "context")},
+            ClassNode.EMPTY_ARRAY,
+            stmt);
+
+        for (MethodNode node : methods) {
+            int modifiers = node.getModifiers();
+            if ((modifiers & ACC_ABSTRACT) != 0) {
+                throw new RuntimeException(
+                    "Cannot use abstract methods in a script, they are only available inside classes. Method: "
+                        + node.getName());
+            }
+            // br: the old logic seems to add static to all def f().... in a script, which makes enclosing
+            // inner classes (including closures) in a def function difficult. Comment it out.
+            node.setModifiers(modifiers /*| ACC_STATIC*/);
+
+            classNode.addMethod(node);
+        }
+        return classNode;
+    }
+
+    /*
+     * If a main method is provided by user, account for it under run() as scripts generate their own 'main' so they can run.  
+     */
+    private void handleMainMethodIfPresent(List methods) {
+        boolean found = false;
+        for (Iterator iter = methods.iterator(); iter.hasNext();) {
+            MethodNode node = (MethodNode) iter.next();
+            if(node.getName().equals("main")) {
+                if (node.isStatic() && node.getParameters().length == 1) {
+                    boolean retTypeMatches, argTypeMatches;
+                    ClassNode argType = node.getParameters()[0].getType();
+                    ClassNode retType = node.getReturnType();
+
+                    argTypeMatches = (argType.equals(ClassHelper.OBJECT_TYPE) || argType.getName().contains("String[]"));
+                    retTypeMatches = (retType == ClassHelper.VOID_TYPE || retType == ClassHelper.OBJECT_TYPE);
+                    
+                    if(retTypeMatches && argTypeMatches) {
+                        if(found) {
+                            throw new RuntimeException("Repetitive main method found.");
+                        } else {
+                            found = true;
+                        }
+                        // if script has both loose statements as well as main(), then main() is ignored
+                        if(statementBlock.isEmpty()) {
+                            addStatement(node.getCode());
+                        }
+                        iter.remove();
+                    }
+                }
+            }
+        }
+    }
+
+    protected String extractClassFromFileDescription() {
+        String answer = getDescription();
+        try {
+            URI uri = new URI(answer);
+            String path = uri.getPath();
+            String schemeSpecific = uri.getSchemeSpecificPart();
+            if (path!=null) {
+                answer = path;
+            } else if (schemeSpecific!=null) {
+                answer = schemeSpecific;
+            }
+        } catch (URISyntaxException e) {}
+        // let's strip off everything after the last '.'
+        int slashIdx = answer.lastIndexOf('/');
+        int separatorIdx = answer.lastIndexOf(File.separatorChar);
+        int dotIdx = answer.lastIndexOf('.');
+        if (dotIdx > 0 && dotIdx > Math.max(slashIdx, separatorIdx)) {
+            answer = answer.substring(0, dotIdx);
+        }
+        // new let's strip everything up to and including the path separators
+        if (slashIdx >= 0) {
+            answer = answer.substring(slashIdx + 1);
+        }
+        // recalculate in case we have already done some stripping
+        separatorIdx = answer.lastIndexOf(File.separatorChar);
+        if (separatorIdx >= 0) {
+            answer = answer.substring(separatorIdx + 1);
+        }
+        return answer;
+    }
+
+    public boolean isEmpty() {
+        return classes.isEmpty() && statementBlock.getStatements().isEmpty();
+    }
+    
+    public void sortClasses(){
+        if (isEmpty()) return;
+        List<ClassNode> classes = getClasses();
+        LinkedList<ClassNode> sorted = new LinkedList<ClassNode>();
+        int level=1;
+        while (!classes.isEmpty()) {
+            for (Iterator<ClassNode> cni = classes.iterator(); cni.hasNext();) {
+                ClassNode cn = cni.next();
+                ClassNode sn = cn;
+                for (int i=0; sn!=null && i<level; i++) sn = sn.getSuperClass();
+                if (sn!=null && sn.isPrimaryClassNode()) continue;
+                cni.remove();
+                sorted.addLast(cn);
+            }
+            level++;
+        }
+        this.classes = sorted;
+    }
+
+    public boolean hasImportsResolved() {
+        return importsResolved;
+    }
+
+    public void setImportsResolved(boolean importsResolved) {
+        this.importsResolved = importsResolved;
+    }
+
+    public Map<String, ImportNode> getStaticImports() {
+        return staticImports;
+    }
+
+    public Map<String, ImportNode> getStaticStarImports() {
+        return staticStarImports;
+    }
+
+    public void addStaticImport(ClassNode type, String fieldName, String alias) {
+        addStaticImport(type, fieldName, alias, new ArrayList<AnnotationNode>());
+    }
+
+    public void addStaticImport(ClassNode type, String fieldName, String alias, List<AnnotationNode> annotations) {
+        ImportNode node = new ImportNode(type, fieldName, alias);
+        node.addAnnotations(annotations);
+        staticImports.put(alias, node);
+        storeLastAddedImportNode(node);
+    }
+
+    public void addStaticStarImport(String name, ClassNode type) {
+        addStaticStarImport(name, type, new ArrayList<AnnotationNode>());
+    }
+
+    public void addStaticStarImport(String name, ClassNode type, List<AnnotationNode> annotations) {
+        ImportNode node = new ImportNode(type);
+        node.addAnnotations(annotations);
+        staticStarImports.put(name, node);
+        storeLastAddedImportNode(node);
+    }
+
+    // This method only exists as a workaround for GROOVY-6094
+    // In order to keep binary compatibility
+    private void storeLastAddedImportNode(final ImportNode node) {
+        if (getNodeMetaData(ImportNode.class)==ImportNode.class) {
+            putNodeMetaData(ImportNode.class, node);
+        }
+    }
+
+    public String getMainClassName() {
+        return mainClassName;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java b/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java
new file mode 100644
index 0000000..74197a9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandler.java
@@ -0,0 +1,82 @@
+/*
+ *  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.GroovyBugError;
+
+import java.util.Map;
+
+/**
+ * An interface to mark a node being able to handle metadata
+ */
+public interface NodeMetaDataHandler {
+    /**
+     * Gets the node meta data.
+     *
+     * @param key - the meta data key
+     * @return the node meta data value for this key
+     */
+    <T> T getNodeMetaData(Object key);
+
+    /**
+     * Copies all node meta data from the other node to this one
+     *
+     * @param other - the other node
+     */
+    void copyNodeMetaData(NodeMetaDataHandler other);
+
+    /**
+     * Sets the node meta data.
+     *
+     * @param key   - the meta data key
+     * @param value - the meta data value
+     * @throws GroovyBugError if key is null or there is already meta
+     *                        data under that key
+     */
+    void setNodeMetaData(Object key, Object value);
+
+    /**
+     * Sets the node meta data but allows overwriting values.
+     *
+     * @param key   - the meta data key
+     * @param value - the meta data value
+     * @return the old node meta data value for this key
+     * @throws GroovyBugError if key is null
+     */
+    Object putNodeMetaData(Object key, Object value);
+
+    /**
+     * Removes a node meta data entry.
+     *
+     * @param key - the meta data key
+     * @throws GroovyBugError if the key is null
+     */
+    void removeNodeMetaData(Object key);
+
+    /**
+     * Returns an unmodifiable view of the current node metadata.
+     *
+     * @return the node metadata. Always not null.
+     */
+    Map<?, ?> getNodeMetaData();
+
+    Map<?, ?> getMetaDataMap();
+
+    void setMetaDataMap(Map<?, ?> metaDataMap);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandlerHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandlerHelper.java b/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandlerHelper.java
new file mode 100644
index 0000000..1287d3c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/NodeMetaDataHandlerHelper.java
@@ -0,0 +1,138 @@
+/*
+ *  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.GroovyBugError;
+import org.codehaus.groovy.util.ListHashMap;
+
+import java.util.Collections;
+import java.util.Map;
+
+public class NodeMetaDataHandlerHelper {
+
+    private NodeMetaDataHandler delegate;
+
+    public NodeMetaDataHandlerHelper(NodeMetaDataHandler delegate) {
+        this.delegate = delegate;
+    }
+
+    /**
+     * Gets the node meta data.
+     *
+     * @param key - the meta data key
+     * @return the node meta data value for this key
+     */
+    public <T> T getNodeMetaData(Object key) {
+        Map<?, ?> metaDataMap = delegate.getMetaDataMap();
+
+        if (metaDataMap == null) {
+            return null;
+        }
+        return (T) metaDataMap.get(key);
+    }
+
+    /**
+     * Copies all node meta data from the other node to this one
+     *
+     * @param other - the other node
+     */
+    public void copyNodeMetaData(NodeMetaDataHandler other) {
+        Map otherMetaDataMap = other.getMetaDataMap();
+        if (otherMetaDataMap == null) {
+            return;
+        }
+        Map metaDataMap = delegate.getMetaDataMap();
+        if (metaDataMap == null) {
+            metaDataMap = new ListHashMap();
+            delegate.setMetaDataMap(metaDataMap);
+        }
+
+        metaDataMap.putAll(otherMetaDataMap);
+    }
+
+    /**
+     * Sets the node meta data.
+     *
+     * @param key   - the meta data key
+     * @param value - the meta data value
+     * @throws GroovyBugError if key is null or there is already meta
+     *                        data under that key
+     */
+    public void setNodeMetaData(Object key, Object value) {
+        if (key == null) throw new GroovyBugError("Tried to set meta data with null key on " + this + ".");
+
+        Map metaDataMap = delegate.getMetaDataMap();
+        if (metaDataMap == null) {
+            metaDataMap = new ListHashMap();
+            delegate.setMetaDataMap(metaDataMap);
+        }
+        Object old = metaDataMap.put(key, value);
+        if (old != null) throw new GroovyBugError("Tried to overwrite existing meta data " + this + ".");
+    }
+
+    /**
+     * Sets the node meta data but allows overwriting values.
+     *
+     * @param key   - the meta data key
+     * @param value - the meta data value
+     * @return the old node meta data value for this key
+     * @throws GroovyBugError if key is null
+     */
+    public Object putNodeMetaData(Object key, Object value) {
+        if (key == null) throw new GroovyBugError("Tried to set meta data with null key on " + this + ".");
+
+        Map metaDataMap = delegate.getMetaDataMap();
+        if (metaDataMap == null) {
+            metaDataMap = new ListHashMap();
+            delegate.setMetaDataMap(metaDataMap);
+        }
+        return metaDataMap.put(key, value);
+    }
+
+    /**
+     * Removes a node meta data entry.
+     *
+     * @param key - the meta data key
+     * @throws GroovyBugError if the key is null
+     */
+    public void removeNodeMetaData(Object key) {
+        if (key == null) throw new GroovyBugError("Tried to remove meta data with null key " + this + ".");
+
+        Map metaDataMap = delegate.getMetaDataMap();
+        if (metaDataMap == null) {
+            return;
+        }
+        metaDataMap.remove(key);
+    }
+
+    /**
+     * Returns an unmodifiable view of the current node metadata.
+     *
+     * @return the node metadata. Always not null.
+     */
+    public Map<?, ?> getNodeMetaData() {
+        Map metaDataMap = delegate.getMetaDataMap();
+
+        if (metaDataMap == null) {
+            return Collections.emptyMap();
+        }
+        return Collections.unmodifiableMap(metaDataMap);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/PackageNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/PackageNode.java b/src/main/java/org/codehaus/groovy/ast/PackageNode.java
new file mode 100644
index 0000000..946f9bd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/PackageNode.java
@@ -0,0 +1,46 @@
+/*
+ *  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;
+
+/**
+ * Represents a package in the AST.
+ *
+ * @author Paul King
+ */
+public class PackageNode extends AnnotatedNode {
+    private final String name;
+
+    public PackageNode(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @return the text display of this package definition
+     */
+    public String getText() {
+        return "package " + name;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/Parameter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/Parameter.java b/src/main/java/org/codehaus/groovy/ast/Parameter.java
new file mode 100644
index 0000000..1b22128
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/Parameter.java
@@ -0,0 +1,126 @@
+/*
+ *  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.Expression;
+
+
+/**
+ * Represents a parameter on a constructor or method call. The type name is
+ * optional - it defaults to java.lang.Object if unknown.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class Parameter extends AnnotatedNode implements Variable {
+
+    public static final Parameter[] EMPTY_ARRAY = {};
+
+    private ClassNode type;
+    private final String name;
+    private boolean dynamicTyped;
+    private Expression defaultValue;
+    private boolean hasDefaultValue;
+    private boolean inStaticContext;
+    private boolean closureShare=false;
+    private int modifiers;
+    private ClassNode originType=ClassHelper.DYNAMIC_TYPE;
+
+    public Parameter(ClassNode type, String name) {
+        this.name = name;
+        this.setType(type);
+        this.originType = type;
+        this.hasDefaultValue = false;
+    }
+    
+    public Parameter(ClassNode type, String name, Expression defaultValue) {
+        this(type,name);
+        this.defaultValue = defaultValue;
+        this.hasDefaultValue = defaultValue != null;
+    }
+
+    public String toString() {
+        return super.toString() + "[name:" + name + ((type == null) ? "" : " type: " + type.getName()) + ", hasDefaultValue: " + this.hasInitialExpression() + "]";
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+        dynamicTyped |= type==ClassHelper.DYNAMIC_TYPE;
+    }
+    
+    public boolean hasInitialExpression() {
+        return this.hasDefaultValue;
+    }
+    
+    /**
+     * @return the default value expression for this parameter or null if
+     * no default value is specified
+     */
+    public Expression getInitialExpression() {
+        return defaultValue;
+    }
+    
+    public void setInitialExpression(Expression init) {
+        defaultValue = init;
+        hasDefaultValue = defaultValue != null;
+    }
+    
+    public boolean isInStaticContext() {
+        return inStaticContext;
+    }
+    
+    public void setInStaticContext(boolean inStaticContext) {
+        this.inStaticContext = inStaticContext;
+    }
+
+    public boolean isDynamicTyped() {
+        return dynamicTyped;
+    }
+
+    public boolean isClosureSharedVariable() {
+        return closureShare;
+    }
+
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;        
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public ClassNode getOriginType() {
+        return originType;
+    }
+    
+    public void setOriginType(ClassNode cn) {
+        originType = cn;
+    }
+
+    public void setModifiers(int modifiers) {
+        this.modifiers = modifiers;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/PropertyNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/PropertyNode.java b/src/main/java/org/codehaus/groovy/ast/PropertyNode.java
new file mode 100644
index 0000000..49b941f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/PropertyNode.java
@@ -0,0 +1,135 @@
+/*
+ *  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.Expression;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Represents a property (member variable, a getter and setter)
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class PropertyNode extends AnnotatedNode implements Opcodes, Variable {
+
+    private FieldNode field;
+
+    private Statement getterBlock;
+    private Statement setterBlock;
+    private final int modifiers;
+
+    public PropertyNode(
+            String name, int modifiers, ClassNode type, ClassNode owner,
+            Expression initialValueExpression, Statement getterBlock,
+            Statement setterBlock) {
+        this(new FieldNode(name, modifiers & ACC_STATIC, type, owner, initialValueExpression), modifiers, getterBlock, setterBlock);
+    }
+
+    public PropertyNode(FieldNode field, int modifiers, Statement getterBlock, Statement setterBlock) {
+        this.field = field;
+        this.modifiers = modifiers;
+        this.getterBlock = getterBlock;
+        this.setterBlock = setterBlock;
+    }
+
+    public Statement getGetterBlock() {
+        return getterBlock;
+    }
+
+    public Expression getInitialExpression() {
+        return field.getInitialExpression();
+    }
+
+    public void setGetterBlock(Statement getterBlock) {
+        this.getterBlock = getterBlock;
+    }
+
+    public void setSetterBlock(Statement setterBlock) {
+        this.setterBlock = setterBlock;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public String getName() {
+        return field.getName();
+    }
+
+    public Statement getSetterBlock() {
+        return setterBlock;
+    }
+
+    public ClassNode getType() {
+        return field.getType();
+    }
+
+    public void setType(ClassNode t) {
+        field.setType(t);
+    }
+
+    public FieldNode getField() {
+        return field;
+    }
+
+    public void setField(FieldNode fn) {
+        field = fn;
+    }
+
+    public boolean isPrivate() {
+        return (modifiers & ACC_PRIVATE) != 0;
+    }
+
+    public boolean isPublic() {
+        return (modifiers & ACC_PUBLIC) != 0;
+    }
+
+    public boolean isStatic() {
+        return (modifiers & ACC_STATIC) != 0;
+    }
+
+    public boolean hasInitialExpression() {
+        return field.hasInitialExpression();
+    }
+
+    public boolean isInStaticContext() {
+        return field.isInStaticContext();
+    }
+
+    public boolean isDynamicTyped() {
+        return field.isDynamicTyped();
+    }
+
+    public boolean isClosureSharedVariable() {
+        return false;
+    }
+
+    /**
+      * @deprecated not used anymore, has no effect
+      */
+    @Deprecated
+    public void setClosureSharedVariable(boolean inClosure) {
+        // unused
+    }
+
+    public ClassNode getOriginType() {
+        return getType();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/TransformingCodeVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/TransformingCodeVisitor.java b/src/main/java/org/codehaus/groovy/ast/TransformingCodeVisitor.java
new file mode 100644
index 0000000..f3d6dbe
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/TransformingCodeVisitor.java
@@ -0,0 +1,371 @@
+/*
+ *  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.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BitwiseNegationExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ClosureListExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MapExpression;
+import org.codehaus.groovy.ast.expr.MethodPointerExpression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.PostfixExpression;
+import org.codehaus.groovy.ast.expr.PrefixExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.RangeExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.SpreadMapExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TernaryExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.UnaryMinusExpression;
+import org.codehaus.groovy.ast.expr.UnaryPlusExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+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/0edfcde9/src/main/java/org/codehaus/groovy/ast/Variable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/Variable.java b/src/main/java/org/codehaus/groovy/ast/Variable.java
new file mode 100644
index 0000000..2e94739
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/Variable.java
@@ -0,0 +1,69 @@
+/*
+ *  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.Expression;
+
+/**
+ * interface to mark a AstNode as Variable. Typically these are 
+ * VariableExpression, FieldNode, PropertyNode and Parameter
+ * 
+ * @author Jochen Theodorou
+ */
+public interface Variable {
+    
+    /**
+     * the type of the variable
+     */
+    ClassNode getType();
+    
+    /**
+     * the type before wrapping primitives type of the variable
+     */
+    ClassNode getOriginType();
+    
+    /**
+     * the name of the variable
+     */
+    String getName();
+    
+    /**
+     * expression used to initialize the variable or null of there
+     * is no initialization.
+     */
+    Expression getInitialExpression();
+    
+    /**
+     * returns true if there is an initialization expression
+     */
+    boolean hasInitialExpression();
+    
+    /**
+     * returns true if this variable is used in a static context.
+     * A static context is any static initializer block, when this variable
+     * is declared as static or when this variable is used in a static method 
+     */
+    boolean isInStaticContext();
+
+    boolean isDynamicTyped();
+    boolean isClosureSharedVariable();
+    void setClosureSharedVariable(boolean inClosure);
+
+    int getModifiers();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/VariableScope.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/VariableScope.java b/src/main/java/org/codehaus/groovy/ast/VariableScope.java
new file mode 100644
index 0000000..521b301
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/VariableScope.java
@@ -0,0 +1,200 @@
+/*
+ *  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 java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Represents a variable scope. This is primarily used to determine variable sharing
+ * across method and closure boundaries.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Jochen Theodorou
+ */
+public class VariableScope  {
+    private Map<String, Variable> declaredVariables = Collections.emptyMap();
+    private Map<String, Variable> referencedLocalVariables = Collections.emptyMap();
+    private Map<String, Variable> referencedClassVariables = Collections.emptyMap();
+ 
+    private boolean inStaticContext = false;
+    private boolean resolvesDynamic = false; 
+    // Non-null iff this scope corresponds to a class, as opposed to a method, "if" statement,
+    // block statement, etc.
+    private ClassNode clazzScope;
+    private VariableScope parent;
+
+    public VariableScope() {
+    }
+    public VariableScope(VariableScope parent) {
+        this.parent = parent;
+    }
+
+    public Variable getDeclaredVariable(String name) {
+        return declaredVariables.get(name);
+    }
+
+    public boolean isReferencedLocalVariable(String name) {
+        return referencedLocalVariables.containsKey(name);
+    }
+    
+    public boolean isReferencedClassVariable(String name) {
+        return referencedClassVariables.containsKey(name);
+    }
+    public VariableScope getParent() {
+        return parent;
+    }
+
+    public boolean isInStaticContext() {
+        return inStaticContext;
+    }
+
+    public void setInStaticContext(boolean inStaticContext) {
+        this.inStaticContext = inStaticContext;
+    }
+
+    public void setClassScope(ClassNode node) {
+        this.clazzScope = node;
+    }
+    
+    /**
+     * Non-null iff this scope corresponds to a class; as opposed to a method, "if" statement,
+     * block statement, etc.
+     */
+    public ClassNode getClassScope(){
+        return clazzScope;
+    }
+    
+    /**
+     * Returns true iff this scope corresponds to a class; as opposed to a method, "if" statement,
+     * block statement, etc.
+     */
+    public boolean isClassScope(){
+        return clazzScope!=null;
+    }
+    
+    public boolean isRoot() {
+        return parent==null;
+    }
+    
+    public VariableScope copy() {
+        VariableScope copy = new VariableScope();
+        copy.clazzScope = clazzScope;
+        if (!declaredVariables.isEmpty()) {
+          copy.declaredVariables = new LinkedHashMap<String, Variable>(declaredVariables);
+        }
+        copy.inStaticContext = inStaticContext;
+        copy.parent = parent;
+        if (!referencedClassVariables.isEmpty()) {
+            copy.referencedClassVariables = new LinkedHashMap<String, Variable>(referencedClassVariables);
+        }
+        if (!referencedLocalVariables.isEmpty()) {
+            copy.referencedLocalVariables = new LinkedHashMap<String, Variable>(referencedLocalVariables);
+        }
+        copy.resolvesDynamic = resolvesDynamic;
+        return copy;
+    }
+
+    public void putDeclaredVariable(Variable var) {
+        if (declaredVariables == Collections.EMPTY_MAP)
+          declaredVariables = new LinkedHashMap<String, Variable>();
+        declaredVariables.put(var.getName(), var);
+    }
+
+    public Iterator<Variable> getReferencedLocalVariablesIterator() {
+        return referencedLocalVariables.values().iterator();
+    }
+
+    public int getReferencedLocalVariablesCount() {
+        return referencedLocalVariables.size();
+    }
+
+    public Variable getReferencedLocalVariable(String name) {
+        return referencedLocalVariables.get(name);
+    }
+
+    public void putReferencedLocalVariable(Variable var) {
+        if (referencedLocalVariables == Collections.EMPTY_MAP)
+          referencedLocalVariables = new LinkedHashMap<String, Variable>();
+        referencedLocalVariables.put(var.getName(), var);
+    }
+
+    public void putReferencedClassVariable(Variable var) {
+        if (referencedClassVariables == Collections.EMPTY_MAP)
+          referencedClassVariables = new LinkedHashMap<String, Variable>();
+        referencedClassVariables.put(var.getName(), var);
+    }
+
+    public Variable getReferencedClassVariable(String name) {
+        return referencedClassVariables.get(name);
+    }
+
+    public Object removeReferencedClassVariable(String name) {
+        if (referencedClassVariables == Collections.EMPTY_MAP)
+          return null;
+        else
+          return referencedClassVariables.remove(name);
+    }
+    
+    /**
+     * Gets a map containing the class variables referenced 
+     * by this scope. This not can not be modified.
+     * @return a map containing the class variable references
+     */
+    public Map<String, Variable> getReferencedClassVariables() {
+        if (referencedClassVariables == Collections.EMPTY_MAP) {
+            return referencedClassVariables;
+        } else {
+            return Collections.unmodifiableMap(referencedClassVariables);
+        }
+    }
+    
+    /**
+     * Gets an iterator for the referenced class variables. The
+     * remove operation is not supported.
+     * @return an iterator for the referenced class variables
+     */
+    public Iterator<Variable> getReferencedClassVariablesIterator() {
+        return getReferencedClassVariables().values().iterator();
+    }
+
+    /**
+     * Gets a map containing the variables declared in this scope.
+     * This map cannot be modified.
+     * @return a map containing the declared variable references
+     */
+    public Map<String, Variable> getDeclaredVariables() {
+        if (declaredVariables == Collections.EMPTY_MAP) {
+            return declaredVariables;
+        } else {
+            return Collections.unmodifiableMap(declaredVariables);
+        }
+    }
+
+    /**
+     * Gets an iterator for the declared class variables. The remove
+     * operation is not supported.
+     * @return an iterator for the declared variables
+     */
+    public Iterator<Variable> getDeclaredVariablesIterator() {
+        return getDeclaredVariables().values().iterator();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java b/src/main/java/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java
new file mode 100644
index 0000000..6882498
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java
@@ -0,0 +1,186 @@
+/*
+ *  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.builder;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.MethodCallTransformation;
+import org.codehaus.groovy.ast.MethodInvocationTrap;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+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.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.transform.GroovyASTTransformation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Transformation to capture ASTBuilder from code statements.
+ * <p>
+ * The AstBuilder "from code" approach is used with a single Closure
+ * parameter. This transformation converts the ClosureExpression back
+ * into source code and rewrites the AST so that the "from string"
+ * builder is invoked on the source. In order for this to work, the
+ * closure source must be given a goto label. It is the "from string"
+ * approach's responsibility to remove the BlockStatement created
+ * by the label.
+ *
+ * @author Hamlet D'Arcy
+ */
+
+@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
+public class AstBuilderTransformation extends MethodCallTransformation {
+
+    @Override
+    protected GroovyCodeVisitor getTransformer(ASTNode[] nodes, SourceUnit sourceUnit) {
+        // todo : are there other import types that can be specified?
+        return new AstBuilderInvocationTrap(
+            sourceUnit.getAST().getImports(),
+            sourceUnit.getAST().getStarImports(),
+            sourceUnit.getSource(),
+            sourceUnit
+        );
+    }
+
+    /**
+     * This class traps invocations of AstBuilder.build(CompilePhase, boolean, Closure) and converts
+     * the contents of the closure into expressions by reading the source of the Closure and sending
+     * that as a String to AstBuilder.build(String, CompilePhase, boolean) at runtime.
+     */
+    private static class AstBuilderInvocationTrap extends MethodInvocationTrap {
+
+        private final List<String> factoryTargets = new ArrayList<String>();
+
+        /**
+         * Creates the trap and captures all the ways in which a class may be referenced via imports.
+         *
+         * @param imports        all the imports from the source
+         * @param importPackages all the imported packages from the source
+         * @param source         the reader source that contains source for the SourceUnit
+         * @param sourceUnit     the source unit being compiled. Used for error messages.
+         */
+        AstBuilderInvocationTrap(List<ImportNode> imports, List<ImportNode> importPackages, ReaderSource source, SourceUnit sourceUnit) {
+            super(source, sourceUnit);
+
+            // factory type may be references as fully qualified, an import, or an alias
+            factoryTargets.add("org.codehaus.groovy.ast.builder.AstBuilder");//default package
+
+            if (imports != null) {
+                for (ImportNode importStatement : imports) {
+                    if ("org.codehaus.groovy.ast.builder.AstBuilder".equals(importStatement.getType().getName())) {
+                        factoryTargets.add(importStatement.getAlias());
+                    }
+                }
+            }
+
+            if (importPackages != null) {
+                for (ImportNode importPackage : importPackages) {
+                    if ("org.codehaus.groovy.ast.builder.".equals(importPackage.getPackageName())) {
+                        factoryTargets.add("AstBuilder");
+                        break;
+                    }
+                }
+            }
+        }
+        
+        @Override
+        protected boolean handleTargetMethodCallExpression(MethodCallExpression call) {
+            ClosureExpression closureExpression = getClosureArgument(call);
+            List<Expression> otherArgs = getNonClosureArguments(call);
+            String source = convertClosureToSource(closureExpression);
+
+            // parameter order is build(CompilePhase, boolean, String)
+            otherArgs.add(new ConstantExpression(source));
+            call.setArguments(new ArgumentListExpression(otherArgs));
+            call.setMethod(new ConstantExpression("buildFromBlock"));
+            call.setSpreadSafe(false);
+            call.setSafe(false);
+            call.setImplicitThis(false);
+            
+            return false;
+        }
+
+        private static List<Expression> getNonClosureArguments(MethodCallExpression call) {
+            List<Expression> result = new ArrayList<Expression>();
+            if (call.getArguments() instanceof TupleExpression) {
+                for (ASTNode node : ((TupleExpression) call.getArguments()).getExpressions()) {
+                    if (!(node instanceof ClosureExpression)) {
+                        result.add((Expression) node);
+                    }
+                }
+            }
+            return result;
+        }
+
+        private static ClosureExpression getClosureArgument(MethodCallExpression call) {
+
+            if (call.getArguments() instanceof TupleExpression) {
+                for (ASTNode node : ((TupleExpression) call.getArguments()).getExpressions()) {
+                    if (node instanceof ClosureExpression) {
+                        return (ClosureExpression) node;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Looks for method calls on the AstBuilder class called build that take
+         * a Closure as parameter. This is all needed b/c build is overloaded.
+         *
+         * @param call the method call expression, may not be null
+         */
+        @Override
+        protected boolean isBuildInvocation(MethodCallExpression call) {
+            if (call == null) throw new IllegalArgumentException("Null: call");
+
+            // is method name correct?
+            if (call.getMethod() instanceof ConstantExpression && "buildFromCode".equals(((ConstantExpression) call.getMethod()).getValue())) {
+
+                // is method object correct type?
+                if (call.getObjectExpression() != null && call.getObjectExpression().getType() != null) {
+                    String name = call.getObjectExpression().getType().getName();
+                    if (name != null && !"".equals(name) && factoryTargets.contains(name)) {
+
+                        // is one of the arguments a closure?
+                        if (call.getArguments() != null && call.getArguments() instanceof TupleExpression) {
+                            if (((TupleExpression) call.getArguments()).getExpressions() != null) {
+                                for (ASTNode node : ((TupleExpression) call.getArguments()).getExpressions()) {
+                                    if (node instanceof ClosureExpression) {
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+    }
+}
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java b/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java
new file mode 100644
index 0000000..2974d00
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/Annotations.java
@@ -0,0 +1,136 @@
+/*
+ *  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.decompiled;
+
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+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.PropertyExpression;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Array;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Peter Gromov
+ */
+class Annotations {
+    static AnnotationNode createAnnotationNode(AnnotationStub annotation, AsmReferenceResolver resolver) {
+        ClassNode classNode = resolver.resolveClassNullable(Type.getType(annotation.className).getClassName());
+        if (classNode == null) {
+            // there might be annotations not present in the classpath
+            // e.g. java.lang.Synthetic (http://forge.ow2.org/tracker/?aid=307392&group_id=23&atid=100023&func=detail)
+            // so skip them
+            return null;
+        }
+
+        AnnotationNode node = new DecompiledAnnotationNode(classNode);
+        for (Map.Entry<String, Object> entry : annotation.members.entrySet()) {
+            node.addMember(entry.getKey(), annotationValueToExpression(entry.getValue(), resolver));
+        }
+        return node;
+    }
+
+    private static Expression annotationValueToExpression(Object value, AsmReferenceResolver resolver) {
+        if (value instanceof TypeWrapper) {
+            return new ClassExpression(resolver.resolveType(Type.getType(((TypeWrapper) value).desc)));
+        }
+
+        if (value instanceof EnumConstantWrapper) {
+            EnumConstantWrapper wrapper = (EnumConstantWrapper) value;
+            return new PropertyExpression(new ClassExpression(resolver.resolveType(Type.getType(wrapper.enumDesc))), wrapper.constant);
+        }
+
+        if (value instanceof AnnotationStub) {
+            AnnotationNode annotationNode = createAnnotationNode((AnnotationStub) value, resolver);
+            return annotationNode != null ? new AnnotationConstantExpression(annotationNode) : ConstantExpression.NULL;
+        }
+
+        if (value != null && value.getClass().isArray()) {
+            ListExpression elementExprs = new ListExpression();
+            int len = Array.getLength(value);
+            for (int i = 0; i != len; ++i) {
+                elementExprs.addExpression(annotationValueToExpression(Array.get(value, i), resolver));
+            }
+            return elementExprs;
+        }
+
+        if (value instanceof List) {
+            ListExpression elementExprs = new ListExpression();
+            for (Object o : (List) value) {
+                elementExprs.addExpression(annotationValueToExpression(o, resolver));
+            }
+            return elementExprs;
+        }
+
+        return new ConstantExpression(value);
+    }
+
+    private static class DecompiledAnnotationNode extends AnnotationNode {
+        private final Object initLock;
+        private volatile boolean lazyInitDone;
+
+        public DecompiledAnnotationNode(ClassNode type) {
+            super(type);
+            initLock = new Object();
+        }
+
+        private void lazyInit() {
+            if (lazyInitDone) return;
+            synchronized (initLock) {
+                if (!lazyInitDone) {
+                    for (AnnotationNode annotation : getClassNode().getAnnotations()) {
+                        VMPluginFactory.getPlugin().configureAnnotationNodeFromDefinition(annotation, this);
+                    }
+                    lazyInitDone = true;
+                }
+            }
+        }
+
+        @Override
+        public boolean isTargetAllowed(int target) {
+            lazyInit();
+            return super.isTargetAllowed(target);
+        }
+
+        @Override
+        public boolean hasRuntimeRetention() {
+            lazyInit();
+            return super.hasRuntimeRetention();
+        }
+
+        @Override
+        public boolean hasSourceRetention() {
+            lazyInit();
+            return super.hasSourceRetention();
+        }
+
+        @Override
+        public boolean hasClassRetention() {
+            lazyInit();
+            return super.hasClassRetention();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java b/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java
new file mode 100644
index 0000000..933f1b5
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/AsmDecompiler.java
@@ -0,0 +1,218 @@
+/*
+ *  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.decompiled;
+
+import groovy.lang.GroovyRuntimeException;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.SoftReference;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A utility class responsible for decompiling JVM class files and producing {@link ClassStub} objects reflecting their structure.
+ *
+ * @author Peter Gromov
+ */
+public abstract class AsmDecompiler {
+
+    private static class StubCache {
+        /**
+         * Caches stubs per URI. This cache is useful when performing multiple compilations in the same JVM/class loader and in tests.
+         *
+         * It's synchronized "just in case". Occasional misses are expected if several threads attempt to load the same class,
+         * but this shouldn't result in serious memory issues.
+         */
+        static final Map<URI, SoftReference<ClassStub>> map = new ConcurrentHashMap<URI, SoftReference<ClassStub>>();         // According to http://michaelscharf.blogspot.jp/2006/11/javaneturlequals-and-hashcode-make.html, use java.net.URI instead.
+    }
+
+    /**
+     * Loads the URL contents and parses them with ASM, producing a {@link ClassStub} object representing the structure of
+     * the corresponding class file. Stubs are cached and reused if queried several times with equal URLs.
+     *
+     * @param url an URL from a class loader, most likely a file system file or a JAR entry.
+     * @return the class stub
+     * @throws IOException if reading from this URL is impossible
+     */
+    public static ClassStub parseClass(URL url) throws IOException {
+        URI uri;
+        try {
+            uri = url.toURI();
+        } catch (URISyntaxException e) {
+            throw new GroovyRuntimeException(e);
+        }
+
+        SoftReference<ClassStub> ref = StubCache.map.get(uri);
+        ClassStub stub = ref == null ? null : ref.get();
+        if (stub == null) {
+            DecompilingVisitor visitor = new DecompilingVisitor();
+            InputStream stream = url.openStream();
+            try {
+                new ClassReader(new BufferedInputStream(stream)).accept(visitor, ClassReader.SKIP_FRAMES);
+            } finally {
+                stream.close();
+            }
+            stub = visitor.result;
+            StubCache.map.put(uri, new SoftReference<ClassStub>(stub));
+        }
+        return stub;
+    }
+
+    private static class DecompilingVisitor extends ClassVisitor {
+        private static final String[] EMPTY_STRING_ARRAY = new String[0];
+        private ClassStub result;
+
+        public DecompilingVisitor() {
+            super(Opcodes.ASM5);
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaceNames) {
+            result = new ClassStub(fromInternalName(name), access, signature, superName, interfaceNames);
+        }
+
+        @Override
+        public void visitInnerClass(String name, String outerName, String innerName, int access) {
+            result.innerClassModifiers.put(innerName, access);
+        }
+
+        @Override
+        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+            if (!"<clinit>".equals(name)) {
+                final MethodStub stub = new MethodStub(name, access, desc, signature, exceptions != null ? exceptions : EMPTY_STRING_ARRAY);
+                if (result.methods == null) result.methods = new ArrayList<MethodStub>(1);
+                result.methods.add(stub);
+                return new MethodVisitor(api) {
+                    @Override
+                    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+                        return readAnnotationMembers(stub.addAnnotation(desc));
+                    }
+
+                    @Override
+                    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
+                        if (stub.parameterAnnotations == null) stub.parameterAnnotations = new HashMap<Integer, List<AnnotationStub>>(1);
+                        List<AnnotationStub> list = stub.parameterAnnotations.get(parameter);
+                        if (list == null) {
+                            stub.parameterAnnotations.put(parameter, list = new ArrayList<AnnotationStub>());
+                        }
+                        AnnotationStub annotationStub = new AnnotationStub(desc);
+                        list.add(annotationStub);
+                        return readAnnotationMembers(annotationStub);
+                    }
+
+                    @Override
+                    public AnnotationVisitor visitAnnotationDefault() {
+                        return new AnnotationReader() {
+                            @Override
+                            void visitAttribute(String name, Object value) {
+                                stub.annotationDefault = value;
+                            }
+                        };
+                    }
+                };
+            }
+            return null;
+        }
+
+        @Override
+        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+            return readAnnotationMembers(result.addAnnotation(desc));
+        }
+
+        @Override
+        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+            final FieldStub stub = new FieldStub(name, access, desc, signature);
+            if (result.fields == null) result.fields = new ArrayList<FieldStub>(1);
+            result.fields.add(stub);
+            return new FieldVisitor(api) {
+                @Override
+                public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+                    return readAnnotationMembers(stub.addAnnotation(desc));
+                }
+            };
+        }
+    }
+
+    private static AnnotationReader readAnnotationMembers(final AnnotationStub stub) {
+        return new AnnotationReader() {
+            @Override
+            void visitAttribute(String name, Object value) {
+                stub.members.put(name, value);
+            }
+        };
+    }
+
+    static String fromInternalName(String name) {
+        return name.replace('/', '.');
+    }
+
+    private abstract static class AnnotationReader extends AnnotationVisitor {
+        public AnnotationReader() {
+            super(Opcodes.ASM5);
+        }
+
+        abstract void visitAttribute(String name, Object value);
+
+        @Override
+        public void visit(String name, Object value) {
+            visitAttribute(name, value instanceof Type ? new TypeWrapper(((Type) value).getDescriptor()) : value);
+        }
+
+        @Override
+        public void visitEnum(String name, String desc, String value) {
+            visitAttribute(name, new EnumConstantWrapper(desc, value));
+        }
+
+        @Override
+        public AnnotationVisitor visitAnnotation(String name, String desc) {
+            AnnotationStub stub = new AnnotationStub(desc);
+            visitAttribute(name, stub);
+            return readAnnotationMembers(stub);
+        }
+
+        @Override
+        public AnnotationVisitor visitArray(String name) {
+            final List<Object> list = new ArrayList<Object>();
+            visitAttribute(name, list);
+            return new AnnotationReader() {
+                @Override
+                void visitAttribute(String name, Object value) {
+                    list.add(value);
+                }
+            };
+        }
+
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/AsmReferenceResolver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/AsmReferenceResolver.java b/src/main/java/org/codehaus/groovy/ast/decompiled/AsmReferenceResolver.java
new file mode 100644
index 0000000..9b96fa1
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/AsmReferenceResolver.java
@@ -0,0 +1,92 @@
+/*
+ *  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.decompiled;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.control.ClassNodeResolver;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.objectweb.asm.Type;
+
+/**
+ * A helper class used to resolve references found in ASM-decompiled classes.
+ *
+ * @see DecompiledClassNode
+ * @see AsmDecompiler
+ *
+ * @author Peter Gromov
+ */
+public class AsmReferenceResolver {
+    private final ClassNodeResolver resolver;
+    private final CompilationUnit unit;
+
+    public AsmReferenceResolver(ClassNodeResolver resolver, CompilationUnit unit) {
+        this.resolver = resolver;
+        this.unit = unit;
+    }
+
+    public ClassNode resolveClass(String className) {
+        ClassNode classNode = resolveClassNullable(className);
+        if (classNode == null) {
+            throw new NoClassDefFoundError(className);
+        }
+        return classNode;
+    }
+
+    public ClassNode resolveClassNullable(String className) {
+        ClassNode beingCompiled = unit.getAST().getClass(className);
+        if (beingCompiled != null) {
+            return beingCompiled;
+        }
+
+        ClassNodeResolver.LookupResult lookupResult = resolver.resolveName(className, unit);
+        return lookupResult == null ? null :lookupResult.getClassNode();
+    }
+
+    public ClassNode resolveType(Type type) {
+        if (type.getSort() == Type.ARRAY) {
+            ClassNode result = resolveNonArrayType(type.getElementType());
+            for (int i = 0; i < type.getDimensions(); i++) {
+                result = result.makeArray();
+            }
+            return result;
+        }
+
+        return resolveNonArrayType(type);
+    }
+
+    private ClassNode resolveNonArrayType(Type type) {
+        String className = type.getClassName();
+        if (type.getSort() != Type.OBJECT) {
+            return ClassHelper.make(className);
+        }
+
+        return resolveClass(className);
+    }
+
+    public Class resolveJvmClass(String name) {
+        try {
+            return unit.getClassLoader().loadClass(name, false, true);
+        } catch (ClassNotFoundException e) {
+            throw new GroovyBugError("JVM class can't be loaded for " + name, e);
+        }
+    }
+
+}