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:12 UTC

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

Repository: groovy
Updated Branches:
  refs/heads/GROOVY_2_6_X 25007b260 -> f8be74296


http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
new file mode 100644
index 0000000..7839a59
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/MetaClassHelper.java
@@ -0,0 +1,1034 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ParameterTypes;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.wrappers.Wrapper;
+import org.codehaus.groovy.util.FastArray;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @author John Wilson
+ * @author Jochen Theodorou
+ */
+public class MetaClassHelper {
+
+    public static final Object[] EMPTY_ARRAY = {};
+    public static final Class[] EMPTY_TYPE_ARRAY = {};
+    public static final Object[] ARRAY_WITH_NULL = {null};
+    protected static final Logger LOG = Logger.getLogger(MetaClassHelper.class.getName());
+    private static final int MAX_ARG_LEN = 12;
+    private static final int
+            OBJECT_SHIFT = 23, INTERFACE_SHIFT = 0,
+            PRIMITIVE_SHIFT = 21, VARGS_SHIFT = 44;
+    /* dist binary layout:
+    * 0-20: interface
+    * 21-22: primitive dist
+    * 23-43: object dist
+    * 44-48: vargs penalty
+    */
+
+    public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
+
+    public static boolean accessibleToConstructor(final Class at, final Constructor constructor) {
+        boolean accessible = false;
+        final int modifiers = constructor.getModifiers();
+        if (Modifier.isPublic(modifiers)) {
+            accessible = true;
+        } else if (Modifier.isPrivate(modifiers)) {
+            accessible = at.getName().equals(constructor.getName());
+        } else if (Modifier.isProtected(modifiers)) {
+            Boolean isAccessible = checkCompatiblePackages(at, constructor);
+            if (isAccessible != null) {
+                accessible = isAccessible;
+            } else {
+                boolean flag = false;
+                Class clazz = at;
+                while (!flag && clazz != null) {
+                    if (clazz.equals(constructor.getDeclaringClass())) {
+                        flag = true;
+                        break;
+                    }
+                    if (clazz.equals(Object.class)) {
+                        break;
+                    }
+                    clazz = clazz.getSuperclass();
+                }
+                accessible = flag;
+            }
+        } else {
+            Boolean isAccessible = checkCompatiblePackages(at, constructor);
+            if (isAccessible != null) {
+                accessible = isAccessible;
+            }
+        }
+        return accessible;
+    }
+
+    private static Boolean checkCompatiblePackages(Class at, Constructor constructor) {
+        if (at.getPackage() == null && constructor.getDeclaringClass().getPackage() == null) {
+            return Boolean.TRUE;
+        }
+        if (at.getPackage() == null && constructor.getDeclaringClass().getPackage() != null) {
+            return Boolean.FALSE;
+        }
+        if (at.getPackage() != null && constructor.getDeclaringClass().getPackage() == null) {
+            return Boolean.FALSE;
+        }
+        if (at.getPackage().equals(constructor.getDeclaringClass().getPackage())) {
+            return Boolean.TRUE;
+        }
+        return null;
+    }
+
+    public static Object[] asWrapperArray(Object parameters, Class componentType) {
+        Object[] ret = null;
+        if (componentType == boolean.class) {
+            boolean[] array = (boolean[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        } else if (componentType == char.class) {
+            char[] array = (char[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        } else if (componentType == byte.class) {
+            byte[] array = (byte[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        } else if (componentType == int.class) {
+            int[] array = (int[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        } else if (componentType == short.class) {
+            short[] array = (short[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        } else if (componentType == long.class) {
+            long[] array = (long[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        } else if (componentType == double.class) {
+            double[] array = (double[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        } else if (componentType == float.class) {
+            float[] array = (float[]) parameters;
+            ret = new Object[array.length];
+            for (int i = 0; i < array.length; i++) {
+                ret[i] = array[i];
+            }
+        }
+
+        return ret;
+    }
+
+
+    /**
+     * @param list          the original list
+     * @param parameterType the resulting array type
+     * @return the constructed array
+     */
+    public static Object asPrimitiveArray(List list, Class parameterType) {
+        Class arrayType = parameterType.getComponentType();
+        Object objArray = Array.newInstance(arrayType, list.size());
+        for (int i = 0; i < list.size(); i++) {
+            Object obj = list.get(i);
+            if (arrayType.isPrimitive()) {
+                if (obj instanceof Integer) {
+                    Array.setInt(objArray, i, (Integer) obj);
+                } else if (obj instanceof Double) {
+                    Array.setDouble(objArray, i, (Double) obj);
+                } else if (obj instanceof Boolean) {
+                    Array.setBoolean(objArray, i, (Boolean) obj);
+                } else if (obj instanceof Long) {
+                    Array.setLong(objArray, i, (Long) obj);
+                } else if (obj instanceof Float) {
+                    Array.setFloat(objArray, i, (Float) obj);
+                } else if (obj instanceof Character) {
+                    Array.setChar(objArray, i, (Character) obj);
+                } else if (obj instanceof Byte) {
+                    Array.setByte(objArray, i, (Byte) obj);
+                } else if (obj instanceof Short) {
+                    Array.setShort(objArray, i, (Short) obj);
+                }
+            } else {
+                Array.set(objArray, i, obj);
+            }
+        }
+        return objArray;
+    }
+
+    private static final Class[] PRIMITIVES = {
+            boolean.class,
+            Boolean.class,
+            byte.class,
+            Byte.class,
+            short.class,
+            Short.class,
+            char.class,
+            Character.class,
+            int.class,
+            Integer.class,
+            long.class,
+            Long.class,
+            BigInteger.class,
+            float.class,
+            Float.class,
+            double.class,
+            Double.class,
+            BigDecimal.class,
+            Number.class,
+            Object.class
+    };
+
+    private static final int[][] PRIMITIVE_DISTANCE_TABLE = {
+            //                    0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19
+            /*boolean[0]*/      { 0,  1,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  2,},
+            /*Boolean[1]*/      { 1,  0,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,  2,},
+            /*byte[2]*/         {18, 19,  0,  1,  2,  3, 16, 17,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,},
+            /*Byte[3]*/         {18, 19,  1,  0,  2,  3, 16, 17,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,},
+            /*short[4]*/        {18, 19, 14, 15,  0,  1, 16, 17,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,},
+            /*Short[5]*/        {18, 19, 14, 15,  1,  0, 16, 17,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,},
+            /*char[6]*/         {18, 19, 16, 17, 14, 15,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,},
+            /*Character[7]*/    {18, 19, 16, 17, 14, 15,  1,  0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13,},
+            /*int[8]*/          {18, 19, 14, 15, 12, 13, 16, 17,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,},
+            /*Integer[9]*/      {18, 19, 14, 15, 12, 13, 16, 17,  1,  0,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,},
+            /*long[10]*/        {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,},
+            /*Long[11]*/        {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  1,  0,  2,  3,  4,  5,  6,  7,  8,  9,},
+            /*BigInteger[12]*/  {18, 19,  9, 10,  7,  8, 16, 17,  5,  6,  3,  4,  0, 14, 15, 12, 13, 11,  1,  2,},
+            /*float[13]*/       {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  8,  9,  7,  0,  1,  2,  3,  4,  5,  6,},
+            /*Float[14]*/       {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  8,  9,  7,  1,  0,  2,  3,  4,  5,  6,},
+            /*double[15]*/      {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  8,  9,  7,  5,  6,  0,  1,  2,  3,  4,},
+            /*Double[16]*/      {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  8,  9,  7,  5,  6,  1,  0,  2,  3,  4,},
+            /*BigDecimal[17]*/  {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  8,  9,  7,  5,  6,  3,  4,  0,  1,  2,},
+            /*Number[18]*/      {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  8,  9,  7,  5,  6,  3,  4,  2,  0,  1,},
+            /*Object[19]*/      {18, 19, 14, 15, 12, 13, 16, 17, 10, 11,  8,  9,  7,  5,  6,  3,  4,  2,  1,  0,},
+    };
+
+    private static int getPrimitiveIndex(Class c) {
+        for (byte i = 0; i < PRIMITIVES.length; i++) {
+            if (PRIMITIVES[i] == c) return i;
+        }
+        return -1;
+    }
+
+    private static int getPrimitiveDistance(Class from, Class to) {
+        // we know here that from!=to, so a distance of 0 is never valid
+        // get primitive type indexes
+        int fromIndex = getPrimitiveIndex(from);
+        int toIndex = getPrimitiveIndex(to);
+        if (fromIndex == -1 || toIndex == -1) return -1;
+        return PRIMITIVE_DISTANCE_TABLE[toIndex][fromIndex];
+    }
+
+    private static int getMaximumInterfaceDistance(Class c, Class interfaceClass) {
+        // -1 means a mismatch
+        if (c == null) return -1;
+        // 0 means a direct match
+        if (c == interfaceClass) return 0;
+        Class[] interfaces = c.getInterfaces();
+        int max = -1;
+        for (Class anInterface : interfaces) {
+            int sub = getMaximumInterfaceDistance(anInterface, interfaceClass);
+            // we need to keep the -1 to track the mismatch, a +1
+            // by any means could let it look like a direct match
+            // we want to add one, because there is an interface between
+            // the interface we search for and the interface we are in.
+            if (sub != -1) sub++;
+            // we are interested in the longest path only
+            max = Math.max(max, sub);
+        }
+        // we do not add one for super classes, only for interfaces
+        int superClassMax = getMaximumInterfaceDistance(c.getSuperclass(), interfaceClass);
+        if (superClassMax != -1) superClassMax++;
+        return Math.max(max, superClassMax);
+    }
+
+    private static long calculateParameterDistance(Class argument, CachedClass parameter) {
+        /**
+         * note: when shifting with 32 bit, you should only shift on a long. If you do
+         *       that with an int, then i==(i<<32), which means you loose the shift
+         *       information
+         */
+
+        if (parameter.getTheClass() == argument) return 0;
+
+        if (parameter.isInterface()) {
+            int dist = getMaximumInterfaceDistance(argument, parameter.getTheClass()) << INTERFACE_SHIFT;
+            if (dist>-1 || !(argument!=null && Closure.class.isAssignableFrom(argument))) {
+                return dist;
+            } // else go to object case
+        }
+
+        long objectDistance = 0;
+        if (argument != null) {
+            long pd = getPrimitiveDistance(parameter.getTheClass(), argument);
+            if (pd != -1) return pd << PRIMITIVE_SHIFT;
+
+            // add one to dist to be sure interfaces are preferred
+            objectDistance += PRIMITIVES.length + 1;
+
+            // GROOVY-5114 : if we have to choose between two methods
+            // foo(Object[]) and foo(Object) and that the argument is an array type
+            // then the array version should be preferred
+            if (argument.isArray() && !parameter.isArray) {
+                objectDistance+=4;
+            }
+            Class clazz = ReflectionCache.autoboxType(argument);
+            while (clazz != null) {
+                if (clazz == parameter.getTheClass()) break;
+                if (clazz == GString.class && parameter.getTheClass() == String.class) {
+                    objectDistance += 2;
+                    break;
+                }
+                clazz = clazz.getSuperclass();
+                objectDistance += 3;
+            }
+        } else {
+            // choose the distance to Object if a parameter is null
+            // this will mean that Object is preferred over a more
+            // specific type
+            Class clazz = parameter.getTheClass();
+            if (clazz.isPrimitive()) {
+                objectDistance += 2;
+            } else {
+                while (clazz != Object.class && clazz != null) {
+                    clazz = clazz.getSuperclass();
+                    objectDistance += 2;
+                }
+            }
+        }
+        return objectDistance << OBJECT_SHIFT;
+    }
+
+    public static long calculateParameterDistance(Class[] arguments, ParameterTypes pt) {
+        CachedClass[] parameters = pt.getParameterTypes();
+        if (parameters.length == 0) return 0;
+
+        long ret = 0;
+        int noVargsLength = parameters.length - 1;
+
+        // if the number of parameters does not match we have 
+        // a vargs usage
+        //
+        // case A: arguments.length<parameters.length
+        //
+        //         In this case arguments.length is always equal to
+        //         noVargsLength because only the last parameter
+        //         might be a optional vargs parameter
+        //
+        //         VArgs penalty: 1l
+        //
+        // case B: arguments.length>parameters.length
+        //
+        //         In this case all arguments with a index bigger than
+        //         paramMinus1 are part of the vargs, so a 
+        //         distance calculation needs to be done against 
+        //         parameters[noVargsLength].getComponentType()
+        //
+        //         VArgs penalty: 2l+arguments.length-parameters.length
+        //
+        // case C: arguments.length==parameters.length && 
+        //         isAssignableFrom( parameters[noVargsLength],
+        //                           arguments[noVargsLength] )
+        //
+        //         In this case we have no vargs, so calculate directly
+        //
+        //         VArgs penalty: 0l
+        //
+        // case D: arguments.length==parameters.length && 
+        //         !isAssignableFrom( parameters[noVargsLength],
+        //                            arguments[noVargsLength] )
+        //
+        //         In this case we have a vargs case again, we need 
+        //         to calculate arguments[noVargsLength] against
+        //         parameters[noVargsLength].getComponentType
+        //
+        //         VArgs penalty: 2l
+        //
+        //         This gives: VArgs_penalty(C)<VArgs_penalty(A)
+        //                     VArgs_penalty(A)<VArgs_penalty(D)
+        //                     VArgs_penalty(D)<VArgs_penalty(B)
+
+        /**
+         * In general we want to match the signature that allows us to use
+         * as less arguments for the vargs part as possible. That means the
+         * longer signature usually wins if both signatures are vargs, while
+         * vargs looses always against a signature without vargs.
+         *
+         *  A vs B :
+         *      def foo(Object[] a) {1}     -> case B
+         *      def foo(a,b,Object[] c) {2} -> case A
+         *      assert foo(new Object(),new Object()) == 2
+         *  --> A preferred over B
+         *
+         *  A vs C :
+         *      def foo(Object[] a) {1}     -> case B
+         *      def foo(a,b)        {2}     -> case C
+         *      assert foo(new Object(),new Object()) == 2
+         *  --> C preferred over A
+         *
+         *  A vs D :
+         *      def foo(Object[] a) {1}     -> case D
+         *      def foo(a,Object[] b) {2}   -> case A
+         *      assert foo(new Object()) == 2
+         *  --> A preferred over D
+         *
+         *  This gives C<A<B,D
+         *
+         *  B vs C :
+         *      def foo(Object[] a) {1}     -> case B
+         *      def foo(a,b) {2}            -> case C
+         *      assert foo(new Object(),new Object()) == 2
+         *  --> C preferred over B, matches C<A<B,D
+         *
+         *  B vs D :
+         *      def foo(Object[] a)   {1}   -> case B
+         *      def foo(a,Object[] b) {2}   -> case D
+         *      assert foo(new Object(),new Object()) == 2
+         *  --> D preferred over B
+         *
+         *  This gives C<A<D<B 
+         */
+
+        // first we calculate all arguments, that are for sure not part
+        // of vargs.  Since the minimum for arguments is noVargsLength
+        // we can safely iterate to this point
+        for (int i = 0; i < noVargsLength; i++) {
+            ret += calculateParameterDistance(arguments[i], parameters[i]);
+        }
+
+        if (arguments.length == parameters.length) {
+            // case C&D, we use baseType to calculate and set it
+            // to the value we need according to case C and D
+            CachedClass baseType = parameters[noVargsLength]; // case C
+            if (!parameters[noVargsLength].isAssignableFrom(arguments[noVargsLength])) {
+                baseType = ReflectionCache.getCachedClass(baseType.getTheClass().getComponentType()); // case D
+                ret += 2L << VARGS_SHIFT; // penalty for vargs
+            }
+            ret += calculateParameterDistance(arguments[noVargsLength], baseType);
+        } else if (arguments.length > parameters.length) {
+            // case B
+            // we give our a vargs penalty for each exceeding argument and iterate
+            // by using parameters[noVargsLength].getComponentType()
+            ret += (2L + arguments.length - parameters.length) << VARGS_SHIFT; // penalty for vargs
+            CachedClass vargsType = ReflectionCache.getCachedClass(parameters[noVargsLength].getTheClass().getComponentType());
+            for (int i = noVargsLength; i < arguments.length; i++) {
+                ret += calculateParameterDistance(arguments[i], vargsType);
+            }
+        } else {
+            // case A
+            // we give a penalty for vargs, since we have no direct
+            // match for the last argument
+            ret += 1L << VARGS_SHIFT;
+        }
+
+        return ret;
+    }
+
+    /**
+     * This is the complement to the java.beans.Introspector.decapitalize(String) method.
+     * We handle names that begin with an initial lowerCase followed by upperCase specially
+     * (which is to make no change).
+     * See GROOVY-3211.
+     *
+     * @param property the property name to capitalize
+     * @return the name capitalized, except when we don't
+     */
+    public static String capitalize(final String property) {
+        final String rest = property.substring(1);
+
+        // Funky rule so that names like 'pNAME' will still work.
+        if (Character.isLowerCase(property.charAt(0)) && (rest.length() > 0) && Character.isUpperCase(rest.charAt(0))) {
+            return property;
+        }
+
+        return property.substring(0, 1).toUpperCase() + rest;
+    }
+
+    /**
+     * @param methods the methods to choose from
+     * @return the method with 1 parameter which takes the most general type of
+     *         object (e.g. Object)
+     */
+    public static Object chooseEmptyMethodParams(FastArray methods) {
+        Object vargsMethod = null;
+        final int len = methods.size();
+        final Object[] data = methods.getArray();
+        for (int i = 0; i != len; ++i) {
+            Object method = data[i];
+            final ParameterTypes pt = (ParameterTypes) method;
+            CachedClass[] paramTypes = pt.getParameterTypes();
+            int paramLength = paramTypes.length;
+            if (paramLength == 0) {
+                return method;
+            } else if (paramLength == 1 && pt.isVargsMethod(EMPTY_ARRAY)) {
+                vargsMethod = method;
+            }
+        }
+        return vargsMethod;
+    }
+
+    /**
+     * Warning: this method does not choose properly if multiple methods with
+     * the same distance are encountered
+     * @param methods the methods to choose from
+     * @return the method with 1 parameter which takes the most general type of
+     *         object (e.g. Object) ignoring primitive types
+     * @deprecated
+     */
+    @Deprecated
+    public static Object chooseMostGeneralMethodWith1NullParam(FastArray methods) {
+        // let's look for methods with 1 argument which matches the type of the
+        // arguments
+        CachedClass closestClass = null;
+        CachedClass closestVargsClass = null;
+        Object answer = null;
+        int closestDist = -1;
+        final int len = methods.size();
+        for (int i = 0; i != len; ++i) {
+            final Object[] data = methods.getArray();
+            Object method = data[i];
+            final ParameterTypes pt = (ParameterTypes) method;
+            CachedClass[] paramTypes = pt.getParameterTypes();
+            int paramLength = paramTypes.length;
+            if (paramLength == 0 || paramLength > 2) continue;
+
+            CachedClass theType = paramTypes[0];
+            if (theType.isPrimitive) continue;
+
+            if (paramLength == 2) {
+                if (!pt.isVargsMethod(ARRAY_WITH_NULL)) continue;
+                if (closestClass == null) {
+                    closestVargsClass = paramTypes[1];
+                    closestClass = theType;
+                    answer = method;
+                } else if (closestClass.getTheClass() == theType.getTheClass()) {
+                    if (closestVargsClass == null) continue;
+                    CachedClass newVargsClass = paramTypes[1];
+                    if (isAssignableFrom(newVargsClass.getTheClass(), closestVargsClass.getTheClass())) {
+                        closestVargsClass = newVargsClass;
+                        answer = method;
+                    }
+                } else if (isAssignableFrom(theType.getTheClass(), closestClass.getTheClass())) {
+                    closestVargsClass = paramTypes[1];
+                    closestClass = theType;
+                    answer = method;
+                }
+            } else {
+                if (closestClass == null || isAssignableFrom(theType.getTheClass(), closestClass.getTheClass())) {
+                    closestVargsClass = null;
+                    closestClass = theType;
+                    answer = method;
+                    closestDist = -1;
+                } else {
+                    // closestClass and theType are not in a subtype relation, we need
+                    // to check the distance to Object
+                    if (closestDist == -1) closestDist = closestClass.getSuperClassDistance();
+                    int newDist = theType.getSuperClassDistance();
+                    if (newDist < closestDist) {
+                        closestDist = newDist;
+                        closestVargsClass = null;
+                        closestClass = theType;
+                        answer = method;
+                    }
+                }
+            }
+        }
+        return answer;
+    }
+
+    // 
+
+    /**
+     * @param list   a list of MetaMethods
+     * @param method the MetaMethod of interest
+     * @return true if a method of the same matching prototype was found in the
+     *         list
+     */
+    public static boolean containsMatchingMethod(List list, MetaMethod method) {
+        for (Object aList : list) {
+            MetaMethod aMethod = (MetaMethod) aList;
+            CachedClass[] params1 = aMethod.getParameterTypes();
+            CachedClass[] params2 = method.getParameterTypes();
+            if (params1.length == params2.length) {
+                boolean matches = true;
+                for (int i = 0; i < params1.length; i++) {
+                    if (params1[i] != params2[i]) {
+                        matches = false;
+                        break;
+                    }
+                }
+                if (matches) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * param instance array to the type array
+     *
+     * @param args the arguments
+     * @return the types of the arguments
+     */
+    public static Class[] convertToTypeArray(Object[] args) {
+        if (args == null)
+            return null;
+        int s = args.length;
+        Class[] ans = new Class[s];
+        for (int i = 0; i < s; i++) {
+            Object o = args[i];
+            ans[i] = getClassWithNullAndWrapper(o);
+        }
+        return ans;
+    }
+
+    public static Object makeCommonArray(Object[] arguments, int offset, Class fallback) {
+        // arguments.length>0 && !=null
+        Class baseClass = null;
+        for (int i = offset; i < arguments.length; i++) {
+            if (arguments[i] == null) continue;
+            Class argClass = arguments[i].getClass();
+            if (baseClass == null) {
+                baseClass = argClass;
+            } else {
+                for (; baseClass != Object.class; baseClass = baseClass.getSuperclass()) {
+                    if (baseClass.isAssignableFrom(argClass)) break;
+                }
+            }
+        }
+        if (baseClass == null) {
+            // all arguments were null
+            baseClass = fallback;
+        }
+        /*
+         * If no specific super class has been found and type fallback is an interface, check if all arg classes 
+         * implement it. If yes, then that interface is the common type across arguments.
+         */
+        if (baseClass == Object.class && fallback.isInterface()) {
+            int tmpCount = 0;
+            for (int i = offset; i < arguments.length; i++) {
+                if (arguments[i] != null) {
+                    Class tmpClass;
+                    Set<Class> intfs = new HashSet<Class>();
+                    tmpClass = arguments[i].getClass();
+                    for (; tmpClass != Object.class; tmpClass = tmpClass.getSuperclass()) {
+                        intfs.addAll(Arrays.asList(tmpClass.getInterfaces()));
+                    }
+                    if (intfs.contains(fallback)) {
+                        tmpCount++;
+                    }
+                }
+            }
+            // all arg classes implement interface fallback, so use that as the array component type
+            if (tmpCount == arguments.length - offset) {
+                baseClass = fallback;
+            }
+        }
+        Object result = makeArray(null, baseClass, arguments.length - offset);
+        System.arraycopy(arguments, offset, result, 0, arguments.length - offset);
+        return result;
+    }
+
+    public static Object makeArray(Object obj, Class secondary, int length) {
+        Class baseClass = secondary;
+        if (obj != null) {
+            baseClass = obj.getClass();
+        }
+        /*if (GString.class.isAssignableFrom(baseClass)) {
+              baseClass = GString.class;
+          }*/
+        return Array.newInstance(baseClass, length);
+    }
+
+    public static GroovyRuntimeException createExceptionText(String init, MetaMethod method, Object object, Object[] args, Throwable reason, boolean setReason) {
+        return new GroovyRuntimeException(
+                init
+                        + method
+                        + " on: "
+                        + object
+                        + " with arguments: "
+                        + InvokerHelper.toString(args)
+                        + " reason: "
+                        + reason,
+                setReason ? reason : null);
+    }
+
+    protected static String getClassName(Object object) {
+        if (object == null) return null;
+        return (object instanceof Class) ? ((Class) object).getName() : object.getClass().getName();
+    }
+
+    /**
+     * Returns a callable object for the given method name on the object.
+     * The object acts like a Closure in that it can be called, like a closure
+     * and passed around - though really its a method pointer, not a closure per se.
+     *
+     * @param object     the object containing the method
+     * @param methodName the method of interest
+     * @return the resulting closure-like method pointer
+     */
+    public static Closure getMethodPointer(Object object, String methodName) {
+        return new MethodClosure(object, methodName);
+    }
+
+    public static boolean isAssignableFrom(Class classToTransformTo, Class classToTransformFrom) {
+        if (classToTransformTo == classToTransformFrom
+                || classToTransformFrom == null
+                || classToTransformTo == Object.class) {
+            return true;
+        }
+
+        classToTransformTo = ReflectionCache.autoboxType(classToTransformTo);
+        classToTransformFrom = ReflectionCache.autoboxType(classToTransformFrom);
+        if (classToTransformTo == classToTransformFrom) return true;
+
+        // note: there is no coercion for boolean and char. Range matters, precision doesn't
+        if (classToTransformTo == Integer.class) {
+            if (classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class
+                    || classToTransformFrom == BigInteger.class)
+                return true;
+        } else if (classToTransformTo == Double.class) {
+            if (classToTransformFrom == Integer.class
+                    || classToTransformFrom == Long.class
+                    || classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class
+                    || classToTransformFrom == Float.class
+                    || classToTransformFrom == BigDecimal.class
+                    || classToTransformFrom == BigInteger.class)
+                return true;
+        } else if (classToTransformTo == BigDecimal.class) {
+            if (classToTransformFrom == Double.class
+                    || classToTransformFrom == Integer.class
+                    || classToTransformFrom == Long.class
+                    || classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class
+                    || classToTransformFrom == Float.class
+                    || classToTransformFrom == BigInteger.class)
+                return true;
+        } else if (classToTransformTo == BigInteger.class) {
+            if (classToTransformFrom == Integer.class
+                    || classToTransformFrom == Long.class
+                    || classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class)
+                return true;
+        } else if (classToTransformTo == Long.class) {
+            if (classToTransformFrom == Integer.class
+                    || classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class)
+                return true;
+        } else if (classToTransformTo == Float.class) {
+            if (classToTransformFrom == Integer.class
+                    || classToTransformFrom == Long.class
+                    || classToTransformFrom == Short.class
+                    || classToTransformFrom == Byte.class)
+                return true;
+        } else if (classToTransformTo == Short.class) {
+            if (classToTransformFrom == Byte.class)
+                return true;
+        } else if (classToTransformTo == String.class) {
+            if (GString.class.isAssignableFrom(classToTransformFrom)) {
+                return true;
+            }
+        }
+
+        return ReflectionCache.isAssignableFrom(classToTransformTo, classToTransformFrom);
+    }
+
+    public static boolean isGenericSetMethod(MetaMethod method) {
+        return (method.getName().equals("set"))
+                && method.getParameterTypes().length == 2;
+    }
+
+    protected static boolean isSuperclass(Class clazz, Class superclass) {
+        while (clazz != null) {
+            if (clazz == superclass) return true;
+            clazz = clazz.getSuperclass();
+        }
+        return false;
+    }
+
+    public static boolean parametersAreCompatible(Class[] arguments, Class[] parameters) {
+        if (arguments.length != parameters.length) return false;
+        for (int i = 0; i < arguments.length; i++) {
+            if (!isAssignableFrom(parameters[i], arguments[i])) return false;
+        }
+        return true;
+    }
+
+    public static void logMethodCall(Object object, String methodName, Object[] arguments) {
+        String className = getClassName(object);
+        String logname = "methodCalls." + className + "." + methodName;
+        Logger objLog = Logger.getLogger(logname);
+        if (!objLog.isLoggable(Level.FINER)) return;
+        StringBuilder msg = new StringBuilder(methodName);
+        msg.append("(");
+        if (arguments != null) {
+            for (int i = 0; i < arguments.length;) {
+                msg.append(normalizedValue(arguments[i]));
+                if (++i < arguments.length) {
+                    msg.append(",");
+                }
+            }
+        }
+        msg.append(")");
+        objLog.logp(Level.FINER, className, msg.toString(), "called from MetaClass.invokeMethod");
+    }
+
+    protected static String normalizedValue(Object argument) {
+        String value;
+        try {
+            value = argument.toString();
+            if (value.length() > MAX_ARG_LEN) {
+                value = value.substring(0, MAX_ARG_LEN - 2) + "..";
+            }
+            if (argument instanceof String) {
+                value = "\'" + value + "\'";
+            }
+        } catch (Exception e) {
+            value = shortName(argument);
+        }
+        return value;
+    }
+
+    protected static String shortName(Object object) {
+        if (object == null || object.getClass() == null) return "unknownClass";
+        String name = getClassName(object);
+        if (name == null) return "unknownClassName"; // *very* defensive...
+        int lastDotPos = name.lastIndexOf('.');
+        if (lastDotPos < 0 || lastDotPos >= name.length() - 1) return name;
+        return name.substring(lastDotPos + 1);
+    }
+
+    public static Class[] wrap(Class[] classes) {
+        Class[] wrappedArguments = new Class[classes.length];
+        for (int i = 0; i < wrappedArguments.length; i++) {
+            Class c = classes[i];
+            if (c == null) continue;
+            if (c.isPrimitive()) {
+                if (c == Integer.TYPE) {
+                    c = Integer.class;
+                } else if (c == Byte.TYPE) {
+                    c = Byte.class;
+                } else if (c == Long.TYPE) {
+                    c = Long.class;
+                } else if (c == Double.TYPE) {
+                    c = Double.class;
+                } else if (c == Float.TYPE) {
+                    c = Float.class;
+                }
+            } else if (isSuperclass(c, GString.class)) {
+                c = String.class;
+            }
+            wrappedArguments[i] = c;
+        }
+        return wrappedArguments;
+    }
+
+    public static boolean sameClasses(Class[] params, Object[] arguments, boolean weakNullCheck) {
+        if (params.length != arguments.length)
+            return false;
+
+        for (int i = params.length - 1; i >= 0; i--) {
+            Object arg = arguments[i];
+            Class compareClass = getClassWithNullAndWrapper(arg);
+            if (params[i] != compareClass) return false;
+        }
+
+        return true;
+    }
+
+    private static Class getClassWithNullAndWrapper(Object arg) {
+        if (arg == null) return null;
+        if (arg instanceof Wrapper) {
+            Wrapper w = (Wrapper) arg;
+            return w.getType();
+        }
+        return arg.getClass();
+    }
+
+    public static boolean sameClasses(Class[] params, Object[] arguments) {
+        if (params.length != arguments.length)
+            return false;
+
+        for (int i = params.length - 1; i >= 0; i--) {
+            Object arg = arguments[i];
+            if (arg == null) {
+                if (params[i] != null)
+                    return false;
+            } else {
+                if (params[i] != getClassWithNullAndWrapper(arg))
+                    return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static boolean sameClasses(Class[] params) {
+        if (params.length != 0)
+            return false;
+
+        return true;
+    }
+
+    public static boolean sameClasses(Class[] params, Object arg1) {
+        if (params.length != 1)
+            return false;
+
+        if (params[0] != getClassWithNullAndWrapper(arg1)) return false;
+
+        return true;
+    }
+
+    public static boolean sameClasses(Class[] params, Object arg1, Object arg2) {
+        if (params.length != 2)
+            return false;
+
+        if (params[0] != getClassWithNullAndWrapper(arg1)) return false;
+        if (params[1] != getClassWithNullAndWrapper(arg2)) return false;
+
+        return true;
+    }
+
+    public static boolean sameClasses(Class[] params, Object arg1, Object arg2, Object arg3) {
+        if (params.length != 3)
+            return false;
+
+        if (params[0] != getClassWithNullAndWrapper(arg1)) return false;
+        if (params[1] != getClassWithNullAndWrapper(arg2)) return false;
+        if (params[2] != getClassWithNullAndWrapper(arg3)) return false;
+
+        return true;
+    }
+
+    public static boolean sameClasses(Class[] params, Object arg1, Object arg2, Object arg3, Object arg4) {
+        if (params.length != 4)
+            return false;
+
+        if (params[0] != getClassWithNullAndWrapper(arg1)) return false;
+        if (params[1] != getClassWithNullAndWrapper(arg2)) return false;
+        if (params[2] != getClassWithNullAndWrapper(arg3)) return false;
+        if (params[3] != getClassWithNullAndWrapper(arg4)) return false;
+        
+        return true;
+    }
+
+    public static boolean sameClass(Class[] params, Object arg) {
+        return params[0] == getClassWithNullAndWrapper(arg);
+
+    }
+
+    public static Class[] castArgumentsToClassArray(Object[] argTypes) {
+        if (argTypes == null) return EMPTY_CLASS_ARRAY;
+        Class[] classes = new Class[argTypes.length];
+        for (int i = 0; i < argTypes.length; i++) {
+            Object argType = argTypes[i];
+            if (argType instanceof Class) {
+                classes[i] = (Class) argType;
+            } else if (argType == null) {
+                classes[i] = null;
+            } else {
+//                throw new IllegalArgumentException("Arguments to method [respondsTo] must be of type java.lang.Class!");
+                classes[i] = argType.getClass();
+            }
+        }
+        return classes;
+    }
+
+    public static void unwrap(Object[] arguments) {
+        //
+        // Temp code to ignore wrapped parameters
+        // The New MOP will deal with these properly
+        //
+        for (int i = 0; i != arguments.length; i++) {
+            if (arguments[i] instanceof Wrapper) {
+                arguments[i] = ((Wrapper) arguments[i]).unwrap();
+            }
+        }
+    }
+
+    /**
+     * Sets the meta class for an object, by delegating to the appropriate
+     * {@link DefaultGroovyMethods} helper method. This method was introduced as
+     * a breaking change in 2.0 to solve rare cases of stack overflow. See GROOVY-5285.
+     *
+     * The method is named doSetMetaClass in order to prevent misusages. Do not use
+     * this method directly unless you know what you do.
+     *
+     * @param self the object for which to set the meta class
+     * @param mc the metaclass
+     */
+    public static void doSetMetaClass(Object self, MetaClass mc) {
+        if (self instanceof GroovyObject) {
+            DefaultGroovyMethods.setMetaClass((GroovyObject)self, mc);
+        } else {
+            DefaultGroovyMethods.setMetaClass(self, mc);
+        }
+    }
+
+    /**
+     * Converts a String into a standard property name.
+     *
+     * @param prop the original name
+     * @return the converted name
+     */
+    public static String convertPropertyName(String prop) {
+        if (Character.isDigit(prop.charAt(0))) {
+            return prop;
+        }
+        return java.beans.Introspector.decapitalize(prop);
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java
new file mode 100644
index 0000000..305e397
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/CompositeVisitor.java
@@ -0,0 +1,1179 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A composite of many visitors. Any call to a method from Visitor
+ * will invoke each visitor in turn, and reverse the invocation
+ * order on a closing visit.
+ * i.e.
+ * with the list of visitors = [a,b,c]
+ * composite.visitDefault() would...
+ * call on the opening visit - a.visitDefault() then b.visitDefault() then c.visitDefault()
+ * call on the closing visit - c.visitDefault() then b.visitDefault() then a.visitDefault()
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public class CompositeVisitor implements Visitor{
+    final List visitors;
+    final List backToFrontVisitors;
+
+    /**
+     * A composite of the supplied list of antlr AST visitors.
+     * @param visitors a List of implementations of the Visitor interface
+     */
+    public CompositeVisitor(List visitors) {
+        this.visitors = visitors;
+        backToFrontVisitors = new ArrayList();
+        backToFrontVisitors.addAll(visitors);
+        Collections.reverse(backToFrontVisitors);
+    }
+
+    private Iterator itr(int visit) {
+        Iterator itr=visitors.iterator();
+        if (visit == CLOSING_VISIT) {
+            itr = backToFrontVisitors.iterator();
+        }
+        return itr;
+    }
+
+    public void setUp() {
+        Iterator itr = visitors.iterator();
+        while (itr.hasNext()) {((Visitor)itr.next()).setUp();}
+    }
+
+    public void visitAbstract(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAbstract(t,visit);}
+    }
+
+    public void visitAnnotation(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotation(t,visit);}
+    }
+
+    public void visitAnnotations(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotations(t,visit);}
+    }
+
+    public void visitAnnotationArrayInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationArrayInit(t,visit);}
+    }
+
+    public void visitAnnotationDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationDef(t,visit);}
+    }
+
+    public void visitAnnotationFieldDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationFieldDef(t,visit);}
+    }
+
+    public void visitAnnotationMemberValuePair(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAnnotationMemberValuePair(t,visit);}
+    }
+
+    public void visitArrayDeclarator(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitArrayDeclarator(t,visit);}
+    }
+
+    public void visitAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAssign(t,visit);}
+    }
+
+    public void visitAt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitAt(t,visit);}
+    }
+
+    public void visitBand(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBand(t,visit);}
+    }
+
+    public void visitBandAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBandAssign(t,visit);}
+    }
+
+    public void visitBigSuffix(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBigSuffix(t,visit);}
+    }
+
+    public void visitBlock(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBlock(t,visit);}
+    }
+
+    public void visitBnot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBnot(t,visit);}
+    }
+
+    public void visitBor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBor(t,visit);}
+    }
+
+    public void visitBorAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBorAssign(t,visit);}
+    }
+
+    public void visitBsr(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBsr(t,visit);}
+    }
+
+    public void visitBsrAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBsrAssign(t,visit);}
+    }
+
+    public void visitBxor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBxor(t,visit);}
+    }
+
+    public void visitBxorAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitBxorAssign(t,visit);}
+    }
+
+    public void visitCaseGroup(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCaseGroup(t,visit);}
+    }
+
+    public void visitClassDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitClassDef(t,visit);}
+    }
+
+    public void visitClosedBlock(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitClosedBlock(t,visit);}
+    }
+
+    public void visitClosureList(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitClosureList(t,visit);}
+    }
+
+    public void visitClosureOp(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitClosureOp(t,visit);}
+    }
+
+    public void visitColon(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitColon(t,visit);}
+    }
+
+    public void visitComma(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitComma(t,visit);}
+    }
+
+    public void visitCompareTo(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCompareTo(t,visit);}
+    }
+
+    public void visitCtorCall(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCtorCall(t,visit);}
+    }
+
+    public void visitCtorIdent(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitCtorIdent(t,visit);}
+    }
+
+    public void visitDec(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDec(t,visit);}
+    }
+
+    public void visitDigit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDigit(t,visit);}
+    }
+
+    public void visitDiv(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDiv(t,visit);}
+    }
+
+    public void visitDivAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDivAssign(t,visit);}
+    }
+
+    public void visitDollar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDollar(t,visit);}
+    }
+
+    public void visitDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDot(t,visit);}
+    }
+
+    public void visitDynamicMember(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDynamicMember(t,visit);}
+    }
+
+    public void visitElist(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitElist(t,visit);}
+    }
+
+    public void visitEmptyStat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEmptyStat(t,visit);}
+    }
+
+    public void visitEnumConstantDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEnumConstantDef(t,visit);}
+    }
+
+    public void visitEnumDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEnumDef(t,visit);}
+    }
+
+    public void visitEof(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEof(t,visit);}
+    }
+
+    public void visitEqual(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEqual(t,visit);}
+    }
+
+    public void visitEsc(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitEsc(t,visit);}
+    }
+
+    public void visitExponent(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitExponent(t,visit);}
+    }
+
+    public void visitExpr(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitExpr(t,visit);}
+    }
+
+    public void visitExtendsClause(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitExtendsClause(t,visit);}
+    }
+
+    public void visitFinal(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitFinal(t,visit);}
+    }
+
+    public void visitFloatSuffix(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitFloatSuffix(t,visit);}
+    }
+
+    public void visitForCondition(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForCondition(t,visit);}
+    }
+
+    public void visitForEachClause(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForEachClause(t,visit);}
+    }
+
+    public void visitForInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForInit(t,visit);}
+    }
+
+    public void visitForInIterable(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForInIterable(t,visit);}
+    }
+
+    public void visitForIterator(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitForIterator(t,visit);}
+    }
+
+    public void visitGe(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitGe(t,visit);}
+    }
+
+    public void visitGt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitGt(t,visit);}
+    }
+
+    public void visitHexDigit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitHexDigit(t,visit);}
+    }
+
+    public void visitIdent(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitIdent(t,visit);}
+    }
+
+    public void visitImplementsClause(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitImplementsClause(t,visit);}
+    }
+
+    public void visitImplicitParameters(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitImplicitParameters(t,visit);}
+    }
+
+    public void visitImport(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitImport(t,visit);}
+    }
+
+    public void visitInc(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitInc(t,visit);}
+    }
+
+    public void visitIndexOp(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitIndexOp(t,visit);}
+    }
+
+    public void visitInstanceInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitInstanceInit(t,visit);}
+    }
+
+    public void visitInterfaceDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitInterfaceDef(t,visit);}
+    }
+
+    public void visitLabeledArg(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLabeledArg(t,visit);}
+    }
+
+    public void visitLabeledStat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLabeledStat(t,visit);}
+    }
+
+    public void visitLand(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLand(t,visit);}
+    }
+
+    public void visitLbrack(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLbrack(t,visit);}
+    }
+
+    public void visitLcurly(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLcurly(t,visit);}
+    }
+
+    public void visitLe(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLe(t,visit);}
+    }
+
+    public void visitLetter(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLetter(t,visit);}
+    }
+
+    public void visitListConstructor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitListConstructor(t,visit);}
+    }
+
+    public void visitLiteralAs(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralAs(t,visit);}
+    }
+
+    public void visitLiteralAssert(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralAssert(t,visit);}
+    }
+
+    public void visitLiteralBoolean(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralBoolean(t,visit);}
+    }
+
+    public void visitLiteralBreak(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralBreak(t,visit);}
+    }
+
+    public void visitLiteralByte(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralByte(t,visit);}
+    }
+
+    public void visitLiteralCase(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralCase(t,visit);}
+    }
+
+    public void visitLiteralCatch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralCatch(t,visit);}
+    }
+
+    public void visitLiteralChar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralChar(t,visit);}
+    }
+
+    public void visitLiteralClass(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralClass(t,visit);}
+    }
+
+    public void visitLiteralContinue(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralContinue(t,visit);}
+    }
+
+    public void visitLiteralDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralDef(t,visit);}
+    }
+
+    public void visitLiteralDefault(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralDefault(t,visit);}
+    }
+
+    public void visitLiteralDouble(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralDouble(t,visit);}
+    }
+
+    public void visitLiteralElse(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralElse(t,visit);}
+    }
+
+    public void visitLiteralEnum(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralEnum(t,visit);}
+    }
+
+    public void visitLiteralExtends(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralExtends(t,visit);}
+    }
+
+    public void visitLiteralFalse(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFalse(t,visit);}
+    }
+
+    public void visitLiteralFinally(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFinally(t,visit);}
+    }
+
+    public void visitLiteralFloat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFloat(t,visit);}
+    }
+
+    public void visitLiteralFor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralFor(t,visit);}
+    }
+
+    public void visitLiteralIf(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralIf(t,visit);}
+    }
+
+    public void visitLiteralImplements(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralImplements(t,visit);}
+    }
+
+    public void visitLiteralImport(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralImport(t,visit);}
+    }
+
+    public void visitLiteralIn(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralIn(t,visit);}
+    }
+
+    public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralInstanceof(t,visit);}
+    }
+
+    public void visitLiteralInt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralInt(t,visit);}
+    }
+
+    public void visitLiteralInterface(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralInterface(t,visit);}
+    }
+
+    public void visitLiteralLong(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralLong(t,visit);}
+    }
+
+    public void visitLiteralNative(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralNative(t,visit);}
+    }
+
+    public void visitLiteralNew(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralNew(t,visit);}
+    }
+
+    public void visitLiteralNull(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralNull(t,visit);}
+    }
+
+    public void visitLiteralPackage(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralPackage(t,visit);}
+    }
+
+    public void visitLiteralPrivate(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralPrivate(t,visit);}
+    }
+
+    public void visitLiteralProtected(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralProtected(t,visit);}
+    }
+
+    public void visitLiteralPublic(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralPublic(t,visit);}
+    }
+
+    public void visitLiteralReturn(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralReturn(t,visit);}
+    }
+
+    public void visitLiteralShort(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralShort(t,visit);}
+    }
+
+    public void visitLiteralStatic(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralStatic(t,visit);}
+    }
+
+    public void visitLiteralSuper(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralSuper(t,visit);}
+    }
+
+    public void visitLiteralSwitch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralSwitch(t,visit);}
+    }
+
+    public void visitLiteralSynchronized(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralSynchronized(t,visit);}
+    }
+
+    public void visitLiteralThis(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThis(t,visit);}
+    }
+
+    public void visitLiteralThreadsafe(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThreadsafe(t,visit);}
+    }
+
+    public void visitLiteralThrow(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThrow(t,visit);}
+    }
+
+    public void visitLiteralThrows(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralThrows(t,visit);}
+    }
+
+    public void visitLiteralTransient(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralTransient(t,visit);}
+    }
+
+    public void visitLiteralTrue(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralTrue(t,visit);}
+    }
+
+    public void visitLiteralTry(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralTry(t,visit);}
+    }
+
+    public void visitLiteralVoid(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralVoid(t,visit);}
+    }
+
+    public void visitLiteralVolatile(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralVolatile(t,visit);}
+    }
+
+    public void visitLiteralWhile(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLiteralWhile(t,visit);}
+    }
+
+    public void visitLnot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLnot(t,visit);}
+    }
+
+    public void visitLor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLor(t,visit);}
+    }
+
+    public void visitLparen(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLparen(t,visit);}
+    }
+
+    public void visitLt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitLt(t,visit);}
+    }
+
+    public void visitMapConstructor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMapConstructor(t,visit);}
+    }
+
+    public void visitMemberPointer(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMemberPointer(t,visit);}
+    }
+
+    public void visitMethodCall(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMethodCall(t,visit);}
+    }
+
+    public void visitMethodDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMethodDef(t,visit);}
+    }
+
+    public void visitMinus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMinus(t,visit);}
+    }
+
+    public void visitMinusAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMinusAssign(t,visit);}
+    }
+
+    public void visitMlComment(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMlComment(t,visit);}
+    }
+
+    public void visitMod(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMod(t,visit);}
+    }
+
+    public void visitModifiers(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitModifiers(t,visit);}
+    }
+
+    public void visitModAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitModAssign(t,visit);}
+    }
+
+    public void visitMultiCatch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMultiCatch(t, visit);}
+    }
+
+    public void visitMultiCatchTypes(final GroovySourceAST t, final int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitMultiCatchTypes(t, visit);}
+    }
+
+    public void visitNls(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNls(t,visit);}
+    }
+
+    public void visitNotEqual(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNotEqual(t,visit);}
+    }
+
+    public void visitNullTreeLookahead(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNullTreeLookahead(t,visit);}
+    }
+
+    public void visitNumBigDecimal(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumBigDecimal(t,visit);}
+    }
+
+    public void visitNumBigInt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumBigInt(t,visit);}
+    }
+
+    public void visitNumDouble(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumDouble(t,visit);}
+    }
+
+    public void visitNumFloat(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumFloat(t,visit);}
+    }
+
+    public void visitNumInt(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumInt(t,visit);}
+    }
+
+    public void visitNumLong(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitNumLong(t,visit);}
+    }
+
+    public void visitObjblock(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitObjblock(t,visit);}
+    }
+
+    public void visitOneNl(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitOneNl(t,visit);}
+    }
+
+    public void visitOptionalDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitOptionalDot(t,visit);}
+    }
+
+    public void visitPackageDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPackageDef(t,visit);}
+    }
+
+    public void visitParameters(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitParameters(t,visit);}
+    }
+
+    public void visitParameterDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitParameterDef(t,visit);}
+    }
+
+    public void visitPlus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPlus(t,visit);}
+    }
+
+    public void visitPlusAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPlusAssign(t,visit);}
+    }
+
+    public void visitPostDec(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPostDec(t,visit);}
+    }
+
+    public void visitPostInc(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitPostInc(t,visit);}
+    }
+
+    public void visitQuestion(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitQuestion(t,visit);}
+    }
+
+    public void visitRangeExclusive(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRangeExclusive(t,visit);}
+    }
+
+    public void visitRangeInclusive(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRangeInclusive(t,visit);}
+    }
+
+    public void visitRbrack(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRbrack(t,visit);}
+    }
+
+    public void visitRcurly(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRcurly(t,visit);}
+    }
+
+    public void visitRegexpCtorEnd(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexpCtorEnd(t,visit);}
+    }
+
+    public void visitRegexpLiteral(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexpLiteral(t,visit);}
+    }
+
+    public void visitRegexpSymbol(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexpSymbol(t,visit);}
+    }
+
+    public void visitRegexFind(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexFind(t,visit);}
+    }
+
+    public void visitRegexMatch(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRegexMatch(t,visit);}
+    }
+
+    public void visitRparen(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitRparen(t,visit);}
+    }
+
+    public void visitSelectSlot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSelectSlot(t,visit);}
+    }
+
+    public void visitSemi(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSemi(t,visit);}
+    }
+
+    public void visitShComment(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitShComment(t,visit);}
+    }
+
+    public void visitSl(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSl(t,visit);}
+    }
+
+    public void visitSlist(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSlist(t,visit);}
+    }
+
+    public void visitSlAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSlAssign(t,visit);}
+    }
+
+    public void visitSlComment(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSlComment(t,visit);}
+    }
+
+    public void visitSpreadArg(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSpreadArg(t,visit);}
+    }
+
+    public void visitSpreadDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSpreadDot(t,visit);}
+    }
+
+    public void visitSpreadMapArg(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSpreadMapArg(t,visit);}
+    }
+
+    public void visitSr(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSr(t,visit);}
+    }
+
+    public void visitSrAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSrAssign(t,visit);}
+    }
+
+    public void visitStar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStar(t,visit);}
+    }
+
+    public void visitStarAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStarAssign(t,visit);}
+    }
+
+    public void visitStarStar(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStarStar(t,visit);}
+    }
+
+    public void visitStarStarAssign(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStarStarAssign(t,visit);}
+    }
+
+    public void visitStaticImport(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStaticImport(t,visit);}
+    }
+
+    public void visitStaticInit(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStaticInit(t,visit);}
+    }
+
+    public void visitStrictfp(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStrictfp(t,visit);}
+    }
+
+    public void visitStringCh(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCh(t,visit);}
+    }
+
+    public void visitStringConstructor(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringConstructor(t,visit);}
+    }
+
+    public void visitStringCtorEnd(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCtorEnd(t,visit);}
+    }
+
+    public void visitStringCtorMiddle(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCtorMiddle(t,visit);}
+    }
+
+    public void visitStringCtorStart(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringCtorStart(t,visit);}
+    }
+
+    public void visitStringLiteral(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringLiteral(t,visit);}
+    }
+
+    public void visitStringNl(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitStringNl(t,visit);}
+    }
+
+    public void visitSuperCtorCall(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitSuperCtorCall(t,visit);}
+    }
+
+    public void visitTraitDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTraitDef(t,visit);}
+    }
+
+    public void visitTripleDot(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTripleDot(t,visit);}
+    }
+
+    public void visitType(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitType(t,visit);}
+    }
+
+    public void visitTypecast(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypecast(t,visit);}
+    }
+
+    public void visitTypeArgument(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeArgument(t,visit);}
+    }
+
+    public void visitTypeArguments(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeArguments(t,visit);}
+    }
+
+    public void visitTypeLowerBounds(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeLowerBounds(t,visit);}
+    }
+
+    public void visitTypeParameter(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeParameter(t,visit);}
+    }
+
+    public void visitTypeParameters(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeParameters(t,visit);}
+    }
+
+    public void visitTypeUpperBounds(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitTypeUpperBounds(t,visit);}
+    }
+
+    public void visitUnaryMinus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnaryMinus(t,visit);}
+    }
+
+    public void visitUnaryPlus(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnaryPlus(t,visit);}
+    }
+
+    public void visitUnusedConst(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnusedConst(t,visit);}
+    }
+
+    public void visitUnusedDo(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnusedDo(t,visit);}
+    }
+
+    public void visitUnusedGoto(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitUnusedGoto(t,visit);}
+    }
+
+    public void visitVariableDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitVariableDef(t,visit);}
+    }
+
+    public void visitVariableParameterDef(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitVariableParameterDef(t,visit);}
+    }
+
+    public void visitVocab(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitVocab(t,visit);}
+    }
+
+    public void visitWildcardType(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitWildcardType(t,visit);}
+    }
+
+    public void visitWs(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitWs(t,visit);}
+    }
+
+    public void visitDefault(GroovySourceAST t, int visit) {
+        Iterator itr = itr(visit);
+        while (itr.hasNext()) {((Visitor)itr.next()).visitDefault(t,visit);}
+    }
+
+    public void tearDown() {
+        Iterator itr = backToFrontVisitors.iterator();
+        while (itr.hasNext()) {((Visitor)itr.next()).tearDown();}
+    }
+
+    public void push(GroovySourceAST t) {
+        Iterator itr = visitors.iterator();
+        while (itr.hasNext()) {((Visitor)itr.next()).push(t);}
+    }
+    public GroovySourceAST pop() {
+        GroovySourceAST lastNodePopped = null;
+        Iterator itr = backToFrontVisitors.iterator();
+        while (itr.hasNext()) {lastNodePopped = (GroovySourceAST) ((Visitor)itr.next()).pop();}
+        return lastNodePopped;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/FlatNodeListTraversal.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/FlatNodeListTraversal.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/FlatNodeListTraversal.java
new file mode 100644
index 0000000..6f17dfe
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/FlatNodeListTraversal.java
@@ -0,0 +1,63 @@
+/*
+ *  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.antlr.treewalker;
+
+import antlr.collections.AST;
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A simple iterator over an ordered (flat) List of the nodes of the AST.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+public class FlatNodeListTraversal extends TraversalHelper {
+    
+    public FlatNodeListTraversal(Visitor visitor) {
+        super(visitor);
+    }
+
+    public AST process(AST t) {
+        GroovySourceAST node = (GroovySourceAST) t;
+
+        // fetch all the nodes in this AST into a List
+        NodeCollector collector = new NodeCollector();
+        AntlrASTProcessor internalTraversal = new PreOrderTraversal(collector);
+        internalTraversal.process(t);
+        List listOfAllNodesInThisAST = collector.getNodes();
+        
+        // process each node in turn
+        setUp(node);        
+        Iterator itr = listOfAllNodesInThisAST.iterator();
+        while (itr.hasNext()) {
+            GroovySourceAST currentNode = (GroovySourceAST) itr.next();
+            accept(currentNode);
+        }
+        tearDown(node);
+        return null;
+    }
+
+    protected void accept(GroovySourceAST currentNode) {
+        openingVisit(currentNode);
+        closingVisit(currentNode);
+    }    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/MindMapPrinter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/MindMapPrinter.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/MindMapPrinter.java
new file mode 100644
index 0000000..7271466
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/MindMapPrinter.java
@@ -0,0 +1,379 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.LineColumn;
+import org.codehaus.groovy.antlr.SourceBuffer;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+import java.io.PrintStream;
+
+/**
+ * An antlr AST visitor that prints a format suitable for viewing in http://freemind.sourceforge.net
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public class MindMapPrinter extends VisitorAdapter {
+    private final String[] tokenNames;
+    private final PrintStream out;
+    private int depth;
+    private SourceBuffer sourceBuffer;
+
+    /**
+     * A visitor that prints a format suitable for viewing in http://freemind.sourceforge.net
+     * @param out where to print the mindmap file contents to
+     * @param tokenNames an array of token names from antlr
+     */
+
+    public MindMapPrinter(PrintStream out,String[] tokenNames) {
+        this.tokenNames = tokenNames;
+        this.out = out;
+    }
+
+    public MindMapPrinter(PrintStream out,String[] tokenNames, SourceBuffer sourceBuffer) {
+        this.tokenNames = tokenNames;
+        this.out = out;
+        this.sourceBuffer = sourceBuffer;
+    }
+    public void setUp() {
+        depth = 0;
+        out.println("<map version='0.7.1'><node TEXT='AST'>");
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            depth++;
+            String name = getName(t);
+            String colour = getColour(t);
+            String folded = getFolded(t);
+            out.print("<node TEXT='" + name + "' POSITION='right'" + colour + folded + ">");
+        } else if (visit == CLOSING_VISIT) {
+            out.println("</node>");
+            depth--;
+        }
+    }
+
+    public void tearDown() {
+        out.println("</node></map>");
+    }
+
+    private String getFolded(GroovySourceAST t) {
+        if (depth > 2 && t.getNumberOfChildren() > 0) {
+            switch (t.getType()) {
+                case GroovyTokenTypes.EXPR :
+                case GroovyTokenTypes.METHOD_DEF :
+                case GroovyTokenTypes.VARIABLE_DEF :
+                    return " FOLDED='true'";
+            }
+        }
+        if (t.getType() == GroovyTokenTypes.IMPORT) {
+            return " FOLDED='true'";
+        }
+        return "";
+    }
+
+    private static String getColour(GroovySourceAST t) {
+        String colour = "";
+        String black = " COLOR=\"#000000\"";
+        String cyan = " COLOR=\"#006699\"";
+        String blue = " COLOR=\"#17178B\"";
+        String green = " COLOR=\"#008000\"";
+        switch (t.getType()) {
+            case GroovyTokenTypes.ABSTRACT                      :
+            case GroovyTokenTypes.ANNOTATION                    :
+            case GroovyTokenTypes.ANNOTATIONS                   :
+            case GroovyTokenTypes.ANNOTATION_ARRAY_INIT         :
+            case GroovyTokenTypes.ANNOTATION_DEF                :
+            case GroovyTokenTypes.ANNOTATION_FIELD_DEF          :
+            case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR  :
+            case GroovyTokenTypes.ARRAY_DECLARATOR              :
+            case GroovyTokenTypes.ASSIGN                        :
+            case GroovyTokenTypes.AT                            :
+            case GroovyTokenTypes.BAND                          :
+            case GroovyTokenTypes.BAND_ASSIGN                   :
+            case GroovyTokenTypes.BIG_SUFFIX                    :
+            case GroovyTokenTypes.BLOCK                         :
+            case GroovyTokenTypes.BNOT                          :
+            case GroovyTokenTypes.BOR                           :
+            case GroovyTokenTypes.BOR_ASSIGN                    :
+            case GroovyTokenTypes.BSR                           :
+            case GroovyTokenTypes.BSR_ASSIGN                    :
+            case GroovyTokenTypes.BXOR                          :
+            case GroovyTokenTypes.BXOR_ASSIGN                   :
+            case GroovyTokenTypes.CASE_GROUP                    :
+            case GroovyTokenTypes.CLOSABLE_BLOCK                :
+            case GroovyTokenTypes.CLOSABLE_BLOCK_OP             :
+            case GroovyTokenTypes.COLON                         :
+            case GroovyTokenTypes.COMMA                         :
+            case GroovyTokenTypes.COMPARE_TO                    :
+            case GroovyTokenTypes.CTOR_CALL                     :
+            case GroovyTokenTypes.CTOR_IDENT                    :
+            case GroovyTokenTypes.DEC                           :
+            case GroovyTokenTypes.DIGIT                         :
+            case GroovyTokenTypes.DIV                           :
+            case GroovyTokenTypes.DIV_ASSIGN                    :
+            case GroovyTokenTypes.DOLLAR                        :
+            case GroovyTokenTypes.DOT                           :
+            case GroovyTokenTypes.DYNAMIC_MEMBER                :
+            case GroovyTokenTypes.ELIST                         :
+            case GroovyTokenTypes.EMPTY_STAT                    :
+            case GroovyTokenTypes.ENUM_CONSTANT_DEF             :
+            case GroovyTokenTypes.ENUM_DEF                      :
+            case GroovyTokenTypes.EOF                           :
+            case GroovyTokenTypes.EQUAL                         :
+            case GroovyTokenTypes.ESC                           :
+            case GroovyTokenTypes.EXPONENT                      :
+            case GroovyTokenTypes.EXPR                          :
+            case GroovyTokenTypes.FINAL                         :
+            case GroovyTokenTypes.FLOAT_SUFFIX                  :
+            case GroovyTokenTypes.FOR_CONDITION                 :
+            case GroovyTokenTypes.FOR_EACH_CLAUSE               :
+            case GroovyTokenTypes.FOR_INIT                      :
+            case GroovyTokenTypes.FOR_IN_ITERABLE               :
+            case GroovyTokenTypes.FOR_ITERATOR                  :
+            case GroovyTokenTypes.GE                            :
+            case GroovyTokenTypes.GT                            :
+            case GroovyTokenTypes.HEX_DIGIT                     :
+            case GroovyTokenTypes.IMPLICIT_PARAMETERS           :
+            case GroovyTokenTypes.INC                           :
+            case GroovyTokenTypes.INDEX_OP                      :
+            case GroovyTokenTypes.INSTANCE_INIT                 :
+            case GroovyTokenTypes.INTERFACE_DEF                 :
+            case GroovyTokenTypes.LABELED_ARG                   :
+            case GroovyTokenTypes.LABELED_STAT                  :
+            case GroovyTokenTypes.LAND                          :
+            case GroovyTokenTypes.LBRACK                        :
+            case GroovyTokenTypes.LCURLY                        :
+            case GroovyTokenTypes.LE                            :
+            case GroovyTokenTypes.LETTER                        :
+            case GroovyTokenTypes.LIST_CONSTRUCTOR              :
+            case GroovyTokenTypes.LNOT                          :
+            case GroovyTokenTypes.LOR                           :
+            case GroovyTokenTypes.LPAREN                        :
+            case GroovyTokenTypes.LT                            :
+            case GroovyTokenTypes.MAP_CONSTRUCTOR               :
+            case GroovyTokenTypes.MEMBER_POINTER                :
+            case GroovyTokenTypes.METHOD_CALL                   :
+            case GroovyTokenTypes.METHOD_DEF                    :
+            case GroovyTokenTypes.MINUS                         :
+            case GroovyTokenTypes.MINUS_ASSIGN                  :
+            case GroovyTokenTypes.ML_COMMENT                    :
+            case GroovyTokenTypes.MOD                           :
+            case GroovyTokenTypes.MODIFIERS                     :
+            case GroovyTokenTypes.MOD_ASSIGN                    :
+            case GroovyTokenTypes.NLS                           :
+            case GroovyTokenTypes.NOT_EQUAL                     :
+            case GroovyTokenTypes.NULL_TREE_LOOKAHEAD           :
+            case GroovyTokenTypes.NUM_BIG_DECIMAL               :
+            case GroovyTokenTypes.NUM_BIG_INT                   :
+            case GroovyTokenTypes.NUM_DOUBLE                    :
+            case GroovyTokenTypes.NUM_FLOAT                     :
+            case GroovyTokenTypes.NUM_INT                       :
+            case GroovyTokenTypes.NUM_LONG                      :
+            case GroovyTokenTypes.OBJBLOCK                      :
+            case GroovyTokenTypes.ONE_NL                        :
+            case GroovyTokenTypes.OPTIONAL_DOT                  :
+            case GroovyTokenTypes.PARAMETERS                    :
+            case GroovyTokenTypes.PARAMETER_DEF                 :
+            case GroovyTokenTypes.PLUS                          :
+            case GroovyTokenTypes.PLUS_ASSIGN                   :
+            case GroovyTokenTypes.POST_DEC                      :
+            case GroovyTokenTypes.POST_INC                      :
+            case GroovyTokenTypes.QUESTION                      :
+            case GroovyTokenTypes.RANGE_EXCLUSIVE               :
+            case GroovyTokenTypes.RANGE_INCLUSIVE               :
+            case GroovyTokenTypes.RBRACK                        :
+            case GroovyTokenTypes.RCURLY                        :
+            case GroovyTokenTypes.REGEXP_CTOR_END               :
+            case GroovyTokenTypes.REGEXP_SYMBOL                 :
+            case GroovyTokenTypes.REGEX_FIND                    :
+            case GroovyTokenTypes.REGEX_MATCH                   :
+            case GroovyTokenTypes.RPAREN                        :
+            case GroovyTokenTypes.SELECT_SLOT                   :
+            case GroovyTokenTypes.SEMI                          :
+            case GroovyTokenTypes.SH_COMMENT                    :
+            case GroovyTokenTypes.SL                            :
+            case GroovyTokenTypes.SLIST                         :
+            case GroovyTokenTypes.SL_ASSIGN                     :
+            case GroovyTokenTypes.SL_COMMENT                    :
+            case GroovyTokenTypes.SPREAD_ARG                    :
+            case GroovyTokenTypes.SPREAD_DOT                    :
+            case GroovyTokenTypes.SPREAD_MAP_ARG                :
+            case GroovyTokenTypes.SR                            :
+            case GroovyTokenTypes.SR_ASSIGN                     :
+            case GroovyTokenTypes.STAR                          :
+            case GroovyTokenTypes.STAR_ASSIGN                   :
+            case GroovyTokenTypes.STAR_STAR                     :
+            case GroovyTokenTypes.STAR_STAR_ASSIGN              :
+            case GroovyTokenTypes.STATIC_IMPORT                 :
+            case GroovyTokenTypes.STATIC_INIT                   :
+            case GroovyTokenTypes.STRICTFP                      :
+            case GroovyTokenTypes.STRING_CH                     :
+            case GroovyTokenTypes.STRING_CONSTRUCTOR            :
+            case GroovyTokenTypes.STRING_CTOR_END               :
+            case GroovyTokenTypes.STRING_CTOR_MIDDLE            :
+            case GroovyTokenTypes.STRING_CTOR_START             :
+            case GroovyTokenTypes.STRING_NL                     :
+            case GroovyTokenTypes.SUPER_CTOR_CALL               :
+            case GroovyTokenTypes.TRIPLE_DOT                    :
+            case GroovyTokenTypes.TYPECAST                      :
+            case GroovyTokenTypes.TYPE_ARGUMENT                 :
+            case GroovyTokenTypes.TYPE_ARGUMENTS                :
+            case GroovyTokenTypes.TYPE_LOWER_BOUNDS             :
+            case GroovyTokenTypes.TYPE_PARAMETER                :
+            case GroovyTokenTypes.TYPE_PARAMETERS               :
+            case GroovyTokenTypes.TYPE_UPPER_BOUNDS             :
+            case GroovyTokenTypes.UNARY_MINUS                   :
+            case GroovyTokenTypes.UNARY_PLUS                    :
+            case GroovyTokenTypes.UNUSED_CONST                  :
+            case GroovyTokenTypes.UNUSED_DO                     :
+            case GroovyTokenTypes.UNUSED_GOTO                   :
+            case GroovyTokenTypes.VARIABLE_DEF                  :
+            case GroovyTokenTypes.VARIABLE_PARAMETER_DEF        :
+            case GroovyTokenTypes.VOCAB                         :
+            case GroovyTokenTypes.WILDCARD_TYPE                 :
+            case GroovyTokenTypes.WS                            :
+                colour = black;
+                break;
+
+            case GroovyTokenTypes.STRING_LITERAL                :
+            case GroovyTokenTypes.REGEXP_LITERAL                :
+            case GroovyTokenTypes.DOLLAR_REGEXP_LITERAL         :
+                colour = green;
+                break;
+
+            case GroovyTokenTypes.CLASS_DEF                     :
+            case GroovyTokenTypes.EXTENDS_CLAUSE                :
+            case GroovyTokenTypes.IMPLEMENTS_CLAUSE             :
+            case GroovyTokenTypes.IMPORT                        :
+            case GroovyTokenTypes.LITERAL_as                    :
+            case GroovyTokenTypes.LITERAL_assert                :
+            case GroovyTokenTypes.LITERAL_boolean               :
+            case GroovyTokenTypes.LITERAL_break                 :
+            case GroovyTokenTypes.LITERAL_byte                  :
+            case GroovyTokenTypes.LITERAL_case                  :
+            case GroovyTokenTypes.LITERAL_catch                 :
+            case GroovyTokenTypes.LITERAL_char                  :
+            case GroovyTokenTypes.LITERAL_class                 :
+            case GroovyTokenTypes.LITERAL_continue              :
+            case GroovyTokenTypes.LITERAL_def                   :
+            case GroovyTokenTypes.LITERAL_default               :
+            case GroovyTokenTypes.LITERAL_double                :
+            case GroovyTokenTypes.LITERAL_else                  :
+            case GroovyTokenTypes.LITERAL_enum                  :
+            case GroovyTokenTypes.LITERAL_extends               :
+            case GroovyTokenTypes.LITERAL_false                 :
+            case GroovyTokenTypes.LITERAL_finally               :
+            case GroovyTokenTypes.LITERAL_float                 :
+            case GroovyTokenTypes.LITERAL_for                   :
+            case GroovyTokenTypes.LITERAL_if                    :
+            case GroovyTokenTypes.LITERAL_implements            :
+            case GroovyTokenTypes.LITERAL_import                :
+            case GroovyTokenTypes.LITERAL_in                    :
+            case GroovyTokenTypes.LITERAL_instanceof            :
+            case GroovyTokenTypes.LITERAL_int                   :
+            case GroovyTokenTypes.LITERAL_interface             :
+            case GroovyTokenTypes.LITERAL_long                  :
+            case GroovyTokenTypes.LITERAL_native                :
+            case GroovyTokenTypes.LITERAL_new                   :
+            case GroovyTokenTypes.LITERAL_null                  :
+            case GroovyTokenTypes.LITERAL_package               :
+            case GroovyTokenTypes.LITERAL_private               :
+            case GroovyTokenTypes.LITERAL_protected             :
+            case GroovyTokenTypes.LITERAL_public                :
+            case GroovyTokenTypes.LITERAL_return                :
+            case GroovyTokenTypes.LITERAL_short                 :
+            case GroovyTokenTypes.LITERAL_static                :
+            case GroovyTokenTypes.LITERAL_super                 :
+            case GroovyTokenTypes.LITERAL_switch                :
+            case GroovyTokenTypes.LITERAL_synchronized          :
+            case GroovyTokenTypes.LITERAL_this                  :
+            case GroovyTokenTypes.LITERAL_threadsafe            :
+            case GroovyTokenTypes.LITERAL_throw                 :
+            case GroovyTokenTypes.LITERAL_throws                :
+            case GroovyTokenTypes.LITERAL_transient             :
+            case GroovyTokenTypes.LITERAL_true                  :
+            case GroovyTokenTypes.LITERAL_try                   :
+            case GroovyTokenTypes.LITERAL_void                  :
+            case GroovyTokenTypes.LITERAL_volatile              :
+            case GroovyTokenTypes.LITERAL_while                 :
+            case GroovyTokenTypes.PACKAGE_DEF                   :
+            case GroovyTokenTypes.TYPE                          :
+                colour = blue;
+                break;
+
+            case GroovyTokenTypes.IDENT                         :
+                colour = cyan;
+                break;
+
+            default:
+                colour = black;
+                break;
+        }
+
+        // leaf nodes that haven't been coloured yet
+        if (black.equals(colour) && t.getNumberOfChildren() == 0) {
+            colour = cyan;
+        }
+
+
+
+        return colour;
+    }
+
+    private String getName(GroovySourceAST t) {
+        String name = tokenNames[t.getType()] + " <" + t.getType() + ">";
+        if (!(escape(tokenNames[t.getType()]).equals(escape(t.getText())))) {
+            name = name + " : " + t.getText();
+        }
+        switch (t.getType()) {
+            case GroovyTokenTypes.METHOD_DEF :
+            case GroovyTokenTypes.VARIABLE_DEF :
+                GroovySourceAST identNode = t.childOfType(GroovyTokenTypes.IDENT);
+                if (identNode != null) {
+                    name = name + " : " + identNode.getText() + "";
+                }
+        }
+        name = escape(name);
+        if (sourceBuffer != null) {
+            name += "&#xa;";
+            name += t.getLine() + "," + t.getColumn() + " - " + t.getLineLast() + "," + t.getColumnLast();
+            name += "&#xa;";
+            name += escape(sourceBuffer.getSnippet(new LineColumn(t.getLine(), t.getColumn()), new LineColumn(t.getLineLast(), t.getColumnLast())));
+        }
+        return name;
+    }
+
+    private static String escape(String name) {
+        if (name == null) return null;
+        // remove middle of large bits of text
+        if (name.length() > 200) {
+            name = name.substring(0,100) + " ..... " + name.substring(name.length() - 100);
+        }
+        name = name.replace('"',' ');
+        name = name.replace('\'',' ');
+        name = name.replaceAll("&","&amp;");
+        name = name.replaceAll("<","&lt;");
+        name = name.replaceAll(">","&gt;");
+        name = name.trim();
+        return name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java
new file mode 100644
index 0000000..d9e985f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeAsHTMLPrinter.java
@@ -0,0 +1,319 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+import java.io.PrintStream;
+import java.util.Stack;
+
+/**
+ * A visitor that prints a html tags of each node to the supplied PrintStream
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public class NodeAsHTMLPrinter extends VisitorAdapter {
+    private final String[] tokenNames;
+    private final PrintStream out;
+    private final Stack stack;
+
+    /**
+     * A visitor that prints a html tags, for each node, to the supplied PrintStream.
+     * @param out supplied PrintStream to output nodes to
+     * @param tokenNames an array of token names to use
+     */
+    public NodeAsHTMLPrinter(PrintStream out,String[] tokenNames) {
+        this.tokenNames = tokenNames;
+        this.out = out;
+        this.stack = new Stack();
+    }
+
+    public void setUp() {
+        out.println("<html><head></head><body><pre>");
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            out.print("<code title=" + quote(tokenNames[t.getType()]) + "><font color='#" + colour(t) + "'>");
+        } else if (visit == CLOSING_VISIT) {
+            out.print("</font></code>");
+        }
+    }
+
+    private static String quote(String tokenName) {
+        if (tokenName.length() > 0 && tokenName.charAt(0) != '\'')
+            return "'" + tokenName + "'";
+        else
+            return "\"" + tokenName + "\"";
+    }
+
+    public void tearDown() {
+        out.println("</pre></body></html>");
+    }
+
+    private static String colour(GroovySourceAST t) {
+        String black = "000000";
+        String blue = "17178B";
+        String green = "008000";
+        //String purple = "7C308D";
+        String colour = black;
+        switch (t.getType()) {
+            case GroovyTokenTypes.ABSTRACT                      :
+            case GroovyTokenTypes.ANNOTATION                    :
+            case GroovyTokenTypes.ANNOTATIONS                   :
+            case GroovyTokenTypes.ANNOTATION_ARRAY_INIT         :
+            case GroovyTokenTypes.ANNOTATION_DEF                :
+            case GroovyTokenTypes.ANNOTATION_FIELD_DEF          :
+            case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR  :
+            case GroovyTokenTypes.ARRAY_DECLARATOR              :
+            case GroovyTokenTypes.ASSIGN                        :
+            case GroovyTokenTypes.AT                            :
+            case GroovyTokenTypes.BAND                          :
+            case GroovyTokenTypes.BAND_ASSIGN                   :
+            case GroovyTokenTypes.BIG_SUFFIX                    :
+            case GroovyTokenTypes.BLOCK                         :
+            case GroovyTokenTypes.BNOT                          :
+            case GroovyTokenTypes.BOR                           :
+            case GroovyTokenTypes.BOR_ASSIGN                    :
+            case GroovyTokenTypes.BSR                           :
+            case GroovyTokenTypes.BSR_ASSIGN                    :
+            case GroovyTokenTypes.BXOR                          :
+            case GroovyTokenTypes.BXOR_ASSIGN                   :
+            case GroovyTokenTypes.CASE_GROUP                    :
+            case GroovyTokenTypes.CLOSABLE_BLOCK                :
+            case GroovyTokenTypes.CLOSABLE_BLOCK_OP             :
+            case GroovyTokenTypes.COLON                         :
+            case GroovyTokenTypes.COMMA                         :
+            case GroovyTokenTypes.COMPARE_TO                    :
+            case GroovyTokenTypes.CTOR_CALL                     :
+            case GroovyTokenTypes.CTOR_IDENT                    :
+            case GroovyTokenTypes.DEC                           :
+            case GroovyTokenTypes.DIGIT                         :
+            case GroovyTokenTypes.DIV                           :
+            case GroovyTokenTypes.DIV_ASSIGN                    :
+            case GroovyTokenTypes.DOLLAR                        :
+            case GroovyTokenTypes.DOT                           :
+            case GroovyTokenTypes.DYNAMIC_MEMBER                :
+            case GroovyTokenTypes.ELIST                         :
+            case GroovyTokenTypes.EMPTY_STAT                    :
+            case GroovyTokenTypes.ENUM_CONSTANT_DEF             :
+            case GroovyTokenTypes.ENUM_DEF                      :
+            case GroovyTokenTypes.EOF                           :
+            case GroovyTokenTypes.EQUAL                         :
+            case GroovyTokenTypes.ESC                           :
+            case GroovyTokenTypes.EXPONENT                      :
+            case GroovyTokenTypes.EXPR                          :
+            case GroovyTokenTypes.FINAL                         :
+            case GroovyTokenTypes.FLOAT_SUFFIX                  :
+            case GroovyTokenTypes.FOR_CONDITION                 :
+            case GroovyTokenTypes.FOR_EACH_CLAUSE               :
+            case GroovyTokenTypes.FOR_INIT                      :
+            case GroovyTokenTypes.FOR_IN_ITERABLE               :
+            case GroovyTokenTypes.FOR_ITERATOR                  :
+            case GroovyTokenTypes.GE                            :
+            case GroovyTokenTypes.GT                            :
+            case GroovyTokenTypes.HEX_DIGIT                     :
+            case GroovyTokenTypes.IDENT                         :
+            case GroovyTokenTypes.IMPLICIT_PARAMETERS           :
+            case GroovyTokenTypes.INC                           :
+            case GroovyTokenTypes.INDEX_OP                      :
+            case GroovyTokenTypes.INSTANCE_INIT                 :
+            case GroovyTokenTypes.INTERFACE_DEF                 :
+            case GroovyTokenTypes.LABELED_ARG                   :
+            case GroovyTokenTypes.LABELED_STAT                  :
+            case GroovyTokenTypes.LAND                          :
+            case GroovyTokenTypes.LBRACK                        :
+            case GroovyTokenTypes.LCURLY                        :
+            case GroovyTokenTypes.LE                            :
+            case GroovyTokenTypes.LETTER                        :
+            case GroovyTokenTypes.LIST_CONSTRUCTOR              :
+            case GroovyTokenTypes.LNOT                          :
+            case GroovyTokenTypes.LOR                           :
+            case GroovyTokenTypes.LPAREN                        :
+            case GroovyTokenTypes.LT                            :
+            case GroovyTokenTypes.MAP_CONSTRUCTOR               :
+            case GroovyTokenTypes.MEMBER_POINTER                :
+            case GroovyTokenTypes.METHOD_CALL                   :
+            case GroovyTokenTypes.METHOD_DEF                    :
+            case GroovyTokenTypes.MINUS                         :
+            case GroovyTokenTypes.MINUS_ASSIGN                  :
+            case GroovyTokenTypes.ML_COMMENT                    :
+            case GroovyTokenTypes.MOD                           :
+            case GroovyTokenTypes.MODIFIERS                     :
+            case GroovyTokenTypes.MOD_ASSIGN                    :
+            case GroovyTokenTypes.NLS                           :
+            case GroovyTokenTypes.NOT_EQUAL                     :
+            case GroovyTokenTypes.NULL_TREE_LOOKAHEAD           :
+            case GroovyTokenTypes.NUM_BIG_DECIMAL               :
+            case GroovyTokenTypes.NUM_BIG_INT                   :
+            case GroovyTokenTypes.NUM_DOUBLE                    :
+            case GroovyTokenTypes.NUM_FLOAT                     :
+            case GroovyTokenTypes.NUM_INT                       :
+            case GroovyTokenTypes.NUM_LONG                      :
+            case GroovyTokenTypes.OBJBLOCK                      :
+            case GroovyTokenTypes.ONE_NL                        :
+            case GroovyTokenTypes.OPTIONAL_DOT                  :
+            case GroovyTokenTypes.PARAMETERS                    :
+            case GroovyTokenTypes.PARAMETER_DEF                 :
+            case GroovyTokenTypes.PLUS                          :
+            case GroovyTokenTypes.PLUS_ASSIGN                   :
+            case GroovyTokenTypes.POST_DEC                      :
+            case GroovyTokenTypes.POST_INC                      :
+            case GroovyTokenTypes.QUESTION                      :
+            case GroovyTokenTypes.RANGE_EXCLUSIVE               :
+            case GroovyTokenTypes.RANGE_INCLUSIVE               :
+            case GroovyTokenTypes.RBRACK                        :
+            case GroovyTokenTypes.RCURLY                        :
+            case GroovyTokenTypes.REGEXP_CTOR_END               :
+            case GroovyTokenTypes.REGEXP_SYMBOL                 :
+            case GroovyTokenTypes.REGEX_FIND                    :
+            case GroovyTokenTypes.REGEX_MATCH                   :
+            case GroovyTokenTypes.RPAREN                        :
+            case GroovyTokenTypes.SELECT_SLOT                   :
+            case GroovyTokenTypes.SEMI                          :
+            case GroovyTokenTypes.SH_COMMENT                    :
+            case GroovyTokenTypes.SL                            :
+            case GroovyTokenTypes.SLIST                         :
+            case GroovyTokenTypes.SL_ASSIGN                     :
+            case GroovyTokenTypes.SL_COMMENT                    :
+            case GroovyTokenTypes.SPREAD_ARG                    :
+            case GroovyTokenTypes.SPREAD_DOT                    :
+            case GroovyTokenTypes.SPREAD_MAP_ARG                :
+            case GroovyTokenTypes.SR                            :
+            case GroovyTokenTypes.SR_ASSIGN                     :
+            case GroovyTokenTypes.STAR                          :
+            case GroovyTokenTypes.STAR_ASSIGN                   :
+            case GroovyTokenTypes.STAR_STAR                     :
+            case GroovyTokenTypes.STAR_STAR_ASSIGN              :
+            case GroovyTokenTypes.STATIC_IMPORT                 :
+            case GroovyTokenTypes.STATIC_INIT                   :
+            case GroovyTokenTypes.STRICTFP                      :
+            case GroovyTokenTypes.STRING_CH                     :
+            case GroovyTokenTypes.STRING_CONSTRUCTOR            :
+            case GroovyTokenTypes.STRING_CTOR_END               :
+            case GroovyTokenTypes.STRING_CTOR_MIDDLE            :
+            case GroovyTokenTypes.STRING_CTOR_START             :
+            case GroovyTokenTypes.STRING_NL                     :
+            case GroovyTokenTypes.SUPER_CTOR_CALL               :
+            case GroovyTokenTypes.TRIPLE_DOT                    :
+            case GroovyTokenTypes.TYPECAST                      :
+            case GroovyTokenTypes.TYPE_ARGUMENT                 :
+            case GroovyTokenTypes.TYPE_ARGUMENTS                :
+            case GroovyTokenTypes.TYPE_LOWER_BOUNDS             :
+            case GroovyTokenTypes.TYPE_PARAMETER                :
+            case GroovyTokenTypes.TYPE_PARAMETERS               :
+            case GroovyTokenTypes.TYPE_UPPER_BOUNDS             :
+            case GroovyTokenTypes.UNARY_MINUS                   :
+            case GroovyTokenTypes.UNARY_PLUS                    :
+            case GroovyTokenTypes.UNUSED_CONST                  :
+            case GroovyTokenTypes.UNUSED_DO                     :
+            case GroovyTokenTypes.UNUSED_GOTO                   :
+            case GroovyTokenTypes.VARIABLE_DEF                  :
+            case GroovyTokenTypes.VARIABLE_PARAMETER_DEF        :
+            case GroovyTokenTypes.VOCAB                         :
+            case GroovyTokenTypes.WILDCARD_TYPE                 :
+            case GroovyTokenTypes.WS                            :
+                colour = black;
+                break;
+
+            case GroovyTokenTypes.STRING_LITERAL                :
+            case GroovyTokenTypes.REGEXP_LITERAL                :
+            case GroovyTokenTypes.DOLLAR_REGEXP_LITERAL         :
+                colour = green;
+                break;
+
+            case GroovyTokenTypes.CLASS_DEF                     :
+            case GroovyTokenTypes.EXTENDS_CLAUSE                :
+            case GroovyTokenTypes.IMPLEMENTS_CLAUSE             :
+            case GroovyTokenTypes.IMPORT                        :
+            case GroovyTokenTypes.LITERAL_as                    :
+            case GroovyTokenTypes.LITERAL_assert                :
+            case GroovyTokenTypes.LITERAL_boolean               :
+            case GroovyTokenTypes.LITERAL_break                 :
+            case GroovyTokenTypes.LITERAL_byte                  :
+            case GroovyTokenTypes.LITERAL_case                  :
+            case GroovyTokenTypes.LITERAL_catch                 :
+            case GroovyTokenTypes.LITERAL_char                  :
+            case GroovyTokenTypes.LITERAL_class                 :
+            case GroovyTokenTypes.LITERAL_continue              :
+            case GroovyTokenTypes.LITERAL_def                   :
+            case GroovyTokenTypes.LITERAL_default               :
+            case GroovyTokenTypes.LITERAL_double                :
+            case GroovyTokenTypes.LITERAL_else                  :
+            case GroovyTokenTypes.LITERAL_enum                  :
+            case GroovyTokenTypes.LITERAL_extends               :
+            case GroovyTokenTypes.LITERAL_false                 :
+            case GroovyTokenTypes.LITERAL_finally               :
+            case GroovyTokenTypes.LITERAL_float                 :
+            case GroovyTokenTypes.LITERAL_for                   :
+            case GroovyTokenTypes.LITERAL_if                    :
+            case GroovyTokenTypes.LITERAL_implements            :
+            case GroovyTokenTypes.LITERAL_import                :
+            case GroovyTokenTypes.LITERAL_in                    :
+            case GroovyTokenTypes.LITERAL_instanceof            :
+            case GroovyTokenTypes.LITERAL_int                   :
+            case GroovyTokenTypes.LITERAL_interface             :
+            case GroovyTokenTypes.LITERAL_long                  :
+            case GroovyTokenTypes.LITERAL_native                :
+            case GroovyTokenTypes.LITERAL_new                   :
+            case GroovyTokenTypes.LITERAL_null                  :
+            case GroovyTokenTypes.LITERAL_package               :
+            case GroovyTokenTypes.LITERAL_private               :
+            case GroovyTokenTypes.LITERAL_protected             :
+            case GroovyTokenTypes.LITERAL_public                :
+            case GroovyTokenTypes.LITERAL_return                :
+            case GroovyTokenTypes.LITERAL_short                 :
+            case GroovyTokenTypes.LITERAL_static                :
+            case GroovyTokenTypes.LITERAL_super                 :
+            case GroovyTokenTypes.LITERAL_switch                :
+            case GroovyTokenTypes.LITERAL_synchronized          :
+            case GroovyTokenTypes.LITERAL_this                  :
+            case GroovyTokenTypes.LITERAL_threadsafe            :
+            case GroovyTokenTypes.LITERAL_throw                 :
+            case GroovyTokenTypes.LITERAL_throws                :
+            case GroovyTokenTypes.LITERAL_transient             :
+            case GroovyTokenTypes.LITERAL_true                  :
+            case GroovyTokenTypes.LITERAL_try                   :
+            case GroovyTokenTypes.LITERAL_void                  :
+            case GroovyTokenTypes.LITERAL_volatile              :
+            case GroovyTokenTypes.LITERAL_while                 :
+            case GroovyTokenTypes.PACKAGE_DEF                   :
+            case GroovyTokenTypes.TYPE                          :
+                colour = blue;
+                break;
+
+            default:
+                colour = black;
+                break;
+        }
+        return colour;
+    }
+
+    public void push(GroovySourceAST t) {
+        stack.push(t);
+    }
+    public GroovySourceAST pop() {
+        if (!stack.empty()) {
+            return (GroovySourceAST) stack.pop();
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeCollector.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeCollector.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeCollector.java
new file mode 100644
index 0000000..5c9659b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/NodeCollector.java
@@ -0,0 +1,45 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A simple antlr AST visitor that collects all nodes into a List.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public class NodeCollector extends VisitorAdapter {
+    private final List nodes;
+    public NodeCollector() {
+        nodes = new ArrayList();
+    }
+    public List getNodes() {
+        return nodes;
+    }
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            nodes.add(t);
+        }
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/EmptyExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/EmptyExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/EmptyExpression.java
new file mode 100644
index 0000000..d1a3596
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/EmptyExpression.java
@@ -0,0 +1,140 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.NodeMetaDataHandler;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is a place holder for an empty expression. 
+ * Empty expression are used in closures lists like (;). During
+ * class Generation this expression should be either ignored or
+ * replace with a null value.
+ *   
+ * @author Jochen Theodorou
+ * @see org.codehaus.groovy.ast.stmt.EmptyStatement
+ */
+public class EmptyExpression extends Expression {
+    public static final EmptyExpression INSTANCE = new EmptyExpression();
+
+    /**
+     * use EmptyExpression.INSTANCE instead
+     */
+    @Deprecated
+    public EmptyExpression() {}
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        return;
+    }
+
+
+    @Override
+    public void setType(ClassNode t) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void addAnnotation(AnnotationNode value) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setSynthetic(boolean synthetic) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setDeclaringClass(ClassNode declaringClass) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setHasNoRealSourcePosition(boolean value) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setLineNumber(int lineNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setColumnNumber(int columnNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setLastLineNumber(int lastLineNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setLastColumnNumber(int lastColumnNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setSourcePosition(ASTNode node) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void copyNodeMetaData(NodeMetaDataHandler other) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setNodeMetaData(Object key, Object value) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public Object putNodeMetaData(Object key, Object value) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void removeNodeMetaData(Object key) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setMetaDataMap(Map<?, ?> metaDataMap) {
+        throw createUnsupportedOperationException();
+    }
+
+    private UnsupportedOperationException createUnsupportedOperationException() {
+        return new UnsupportedOperationException("EmptyExpression.INSTANCE is immutable");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/Expression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/Expression.java b/src/main/java/org/codehaus/groovy/ast/expr/Expression.java
new file mode 100644
index 0000000..f9991d2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/Expression.java
@@ -0,0 +1,81 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a base class for expressions which evaluate as an object
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public abstract class Expression extends AnnotatedNode {
+    public static final Expression[] EMPTY_ARRAY = new Expression[0];
+    private ClassNode type=ClassHelper.DYNAMIC_TYPE;
+    
+    /**
+     * Return a copy of the expression calling the transformer on any nested expressions 
+     * @param transformer
+     */
+    public abstract Expression transformExpression(ExpressionTransformer transformer);
+
+    /**
+     * Transforms the list of expressions
+     * @return a new list of transformed expressions
+     */
+    protected List<Expression> transformExpressions(List<? extends Expression> expressions, ExpressionTransformer transformer) {
+        List<Expression> list = new ArrayList<Expression>(expressions.size());
+        for (Expression expr : expressions ) {
+            list.add(transformer.transform(expr));
+        }
+        return list;
+    }
+
+    /**
+     * Transforms the list of expressions, and checks that all transformed expressions have the given type.
+     *
+     * @return a new list of transformed expressions
+     */
+    protected <T extends Expression> List<T> transformExpressions(List<? extends Expression> expressions,
+            ExpressionTransformer transformer, Class<T> transformedType) {
+        List<T> list = new ArrayList<T>(expressions.size());
+        for (Expression expr : expressions) {
+            Expression transformed = transformer.transform(expr);
+            if (!transformedType.isInstance(transformed))
+                throw new GroovyBugError(String.format("Transformed expression should have type %s but has type %s",
+                    transformedType, transformed.getClass()));
+            list.add(transformedType.cast(transformed));
+        }
+        return list;
+    }
+    
+    public ClassNode getType() {
+        return type;
+    }
+    
+    public void setType(ClassNode t) {
+        type=t;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ExpressionTransformer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ExpressionTransformer.java b/src/main/java/org/codehaus/groovy/ast/expr/ExpressionTransformer.java
new file mode 100644
index 0000000..459ed43
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ExpressionTransformer.java
@@ -0,0 +1,33 @@
+/*
+ *  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.expr;
+
+
+/**
+ * Provides a way to transform expressions
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public interface ExpressionTransformer {
+    
+    /** 
+     * Transforms the given expression into another expression
+     */
+    Expression transform(Expression expression);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/FieldExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/FieldExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/FieldExpression.java
new file mode 100644
index 0000000..41b5acf
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/FieldExpression.java
@@ -0,0 +1,83 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a field access such as the expression "this.foo".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class FieldExpression extends Expression {
+
+    private final FieldNode field;
+    private boolean useRef;
+    
+    public FieldExpression(FieldNode field) {
+        this.field = field;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitFieldExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+    
+    public String getFieldName() {
+        return field.getName();
+    }
+
+    public FieldNode getField() {
+        return field;
+    }
+
+    public String getText() {
+        return "this." + field.getName();
+    }
+
+    public boolean isDynamicTyped() {
+        return field.isDynamicTyped();
+    }
+
+    public void setType(ClassNode type) {
+        super.setType(type);
+        field.setType(type);
+    }
+    
+    public ClassNode getType() {
+        return field.getType();
+    }
+    
+    public void setUseReferenceDirectly(boolean useRef) {
+        this.useRef = useRef;        
+    }
+    
+    public boolean isUseReferenceDirectly() {
+        return useRef;
+    }
+    
+    public String toString() {
+        return "field("+getType()+" "+getFieldName()+")";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/GStringExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/GStringExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/GStringExpression.java
new file mode 100644
index 0000000..7ccf355
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/GStringExpression.java
@@ -0,0 +1,116 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a String expression which contains embedded values inside
+ * it such as "hello there ${user} how are you" which is expanded lazily
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class GStringExpression extends Expression {
+
+    private final String verbatimText;
+    private final List<ConstantExpression> strings;
+    private final List<Expression> values;
+    
+    public GStringExpression(String verbatimText) {
+        this.verbatimText = verbatimText;
+        super.setType(ClassHelper.GSTRING_TYPE);
+        this.strings = new ArrayList<ConstantExpression>();
+        this.values = new ArrayList<Expression>();
+    }
+
+    public GStringExpression(String verbatimText, List<ConstantExpression> strings, List<Expression> values) {
+        this.verbatimText = verbatimText;
+        this.strings = strings;
+        this.values = values;
+        super.setType(ClassHelper.GSTRING_TYPE);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitGStringExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new GStringExpression(
+                verbatimText,
+                transformExpressions(strings, transformer, ConstantExpression.class),
+                transformExpressions(values, transformer));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;        
+    }
+
+    public String toString() {
+        return super.toString() + "[strings: " + strings + " values: " + values + "]";
+    }
+
+    public String getText() {
+        return verbatimText;
+    }
+
+    public List<ConstantExpression> getStrings() {
+        return strings;
+    }
+
+    public List<Expression> getValues() {
+        return values;
+    }
+
+    public void addString(ConstantExpression text) {
+        if (text == null) {
+            throw new NullPointerException("Cannot add a null text expression");
+        }
+        strings.add(text);
+    }
+
+    public void addValue(Expression value) {
+        // If the first thing is an value, then we need a dummy empty string in front of it so that when we
+        // toString it they come out in the correct order.
+        if (strings.isEmpty())
+            strings.add(ConstantExpression.EMPTY_STRING);
+        values.add(value);
+    }
+
+    public Expression getValue(int idx) {
+        return values.get(idx);
+    }
+
+    public boolean isConstantString() {
+        return values.isEmpty();
+    }
+
+    public Expression asConstantString() {
+        StringBuilder buffer = new StringBuilder();
+        for (ConstantExpression expression : strings) {
+            Object value = expression.getValue();
+            if (value != null) {
+                buffer.append(value);
+            }
+        }
+        return new ConstantExpression(buffer.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java
new file mode 100644
index 0000000..f4f1001
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/LambdaExpression.java
@@ -0,0 +1,47 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.AstToTextHelper;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+/**
+ * Represents a lambda expression such as e -> e * 2
+ * or (x, y) -> x + y or (x, y) -> { x + y } or (int x, int y) -> { x + y }
+ *
+ * @author  <a href="mailto:realbluesun@hotmail.com">Daniel.Sun</a>
+ * Created on    2016/10/18
+ */
+public class LambdaExpression extends ClosureExpression {
+    public LambdaExpression(Parameter[] parameters, Statement code) {
+        super(parameters, code);
+    }
+
+    @Override
+    public String getText() {
+        String paramText = AstToTextHelper.getParametersText(this.getParameters());
+        if (paramText.length() > 0) {
+            return "(" + paramText + ") -> { ... }";
+        } else {
+            return "() -> { ... }";
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ListExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ListExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ListExpression.java
new file mode 100644
index 0000000..94ab0d2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ListExpression.java
@@ -0,0 +1,97 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a list expression [1, 2, 3] which creates a mutable List
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ListExpression extends Expression {
+    private final List<Expression> expressions;
+    private boolean wrapped = false;
+
+    public ListExpression() {
+        this(new ArrayList<Expression>());
+    }
+
+    public ListExpression(List<Expression> expressions) {
+        this.expressions = expressions;
+        //TODO: get the type's of the expressions to specify the
+        // list type to List<X> if possible.
+        setType(ClassHelper.LIST_TYPE);
+    }
+
+    public void addExpression(Expression expression) {
+        expressions.add(expression);
+    }
+
+    public List<Expression> getExpressions() {
+        return expressions;
+    }
+
+    public void setWrapped(boolean value) {
+        wrapped = value;
+    }
+
+    public boolean isWrapped() {
+        return wrapped;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitListExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new ListExpression(transformExpressions(getExpressions(), transformer));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public Expression getExpression(int i) {
+        return expressions.get(i);
+    }
+
+    public String getText() {
+        StringBuilder buffer = new StringBuilder("[");
+        boolean first = true;
+        for (Expression expression : expressions) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(", ");
+            }
+
+            buffer.append(expression.getText());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    public String toString() {
+        return super.toString() + expressions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/MapEntryExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/MapEntryExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/MapEntryExpression.java
new file mode 100644
index 0000000..3426fe0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/MapEntryExpression.java
@@ -0,0 +1,68 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents an entry inside a map expression such as 1 : 2.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class MapEntryExpression extends Expression {
+    private Expression keyExpression;
+    private Expression valueExpression;
+
+    public MapEntryExpression(Expression keyExpression, Expression valueExpression) {
+        this.keyExpression = keyExpression;
+        this.valueExpression = valueExpression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMapEntryExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new MapEntryExpression(transformer.transform(keyExpression), transformer.transform(valueExpression));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;        
+    }
+
+    public String toString() {
+        return super.toString() + "(key: " + keyExpression + ", value: " + valueExpression + ")";
+    }
+
+    public Expression getKeyExpression() {
+        return keyExpression;
+    }
+
+    public Expression getValueExpression() {
+        return valueExpression;
+    }
+
+    public void setKeyExpression(Expression keyExpression) {
+        this.keyExpression = keyExpression;
+    }
+
+    public void setValueExpression(Expression valueExpression) {
+        this.valueExpression = valueExpression;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/MapExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/MapExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/MapExpression.java
new file mode 100644
index 0000000..0effc80
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/MapExpression.java
@@ -0,0 +1,100 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a map expression [1 : 2, "a" : "b", x : y] which creates a mutable Map
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class MapExpression extends Expression {
+    private final List<MapEntryExpression> mapEntryExpressions;
+
+    public MapExpression() {
+        this(new ArrayList<MapEntryExpression>());
+    }
+
+    public MapExpression(List<MapEntryExpression> mapEntryExpressions) {
+        this.mapEntryExpressions = mapEntryExpressions;
+        //TODO: get the type's of the expressions to specify the
+        // map type to Map<X> if possible.
+        setType(ClassHelper.MAP_TYPE);
+    }
+
+    public void addMapEntryExpression(MapEntryExpression expression) {
+        mapEntryExpressions.add(expression);
+    }
+
+    public List<MapEntryExpression> getMapEntryExpressions() {
+        return mapEntryExpressions;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMapExpression(this);
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new MapExpression(transformExpressions(getMapEntryExpressions(), transformer, MapEntryExpression.class));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public String toString() {
+        return super.toString() + mapEntryExpressions;
+    }
+
+    public String getText() {
+        StringBuilder sb = new StringBuilder(32);
+        sb.append("[");
+        int size = mapEntryExpressions.size();
+        MapEntryExpression mapEntryExpression = null;
+        if (size > 0) {
+            mapEntryExpression = mapEntryExpressions.get(0);
+            sb.append(mapEntryExpression.getKeyExpression().getText()).append(":").append(mapEntryExpression.getValueExpression().getText());
+            for (int i = 1; i < size; i++) {
+                mapEntryExpression = mapEntryExpressions.get(i);
+                sb.append(", ").append(mapEntryExpression.getKeyExpression().getText()).append(":").append(mapEntryExpression.getValueExpression().getText());
+                if (sb.length() > 120 && i < size - 1) {
+                    sb.append(", ... ");
+                    break;
+                }
+            }
+        } else {
+            sb.append(":");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public void addMapEntryExpression(Expression keyExpression, Expression valueExpression) {
+        addMapEntryExpression(new MapEntryExpression(keyExpression, valueExpression));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/MethodCall.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/MethodCall.java b/src/main/java/org/codehaus/groovy/ast/expr/MethodCall.java
new file mode 100644
index 0000000..e2e889d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/MethodCall.java
@@ -0,0 +1,34 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ASTNode;
+
+/**
+ * Interface defining common methods for method calls.
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+public interface MethodCall {
+    ASTNode getReceiver();
+    String getMethodAsString();
+    Expression getArguments();
+    String getText();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java
new file mode 100644
index 0000000..089d930
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/MethodCallExpression.java
@@ -0,0 +1,214 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.MethodNode;
+
+/**
+ * A method call on an object or class
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class MethodCallExpression extends Expression implements MethodCall {
+
+    private Expression objectExpression;
+    private Expression method;
+    private Expression arguments;
+    private boolean spreadSafe = false;
+    private boolean safe = false;
+    private boolean implicitThis;
+
+    // type spec for generics
+    private GenericsType[] genericsTypes = null;
+    private boolean usesGenerics = false;
+
+    private MethodNode target;
+
+    public static final Expression NO_ARGUMENTS = new TupleExpression();
+
+    public MethodCallExpression(Expression objectExpression, String method, Expression arguments) {
+        this(objectExpression,new ConstantExpression(method),arguments);
+    }
+
+    public MethodCallExpression(Expression objectExpression, Expression method, Expression arguments) {
+        this.objectExpression = objectExpression;
+        this.method = method;
+        if (!(arguments instanceof TupleExpression)){
+            this.arguments = new TupleExpression(arguments);
+        } else {
+            this.arguments = arguments;
+        }
+        //TODO: set correct type here
+        // if setting type and a methodcall is the last expression in a method,
+        // then the method will return null if the method itself is not void too!
+        // (in bytecode after call: aconst_null, areturn)
+        this.setType(ClassHelper.DYNAMIC_TYPE);
+        this.setImplicitThis(true);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMethodCallExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        MethodCallExpression answer =
+            new MethodCallExpression(transformer.transform(objectExpression), transformer.transform(method), transformer.transform(arguments));
+        answer.setSafe(safe);
+        answer.setSpreadSafe(spreadSafe);
+        answer.setImplicitThis(implicitThis);
+        answer.setGenericsTypes(genericsTypes);
+        answer.setSourcePosition(this);
+        answer.setMethodTarget(target);
+        answer.copyNodeMetaData(this);
+        return answer;
+    }
+
+    public Expression getArguments() {
+        return arguments;
+    }
+
+    public void setArguments(Expression arguments) {
+        if (!(arguments instanceof TupleExpression)){
+            this.arguments = new TupleExpression(arguments);
+        } else {
+            this.arguments = arguments;
+        }
+    }
+
+    public Expression getMethod() {
+        return method;
+    }
+
+    public void setMethod(Expression method) {
+      this.method = method;
+    }
+
+    public ASTNode getReceiver() {
+        return getObjectExpression();
+    }
+
+    /**
+     * This method returns the method name as String if it is no dynamic
+     * calculated method name, but a constant.
+     */
+    public String getMethodAsString() {
+        if (! (method instanceof ConstantExpression)) return null;
+        ConstantExpression constant = (ConstantExpression) method;
+        return constant.getText();
+    }
+
+    public void setObjectExpression(Expression objectExpression) {
+      this.objectExpression = objectExpression;
+    }
+
+    public Expression getObjectExpression() {
+        return objectExpression;
+    }
+
+    public String getText() {
+        String object = objectExpression.getText();
+        String meth = method.getText();
+        String args = arguments.getText();
+        String spread = spreadSafe ? "*" : "";
+        String dereference = safe ? "?" : "";
+        return object + spread + dereference + "." + meth + args;
+    }
+
+    /**
+     * @return is this a safe method call, i.e. if true then if the source object is null
+     * then this method call will return null rather than throwing a null pointer exception
+     */
+    public boolean isSafe() {
+        return safe;
+    }
+
+    public void setSafe(boolean safe) {
+        this.safe = safe;
+    }
+
+    public boolean isSpreadSafe() {
+        return spreadSafe;
+    }
+
+    public void setSpreadSafe(boolean value) {
+        spreadSafe = value;
+    }
+
+    /**
+     * @return true if no object expression was specified otherwise if
+     * some expression was specified for the object on which to evaluate
+     * the method then return false
+     */
+    public boolean isImplicitThis() {
+        return implicitThis;
+    }
+
+    public void setImplicitThis(boolean implicitThis) {
+        this.implicitThis = implicitThis;
+    }
+
+    public String toString() {
+        return super.toString()
+            + "[object: "
+            + objectExpression
+            + " method: "
+            + method
+            + " arguments: "
+            + arguments
+            + "]";
+    }
+
+    public GenericsType[] getGenericsTypes() {
+        return genericsTypes;
+    }
+
+    public void setGenericsTypes(GenericsType[] genericsTypes) {
+        usesGenerics = usesGenerics || genericsTypes != null;
+        this.genericsTypes = genericsTypes;
+    }
+
+    public boolean isUsingGenerics() {
+        return usesGenerics;
+    }
+
+    /**
+     * Sets a method call target for a direct method call.
+     * WARNING: A method call made this way will run outside of the MOP!
+     * @param mn the target as MethodNode, mn==null means no target
+     */
+    public void setMethodTarget(MethodNode mn) {
+        this.target = mn;
+        if (mn!=null) {
+            setType(target.getReturnType());
+        } else {
+            setType(ClassHelper.OBJECT_TYPE);
+        }
+    }
+
+    /**
+     * @return the target as method node if set
+     */
+    public MethodNode getMethodTarget() {
+        return target;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/MethodPointerExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/MethodPointerExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/MethodPointerExpression.java
new file mode 100644
index 0000000..f4d2422
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/MethodPointerExpression.java
@@ -0,0 +1,91 @@
+/*
+ *  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.expr;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a method pointer on an object such as
+ * foo.&bar which means find the method pointer on foo for the method called "bar"
+ * which is equivalent to
+ * <code>
+ * foo.metaClass.getMethodPointer(foo, "bar")
+ * </code>
+ */
+public class MethodPointerExpression extends Expression {
+
+    private final Expression expression;
+    private final Expression methodName;
+
+    public MethodPointerExpression(Expression expression, Expression methodName) {
+        this.expression = expression;
+        this.methodName = methodName;
+    }
+
+    public Expression getExpression() {
+        if (expression == null)
+            return VariableExpression.THIS_EXPRESSION;
+        else
+            return expression;
+    }
+
+    public Expression getMethodName() {
+        return methodName;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitMethodPointerExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret;
+        Expression mname = transformer.transform(methodName);
+        if (expression == null) {
+            ret = new MethodPointerExpression(VariableExpression.THIS_EXPRESSION, mname);
+        } else {
+            ret = new MethodPointerExpression(transformer.transform(expression), mname);
+        }
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public String getText() {
+        if (expression == null) {
+            return "&" + methodName;
+        } else {
+            return expression.getText() + ".&" + methodName.getText();
+        }
+    }
+
+    public ClassNode getType() {
+        return ClassHelper.CLOSURE_TYPE.getPlainNodeReference();
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+    public Class getTypeClass() {
+        return Closure.class;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java
new file mode 100644
index 0000000..0a8ebc8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/MethodReferenceExpression.java
@@ -0,0 +1,45 @@
+/*
+ *  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.expr;
+
+/**
+ * Represents a method reference or a constructor reference,
+ * e.g. System.out::println OR Objects::requireNonNull OR Integer::new OR int[]::new
+ *
+ * @author  <a href="mailto:realbluesun@hotmail.com">Daniel.Sun</a>
+ * Created on    2016/10/19
+ */
+public class MethodReferenceExpression extends MethodPointerExpression {
+    public MethodReferenceExpression(Expression expression, Expression methodName) {
+        super(expression, methodName);
+    }
+
+    @Override
+    public String getText() {
+        Expression expression = this.getExpression();
+        Expression methodName = this.getMethodName();
+
+        if (expression == null) {
+            return "::" + methodName;
+        } else {
+            return expression.getText() + "::" + methodName.getText();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/NamedArgumentListExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/NamedArgumentListExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/NamedArgumentListExpression.java
new file mode 100644
index 0000000..b53b89b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/NamedArgumentListExpression.java
@@ -0,0 +1,45 @@
+/*
+ *  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.expr;
+
+import java.util.List;
+
+/**
+ * Represents one or more arguments being passed into a method by name
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class NamedArgumentListExpression extends MapExpression {
+
+    public NamedArgumentListExpression() {
+    }
+    
+    public NamedArgumentListExpression(List<MapEntryExpression> mapEntryExpressions) {
+        super(mapEntryExpressions);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new NamedArgumentListExpression(
+            transformExpressions(getMapEntryExpressions(), transformer, MapEntryExpression.class)); 
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;        
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/NotExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/NotExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/NotExpression.java
new file mode 100644
index 0000000..ec227ee
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/NotExpression.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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * @author sam
+ */
+public class NotExpression extends BooleanExpression {
+
+    public NotExpression(Expression expression) {
+        super(expression);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitNotExpression(this);
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new NotExpression(transformer.transform(getExpression()));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/PostfixExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/PostfixExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/PostfixExpression.java
new file mode 100644
index 0000000..16d12dc
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/PostfixExpression.java
@@ -0,0 +1,75 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * Represents a postfix expression like foo++ or bar++
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class PostfixExpression extends Expression {
+
+    private final Token operation;
+    private Expression expression;
+
+    public PostfixExpression(Expression expression, Token operation) {
+        this.operation = operation;
+        this.expression = expression;
+    }
+
+    public String toString() {
+        return super.toString() + "[" + expression + operation + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitPostfixExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new PostfixExpression(transformer.transform(expression), operation); 
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Token getOperation() {
+        return operation;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public String getText() {
+        return "(" + expression.getText() + operation.getText() + ")";
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/PrefixExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/PrefixExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/PrefixExpression.java
new file mode 100644
index 0000000..8d8f7b2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/PrefixExpression.java
@@ -0,0 +1,75 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * Represents a prefix expression like ++foo or --bar
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class PrefixExpression extends Expression {
+
+    private final Token operation;
+    private Expression expression;
+
+    public PrefixExpression(Token operation, Expression expression) {
+        this.operation = operation;
+        this.expression = expression;
+    }
+
+    public String toString() {
+        return super.toString() + "[" + operation + expression + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitPrefixExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new PrefixExpression(operation, transformer.transform(expression)); 
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Token getOperation() {
+        return operation;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public String getText() {
+        return "(" + operation.getText() + expression.getText() + ")";
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/PropertyExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/PropertyExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/PropertyExpression.java
new file mode 100644
index 0000000..0b22c02
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/PropertyExpression.java
@@ -0,0 +1,133 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a property access such as the expression "foo.bar".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class PropertyExpression extends Expression {
+
+    private Expression objectExpression;
+    private final Expression property;
+    private boolean spreadSafe = false;
+    private boolean safe = false;
+    private boolean isStatic = false;
+
+    private boolean implicitThis = false;
+
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    public PropertyExpression(Expression objectExpression, String property) {
+        this(objectExpression, new ConstantExpression(property), false);
+    }
+    
+    public PropertyExpression(Expression objectExpression, Expression property) {
+        this(objectExpression, property, false);
+    }
+
+    public PropertyExpression(Expression objectExpression, Expression property, boolean safe) {
+        this.objectExpression = objectExpression;
+        this.property = property;
+        this.safe = safe;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitPropertyExpression(this);
+    }
+
+    public boolean isDynamic() {
+        return true;
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        PropertyExpression ret = new PropertyExpression(transformer.transform(objectExpression),
+                transformer.transform(property), safe);
+        ret.setSpreadSafe(spreadSafe);
+        ret.setStatic(isStatic);
+        ret.setImplicitThis(implicitThis);
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public Expression getObjectExpression() {
+        return objectExpression;
+    }
+
+    public void setObjectExpression(Expression exp) {
+        objectExpression=exp;
+    }    
+    
+    public Expression getProperty() {
+        return property;
+    }
+    
+    public String getPropertyAsString() {
+        if (property==null) return null;
+        if (! (property instanceof ConstantExpression)) return null;
+        ConstantExpression constant = (ConstantExpression) property;
+        return constant.getText();
+    }
+
+    public String getText() {
+        String object = objectExpression.getText();
+        String text = property.getText();
+        String spread = isSpreadSafe() ? "*" : "";
+        String safe = isSafe() ? "?" : "";
+        return object + spread + safe + "." + text;
+    }
+
+    /**
+     * @return is this a safe navigation, i.e. if true then if the source object is null
+     * then this navigation will return null
+     */
+    public boolean isSafe() {
+        return safe;
+    }
+
+    public boolean isSpreadSafe() {
+        return spreadSafe;
+    }
+
+    public void setSpreadSafe(boolean value) {
+        spreadSafe = value;
+    }
+
+    public String toString() {
+        return super.toString() + "[object: " + objectExpression + " property: " + property + "]";
+    }
+
+    public void setStatic(boolean aStatic) {
+        this.isStatic = aStatic;
+    }
+    
+    public boolean isImplicitThis(){
+        return implicitThis;
+    }
+    
+    public void setImplicitThis(boolean it) {
+        implicitThis  = it;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/RangeExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/RangeExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/RangeExpression.java
new file mode 100644
index 0000000..9067725
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/RangeExpression.java
@@ -0,0 +1,70 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a range expression such as for iterating.
+ * E.g.:
+ * <pre>for i in 0..10 {...}</pre>
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class RangeExpression extends Expression {
+
+    private final Expression from;
+    private final Expression to;
+    private final boolean inclusive;
+
+    public RangeExpression(Expression from, Expression to, boolean inclusive) {
+        this.from = from;
+        this.to = to;
+        this.inclusive = inclusive;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitRangeExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new RangeExpression(transformer.transform(from), transformer.transform(to), inclusive); 
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public Expression getFrom() {
+        return from;
+    }
+
+    public Expression getTo() {
+        return to;
+    }
+
+    public boolean isInclusive() {
+        return inclusive;
+    }
+
+    public String getText() {
+        return "(" + from.getText() +
+               (!isInclusive()? "..<" : ".." ) +
+               to.getText() + ")";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/SpreadExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/SpreadExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/SpreadExpression.java
new file mode 100644
index 0000000..43a8926
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/SpreadExpression.java
@@ -0,0 +1,58 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a spread expression *x in the list expression [1, *x, 2].
+ *
+ */
+public class SpreadExpression extends Expression {
+
+    private final Expression expression;
+
+    public SpreadExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSpreadExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new SpreadExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public String getText() {
+        return "*" + expression.getText();
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/SpreadMapExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/SpreadMapExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/SpreadMapExpression.java
new file mode 100644
index 0000000..ea6318b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/SpreadMapExpression.java
@@ -0,0 +1,60 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a spread map expression *:m
+ * in the map expression [1, *:m, 2, "c":100]
+ * or in the method invoke expression func(1, *:m, 2, "c":100).
+ *
+ */
+public class SpreadMapExpression extends Expression {
+
+    private final Expression expression;
+
+    public SpreadMapExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSpreadMapExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new SpreadMapExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public String getText() {
+        return "*:" + expression.getText();
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/StaticMethodCallExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/StaticMethodCallExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/StaticMethodCallExpression.java
new file mode 100644
index 0000000..679b250
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/StaticMethodCallExpression.java
@@ -0,0 +1,95 @@
+/*
+ *  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.expr;
+
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * A static method call on a class
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class StaticMethodCallExpression extends Expression implements MethodCall {
+
+    private ClassNode ownerType;
+    private final String method;
+    private final Expression arguments;
+    private MetaMethod metaMethod = null;
+
+    public StaticMethodCallExpression(ClassNode type, String method, Expression arguments) {
+        ownerType = type;
+        this.method = method;
+        this.arguments = arguments;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitStaticMethodCallExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new StaticMethodCallExpression(getOwnerType(), method, transformer.transform(arguments));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public ASTNode getReceiver() {
+        return ownerType;
+    }
+
+    public String getMethodAsString() {
+        return method;
+    }
+
+    public Expression getArguments() {
+        return arguments;
+    }
+
+    public String getMethod() {
+        return method;
+    }
+
+    public String getText() {
+        return getOwnerType().getName() + "." + method + arguments.getText();
+    }
+
+    public String toString() {
+        return super.toString() + "[" + getOwnerType().getName() + "#" + method + " arguments: " + arguments + "]";
+    }
+
+    public ClassNode getOwnerType() {
+        return ownerType;
+    }
+
+    public void setOwnerType(ClassNode ownerType) {
+        this.ownerType = ownerType;
+    }
+
+    public void setMetaMethod(MetaMethod metaMethod) {
+        this.metaMethod = metaMethod;
+    }
+
+    public MetaMethod getMetaMethod() {
+        return metaMethod;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/TernaryExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/TernaryExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/TernaryExpression.java
new file mode 100644
index 0000000..a24fd63
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/TernaryExpression.java
@@ -0,0 +1,86 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a ternary expression (booleanExpression) ? expression : expression
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class TernaryExpression extends Expression {
+
+    private final BooleanExpression booleanExpression;
+    private final Expression trueExpression;
+    private final Expression falseExpression;
+
+    public TernaryExpression(
+        BooleanExpression booleanExpression,
+        Expression trueExpression,
+        Expression falseExpression) {
+        this.booleanExpression = booleanExpression;
+        this.trueExpression = trueExpression;
+        this.falseExpression = falseExpression;
+    }
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitTernaryExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new TernaryExpression(
+                (BooleanExpression) transformer.transform(booleanExpression),
+                transformer.transform(trueExpression),
+                transformer.transform(falseExpression)); 
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret; 
+    }
+
+    public String toString() {
+        return super.toString() +"[" + booleanExpression + " ? " + trueExpression + " : " + falseExpression + "]";
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Expression getFalseExpression() {
+        return falseExpression;
+    }
+
+    public Expression getTrueExpression() {
+        return trueExpression;
+    }
+
+    public String getText() {
+        return "("
+            + booleanExpression.getText()
+            + ") ? "
+            + trueExpression.getText()
+            + " : "
+            + falseExpression.getText();
+    }
+
+    public ClassNode getType() {
+        return ClassHelper.OBJECT_TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/TupleExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/TupleExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/TupleExpression.java
new file mode 100644
index 0000000..113706a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/TupleExpression.java
@@ -0,0 +1,120 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Represents a tuple expression {1, 2, 3} which creates an immutable List
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class TupleExpression extends Expression implements Iterable<Expression> {
+    private final List<Expression> expressions;
+
+    public TupleExpression() {
+        this(0);
+    }
+
+    public TupleExpression(Expression expr) {
+        this(1);
+        addExpression(expr);
+    }
+
+    public TupleExpression(Expression expr1, Expression expr2) {
+        this(2);
+        addExpression(expr1);
+        addExpression(expr2);
+    }
+
+    public TupleExpression(Expression expr1, Expression expr2, Expression expr3) {
+        this(3);
+        addExpression(expr1);
+        addExpression(expr2);
+        addExpression(expr3);
+    }
+    
+    public TupleExpression(int length) {
+        this.expressions = new ArrayList<Expression>(length);
+    }
+    
+    public TupleExpression(List<Expression> expressions) {
+        this.expressions = expressions;
+    }
+    
+    public TupleExpression(Expression[] expressionArray) {
+        this();
+        expressions.addAll(Arrays.asList(expressionArray));
+    }
+
+    public TupleExpression addExpression(Expression expression) {
+        expressions.add(expression);
+        return this;
+    }
+    
+    public List<Expression> getExpressions() {
+        return expressions;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitTupleExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new TupleExpression(transformExpressions(getExpressions(), transformer)); 
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public Expression getExpression(int i) {
+        return expressions.get(i);
+    }
+
+    public String getText() {
+        StringBuilder buffer = new StringBuilder("(");
+        boolean first = true;
+        for (Expression expression : expressions) {
+            if (first) {
+                first = false;
+            }
+            else {
+                buffer.append(", ");
+            }
+            
+            buffer.append(expression.getText());
+        }
+        buffer.append(")");
+        return buffer.toString();
+    }
+
+    public String toString() {
+        return super.toString() + expressions;
+    }
+
+    public Iterator<Expression> iterator() {
+        return Collections.unmodifiableList(expressions).iterator();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/UnaryMinusExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/UnaryMinusExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/UnaryMinusExpression.java
new file mode 100644
index 0000000..8d1315e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/UnaryMinusExpression.java
@@ -0,0 +1,62 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * @author sam
+ */
+public class UnaryMinusExpression extends Expression {
+
+    private final Expression expression;
+
+    public UnaryMinusExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitUnaryMinusExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new UnaryMinusExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public String getText() {
+        return expression.getText();
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/UnaryPlusExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/UnaryPlusExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/UnaryPlusExpression.java
new file mode 100644
index 0000000..7c3f990
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/UnaryPlusExpression.java
@@ -0,0 +1,62 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * @author Paul King
+ */
+public class UnaryPlusExpression extends Expression {
+
+    private final Expression expression;
+
+    public UnaryPlusExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitUnaryPlusExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new UnaryPlusExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public String getText() {
+        return expression.getText();
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+}
\ No newline at end of file


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java b/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
new file mode 100644
index 0000000..aa8096f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ArrayUtil.java
@@ -0,0 +1,1312 @@
+/*
+ *  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.runtime;
+
+/**
+* This is a generated class used internally during the writing of bytecode within the CallSiteWriter logic.
+* This is not a class exposed to users, as is the case with almost all classes in the org.codehaus.groovy packages.
+* <p>
+* The purpose is the reduction of the size of the bytecode. Consider creating a three element Object[] with null values:
+* <pre>
+*  ANEWARRAY java/lang/Object    
+*  DUP
+*  ICONST_0
+*  ACONST_NULL
+*  AASTORE
+*  DUP
+*  ICONST_1
+*  ACONST_NULL
+*  AASTORE
+*  DUP
+*  ICONST_2
+*  ACONST_NULL
+*  AASTORE
+* </pre>
+* with ArrayUtils you can have it like this:
+* <pre>
+*  ACONST_NULL
+*  ACONST_NULL
+*  ACONST_NULL
+*  INVOKESTATIC ArrayUtils.createArray(Object,Object,Object)
+* </pre>
+* The number of needed instructions is thus reduced from 15 to 4. For every entry we save 3 bytecode instructions.
+* This allows better readable bytecode and it allows the JIT to see less bytecode to optimize, helping under the
+* inlining threshold here or there.
+* <p>
+* So even though the class is ugly, there are good reason to have this in Groovy, even if the class makes
+* absolutely no sense in normal Java. But it is not used in normal Java, but from the bytecode. 
+*/ 
+public class ArrayUtil {
+    private static final Object[] EMPTY = new Object[0]
+            ;
+
+    public static Object[] createArray() {
+        return EMPTY;
+    }
+
+    public static Object[] createArray(Object arg0) {
+        return new Object[]{
+                arg0};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1) {
+        return new Object[]{
+                arg0, arg1};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2) {
+        return new Object[]{
+                arg0, arg1, arg2};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78, arg79};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79, Object arg80) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78, arg79, arg80};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79, Object arg80, Object arg81) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78, arg79, arg80, arg81};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79, Object arg80, Object arg81, Object arg82) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78, arg79, arg80, arg81, arg82};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79, Object arg80, Object arg81, Object arg82, Object arg83) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78, arg79, arg80, arg81, arg82, arg83};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79, Object arg80, Object arg81, Object arg82, Object arg83, Object arg84) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78, arg79, arg80, arg81, arg82, arg83, arg84};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79, Object arg80, Object arg81, Object arg82, Object arg83, Object arg84, Object arg85) {
+        return new Object[]{
+                arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50, arg51, arg52, arg53, arg54, arg55, arg56, arg57, arg58, arg59, arg60, arg61, arg62, arg63, arg64, arg65, arg66, arg67, arg68, arg69, arg70, arg71, arg72, arg73, arg74, arg75, arg76, arg77, arg78, arg79, arg80, arg81, arg82, arg83, arg84, arg85};
+    }
+
+    public static Object[] createArray(Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10, Object arg11, Object arg12, Object arg13, Object arg14, Object arg15, Object arg16, Object arg17, Object arg18, Object arg19, Object arg20, Object arg21, Object arg22, Object arg23, Object arg24, Object arg25, Object arg26, Object arg27, Object arg28, Object arg29, Object arg30, Object arg31, Object arg32, Object arg33, Object arg34, Object arg35, Object arg36, Object arg37, Object arg38, Object arg39, Object arg40, Object arg41, Object arg42, Object arg43, Object arg44, Object arg45, Object arg46, Object arg47, Object arg48, Object arg49, Object arg50, Object arg51, Object arg52, Object arg53, Object arg54, Object arg55, Object arg56, Object arg57, Object arg58, Object arg59, Object arg60, Object arg61, Object arg62, Object arg63, Object arg64, Object arg65, Object arg66, Object arg67, Object arg68, Ob
 ject arg69, Object arg70, Object arg71, Object arg72, Object arg73, Object arg74, Object arg75, Object arg76, Object arg77, Object arg78, Object arg79, Object arg80, Object arg81, Object arg82, Object arg83, Object arg84, Object arg85, Object arg86) {
+        return new Object[]{
+                arg0, arg1, a

<TRUNCATED>

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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/CachedMethod.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/CachedMethod.java b/src/main/java/org/codehaus/groovy/reflection/CachedMethod.java
new file mode 100644
index 0000000..58314e2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/CachedMethod.java
@@ -0,0 +1,345 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import groovy.lang.MissingMethodException;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.codehaus.groovy.runtime.callsite.CallSiteGenerator;
+import org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite;
+import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite;
+import org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite;
+import org.codehaus.groovy.runtime.metaclass.MethodHelper;
+
+import java.io.Serializable;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class CachedMethod extends MetaMethod implements Comparable {
+    public final CachedClass cachedClass;
+
+    private final Method cachedMethod;
+    private int hashCode;
+
+    private static final MyComparator COMPARATOR = new MyComparator();
+
+    private SoftReference<Constructor> pogoCallSiteConstructor, pojoCallSiteConstructor, staticCallSiteConstructor;
+
+    private boolean skipCompiled;
+
+    public CachedMethod(CachedClass clazz, Method method) {
+        this.cachedMethod = method;
+        this.cachedClass = clazz;
+    }
+
+    public CachedMethod(Method method) {
+        this(ReflectionCache.getCachedClass(method.getDeclaringClass()),method);
+    }
+
+    public static CachedMethod find(Method method) {
+        CachedMethod[] methods = ReflectionCache.getCachedClass(method.getDeclaringClass()).getMethods();
+//        for (int i = 0; i < methods.length; i++) {
+//            CachedMethod cachedMethod = methods[i];
+//            if (cachedMethod.cachedMethod.equals(method))
+//                return cachedMethod;
+//        }
+//        return null;
+        int i = Arrays.binarySearch(methods, method, COMPARATOR);
+        if (i < 0)
+          return null;
+
+        return methods[i];
+    }
+
+    protected Class[] getPT() {
+        return cachedMethod.getParameterTypes();
+    }
+
+    public String getName() {
+        return cachedMethod.getName();
+    }
+
+    public String getDescriptor() {
+        return BytecodeHelper.getMethodDescriptor(getReturnType(), getNativeParameterTypes());
+    }
+
+    public CachedClass getDeclaringClass() {
+        return cachedClass;
+    }
+
+    public final Object invoke(Object object, Object[] arguments) {
+        try {
+            AccessPermissionChecker.checkAccessPermission(cachedMethod);
+        } catch (CacheAccessControlException ex) {
+            throw new InvokerInvocationException(ex);
+        }
+        try {
+            return cachedMethod.invoke(object, arguments);
+        } catch (IllegalArgumentException e) {
+            throw new InvokerInvocationException(e);
+        } catch (IllegalAccessException e) {
+            throw new InvokerInvocationException(e);
+        } catch (InvocationTargetException e) {
+            Throwable cause = e.getCause(); 
+            throw (cause instanceof RuntimeException && !(cause instanceof MissingMethodException)) ? 
+                    (RuntimeException) cause : new InvokerInvocationException(e);
+        }
+    }
+
+    public ParameterTypes getParamTypes() {
+        return null;
+    }
+
+    public Class getReturnType() {
+        return cachedMethod.getReturnType();
+    }
+
+    public int getParamsCount() {
+        return getParameterTypes().length;
+    }
+
+    public int getModifiers() {
+        return cachedMethod.getModifiers();
+    }
+
+
+    public String getSignature() {
+        return getName() + getDescriptor();
+    }
+
+    public final Method setAccessible() {
+        AccessPermissionChecker.checkAccessPermission(cachedMethod);
+//        if (queuedToCompile.compareAndSet(false,true)) {
+//            if (isCompilable())
+//              CompileThread.addMethod(this);
+//        }
+        return cachedMethod;
+    }
+
+    public boolean isStatic() {
+        return MethodHelper.isStatic(cachedMethod);
+    }
+
+    public int compareTo(Object o) {
+      if (o instanceof CachedMethod)
+        return compareToCachedMethod((CachedMethod)o);
+      else
+        return compareToMethod((Method)o);
+    }
+
+    private int compareToCachedMethod(CachedMethod other) {
+        if (other == null)
+            return -1;
+
+        final int strComp = getName().compareTo(other.getName());
+        if (strComp != 0)
+            return strComp;
+
+        final int retComp = getReturnType().getName().compareTo(other.getReturnType().getName());
+        if (retComp != 0)
+            return retComp;
+
+        CachedClass[] params = getParameterTypes();
+        CachedClass[] otherParams = other.getParameterTypes();
+
+        final int pd = params.length - otherParams.length;
+        if (pd != 0)
+            return pd;
+
+        for (int i = 0; i != params.length; ++i) {
+            final int nameComp = params[i].getName().compareTo(otherParams[i].getName());
+            if (nameComp != 0)
+                return nameComp;
+        }
+
+        final int classComp = cachedClass.toString().compareTo(other.getDeclaringClass().toString());
+        if (classComp != 0)
+            return classComp;
+
+        throw new RuntimeException("Should never happen");
+    }
+
+    private int compareToMethod(Method other) {
+        if (other == null)
+            return -1;
+
+        final int strComp = getName().compareTo(other.getName());
+        if (strComp != 0)
+            return strComp;
+
+        final int retComp = getReturnType().getName().compareTo(other.getReturnType().getName());
+        if (retComp != 0)
+            return retComp;
+
+        CachedClass[] params = getParameterTypes();
+        Class[] mparams = other.getParameterTypes();
+
+        final int pd = params.length - mparams.length;
+        if (pd != 0)
+            return pd;
+
+        for (int i = 0; i != params.length; ++i) {
+            final int nameComp = params[i].getName().compareTo(mparams[i].getName());
+            if (nameComp != 0)
+                return nameComp;
+        }
+
+        return 0;
+    }
+
+    public boolean equals(Object o) {
+        return (o instanceof CachedMethod && cachedMethod.equals(((CachedMethod)o).cachedMethod))
+                || (o instanceof Method && cachedMethod.equals(o));
+    }
+
+    public int hashCode() {
+        if (hashCode == 0) {
+           hashCode = cachedMethod.hashCode();
+           if (hashCode == 0)
+             hashCode = 0xcafebebe;
+        }
+        return hashCode;
+    }
+
+    public String toString() {
+        return cachedMethod.toString();
+    }
+    
+    private static Constructor getConstructor(SoftReference<Constructor> ref) {
+        if (ref==null) return null;
+        return ref.get();
+    }
+
+    public CallSite createPogoMetaMethodSite(CallSite site, MetaClassImpl metaClass, Class[] params) {
+        if (!skipCompiled) {
+            Constructor constr = getConstructor(pogoCallSiteConstructor);
+            if (constr==null) {
+                if (CallSiteGenerator.isCompilable(this)) {
+                  constr = CallSiteGenerator.compilePogoMethod(this);
+                }
+                if (constr != null) {
+                     pogoCallSiteConstructor = new SoftReference<Constructor> (constr);
+                } else {
+                    skipCompiled = true;
+                }
+            }
+    
+            if (constr!=null) {
+                try {
+                    return (CallSite) constr.newInstance(site, metaClass, this, params, constr);
+                } catch (Error e) {
+                    skipCompiled=true;
+                    throw e;
+                } catch (Throwable e) {
+                    skipCompiled=true;
+                }
+            }
+        }
+        return new PogoMetaMethodSite.PogoCachedMethodSiteNoUnwrapNoCoerce(site, metaClass, this, params);
+    }
+
+
+    public CallSite createPojoMetaMethodSite(CallSite site, MetaClassImpl metaClass, Class[] params) {
+        if (!skipCompiled) {
+            Constructor constr = getConstructor(pojoCallSiteConstructor);
+            if (constr==null) {
+                if (CallSiteGenerator.isCompilable(this)) {
+                  constr = CallSiteGenerator.compilePojoMethod(this);
+                }
+                if (constr != null) {
+                    pojoCallSiteConstructor = new SoftReference<Constructor> (constr);
+                } else {
+                    skipCompiled = true;
+                }
+            }
+    
+            if (constr!=null) {
+                try {
+                    return (CallSite) constr.newInstance(site, metaClass, this, params, constr);
+                } catch (Error e) {
+                    skipCompiled=true;
+                    throw e;
+                } catch (Throwable e) {
+                    skipCompiled=true;
+                }
+            }
+        }
+        return new PojoMetaMethodSite.PojoCachedMethodSiteNoUnwrapNoCoerce(site, metaClass, this, params);
+    }
+
+    public CallSite createStaticMetaMethodSite(CallSite site, MetaClassImpl metaClass, Class[] params) {
+        if (!skipCompiled) {
+            Constructor constr = getConstructor(staticCallSiteConstructor);
+            if (constr==null) {
+                if (CallSiteGenerator.isCompilable(this)) {
+                  constr = CallSiteGenerator.compileStaticMethod(this);
+                }
+                if (constr != null) {
+                    staticCallSiteConstructor = new SoftReference<Constructor> (constr);
+                } else {
+                    skipCompiled = true;
+                }
+            }
+    
+            if (constr!=null) {
+                try {
+                    return (CallSite) constr.newInstance(site, metaClass, this, params, constr);
+                } catch (Error e) {
+                    skipCompiled=true;
+                    throw e;
+                } catch (Throwable e) {
+                    skipCompiled=true;
+                }
+            }
+        }
+
+        return new StaticMetaMethodSite.StaticMetaMethodSiteNoUnwrapNoCoerce(site, metaClass, this, params);
+    }
+
+    private static class MyComparator implements Comparator, Serializable {
+        private static final long serialVersionUID = 8909277090690131302L;
+
+        public int compare(Object o1, Object o2) {
+            if (o1 instanceof CachedMethod)
+                return ((CachedMethod)o1).compareTo(o2);
+            else if (o2 instanceof CachedMethod)
+                return -((CachedMethod)o2).compareTo(o1);
+            else
+                // really, this should never happen, it's evidence of corruption if it does
+                throw new ClassCastException("One of the two comparables must be a CachedMethod");
+        }
+    }
+
+    public Method getCachedMethod() {
+        AccessPermissionChecker.checkAccessPermission(cachedMethod);
+        return cachedMethod;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java b/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
new file mode 100644
index 0000000..b4dc133
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/ClassInfo.java
@@ -0,0 +1,505 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.Closure;
+import groovy.lang.ExpandoMetaClass;
+import groovy.lang.ExpandoMetaClassCreationHandle;
+import groovy.lang.GroovySystem;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaClassRegistry;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue;
+import org.codehaus.groovy.reflection.stdclasses.ArrayCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.BigDecimalCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.BigIntegerCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.BooleanCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.ByteCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.CachedClosureClass;
+import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
+import org.codehaus.groovy.reflection.stdclasses.CharacterCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.DoubleCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.FloatCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.IntegerCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.LongCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.NumberCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.ObjectCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.ShortCachedClass;
+import org.codehaus.groovy.reflection.stdclasses.StringCachedClass;
+import org.codehaus.groovy.util.Finalizable;
+import org.codehaus.groovy.util.LazyReference;
+import org.codehaus.groovy.util.LockableObject;
+import org.codehaus.groovy.util.ManagedConcurrentLinkedQueue;
+import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ManagedReference;
+import org.codehaus.groovy.util.ReferenceBundle;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.lang.ref.WeakReference;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Handle for all information we want to keep about the class
+ * <p>
+ * This class handles caching internally and its advisable to not store
+ * references directly to objects of this class.  The static factory method
+ * {@link ClassInfo#getClassInfo(Class)} should be used to retrieve an instance
+ * from the cache.  Internally the {@code Class} associated with a {@code ClassInfo}
+ * instance is kept as {@link WeakReference}, so it not safe to reference
+ * and instance without the Class being either strongly or softly reachable.
+ *
+ * @author Alex.Tkachman
+ */
+public class ClassInfo implements Finalizable {
+
+    private final LazyCachedClassRef cachedClassRef;
+    private final LazyClassLoaderRef artifactClassLoader;
+    private final LockableObject lock = new LockableObject();
+    public final int hash = -1;
+    private final WeakReference<Class<?>> classRef;
+
+    // TODO: should be able to remove the klazz field once 2.5 becomes the mainline release
+    // Gradle has a cleanup mechanism in place to reflectively access this klazz field.
+    // The klazz field is being kept for compatibility so as to not break builds that depend
+    // on versions of Groovy after the field was changed to a WeakReference (classRef).  It
+    // appears that Gradle only performs the cleanup when it detects a groovy version of 2.4.x,
+    // so the klazz field and placeholder Sentinel class can likely be safely removed once
+    // the release version bumps to 2.5 (or beyond).
+    // See:
+    // https://github.com/gradle/gradle/blob/711f64/subprojects/core/src/main/java/org/gradle/api/internal/classloading/LeakyOnJava7GroovySystemLoader.java#L74
+    private static final class Sentinel {}
+    private static final Class<?> klazz = Sentinel.class;
+
+    private final AtomicInteger version = new AtomicInteger();
+
+    private MetaClass strongMetaClass;
+    private ManagedReference<MetaClass> weakMetaClass;
+    MetaMethod[] dgmMetaMethods = CachedClass.EMPTY;
+    MetaMethod[] newMetaMethods = CachedClass.EMPTY;
+    private ManagedConcurrentMap<Object, MetaClass> perInstanceMetaClassMap;
+    
+    private static final ReferenceBundle softBundle = ReferenceBundle.getSoftBundle();
+    private static final ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
+    
+    private static final ManagedConcurrentLinkedQueue<ClassInfo> modifiedExpandos =
+            new ManagedConcurrentLinkedQueue<ClassInfo>(weakBundle);
+
+    private static final GroovyClassValue<ClassInfo> globalClassValue = GroovyClassValueFactory.createGroovyClassValue(new ComputeValue<ClassInfo>(){
+		@Override
+		public ClassInfo computeValue(Class<?> type) {
+			ClassInfo ret = new ClassInfo(type);
+			globalClassSet.add(ret);
+			return ret;
+		}
+	});
+    
+    private static final GlobalClassSet globalClassSet = new GlobalClassSet();
+
+    ClassInfo(Class klazz) {
+        this.classRef = new WeakReference<Class<?>>(klazz);
+        cachedClassRef = new LazyCachedClassRef(softBundle, this);
+        artifactClassLoader = new LazyClassLoaderRef(softBundle, this);
+    }
+
+    public int getVersion() {
+        return version.get();
+    }
+
+    public void incVersion() {
+        version.incrementAndGet();
+        VMPluginFactory.getPlugin().invalidateCallSites();
+    }
+
+    public ExpandoMetaClass getModifiedExpando() {
+        // safe value here to avoid multiple reads with possibly
+        // differing values due to concurrency
+        MetaClass strongRef = strongMetaClass;
+        return strongRef == null ? null : strongRef instanceof ExpandoMetaClass ? (ExpandoMetaClass)strongRef : null;
+    }
+
+    public static void clearModifiedExpandos() {
+        for (Iterator<ClassInfo> itr = modifiedExpandos.iterator(); itr.hasNext(); ) {
+            ClassInfo info = itr.next();
+            itr.remove();
+            info.setStrongMetaClass(null);
+        }
+    }
+
+    /**
+     * Returns the {@code Class} associated with this {@code ClassInfo}.
+     * <p>
+     * This method can return {@code null} if the {@code Class} is no longer reachable
+     * through any strong or soft references.  A non-null return value indicates that this
+     * {@code ClassInfo} is valid.
+     *
+     * @return the {@code Class} associated with this {@code ClassInfo}, else {@code null}
+     */
+    public final Class<?> getTheClass() {
+        return classRef.get();
+    }
+
+    public CachedClass getCachedClass() {
+        return cachedClassRef.get();
+    }
+
+    public ClassLoaderForClassArtifacts getArtifactClassLoader() {
+        return artifactClassLoader.get();
+    }
+
+    public static ClassInfo getClassInfo (Class cls) {
+        return globalClassValue.get(cls);
+    }
+
+    /**
+     * Removes a {@code ClassInfo} from the cache.
+     *
+     * This is useful in cases where the Class is parsed from a script, such as when
+     * using GroovyClassLoader#parseClass, and is executed for its result but the Class
+     * is not retained or cached.  Removing the {@code ClassInfo} associated with the Class
+     * will make the Class and its ClassLoader eligible for garbage collection sooner that
+     * it would otherwise.
+     *
+     * @param cls the Class associated with the ClassInfo to remove
+     *            from cache
+     */
+    public static void remove(Class<?> cls) {
+        globalClassValue.remove(cls);
+    }
+
+    public static Collection<ClassInfo> getAllClassInfo () {
+        return getAllGlobalClassInfo();
+    }
+
+    public static void onAllClassInfo(ClassInfoAction action) {
+        for (ClassInfo classInfo : getAllGlobalClassInfo()) {
+            action.onClassInfo(classInfo);
+        }
+    }
+
+    private static Collection<ClassInfo> getAllGlobalClassInfo() {
+        return globalClassSet.values();
+    }
+
+    public MetaClass getStrongMetaClass() {
+        return strongMetaClass;
+    }
+
+    public void setStrongMetaClass(MetaClass answer) {
+        version.incrementAndGet();
+
+        // safe value here to avoid multiple reads with possibly
+        // differing values due to concurrency
+        MetaClass strongRef = strongMetaClass;
+        
+        if (strongRef instanceof ExpandoMetaClass) {
+            ((ExpandoMetaClass)strongRef).inRegistry = false;
+            for (Iterator<ClassInfo> itr = modifiedExpandos.iterator(); itr.hasNext(); ) {
+                ClassInfo info = itr.next();
+                if(info == this) {
+                    itr.remove();
+                }
+            }
+        }
+
+        strongMetaClass = answer;
+
+        if (answer instanceof ExpandoMetaClass) {
+            ((ExpandoMetaClass)answer).inRegistry = true;
+            modifiedExpandos.add(this);
+        }
+
+        replaceWeakMetaClassRef(null);
+    }
+
+    public MetaClass getWeakMetaClass() {
+        // safe value here to avoid multiple reads with possibly
+        // differing values due to concurrency
+        ManagedReference<MetaClass> weakRef = weakMetaClass;
+        return weakRef == null ? null : weakRef.get();
+    }
+
+    public void setWeakMetaClass(MetaClass answer) {
+        version.incrementAndGet();
+
+        strongMetaClass = null;
+        ManagedReference<MetaClass> newRef = null;
+        if (answer != null) {
+            newRef = new ManagedReference<MetaClass> (softBundle,answer);
+        }
+        replaceWeakMetaClassRef(newRef);
+    }
+
+    private void replaceWeakMetaClassRef(ManagedReference<MetaClass> newRef) {
+        // safe value here to avoid multiple reads with possibly
+        // differing values due to concurrency
+        ManagedReference<MetaClass> weakRef = weakMetaClass;
+        if (weakRef != null) {
+            weakRef.clear();
+        }
+        weakMetaClass = newRef;
+    }
+
+    public MetaClass getMetaClassForClass() {
+        // safe value here to avoid multiple reads with possibly
+        // differing values due to concurrency
+        MetaClass strongMc = strongMetaClass;
+        if (strongMc!=null) return strongMc;
+        MetaClass weakMc = getWeakMetaClass();
+        if (isValidWeakMetaClass(weakMc)) {
+            return weakMc;
+        }
+        return null;
+    }
+
+    private MetaClass getMetaClassUnderLock() {
+        MetaClass answer = getStrongMetaClass();
+        if (answer!=null) return answer;
+        
+        answer = getWeakMetaClass();
+        final MetaClassRegistry metaClassRegistry = GroovySystem.getMetaClassRegistry();
+        MetaClassRegistry.MetaClassCreationHandle mccHandle = metaClassRegistry.getMetaClassCreationHandler();
+        
+        if (isValidWeakMetaClass(answer, mccHandle)) {
+            return answer;
+        }
+
+        answer = mccHandle.create(classRef.get(), metaClassRegistry);
+        answer.initialize();
+
+        if (GroovySystem.isKeepJavaMetaClasses()) {
+            setStrongMetaClass(answer);
+        } else {
+            setWeakMetaClass(answer);
+        }
+        return answer;
+    }
+    
+    private static boolean isValidWeakMetaClass(MetaClass metaClass) {
+        return isValidWeakMetaClass(metaClass, GroovySystem.getMetaClassRegistry().getMetaClassCreationHandler());
+    }
+
+    /**
+     * if EMC.enableGlobally() is OFF, return whatever the cached answer is.
+     * but if EMC.enableGlobally() is ON and the cached answer is not an EMC, come up with a fresh answer
+     */
+    private static boolean isValidWeakMetaClass(MetaClass metaClass, MetaClassRegistry.MetaClassCreationHandle mccHandle) {
+        if(metaClass==null) return false;
+        boolean enableGloballyOn = (mccHandle instanceof ExpandoMetaClassCreationHandle);
+        boolean cachedAnswerIsEMC = (metaClass instanceof ExpandoMetaClass);
+        return (!enableGloballyOn || cachedAnswerIsEMC);
+    }
+
+    /**
+     * Returns the {@code MetaClass} for the {@code Class} associated with this {@code ClassInfo}.
+     * If no {@code MetaClass} exists one will be created.
+     * <p>
+     * It is not safe to call this method without a {@code Class} associated with this {@code ClassInfo}.
+     * It is advisable to aways retrieve a ClassInfo instance from the cache by using the static
+     * factory method {@link ClassInfo#getClassInfo(Class)} to ensure the referenced Class is
+     * strongly reachable.
+     *
+     * @return a {@code MetaClass} instance
+     */
+    public final MetaClass getMetaClass() {
+        MetaClass answer = getMetaClassForClass();
+        if (answer != null) return answer;
+
+        lock();
+        try {
+            return getMetaClassUnderLock();
+        } finally {
+            unlock();
+        }
+    }
+
+    public MetaClass getMetaClass(Object obj) {
+        final MetaClass instanceMetaClass = getPerInstanceMetaClass(obj);
+        if (instanceMetaClass != null)
+            return instanceMetaClass;
+        return getMetaClass();
+    }
+
+    public static int size () {
+        return globalClassSet.size();
+    }
+
+    public static int fullSize () {
+        return globalClassSet.fullSize();
+    }
+
+    private static CachedClass createCachedClass(Class klazz, ClassInfo classInfo) {
+        if (klazz == Object.class)
+            return new ObjectCachedClass(classInfo);
+
+        if (klazz == String.class)
+            return new StringCachedClass(classInfo);
+
+        CachedClass cachedClass;
+        if (Number.class.isAssignableFrom(klazz) || klazz.isPrimitive()) {
+            if (klazz == Number.class) {
+                cachedClass = new NumberCachedClass(klazz, classInfo);
+            } else if (klazz == Integer.class || klazz ==  Integer.TYPE) {
+                cachedClass = new IntegerCachedClass(klazz, classInfo, klazz==Integer.class);
+            } else if (klazz == Double.class || klazz == Double.TYPE) {
+                cachedClass = new DoubleCachedClass(klazz, classInfo, klazz==Double.class);
+            } else if (klazz == BigDecimal.class) {
+                cachedClass = new BigDecimalCachedClass(klazz, classInfo);
+            } else if (klazz == Long.class || klazz == Long.TYPE) {
+                cachedClass = new LongCachedClass(klazz, classInfo, klazz==Long.class);
+            } else if (klazz == Float.class || klazz == Float.TYPE) { 
+                cachedClass = new FloatCachedClass(klazz, classInfo, klazz==Float.class);
+            } else if (klazz == Short.class || klazz == Short.TYPE) {
+                cachedClass = new ShortCachedClass(klazz, classInfo, klazz==Short.class);
+            } else if (klazz == Boolean.TYPE) {
+                cachedClass = new BooleanCachedClass(klazz, classInfo, false);
+            } else if (klazz == Character.TYPE) {
+                cachedClass = new CharacterCachedClass(klazz, classInfo, false);
+            } else if (klazz == BigInteger.class) {
+                cachedClass = new BigIntegerCachedClass(klazz, classInfo);
+            } else if (klazz == Byte.class || klazz == Byte.TYPE) {
+                cachedClass = new ByteCachedClass(klazz, classInfo, klazz==Byte.class);
+            } else {
+                cachedClass = new CachedClass(klazz, classInfo);
+            }
+        } else {
+            if (klazz.getName().charAt(0) == '[')
+              cachedClass = new ArrayCachedClass(klazz, classInfo);
+            else if (klazz == Boolean.class) {
+                cachedClass = new BooleanCachedClass(klazz, classInfo, true);
+            } else if (klazz == Character.class) {
+                cachedClass = new CharacterCachedClass(klazz, classInfo, true);
+            } else if (Closure.class.isAssignableFrom(klazz)) {
+                cachedClass = new CachedClosureClass (klazz, classInfo);
+            } else if (isSAM(klazz)) {
+                cachedClass = new CachedSAMClass(klazz, classInfo);
+            } else {
+                cachedClass = new CachedClass(klazz, classInfo);
+            }
+        }
+        return cachedClass;
+    }
+    
+    private static boolean isSAM(Class<?> c) {
+        return CachedSAMClass.getSAMMethod(c) !=null;
+    }
+
+    public void lock () {
+        lock.lock();
+    }
+
+    public void unlock () {
+        lock.unlock();
+    }
+
+    public MetaClass getPerInstanceMetaClass(Object obj) {
+        if (perInstanceMetaClassMap == null)
+          return null;
+
+        return perInstanceMetaClassMap.get(obj);
+    }
+
+    public void setPerInstanceMetaClass(Object obj, MetaClass metaClass) {
+        version.incrementAndGet();
+
+        if (metaClass != null) {
+            if (perInstanceMetaClassMap == null)
+              perInstanceMetaClassMap = new ManagedConcurrentMap<Object, MetaClass>(ReferenceBundle.getWeakBundle()); 
+
+            perInstanceMetaClassMap.put(obj, metaClass);
+        }
+        else {
+            if (perInstanceMetaClassMap != null) {
+              perInstanceMetaClassMap.remove(obj);
+            }
+        }
+    }
+
+    public boolean hasPerInstanceMetaClasses () {
+        return perInstanceMetaClassMap != null;
+    }
+
+    private static class LazyCachedClassRef extends LazyReference<CachedClass> {
+        private final ClassInfo info;
+
+        LazyCachedClassRef(ReferenceBundle bundle, ClassInfo info) {
+            super(bundle);
+            this.info = info;
+        }
+
+        public CachedClass initValue() {
+            return createCachedClass(info.classRef.get(), info);
+        }
+    }
+
+    private static class LazyClassLoaderRef extends LazyReference<ClassLoaderForClassArtifacts> {
+        private final ClassInfo info;
+
+        LazyClassLoaderRef(ReferenceBundle bundle, ClassInfo info) {
+            super(bundle);
+            this.info = info;
+        }
+
+        public ClassLoaderForClassArtifacts initValue() {
+            return AccessController.doPrivileged(new PrivilegedAction<ClassLoaderForClassArtifacts>() {
+                public ClassLoaderForClassArtifacts run() {
+                    return new ClassLoaderForClassArtifacts(info.classRef.get());
+                }
+            });
+        }
+    }
+
+    @Override
+    public void finalizeReference() {
+        setStrongMetaClass(null);
+        cachedClassRef.clear();
+        artifactClassLoader.clear();
+    }
+
+    private static class GlobalClassSet {
+    	
+    	private final ManagedConcurrentLinkedQueue<ClassInfo> items = new ManagedConcurrentLinkedQueue<ClassInfo>(weakBundle);
+    	
+    	public int size(){
+		    return values().size();
+    	}
+    	
+    	public int fullSize(){
+		    return values().size();
+    	}
+    	
+    	public Collection<ClassInfo> values(){
+    	    return items.values();
+    	}
+    	
+    	public void add(ClassInfo value){
+            items.add(value);
+    	}
+
+    }
+
+    public interface ClassInfoAction {
+        void onClassInfo(ClassInfo classInfo);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/ClassLoaderForClassArtifacts.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/ClassLoaderForClassArtifacts.java b/src/main/java/org/codehaus/groovy/reflection/ClassLoaderForClassArtifacts.java
new file mode 100644
index 0000000..ba24a6d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/ClassLoaderForClassArtifacts.java
@@ -0,0 +1,88 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.codehaus.groovy.runtime.callsite.GroovySunClassLoader;
+
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ClassLoaderForClassArtifacts extends ClassLoader {
+    public final SoftReference<Class> klazz;
+    private final AtomicInteger classNamesCounter = new AtomicInteger(-1);
+
+    public ClassLoaderForClassArtifacts(Class klazz) {
+        super(klazz.getClassLoader());
+        this.klazz = new SoftReference<Class> (klazz);
+    }
+
+    public Class define (String name, byte [] bytes) {
+        Class cls = defineClass(name, bytes, 0, bytes.length, klazz.get().getProtectionDomain());
+        resolveClass(cls);
+        return cls;
+    }
+
+    public Class loadClass(String name) throws ClassNotFoundException {
+        Class cls = findLoadedClass(name);
+        if (cls != null)
+          return cls;
+
+        if (GroovySunClassLoader.sunVM != null) {
+            cls = GroovySunClassLoader.sunVM.doesKnow(name);
+            if (cls != null)
+              return cls;
+        }
+
+        return super.loadClass(name);
+    }
+
+    public String createClassName(Method method) {
+        final String name;
+        final String clsName = klazz.get().getName();
+        if (clsName.startsWith("java."))
+          name = clsName.replace('.','_') + "$" + method.getName();
+        else
+          name = clsName + "$" + method.getName();
+        int suffix = classNamesCounter.getAndIncrement();
+        return suffix == -1? name : name + "$" + suffix;
+    }
+
+    public Constructor defineClassAndGetConstructor(final String name, final byte[] bytes) {
+        final Class cls = AccessController.doPrivileged( new PrivilegedAction<Class>(){
+            public Class run() {
+                return define(name, bytes);
+            }
+        });
+
+        if (cls != null) {
+            try {
+                return cls.getConstructor(CallSite.class, MetaClassImpl.class, MetaMethod.class, Class[].class, Constructor.class);
+            } catch (NoSuchMethodException e) { //
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/GeneratedMetaMethod.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/GeneratedMetaMethod.java b/src/main/java/org/codehaus/groovy/reflection/GeneratedMetaMethod.java
new file mode 100644
index 0000000..3f830fd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/GeneratedMetaMethod.java
@@ -0,0 +1,240 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaMethod;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public abstract class GeneratedMetaMethod extends MetaMethod {
+    private final String name;
+    private final CachedClass declaringClass;
+    private final Class returnType;
+
+    public GeneratedMetaMethod(String name, CachedClass declaringClass, Class returnType, Class[] parameters) {
+        this.name = name;
+        this.declaringClass = declaringClass;
+        this.returnType = returnType;
+        nativeParamTypes = parameters;
+    }
+
+    public int getModifiers() {
+        return Modifier.PUBLIC;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Class getReturnType() {
+        return returnType;
+    }
+
+    public CachedClass getDeclaringClass() {
+        return declaringClass;
+    }
+
+    public static class Proxy extends GeneratedMetaMethod {
+        private volatile MetaMethod proxy;
+        private final String className;
+
+        public Proxy(String className, String name, CachedClass declaringClass, Class returnType, Class[] parameters) {
+            super(name, declaringClass, returnType, parameters);
+            this.className = className;
+        }
+
+        @Override
+        public boolean isValidMethod(Class[] arguments) {
+            return proxy().isValidMethod(arguments);
+        }
+
+        @Override
+        public Object doMethodInvoke(Object object, Object[] argumentArray) {
+            return proxy().doMethodInvoke(object, argumentArray);
+        }
+
+        public Object invoke(Object object, Object[] arguments) {
+            return proxy().invoke(object, arguments);
+        }
+
+        public final MetaMethod proxy() {
+            if (proxy == null) {
+                synchronized(this) {
+                    if (proxy == null) createProxy();
+                }
+            }
+            return proxy;
+        }
+
+        private void createProxy() {
+            try {
+                Class<?> aClass = getClass().getClassLoader().loadClass(className.replace('/', '.'));
+                Constructor<?> constructor = aClass.getConstructor(String.class, CachedClass.class, Class.class, Class[].class);
+                proxy = (MetaMethod) constructor.newInstance(getName(), getDeclaringClass(), getReturnType(), getNativeParameterTypes());
+            } catch (Throwable t) {
+                t.printStackTrace();
+                throw new GroovyRuntimeException("Failed to create DGM method proxy : " + t, t);
+            }
+        }
+    }
+
+    public static class DgmMethodRecord implements Serializable {
+        private static final long serialVersionUID = -5639988016452884450L;
+        public String className;
+        public String methodName;
+        public Class returnType;
+        public Class[] parameters;
+
+        private static final Class[] PRIMITIVE_CLASSES = {
+                Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
+                Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
+
+                boolean[].class, char[].class, byte[].class, short[].class,
+                int[].class, long[].class, double[].class, float[].class,
+
+                Object[].class, String[].class, Class[].class, Byte[].class, CharSequence[].class,
+        };
+
+        public static void saveDgmInfo(List<DgmMethodRecord> records, String file) throws IOException {
+            DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
+            Map<String, Integer> classes = new LinkedHashMap<String, Integer>();
+
+            int nextClassId = 0;
+            for (Class primitive : PRIMITIVE_CLASSES) {
+                classes.put(primitive.getName(), nextClassId++);
+            }
+
+            for (DgmMethodRecord record : records) {
+                String name = record.returnType.getName();
+                Integer id = classes.get(name);
+                if (id == null) {
+                    id = nextClassId++;
+                    classes.put(name, id);
+                }
+
+                for (int i = 0; i < record.parameters.length; i++) {
+                    name = record.parameters[i].getName();
+                    id = classes.get(name);
+                    if (id == null) {
+                        id = nextClassId++;
+                        classes.put(name, id);
+                    }
+                }
+            }
+
+            for (Map.Entry<String, Integer> stringIntegerEntry : classes.entrySet()) {
+                out.writeUTF(stringIntegerEntry.getKey());
+                out.writeInt(stringIntegerEntry.getValue());
+            }
+            out.writeUTF("");
+
+            out.writeInt(records.size());
+            for (DgmMethodRecord record : records) {
+                out.writeUTF(record.className);
+                out.writeUTF(record.methodName);
+                out.writeInt(classes.get(record.returnType.getName()));
+
+                out.writeInt(record.parameters.length);
+                for (int i = 0; i < record.parameters.length; i++) {
+                    Integer key = classes.get(record.parameters[i].getName());
+                    out.writeInt(key);
+                }
+            }
+            out.close();
+        }
+
+        public static List<DgmMethodRecord> loadDgmInfo() throws IOException {
+
+            ClassLoader loader = DgmMethodRecord.class.getClassLoader();
+            DataInputStream in = new DataInputStream(new BufferedInputStream(loader.getResourceAsStream("META-INF/dgminfo")));
+
+            Map<Integer, Class> classes = new HashMap<Integer, Class>();
+            for (int i = 0; i < PRIMITIVE_CLASSES.length; i++) {
+                classes.put(i, PRIMITIVE_CLASSES[i]);
+            }
+
+            int skip = 0;
+            for (; ; ) {
+                String name = in.readUTF();
+                if (name.length() == 0)
+                    break;
+
+                int key = in.readInt();
+
+                if (skip++ < PRIMITIVE_CLASSES.length)
+                    continue;
+
+                Class cls = null;
+                try {
+                    cls = loader.loadClass(name);
+                } catch (ClassNotFoundException e) {
+                    // under certain restrictive environments, loading certain classes may be forbidden
+                    // and could yield a ClassNotFoundException (Google App Engine)
+                    continue;
+                }
+                classes.put(key, cls);
+            }
+
+            int size = in.readInt();
+            List<DgmMethodRecord> res = new ArrayList<DgmMethodRecord>(size);
+            for (int i = 0; i != size; ++i) {
+                boolean skipRecord = false;
+                DgmMethodRecord record = new DgmMethodRecord();
+                record.className = in.readUTF();
+                record.methodName = in.readUTF();
+                record.returnType = classes.get(in.readInt());
+
+                if (record.returnType == null) {
+                    skipRecord = true;
+                }
+
+                int psize = in.readInt();
+                record.parameters = new Class[psize];
+                for (int j = 0; j < record.parameters.length; j++) {
+                    record.parameters[j] = classes.get(in.readInt());
+
+                    if (record.parameters[j] == null) {
+                        skipRecord = true;
+                    }
+                }
+                if (!skipRecord) {
+                    res.add(record);
+                }
+            }
+
+            in.close();
+
+            return res;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/GroovyClassValue.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValue.java b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValue.java
new file mode 100644
index 0000000..909f9b1
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValue.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.reflection;
+
+/** Abstraction for Java version dependent ClassValue implementations.
+ * @see java.lang.ClassValue
+ *
+ * @param <T>
+ */
+public interface GroovyClassValue<T> {
+	
+	interface ComputeValue<T>{
+		T computeValue(Class<?> type);
+	}
+	
+	T get(Class<?> type);
+	
+	void remove(Class<?> type);
+	
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
new file mode 100644
index 0000000..c367791
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
@@ -0,0 +1,42 @@
+/*
+ *  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.reflection;
+
+import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue;
+import org.codehaus.groovy.reflection.v7.GroovyClassValueJava7;
+
+class GroovyClassValueFactory {
+	/**
+	 * This flag is introduced as a (hopefully) temporary workaround for a JVM bug, that is to say that using
+	 * ClassValue prevents the classes and classloaders from being unloaded.
+	 * See https://bugs.openjdk.java.net/browse/JDK-8136353
+	 * This issue does not exist on IBM Java (J9) so use ClassValue by default on that JVM.
+	 */
+	private static final boolean USE_CLASSVALUE;
+	static {
+        String isJ9 = "IBM J9 VM".equals(System.getProperty("java.vm.name")) ? "true" : "false";
+        USE_CLASSVALUE = Boolean.valueOf(System.getProperty("groovy.use.classvalue", isJ9));
+    }
+
+	public static <T> GroovyClassValue<T> createGroovyClassValue(ComputeValue<T> computeValue) {
+		return (USE_CLASSVALUE)
+                ? new GroovyClassValueJava7<>(computeValue)
+                : new GroovyClassValuePreJava7<>(computeValue);
+	}
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
new file mode 100644
index 0000000..56ad0c1
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
@@ -0,0 +1,104 @@
+/*
+ *  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.reflection;
+
+import org.codehaus.groovy.util.Finalizable;
+import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ReferenceBundle;
+
+/** Approximation of Java 7's {@link java.lang.ClassValue} that works on earlier versions of Java.
+ * Note that this implementation isn't as good at Java 7's; it doesn't allow for some GC'ing that Java 7 would allow.
+ * But, it's good enough for our use.
+ *
+ * @param <T>
+ */
+class GroovyClassValuePreJava7<T> implements GroovyClassValue<T> {
+	private static final ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
+
+	private class EntryWithValue extends ManagedConcurrentMap.EntryWithValue<Class<?>,T>{
+
+		public EntryWithValue(GroovyClassValuePreJava7Segment segment, Class<?> key, int hash) {
+			super(weakBundle, segment, key, hash, computeValue.computeValue(key));
+		}
+
+		@Override
+		public void setValue(T value) {
+			if(value!=null) super.setValue(value);
+		}
+
+		@Override
+		public void finalizeReference() {
+			T value = getValue();
+			if (value instanceof Finalizable) {
+				((Finalizable) value).finalizeReference();
+			}
+			super.finalizeReference();
+		}
+	}
+
+	private class GroovyClassValuePreJava7Segment extends ManagedConcurrentMap.Segment<Class<?>,T> {
+
+		GroovyClassValuePreJava7Segment(ReferenceBundle bundle, int initialCapacity) {
+			super(bundle, initialCapacity);
+		}
+
+		@Override
+		protected EntryWithValue createEntry(Class<?> key, int hash,
+				T unused) {
+			return new EntryWithValue(this, key, hash);
+		}
+	}
+
+	private class GroovyClassValuePreJava7Map extends ManagedConcurrentMap<Class<?>,T> {
+
+		public GroovyClassValuePreJava7Map() {
+			super(weakBundle);
+		}
+
+		@Override
+		protected GroovyClassValuePreJava7Segment createSegment(Object segmentInfo, int cap) {
+			ReferenceBundle bundle = (ReferenceBundle) segmentInfo;
+			if (bundle==null) throw new IllegalArgumentException("bundle must not be null ");
+			return new GroovyClassValuePreJava7Segment(bundle, cap);
+		}
+
+	}
+
+	private final ComputeValue<T> computeValue;
+
+	private final GroovyClassValuePreJava7Map map = new GroovyClassValuePreJava7Map();
+
+	public GroovyClassValuePreJava7(ComputeValue<T> computeValue){
+		this.computeValue = computeValue;
+	}
+
+	@Override
+	public T get(Class<?> type) {
+		// the value isn't use in the getOrPut call - see the EntryWithValue constructor above
+		T value = ((EntryWithValue)map.getOrPut(type, null)).getValue();
+		//all entries are guaranteed to be EntryWithValue. Value can only be null if computeValue returns null
+		return value;
+	}
+
+	@Override
+	public void remove(Class<?> type) {
+		map.remove(type);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java b/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
new file mode 100644
index 0000000..4dfa083
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/MixinInMetaClass.java
@@ -0,0 +1,206 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.DelegatingMetaClass;
+import groovy.lang.ExpandoMetaClass;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaMethod;
+import groovy.lang.MetaProperty;
+import org.codehaus.groovy.runtime.HandleMetaClass;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.metaclass.MixedInMetaClass;
+import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaMethod;
+import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaProperty;
+import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod;
+import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ReferenceBundle;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MixinInMetaClass extends ManagedConcurrentMap {
+    final ExpandoMetaClass emc;
+    final CachedClass mixinClass;
+    final CachedConstructor constructor;
+
+    private static final ReferenceBundle softBundle = ReferenceBundle.getSoftBundle();
+
+    public MixinInMetaClass(ExpandoMetaClass emc, CachedClass mixinClass) {
+        super(softBundle);
+        this.emc = emc;
+        this.mixinClass = mixinClass;
+
+        constructor = findDefaultConstructor(mixinClass);
+        emc.addMixinClass(this);
+    }
+
+    private static CachedConstructor findDefaultConstructor(CachedClass mixinClass) {
+        for (CachedConstructor constr : mixinClass.getConstructors()) {
+            if (!Modifier.isPublic(constr.getModifiers()))
+                continue;
+
+            CachedClass[] classes = constr.getParameterTypes();
+            if (classes.length == 0)
+                return constr;
+        }
+
+        throw new GroovyRuntimeException("No default constructor for class " + mixinClass.getName() + "! Can't be mixed in.");
+    }
+
+    public synchronized Object getMixinInstance(Object object) {
+        Object mixinInstance = get(object);
+        if (mixinInstance == null) {
+            mixinInstance = constructor.invoke(MetaClassHelper.EMPTY_ARRAY);
+            new MixedInMetaClass(mixinInstance, object);
+            put(object, mixinInstance);
+        }
+        return mixinInstance;
+    }
+
+    public synchronized void setMixinInstance(Object object, Object mixinInstance) {
+        if (mixinInstance == null) {
+            remove(object);
+        } else {
+            put(object, mixinInstance);
+        }
+    }
+
+    public CachedClass getInstanceClass() {
+        return emc.getTheCachedClass();
+    }
+
+    public CachedClass getMixinClass() {
+        return mixinClass;
+    }
+
+    public static void mixinClassesToMetaClass(MetaClass self, List<Class> categoryClasses) {
+        final Class selfClass = self.getTheClass();
+
+        if (self instanceof HandleMetaClass) {
+            self = (MetaClass) ((HandleMetaClass) self).replaceDelegate();
+        }
+
+        if (!(self instanceof ExpandoMetaClass)) {
+            if (self instanceof DelegatingMetaClass && ((DelegatingMetaClass) self).getAdaptee() instanceof ExpandoMetaClass) {
+                self = ((DelegatingMetaClass) self).getAdaptee();
+            } else {
+                throw new GroovyRuntimeException("Can't mixin methods to meta class: " + self);
+            }
+        }
+
+        ExpandoMetaClass mc = (ExpandoMetaClass) self;
+
+        List<MetaMethod> arr = new ArrayList<MetaMethod>();
+        for (Class categoryClass : categoryClasses) {
+
+            final CachedClass cachedCategoryClass = ReflectionCache.getCachedClass(categoryClass);
+            final MixinInMetaClass mixin = new MixinInMetaClass(mc, cachedCategoryClass);
+
+            final MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(categoryClass);
+            final List<MetaProperty> propList = metaClass.getProperties();
+            for (MetaProperty prop : propList)
+                if (self.getMetaProperty(prop.getName()) == null) {
+                    mc.registerBeanProperty(prop.getName(), new MixinInstanceMetaProperty(prop, mixin));
+                }
+
+            for (MetaProperty prop : cachedCategoryClass.getFields())
+                if (self.getMetaProperty(prop.getName()) == null) {
+                    mc.registerBeanProperty(prop.getName(), new MixinInstanceMetaProperty(prop, mixin));
+                }
+
+            for (MetaMethod method : metaClass.getMethods()) {
+                final int mod = method.getModifiers();
+
+                if (!Modifier.isPublic(mod))
+                    continue;
+
+                if (method instanceof CachedMethod && ((CachedMethod) method).getCachedMethod().isSynthetic())
+                    continue;
+
+                if (Modifier.isStatic(mod)) {
+                    if (method instanceof CachedMethod)
+                        staticMethod(self, arr, (CachedMethod) method);
+                } else if (method.getDeclaringClass().getTheClass() != Object.class || method.getName().equals("toString")) {
+//                    if (self.pickMethod(method.getName(), method.getNativeParameterTypes()) == null) {
+                    final MixinInstanceMetaMethod metaMethod = new MixinInstanceMetaMethod(method, mixin);
+                    arr.add(metaMethod);
+//                    }
+                }
+            }
+        }
+
+        for (Object res : arr) {
+            final MetaMethod metaMethod = (MetaMethod) res;
+            if (metaMethod.getDeclaringClass().isAssignableFrom(selfClass))
+                mc.registerInstanceMethod(metaMethod);
+            else {
+                mc.registerSubclassInstanceMethod(metaMethod);
+            }
+        }
+    }
+
+    private static void staticMethod(final MetaClass self, List<MetaMethod> arr, final CachedMethod method) {
+        CachedClass[] paramTypes = method.getParameterTypes();
+
+        if (paramTypes.length == 0)
+            return;
+
+        NewInstanceMetaMethod metaMethod;
+        if (paramTypes[0].isAssignableFrom(self.getTheClass())) {
+            if (paramTypes[0].getTheClass() == self.getTheClass())
+                metaMethod = new NewInstanceMetaMethod(method);
+            else
+                metaMethod = new NewInstanceMetaMethod(method) {
+                    public CachedClass getDeclaringClass() {
+                        return ReflectionCache.getCachedClass(self.getTheClass());
+                    }
+                };
+            arr.add(metaMethod);
+        } else {
+            if (self.getTheClass().isAssignableFrom(paramTypes[0].getTheClass())) {
+                metaMethod = new NewInstanceMetaMethod(method);
+                arr.add(metaMethod);
+            }
+        }
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof MixinInMetaClass)) return false;
+        if (!super.equals(o)) return false;
+
+        MixinInMetaClass that = (MixinInMetaClass) o;
+
+        if (mixinClass != null ? !mixinClass.equals(that.mixinClass) : that.mixinClass != null) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (emc != null ? emc.hashCode() : 0);
+        result = 31 * result + (mixinClass != null ? mixinClass.hashCode() : 0);
+        result = 31 * result + (constructor != null ? constructor.hashCode() : 0);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java b/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java
new file mode 100644
index 0000000..4c5d5fa
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java
@@ -0,0 +1,385 @@
+/*
+ *  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.reflection;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.wrappers.Wrapper;
+
+import java.lang.reflect.Array;
+
+public class ParameterTypes {
+    private final static Class[] NO_PARAMETERS = new Class[0];
+
+    protected volatile Class[] nativeParamTypes;
+    protected volatile CachedClass[] parameterTypes;
+
+    protected boolean isVargsMethod;
+
+    public ParameterTypes() {
+    }
+
+    public ParameterTypes(Class pt[]) {
+        nativeParamTypes = pt;
+    }
+
+    public ParameterTypes(String pt[]) {
+        nativeParamTypes = new Class[pt.length];
+        for (int i = 0; i != pt.length; ++i) {
+            try {
+                nativeParamTypes[i] = Class.forName(pt[i]);
+            } catch (ClassNotFoundException e) {
+                NoClassDefFoundError err = new NoClassDefFoundError();
+                err.initCause(e);
+                throw err;
+            }
+        }
+    }
+
+    public ParameterTypes(CachedClass[] parameterTypes) {
+        setParametersTypes(parameterTypes);
+    }
+
+    protected final void setParametersTypes(CachedClass[] pt) {
+        this.parameterTypes = pt;
+        isVargsMethod = pt.length > 0 && pt[pt.length - 1].isArray;
+    }
+
+    public CachedClass[] getParameterTypes() {
+        if (parameterTypes == null) {
+            getParametersTypes0();
+        }
+
+        return parameterTypes;
+    }
+
+    private synchronized void getParametersTypes0() {
+        if (parameterTypes != null)
+            return;
+
+        Class[] npt = nativeParamTypes == null ? getPT() : nativeParamTypes;
+        if (npt.length == 0) {
+            nativeParamTypes = NO_PARAMETERS;
+            setParametersTypes(CachedClass.EMPTY_ARRAY);
+        } else {
+
+            CachedClass[] pt = new CachedClass[npt.length];
+            for (int i = 0; i != npt.length; ++i)
+                pt[i] = ReflectionCache.getCachedClass(npt[i]);
+
+            nativeParamTypes = npt;
+            setParametersTypes(pt);
+        }
+    }
+
+    public Class[] getNativeParameterTypes() {
+        if (nativeParamTypes == null) {
+            getNativeParameterTypes0();
+        }
+        return nativeParamTypes;
+    }
+
+    private synchronized void getNativeParameterTypes0() {
+        if (nativeParamTypes != null)
+            return;
+
+        Class[] npt;
+        if (parameterTypes != null) {
+            npt = new Class[parameterTypes.length];
+            for (int i = 0; i != parameterTypes.length; ++i) {
+                npt[i] = parameterTypes[i].getTheClass();
+            }
+        } else
+            npt = getPT();
+        nativeParamTypes = npt;
+    }
+
+    protected Class[] getPT() {
+        throw new UnsupportedOperationException(getClass().getName());
+    }
+
+    public boolean isVargsMethod() {
+        return isVargsMethod;
+    }
+
+    public boolean isVargsMethod(Object[] arguments) {
+        // Uncomment if at some point this method can be called before parameterTypes initialized
+        // getParameterTypes();
+        if (!isVargsMethod)
+            return false;
+
+        final int lenMinus1 = parameterTypes.length - 1;
+        // -1 because the varg part is optional
+        if (lenMinus1 == arguments.length) return true;
+        if (lenMinus1 > arguments.length) return false;
+        if (arguments.length > parameterTypes.length) return true;
+
+        // only case left is arguments.length == parameterTypes.length
+        Object last = arguments[arguments.length - 1];
+        if (last == null) return true;
+        Class clazz = last.getClass();
+        return !clazz.equals(parameterTypes[lenMinus1].getTheClass());
+
+    }
+
+    public final Object[] coerceArgumentsToClasses(Object[] argumentArray) {
+        // Uncomment if at some point this method can be called before parameterTypes initialized
+        // getParameterTypes();
+        argumentArray = correctArguments(argumentArray);
+
+        final CachedClass[] pt = parameterTypes;
+        final int len = argumentArray.length;
+        for (int i = 0; i < len; i++) {
+            final Object argument = argumentArray[i];
+            if (argument != null) {
+                argumentArray[i] = pt[i].coerceArgument(argument);
+            }
+        }
+        return argumentArray;
+    }
+
+    public Object[] correctArguments(Object[] argumentArray) {
+        // correct argumentArray's length
+        if (argumentArray == null) {
+            return MetaClassHelper.EMPTY_ARRAY;
+        }
+
+        final CachedClass[] pt = getParameterTypes();
+        if (pt.length == 1 && argumentArray.length == 0) {
+            if (isVargsMethod)
+                return new Object[]{Array.newInstance(pt[0].getTheClass().getComponentType(), 0)};
+            else
+                return MetaClassHelper.ARRAY_WITH_NULL;
+        }
+
+        if (isVargsMethod && isVargsMethod(argumentArray)) {
+            return fitToVargs(argumentArray, pt);
+        }
+
+        return argumentArray;
+    }
+
+    /**
+     * this method is called when the number of arguments to a method is greater than 1
+     * and if the method is a vargs method. This method will then transform the given
+     * arguments to make the method callable
+     *
+     * @param argumentArrayOrig the arguments used to call the method
+     * @param paramTypes        the types of the parameters the method takes
+     */
+    private static Object[] fitToVargs(Object[] argumentArrayOrig, CachedClass[] paramTypes) {
+        Class vargsClassOrig = paramTypes[paramTypes.length - 1].getTheClass().getComponentType();
+        Class vargsClass = ReflectionCache.autoboxType(vargsClassOrig);
+        Object[] argumentArray = argumentArrayOrig.clone();
+        MetaClassHelper.unwrap(argumentArray);
+
+        if (argumentArray.length == paramTypes.length - 1) {
+            // the vargs argument is missing, so fill it with an empty array
+            Object[] newArgs = new Object[paramTypes.length];
+            System.arraycopy(argumentArray, 0, newArgs, 0, argumentArray.length);
+            Object vargs = Array.newInstance(vargsClass, 0);
+            newArgs[newArgs.length - 1] = vargs;
+            return newArgs;
+        } else if (argumentArray.length == paramTypes.length) {
+            // the number of arguments is correct, but if the last argument
+            // is no array we have to wrap it in a array. If the last argument
+            // is null, then we don't have to do anything
+            Object lastArgument = argumentArray[argumentArray.length - 1];
+            if (lastArgument != null && !lastArgument.getClass().isArray()) {
+                // no array so wrap it
+                Object wrapped = makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
+                Object[] newArgs = new Object[paramTypes.length];
+                System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
+                newArgs[newArgs.length - 1] = wrapped;
+                return newArgs;
+            } else {
+                // we may have to box the argument!
+                return argumentArray;
+            }
+        } else if (argumentArray.length > paramTypes.length) {
+            // the number of arguments is too big, wrap all exceeding elements
+            // in an array, but keep the old elements that are no vargs
+            Object[] newArgs = new Object[paramTypes.length];
+            // copy arguments that are not a varg
+            System.arraycopy(argumentArray, 0, newArgs, 0, paramTypes.length - 1);
+            // create a new array for the vargs and copy them
+            Object vargs = makeCommonArray(argumentArray, paramTypes.length - 1, vargsClass);
+            newArgs[newArgs.length - 1] = vargs;
+            return newArgs;
+        } else {
+            throw new GroovyBugError("trying to call a vargs method without enough arguments");
+        }
+    }
+
+    private static Object makeCommonArray(Object[] arguments, int offset, Class baseClass) {
+        Object[] result = (Object[]) Array.newInstance(baseClass, arguments.length - offset);
+        for (int i = offset; i < arguments.length; i++) {
+            Object v = arguments[i];
+            v = DefaultTypeTransformation.castToType(v, baseClass);
+            result[i - offset] = v;
+        }
+        return result;
+    }
+
+    public boolean isValidMethod(Class[] arguments) {
+        if (arguments == null) return true;
+
+        final int size = arguments.length;
+        CachedClass[] pt = getParameterTypes();
+        final int paramMinus1 = pt.length - 1;
+
+        if (isVargsMethod && size >= paramMinus1)
+            return isValidVarargsMethod(arguments, size, pt, paramMinus1);
+        else if (pt.length == size)
+            return isValidExactMethod(arguments, pt);
+        else if (pt.length == 1 && size == 0 && !pt[0].isPrimitive)
+            return true;
+        return false;
+    }
+
+    private static boolean isValidExactMethod(Class[] arguments, CachedClass[] pt) {
+        // lets check the parameter types match
+        int size = pt.length;
+        for (int i = 0; i < size; i++) {
+            if (!pt[i].isAssignableFrom(arguments[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean isValidExactMethod(Object[] args) {
+        // lets check the parameter types match
+        getParametersTypes0();
+        int size = args.length;
+        if (size != parameterTypes.length)
+            return false;
+
+        for (int i = 0; i < size; i++) {
+            if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i].getClass())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public boolean isValidExactMethod(Class[] args) {
+        // lets check the parameter types match
+        getParametersTypes0();
+        int size = args.length;
+        if (size != parameterTypes.length)
+            return false;
+
+        for (int i = 0; i < size; i++) {
+            if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static boolean testComponentAssignable(Class toTestAgainst, Class toTest) {
+        Class component = toTest.getComponentType();
+        if (component == null) return false;
+        return MetaClassHelper.isAssignableFrom(toTestAgainst, component);
+    }
+
+    private static boolean isValidVarargsMethod(Class[] arguments, int size, CachedClass[] pt, int paramMinus1) {
+        // first check normal number of parameters
+        for (int i = 0; i < paramMinus1; i++) {
+            if (pt[i].isAssignableFrom(arguments[i])) continue;
+            return false;
+        }
+
+        // check direct match
+        CachedClass varg = pt[paramMinus1];
+        Class clazz = varg.getTheClass().getComponentType();
+        if (size == pt.length &&
+                (varg.isAssignableFrom(arguments[paramMinus1]) ||
+                        testComponentAssignable(clazz, arguments[paramMinus1]))) {
+            return true;
+        }
+
+        // check varged
+        for (int i = paramMinus1; i < size; i++) {
+            if (MetaClassHelper.isAssignableFrom(clazz, arguments[i])) continue;
+            return false;
+        }
+        return true;
+    }
+
+    public boolean isValidMethod(Object[] arguments) {
+        if (arguments == null) return true;
+
+        final int size = arguments.length;
+        CachedClass[] paramTypes = getParameterTypes();
+        final int paramMinus1 = paramTypes.length - 1;
+
+        if (size >= paramMinus1 && paramTypes.length > 0 &&
+                paramTypes[(paramMinus1)].isArray) {
+            // first check normal number of parameters
+            for (int i = 0; i < paramMinus1; i++) {
+                if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
+                return false;
+            }
+
+
+            // check direct match
+            CachedClass varg = paramTypes[paramMinus1];
+            Class clazz = varg.getTheClass().getComponentType();
+            if (size == paramTypes.length &&
+                    (varg.isAssignableFrom(getArgClass(arguments[paramMinus1])) ||
+                            testComponentAssignable(clazz, getArgClass(arguments[paramMinus1])))) {
+                return true;
+            }
+
+
+            // check varged
+            for (int i = paramMinus1; i < size; i++) {
+                if (MetaClassHelper.isAssignableFrom(clazz, getArgClass(arguments[i]))) continue;
+                return false;
+            }
+            return true;
+        } else if (paramTypes.length == size) {
+            // lets check the parameter types match
+            for (int i = 0; i < size; i++) {
+                if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
+                return false;
+            }
+            return true;
+        } else if (paramTypes.length == 1 && size == 0 && !paramTypes[0].isPrimitive) {
+            return true;
+        }
+        return false;
+    }
+
+    private static Class getArgClass(Object arg) {
+        Class cls;
+        if (arg == null) {
+            cls = null;
+        } else {
+            if (arg instanceof Wrapper) {
+                cls = ((Wrapper) arg).getType();
+            } else
+                cls = arg.getClass();
+        }
+        return cls;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java b/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java
new file mode 100644
index 0000000..372a0a5
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/ReflectionCache.java
@@ -0,0 +1,113 @@
+/*
+ *  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.reflection;
+
+import org.codehaus.groovy.util.TripleKeyHashMap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class ReflectionCache {
+    private static final Map primitiveTypesMap = new HashMap();
+
+    static {
+        primitiveTypesMap.put(byte.class, Byte.class);
+        primitiveTypesMap.put(boolean.class, Boolean.class);
+        primitiveTypesMap.put(char.class, Character.class);
+        primitiveTypesMap.put(double.class, Double.class);
+        primitiveTypesMap.put(float.class, Float.class);
+        primitiveTypesMap.put(int.class, Integer.class);
+        primitiveTypesMap.put(long.class, Long.class);
+        primitiveTypesMap.put(short.class, Short.class);
+    }
+
+    public static Class autoboxType(Class type) {
+        final Class res = (Class) primitiveTypesMap.get(type);
+        return res == null ? type : res;
+    }
+
+    static TripleKeyHashMap mopNames = new TripleKeyHashMap();
+
+    public static String getMOPMethodName(CachedClass declaringClass, String name, boolean useThis) {
+        TripleKeyHashMap.Entry mopNameEntry = mopNames.getOrPut(declaringClass, name, Boolean.valueOf(useThis));
+        if (mopNameEntry.value == null) {
+            mopNameEntry.value = new StringBuffer().append(useThis ? "this$" : "super$").append(declaringClass.getSuperClassDistance()).append("$").append(name).toString();
+        }
+        return (String) mopNameEntry.value;
+    }
+    
+    static final CachedClass STRING_CLASS = getCachedClass(String.class);
+
+    public static boolean isArray(Class klazz) {
+      return klazz.getName().charAt(0) == '[';
+    }
+
+    static void setAssignableFrom(Class klazz, Class aClass) {
+//        SoftDoubleKeyMap.Entry val = (SoftDoubleKeyMap.Entry) assignableMap.getOrPut(klazz, aClass, null);
+//        if (val.getValue() == null) {
+//            val.setValue(Boolean.TRUE);
+//        }
+    }
+
+    public static boolean isAssignableFrom(Class klazz, Class aClass) {
+        if (klazz == aClass)
+          return true;
+
+//        SoftDoubleKeyMap.Entry val = (SoftDoubleKeyMap.Entry) assignableMap.getOrPut(klazz, aClass, null);
+//        if (val.getValue() == null) {
+//            val.setValue(Boolean.valueOf(klazz.isAssignableFrom(aClass)));
+//        }
+//        return ((Boolean)val.getValue()).booleanValue();
+        return klazz.isAssignableFrom(aClass);
+    }
+
+    static boolean arrayContentsEq(Object[] a1, Object[] a2) {
+        if (a1 == null) {
+            return a2 == null || a2.length == 0;
+        }
+
+        if (a2 == null) {
+            return a1.length == 0;
+        }
+
+        if (a1.length != a2.length) {
+            return false;
+        }
+
+        for (int i = 0; i < a1.length; i++) {
+            if (a1[i] != a2[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    public static final CachedClass OBJECT_CLASS = getCachedClass(Object.class);
+
+    public static final CachedClass OBJECT_ARRAY_CLASS = getCachedClass(Object[].class);
+
+    public static CachedClass getCachedClass(Class klazz) {
+        if (klazz == null)
+          return null;
+        
+        return ClassInfo.getClassInfo(klazz).getCachedClass ();
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
new file mode 100644
index 0000000..1863c1f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -0,0 +1,611 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.Types;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static java.lang.reflect.Modifier.isFinal;
+
+/**
+ * goes through an AST and initializes the scopes
+ */
+public class VariableScopeVisitor extends ClassCodeVisitorSupport {
+
+    private VariableScope currentScope = null;
+    private final VariableScope headScope = new VariableScope();
+    private ClassNode currentClass = null;
+    private final SourceUnit source;
+    private boolean isSpecialConstructorCall = false;
+    private boolean inConstructor = false;
+    private final boolean recurseInnerClasses;
+
+    private final LinkedList stateStack = new LinkedList();
+
+    private class StateStackElement {
+        final VariableScope scope;
+        final ClassNode clazz;
+        final boolean inConstructor;
+
+        StateStackElement() {
+            scope = VariableScopeVisitor.this.currentScope;
+            clazz = VariableScopeVisitor.this.currentClass;
+            inConstructor = VariableScopeVisitor.this.inConstructor;
+        }
+    }
+
+    public VariableScopeVisitor(SourceUnit source, boolean recurseInnerClasses) {
+        this.source = source;
+        currentScope = headScope;
+        this.recurseInnerClasses = recurseInnerClasses;
+    }
+
+
+    public VariableScopeVisitor(SourceUnit source) {
+        this(source, false);
+    }
+
+    // ------------------------------
+    // helper methods
+    //------------------------------
+
+    private void pushState(boolean isStatic) {
+        stateStack.add(new StateStackElement());
+        currentScope = new VariableScope(currentScope);
+        currentScope.setInStaticContext(isStatic);
+    }
+
+    private void pushState() {
+        pushState(currentScope.isInStaticContext());
+    }
+
+    private void popState() {
+        StateStackElement element = (StateStackElement) stateStack.removeLast();
+        currentScope = element.scope;
+        currentClass = element.clazz;
+        inConstructor = element.inConstructor;
+    }
+
+    private void declare(Parameter[] parameters, ASTNode node) {
+        for (Parameter parameter : parameters) {
+            if (parameter.hasInitialExpression()) {
+                parameter.getInitialExpression().visit(this);
+            }
+            declare(parameter, node);
+        }
+    }
+
+    private void declare(VariableExpression vex) {
+        vex.setInStaticContext(currentScope.isInStaticContext());
+        declare(vex, vex);
+        vex.setAccessedVariable(vex);
+    }
+
+    private void declare(Variable var, ASTNode expr) {
+        String scopeType = "scope";
+        String variableType = "variable";
+
+        if (expr.getClass() == FieldNode.class) {
+            scopeType = "class";
+            variableType = "field";
+        } else if (expr.getClass() == PropertyNode.class) {
+            scopeType = "class";
+            variableType = "property";
+        }
+
+        StringBuilder msg = new StringBuilder();
+        msg.append("The current ").append(scopeType);
+        msg.append(" already contains a ").append(variableType);
+        msg.append(" of the name ").append(var.getName());
+
+        if (currentScope.getDeclaredVariable(var.getName()) != null) {
+            addError(msg.toString(), expr);
+            return;
+        }
+
+        for (VariableScope scope = currentScope.getParent(); scope != null; scope = scope.getParent()) {
+            // if we are in a class and no variable is declared until
+            // now, then we can break the loop, because we are allowed
+            // to declare a variable of the same name as a class member
+            if (scope.getClassScope() != null) break;
+
+            if (scope.getDeclaredVariable(var.getName()) != null) {
+                // variable already declared
+                addError(msg.toString(), expr);
+                break;
+            }
+        }
+        // declare the variable even if there was an error to allow more checks
+        currentScope.putDeclaredVariable(var);
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    private Variable findClassMember(ClassNode cn, String name) {
+        if (cn == null) return null;
+        if (cn.isScript()) {
+            return new DynamicVariable(name, false);
+        }
+
+        for (FieldNode fn : cn.getFields()) {
+            if (fn.getName().equals(name)) return fn;
+        }
+
+        for (MethodNode mn : cn.getMethods()) {
+            String pName = getPropertyName(mn);
+            if (pName != null && pName.equals(name))
+                return new PropertyNode(pName, mn.getModifiers(), ClassHelper.OBJECT_TYPE, cn, null, null, null);
+        }
+
+        for (PropertyNode pn : cn.getProperties()) {
+            if (pn.getName().equals(name)) return pn;
+        }
+
+        Variable ret = findClassMember(cn.getSuperClass(), name);
+        if (ret != null) return ret;
+        return findClassMember(cn.getOuterClass(), name);
+    }
+
+    private static String getPropertyName(MethodNode m) {
+        String name = m.getName();
+        if (!(name.startsWith("set") || name.startsWith("get"))) return null;
+        String pname = name.substring(3);
+        if (pname.length() == 0) return null;
+        pname = java.beans.Introspector.decapitalize(pname);
+
+        if (name.startsWith("get") && (m.getReturnType() == ClassHelper.VOID_TYPE || m.getParameters().length != 0)) {
+            return null;
+        }
+        if (name.startsWith("set") && m.getParameters().length != 1) {
+            return null;
+        }
+        return pname;
+    }
+
+    // -------------------------------
+    // different Variable based checks
+    // -------------------------------
+
+    private Variable checkVariableNameForDeclaration(String name, Expression expression) {
+        if ("super".equals(name) || "this".equals(name)) return null;
+
+        VariableScope scope = currentScope;
+        Variable var = new DynamicVariable(name, currentScope.isInStaticContext());
+        Variable orig = var;
+        // try to find a declaration of a variable
+        boolean crossingStaticContext = false;
+        while (true) {
+            crossingStaticContext = crossingStaticContext || scope.isInStaticContext();
+            Variable var1;
+            var1 = scope.getDeclaredVariable(var.getName());
+
+            if (var1 != null) {
+                var = var1;
+                break;
+            }
+
+            var1 = scope.getReferencedLocalVariable(var.getName());
+            if (var1 != null) {
+                var = var1;
+                break;
+            }
+
+            var1 = scope.getReferencedClassVariable(var.getName());
+            if (var1 != null) {
+                var = var1;
+                break;
+            }
+
+            ClassNode classScope = scope.getClassScope();
+            if (classScope != null) {
+                Variable member = findClassMember(classScope, var.getName());
+                if (member != null) {
+                    boolean staticScope = crossingStaticContext || isSpecialConstructorCall;
+                    boolean staticMember = member.isInStaticContext();
+                    // We don't allow a static context (e.g. a static method) to access
+                    // a non-static variable (e.g. a non-static field).
+                    if (!(staticScope && !staticMember))
+                        var = member;
+                }
+                break;
+            }
+            scope = scope.getParent();
+        }
+        if (var == orig && crossingStaticContext) {
+            var = new DynamicVariable(var.getName(), true);
+        }
+
+        VariableScope end = scope;
+
+        scope = currentScope;
+        while (scope != end) {
+            if (end.isClassScope() ||
+                    (end.isReferencedClassVariable(name) && end.getDeclaredVariable(name) == null)) {
+                scope.putReferencedClassVariable(var);
+            } else {
+                //var.setClosureSharedVariable(var.isClosureSharedVariable() || inClosure);
+                scope.putReferencedLocalVariable(var);
+            }
+            scope = scope.getParent();
+        }
+
+        return var;
+    }
+
+    /**
+     * a property on "this", like this.x is transformed to a
+     * direct field access, so we need to check the
+     * static context here
+     *
+     * @param pe the property expression to check
+     */
+    private void checkPropertyOnExplicitThis(PropertyExpression pe) {
+        if (!currentScope.isInStaticContext()) return;
+        Expression object = pe.getObjectExpression();
+        if (!(object instanceof VariableExpression)) return;
+        VariableExpression ve = (VariableExpression) object;
+        if (!ve.getName().equals("this")) return;
+        String name = pe.getPropertyAsString();
+        if (name == null || name.equals("class")) return;
+        Variable member = findClassMember(currentClass, name);
+        if (member == null) return;
+        checkVariableContextAccess(member, pe);
+    }
+
+    private void checkVariableContextAccess(Variable v, Expression expr) {
+        if (v.isInStaticContext() || !currentScope.isInStaticContext()) return;
+
+        String msg = v.getName() +
+                " is declared in a dynamic context, but you tried to" +
+                " access it from a static context.";
+        addError(msg, expr);
+
+        // declare a static variable to be able to continue the check
+        DynamicVariable v2 = new DynamicVariable(v.getName(), currentScope.isInStaticContext());
+        currentScope.putDeclaredVariable(v2);
+    }
+
+    // ------------------------------
+    // code visit
+    // ------------------------------
+
+    public void visitBlockStatement(BlockStatement block) {
+        pushState();
+        block.setVariableScope(currentScope);
+        super.visitBlockStatement(block);
+        popState();
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        pushState();
+        forLoop.setVariableScope(currentScope);
+        Parameter p = forLoop.getVariable();
+        p.setInStaticContext(currentScope.isInStaticContext());
+        if (p != ForStatement.FOR_LOOP_DUMMY) declare(p, forLoop);
+        super.visitForLoop(forLoop);
+        popState();
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        ifElse.getBooleanExpression().visit(this);
+        pushState();
+        ifElse.getIfBlock().visit(this);
+        popState();
+        pushState();
+        ifElse.getElseBlock().visit(this);
+        popState();
+    }
+
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        visitAnnotations(expression);
+        // visit right side first to avoid the usage of a
+        // variable before its declaration
+        expression.getRightExpression().visit(this);
+
+        if (expression.isMultipleAssignmentDeclaration()) {
+            TupleExpression list = expression.getTupleExpression();
+            for (Expression e : list.getExpressions()) {
+                declare((VariableExpression) e);
+            }
+        } else {
+            declare(expression.getVariableExpression());
+        }
+    }
+
+    @Override
+    public void visitBinaryExpression(BinaryExpression be) {
+        super.visitBinaryExpression(be);
+
+        if (Types.isAssignment(be.getOperation().getType())) {
+            checkFinalFieldAccess(be.getLeftExpression());
+        }
+    }
+
+    private void checkFinalFieldAccess(Expression expression) {
+        // currently not looking for PropertyExpression: dealt with at runtime using ReadOnlyPropertyException
+        if (!(expression instanceof VariableExpression) && !(expression instanceof TupleExpression)) return;
+        if (expression instanceof TupleExpression) {
+            TupleExpression list = (TupleExpression) expression;
+            for (Expression e : list.getExpressions()) {
+                checkForFinal(expression, (VariableExpression) e);
+            }
+        } else {
+            checkForFinal(expression, (VariableExpression) expression);
+        }
+    }
+
+    // TODO handle local variables
+    private void checkForFinal(final Expression expression, VariableExpression ve) {
+        Variable v = ve.getAccessedVariable();
+        if (v != null) {
+            boolean isFinal = isFinal(v.getModifiers());
+            boolean isParameter = v instanceof Parameter;
+            if (isFinal && isParameter) {
+                addError("Cannot assign a value to final variable '" + v.getName() + "'", expression);
+            }
+        }
+    }
+
+    public void visitVariableExpression(VariableExpression expression) {
+        String name = expression.getName();
+        Variable v = checkVariableNameForDeclaration(name, expression);
+        if (v == null) return;
+        expression.setAccessedVariable(v);
+        checkVariableContextAccess(v, expression);
+    }
+
+    public void visitPropertyExpression(PropertyExpression expression) {
+        expression.getObjectExpression().visit(this);
+        expression.getProperty().visit(this);
+        checkPropertyOnExplicitThis(expression);
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        pushState();
+
+        expression.setVariableScope(currentScope);
+
+        if (expression.isParameterSpecified()) {
+            Parameter[] parameters = expression.getParameters();
+            for (Parameter parameter : parameters) {
+                parameter.setInStaticContext(currentScope.isInStaticContext());
+                if (parameter.hasInitialExpression()) {
+                    parameter.getInitialExpression().visit(this);
+                }
+                declare(parameter, expression);
+            }
+        } else if (expression.getParameters() != null) {
+            Parameter var = new Parameter(ClassHelper.OBJECT_TYPE, "it");
+            var.setInStaticContext(currentScope.isInStaticContext());
+            currentScope.putDeclaredVariable(var);
+        }
+
+        super.visitClosureExpression(expression);
+        markClosureSharedVariables();
+
+        popState();
+    }
+
+    private void markClosureSharedVariables() {
+        VariableScope scope = currentScope;
+        for (Iterator<Variable> it = scope.getReferencedLocalVariablesIterator(); it.hasNext(); ) {
+            it.next().setClosureSharedVariable(true);
+        }
+    }
+
+    public void visitCatchStatement(CatchStatement statement) {
+        pushState();
+        Parameter p = statement.getVariable();
+        p.setInStaticContext(currentScope.isInStaticContext());
+        declare(p, statement);
+        super.visitCatchStatement(statement);
+        popState();
+    }
+
+    public void visitFieldExpression(FieldExpression expression) {
+        String name = expression.getFieldName();
+        //TODO: change that to get the correct scope
+        Variable v = checkVariableNameForDeclaration(name, expression);
+        checkVariableContextAccess(v, expression);
+    }
+
+    // ------------------------------
+    // class visit
+    // ------------------------------
+
+    public void visitClass(ClassNode node) {
+        // AIC are already done, doing them here again will lead to wrong scopes
+        if (node instanceof InnerClassNode) {
+            InnerClassNode in = (InnerClassNode) node;
+            if (in.isAnonymous() && !in.isEnum()) return;
+        }
+
+        pushState();
+
+        prepareVisit(node);
+
+        super.visitClass(node);
+        if (recurseInnerClasses) {
+            Iterator<InnerClassNode> innerClasses = node.getInnerClasses();
+            while (innerClasses.hasNext()) {
+                visitClass(innerClasses.next());
+            }
+        }
+        popState();
+    }
+
+    /**
+     * Setup the current class node context.
+     * @param node
+     */
+    public void prepareVisit(ClassNode node) {
+        currentClass = node;
+        currentScope.setClassScope(node);
+    }
+
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        pushState(node.isStatic());
+        inConstructor = isConstructor;
+        node.setVariableScope(currentScope);
+        visitAnnotations(node);
+        
+        // GROOVY-2156
+        Parameter[] parameters = node.getParameters();
+        for (Parameter parameter : parameters) {
+            visitAnnotations(parameter);
+        }
+
+        declare(node.getParameters(), node);
+        visitClassCodeContainer(node.getCode());
+
+        popState();
+    }
+
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        if (call.isImplicitThis() && call.getMethod() instanceof ConstantExpression) {
+            ConstantExpression methodNameConstant = (ConstantExpression) call.getMethod();
+            Object value = methodNameConstant.getText();
+
+            if (!(value instanceof String)) {
+                throw new GroovyBugError("tried to make a method call with a non-String constant method name.");
+            }
+
+            String methodName = (String) value;
+            Variable v = checkVariableNameForDeclaration(methodName, call);
+            if (v != null && !(v instanceof DynamicVariable)) {
+                checkVariableContextAccess(v, call);
+            }
+
+            if (v instanceof VariableExpression || v instanceof Parameter) {
+                VariableExpression object = new VariableExpression(v);
+                object.setSourcePosition(methodNameConstant);
+                call.setObjectExpression(object);
+                ConstantExpression method = new ConstantExpression("call");
+                method.setSourcePosition(methodNameConstant); // important for GROOVY-4344
+                call.setImplicitThis(false);
+                call.setMethod(method);
+            }
+
+        }
+        super.visitMethodCallExpression(call);
+    }
+
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        isSpecialConstructorCall = call.isSpecialCall();
+        super.visitConstructorCallExpression(call);
+        isSpecialConstructorCall = false;
+        if (!call.isUsingAnonymousInnerClass()) return;
+
+        pushState();
+        InnerClassNode innerClass = (InnerClassNode) call.getType();
+        innerClass.setVariableScope(currentScope);
+        for (MethodNode method : innerClass.getMethods()) {
+            Parameter[] parameters = method.getParameters();
+            if (parameters.length == 0) parameters = null; // null means no implicit "it"
+            ClosureExpression cl = new ClosureExpression(parameters, method.getCode());
+            visitClosureExpression(cl);
+        }
+
+        for (FieldNode field : innerClass.getFields()) {
+            final Expression expression = field.getInitialExpression();
+            pushState(field.isStatic());
+            if (expression != null) {
+                if (expression instanceof VariableExpression) {
+                    VariableExpression vexp = (VariableExpression) expression;
+                    if (vexp.getAccessedVariable() instanceof Parameter) {
+                        // workaround for GROOVY-6834: accessing a parameter which is not yet seen in scope
+                        popState();
+                        continue;
+                    }
+                }
+                expression.visit(this);
+            }
+            popState();
+        }
+
+        for (Statement statement : innerClass.getObjectInitializerStatements()) {
+            statement.visit(this);
+        }
+        markClosureSharedVariables();
+        popState();
+    }
+
+    public void visitProperty(PropertyNode node) {
+        pushState(node.isStatic());
+        super.visitProperty(node);
+        popState();
+    }
+
+    public void visitField(FieldNode node) {
+        pushState(node.isStatic());
+        super.visitField(node);
+        popState();
+    }
+
+    public void visitAnnotations(AnnotatedNode node) {
+        List<AnnotationNode> annotations = node.getAnnotations();
+        if (annotations.isEmpty()) return;
+        for (AnnotationNode an : annotations) {
+            // skip built-in properties
+            if (an.isBuiltIn()) continue;
+            for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+                Expression annMemberValue = member.getValue();
+                annMemberValue.visit(this);
+            }
+        }
+    }
+}


[52/62] [abbrv] groovy git commit: Remove unnecessary `copyResources`

Posted by cc...@apache.org.
Remove unnecessary `copyResources`


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/d389d26c
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/d389d26c
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/d389d26c

Branch: refs/heads/GROOVY_2_6_X
Commit: d389d26cd3aabdc41745c621dfd6c40171f23f37
Parents: 0edfcde
Author: Cedric Champeau <cc...@apache.org>
Authored: Thu Dec 14 11:39:09 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:28:31 2017 +0100

----------------------------------------------------------------------
 build.gradle | 16 ----------------
 1 file changed, 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/d389d26c/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index f8737b4..4b96673 100644
--- a/build.gradle
+++ b/build.gradle
@@ -112,22 +112,6 @@ allprojects {
     }
 }
 
-// todo: use the conventional "resources" directory for classpath resources
-task(copyResources, type: Copy) {
-    destinationDir = file("$buildDir/classes")
-    // text files requiring filtering
-    into('main') {
-        from('src/main')
-        include('**/*.txt', '**/*.xml', '**/*.properties', '**/*.html')
-        filter(rootProject.propertiesFilter, org.apache.tools.ant.filters.ReplaceTokens)
-    }
-    // other resources
-    into('main') {
-        from 'src/main'
-        include('**/*.png', '**/*.gif', '**/*.ico', '**/*.css')
-    }
-}
-jar.dependsOn(copyResources)
 task(copyTestResources, type: Copy)
         .from('src/test')
         .into("$buildDir/classes/test")


[53/62] [abbrv] groovy git commit: More tweaks to the MANIFEST entry

Posted by cc...@apache.org.
More tweaks to the MANIFEST entry


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/9edb31f4
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/9edb31f4
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/9edb31f4

Branch: refs/heads/GROOVY_2_6_X
Commit: 9edb31f4d8c39f217974c93347cd5c8f5ef1c136
Parents: d389d26
Author: Cedric Champeau <cc...@apache.org>
Authored: Thu Dec 14 12:27:09 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:28:37 2017 +0100

----------------------------------------------------------------------
 gradle/assemble.gradle | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/9edb31f4/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index 819e4cf..d60fab4 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -82,8 +82,15 @@ task copy(type: Copy) {
     into "$buildDir/meta"
 }
 
+// unnecessary entries which in addition may trigger unnecessary rebuilds
+def excludedFromManifest = [
+        'Originally-Created-By',
+        'Bnd-LastModified',
+        'Created-By'
+]
+
 ext.allManifest = manifest {
-    attributes('Built-By': System.properties['user.name'],
+    attributes(
             'Extension-Name': 'groovy',
             'Specification-Title': 'Groovy: a powerful, dynamic language for the JVM',
             'Specification-Version': groovyBundleVersion,
@@ -106,7 +113,7 @@ ext.groovyOsgiManifest = {
     // Exclude the Bnd-LastModified attribute as it always triggers a rebuild without being really needed.
     from(allManifest) {
         eachEntry { details ->
-            if (details.key == 'Bnd-LastModified') {
+            if (excludedFromManifest.any { it == details.key}) {
                 details.exclude()
             }
         }
@@ -121,7 +128,7 @@ ext.subprojectOsgiManifest = {
     // Exclude attributes not needed for subprojects.
     from(allManifest) {
         eachEntry { details ->
-            if (details.key in ['Bnd-LastModified', 'Extension-Name', 'Bundle-Name', 'Bundle-Description', 'Main-class']) {
+            if (details.key in [*excludedFromManifest, 'Bnd-LastModified', 'Extension-Name', 'Bundle-Name', 'Bundle-Description', 'Main-class']) {
                 details.exclude()
             }
         }


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
new file mode 100644
index 0000000..dab0e55
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -0,0 +1,1167 @@
+/*
+ *  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.control;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyRuntimeException;
+import groovy.transform.CompilationUnitAware;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.ClassCompletionVerifier;
+import org.codehaus.groovy.classgen.EnumCompletionVisitor;
+import org.codehaus.groovy.classgen.EnumVisitor;
+import org.codehaus.groovy.classgen.ExtendedVerifier;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.classgen.InnerClassCompletionVisitor;
+import org.codehaus.groovy.classgen.InnerClassVisitor;
+import org.codehaus.groovy.classgen.VariableScopeVisitor;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+import org.codehaus.groovy.control.io.InputStreamReaderSource;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.control.messages.ExceptionMessage;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SimpleMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.tools.GroovyClass;
+import org.codehaus.groovy.transform.ASTTransformationVisitor;
+import org.codehaus.groovy.transform.AnnotationCollectorTransform;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.trait.TraitComposer;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.CodeSource;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The CompilationUnit collects all compilation data as it is generated by the compiler system.
+ * You can use this object to add additional source units to the compilation, or force the
+ * compilation to be run again (to affect only the deltas).
+ * <p>
+ * You can also add PhaseOperations to this compilation using the addPhaseOperation method.
+ * This is commonly used when you want to wire a new AST Transformation into the compilation.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @author <a href="mailto:roshandawrani@codehaus.org">Roshan Dawrani</a>
+ */
+
+public class CompilationUnit extends ProcessingUnit {
+
+    //---------------------------------------------------------------------------
+    // CONSTRUCTION AND SUCH
+
+    protected ASTTransformationsContext astTransformationsContext; // AST transformations state data
+
+    protected Map<String, SourceUnit> sources;    // The SourceUnits from which this unit is built
+    protected Map summariesBySourceName;      // Summary of each SourceUnit
+    protected Map summariesByPublicClassName;       // Summary of each SourceUnit
+    protected Map classSourcesByPublicClassName;    // Summary of each Class
+    protected List<String> names;      // Names for each SourceUnit in sources.
+    protected LinkedList<SourceUnit> queuedSources;
+
+    protected CompileUnit ast;        // The overall AST for this CompilationUnit.
+    protected List<GroovyClass> generatedClasses;  // The classes generated during classgen.
+
+    protected Verifier verifier;   // For use by verify().
+
+    protected boolean debug;      // Controls behavior of classgen() and other routines.
+    protected boolean configured; // Set true after the first configure() operation
+
+    protected ClassgenCallback classgenCallback;  // A callback for use during classgen()
+    protected ProgressCallback progressCallback;  // A callback for use during compile()
+    protected ResolveVisitor resolveVisitor;
+    protected StaticImportVisitor staticImportVisitor;
+    protected OptimizerVisitor optimizer;
+    protected ClassNodeResolver classNodeResolver;
+
+    LinkedList[] phaseOperations;
+    LinkedList[] newPhaseOperations;
+
+    /**
+     * Initializes the CompilationUnit with defaults.
+     */
+    public CompilationUnit() {
+        this(null, null, null);
+    }
+
+
+    /**
+     * Initializes the CompilationUnit with defaults except for class loader.
+     */
+    public CompilationUnit(GroovyClassLoader loader) {
+        this(null, null, loader);
+    }
+
+
+    /**
+     * Initializes the CompilationUnit with no security considerations.
+     */
+    public CompilationUnit(CompilerConfiguration configuration) {
+        this(configuration, null, null);
+    }
+
+    /**
+     * Initializes the CompilationUnit with a CodeSource for controlling
+     * security stuff and a class loader for loading classes.
+     */
+    public CompilationUnit(CompilerConfiguration configuration, CodeSource security, GroovyClassLoader loader) {
+        this(configuration, security, loader, null);
+    }
+
+    /**
+     * Initializes the CompilationUnit with a CodeSource for controlling
+     * security stuff, a class loader for loading classes, and a class
+     * loader for loading AST transformations.
+     * <b>Note</b> The transform loader must be
+     * able to load compiler classes. That means CompilationUnit.class.classLoader
+     * must be at last a parent to transformLoader. The other loader has no such constraint.
+     *
+     * @param transformLoader - the loader for transforms
+     * @param loader          - loader used to resolve classes against during compilation
+     * @param security        - security setting for the compilation
+     * @param configuration   - compilation configuration
+     */
+    public CompilationUnit(CompilerConfiguration configuration, CodeSource security,
+                           GroovyClassLoader loader, GroovyClassLoader transformLoader) {
+        super(configuration, loader, null);
+
+        this.astTransformationsContext = new ASTTransformationsContext(this, transformLoader);
+        this.names = new ArrayList<String>();
+        this.queuedSources = new LinkedList<SourceUnit>();
+        this.sources = new HashMap<String, SourceUnit>();
+        this.summariesBySourceName = new HashMap();
+        this.summariesByPublicClassName = new HashMap();
+        this.classSourcesByPublicClassName = new HashMap();
+
+        this.ast = new CompileUnit(this.classLoader, security, this.configuration);
+        this.generatedClasses = new ArrayList<GroovyClass>();
+
+        this.verifier = new Verifier();
+        this.resolveVisitor = new ResolveVisitor(this);
+        this.staticImportVisitor = new StaticImportVisitor();
+        this.optimizer = new OptimizerVisitor(this);
+
+        phaseOperations = new LinkedList[Phases.ALL + 1];
+        newPhaseOperations = new LinkedList[Phases.ALL + 1];
+        for (int i = 0; i < phaseOperations.length; i++) {
+            phaseOperations[i] = new LinkedList();
+            newPhaseOperations[i] = new LinkedList();
+        }
+        addPhaseOperation(new SourceUnitOperation() {
+            public void call(SourceUnit source) throws CompilationFailedException {
+                source.parse();
+            }
+        }, Phases.PARSING);
+        addPhaseOperation(convert, Phases.CONVERSION);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                EnumVisitor ev = new EnumVisitor(CompilationUnit.this, source);
+                ev.visitClass(classNode);
+            }
+        }, Phases.CONVERSION);
+        addPhaseOperation(resolve, Phases.SEMANTIC_ANALYSIS);
+        addPhaseOperation(staticImport, Phases.SEMANTIC_ANALYSIS);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                InnerClassVisitor iv = new InnerClassVisitor(CompilationUnit.this, source);
+                iv.visitClass(classNode);
+            }
+        }, Phases.SEMANTIC_ANALYSIS);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                if (!classNode.isSynthetic()) {
+                    GenericsVisitor genericsVisitor = new GenericsVisitor(source);
+                    genericsVisitor.visitClass(classNode);
+                }
+            }
+        }, Phases.SEMANTIC_ANALYSIS);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                TraitComposer.doExtendTraits(classNode, source, CompilationUnit.this);
+            }
+        }, Phases.CANONICALIZATION);
+        addPhaseOperation(compileCompleteCheck, Phases.CANONICALIZATION);
+        addPhaseOperation(classgen, Phases.CLASS_GENERATION);
+        addPhaseOperation(output);
+
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                AnnotationCollectorTransform.ClassChanger actt = new AnnotationCollectorTransform.ClassChanger();
+                actt.transformClass(classNode);
+            }
+        }, Phases.SEMANTIC_ANALYSIS);
+        ASTTransformationVisitor.addPhaseOperations(this);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                StaticVerifier sv = new StaticVerifier();
+                sv.visitClass(classNode, source);
+            }
+        }, Phases.SEMANTIC_ANALYSIS);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                InnerClassCompletionVisitor iv = new InnerClassCompletionVisitor(CompilationUnit.this, source);
+                iv.visitClass(classNode);
+            }
+        }, Phases.CANONICALIZATION);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                EnumCompletionVisitor ecv = new EnumCompletionVisitor(CompilationUnit.this, source);
+                ecv.visitClass(classNode);
+            }
+        }, Phases.CANONICALIZATION);
+        addPhaseOperation(new PrimaryClassNodeOperation() {
+            @Override
+            public void call(SourceUnit source, GeneratorContext context,
+                             ClassNode classNode) throws CompilationFailedException {
+                Object callback = classNode.getNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+                if (callback instanceof PrimaryClassNodeOperation) {
+                    ((PrimaryClassNodeOperation) callback).call(source, context, classNode);
+                    classNode.removeNodeMetaData(StaticCompilationMetadataKeys.DYNAMIC_OUTER_NODE_CALLBACK);
+                }
+            }
+        }, Phases.INSTRUCTION_SELECTION);
+
+        // apply configuration customizers if any
+        if (configuration != null) {
+            final List<CompilationCustomizer> customizers = configuration.getCompilationCustomizers();
+            for (CompilationCustomizer customizer : customizers) {
+                if (customizer instanceof CompilationUnitAware) {
+                    ((CompilationUnitAware) customizer).setCompilationUnit(this);
+                }
+                addPhaseOperation(customizer, customizer.getPhase().getPhaseNumber());
+            }
+        }
+        this.classgenCallback = null;
+        this.classNodeResolver = new ClassNodeResolver();
+    }
+
+    /**
+     * Returns the class loader for loading AST transformations.
+     * @return - the transform class loader
+     */
+    public GroovyClassLoader getTransformLoader() {
+        return astTransformationsContext.getTransformLoader() == null ? getClassLoader() : astTransformationsContext.getTransformLoader();
+    }
+
+
+    public void addPhaseOperation(SourceUnitOperation op, int phase) {
+        if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+        phaseOperations[phase].add(op);
+    }
+
+    public void addPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+        if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+        phaseOperations[phase].add(op);
+    }
+
+    public void addFirstPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+        if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+        phaseOperations[phase].add(0, op);
+    }
+
+    public void addPhaseOperation(GroovyClassOperation op) {
+        phaseOperations[Phases.OUTPUT].addFirst(op);
+    }
+
+    public void addNewPhaseOperation(SourceUnitOperation op, int phase) {
+        if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+        newPhaseOperations[phase].add(op);
+    }
+
+    /**
+     * Configures its debugging mode and classloader classpath from a given compiler configuration.
+     * This cannot be done more than once due to limitations in {@link java.net.URLClassLoader URLClassLoader}.
+     */
+    public void configure(CompilerConfiguration configuration) {
+        super.configure(configuration);
+        this.debug = configuration.getDebug();
+
+        if (!this.configured && this.classLoader instanceof GroovyClassLoader) {
+            appendCompilerConfigurationClasspathToClassLoader(configuration, (GroovyClassLoader) this.classLoader);
+        }
+
+        this.configured = true;
+    }
+
+    private void appendCompilerConfigurationClasspathToClassLoader(CompilerConfiguration configuration, GroovyClassLoader classLoader) {
+        /*for (Iterator iterator = configuration.getClasspath().iterator(); iterator.hasNext(); ) {
+            classLoader.addClasspath((String) iterator.next());
+        }*/
+    }
+
+    /**
+     * Returns the CompileUnit that roots our AST.
+     */
+    public CompileUnit getAST() {
+        return this.ast;
+    }
+
+    /**
+     * Get the source summaries
+     */
+    public Map getSummariesBySourceName() {
+        return summariesBySourceName;
+    }
+
+    public Map getSummariesByPublicClassName() {
+        return summariesByPublicClassName;
+    }
+
+    public Map getClassSourcesByPublicClassName() {
+        return classSourcesByPublicClassName;
+    }
+
+    public boolean isPublicClass(String className) {
+        return summariesByPublicClassName.containsKey(className);
+    }
+
+    /**
+     * Get the GroovyClasses generated by compile().
+     */
+    public List getClasses() {
+        return generatedClasses;
+    }
+
+    /**
+     * Convenience routine to get the first ClassNode, for
+     * when you are sure there is only one.
+     */
+    public ClassNode getFirstClassNode() {
+        return this.ast.getModules().get(0).getClasses().get(0);
+    }
+
+    /**
+     * Convenience routine to get the named ClassNode.
+     */
+    public ClassNode getClassNode(final String name) {
+        final ClassNode[] result = new ClassNode[]{null};
+        PrimaryClassNodeOperation handler = new PrimaryClassNodeOperation() {
+            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+                if (classNode.getName().equals(name)) {
+                    result[0] = classNode;
+                }
+            }
+        };
+
+        try {
+            applyToPrimaryClassNodes(handler);
+        } catch (CompilationFailedException e) {
+            if (debug) e.printStackTrace();
+        }
+        return result[0];
+    }
+
+    /**
+     * @return the AST transformations current context
+     */
+    public ASTTransformationsContext getASTTransformationsContext() {
+        return astTransformationsContext;
+    }
+
+    //---------------------------------------------------------------------------
+    // SOURCE CREATION
+
+
+    /**
+     * Adds a set of file paths to the unit.
+     */
+    public void addSources(String[] paths) {
+        for (String path : paths) {
+            addSource(new File(path));
+        }
+    }
+
+
+    /**
+     * Adds a set of source files to the unit.
+     */
+    public void addSources(File[] files) {
+        for (File file : files) {
+            addSource(file);
+        }
+    }
+
+
+    /**
+     * Adds a source file to the unit.
+     */
+    public SourceUnit addSource(File file) {
+        return addSource(new SourceUnit(file, configuration, classLoader, getErrorCollector()));
+    }
+
+    /**
+     * Adds a source file to the unit.
+     */
+    public SourceUnit addSource(URL url) {
+        return addSource(new SourceUnit(url, configuration, classLoader, getErrorCollector()));
+    }
+
+
+    /**
+     * Adds a InputStream source to the unit.
+     */
+    public SourceUnit addSource(String name, InputStream stream) {
+        ReaderSource source = new InputStreamReaderSource(stream, configuration);
+        return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector()));
+    }
+
+    public SourceUnit addSource(String name, String scriptText) {
+        return addSource(new SourceUnit(name, scriptText, configuration, classLoader, getErrorCollector()));
+    }
+
+    /**
+     * Adds a SourceUnit to the unit.
+     */
+    public SourceUnit addSource(SourceUnit source) {
+        String name = source.getName();
+        source.setClassLoader(this.classLoader);
+        for (SourceUnit su : queuedSources) {
+            if (name.equals(su.getName())) return su;
+        }
+        queuedSources.add(source);
+        return source;
+    }
+
+
+    /**
+     * Returns an iterator on the unit's SourceUnits.
+     */
+    public Iterator<SourceUnit> iterator() {
+        return new Iterator<SourceUnit>() {
+            Iterator<String> nameIterator = names.iterator();
+
+            public boolean hasNext() {
+                return nameIterator.hasNext();
+            }
+
+            public SourceUnit next() {
+                String name = nameIterator.next();
+                return sources.get(name);
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+
+    /**
+     * Adds a ClassNode directly to the unit (ie. without source).
+     * WARNING: the source is needed for error reporting, using
+     * this method without setting a SourceUnit will cause
+     * NullPinterExceptions
+     */
+    public void addClassNode(ClassNode node) {
+        ModuleNode module = new ModuleNode(this.ast);
+        this.ast.addModule(module);
+        module.addClass(node);
+    }
+
+    //---------------------------------------------------------------------------
+    // EXTERNAL CALLBACKS
+
+
+    /**
+     * A callback interface you can use to "accompany" the classgen()
+     * code as it traverses the ClassNode tree.  You will be called-back
+     * for each primary and inner class.  Use setClassgenCallback() before
+     * running compile() to set your callback.
+     */
+    public abstract static class ClassgenCallback {
+        public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException;
+    }
+
+    /**
+     * Sets a ClassgenCallback.  You can have only one, and setting
+     * it to null removes any existing setting.
+     */
+    public void setClassgenCallback(ClassgenCallback visitor) {
+        this.classgenCallback = visitor;
+    }
+
+    /**
+     * A callback interface you can use to get a callback after every
+     * unit of the compile process.  You will be called-back with a
+     * ProcessingUnit and a phase indicator.  Use setProgressCallback()
+     * before running compile() to set your callback.
+     */
+    public abstract static class ProgressCallback {
+
+        public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException;
+    }
+
+    /**
+     * Sets a ProgressCallback.  You can have only one, and setting
+     * it to null removes any existing setting.
+     */
+    public void setProgressCallback(ProgressCallback callback) {
+        this.progressCallback = callback;
+    }
+
+    public ClassgenCallback getClassgenCallback() {
+        return classgenCallback;
+    }
+
+    public ProgressCallback getProgressCallback() {
+        return progressCallback;
+    }
+
+    //---------------------------------------------------------------------------
+    // ACTIONS
+
+
+    /**
+     * Synonym for compile(Phases.ALL).
+     */
+    public void compile() throws CompilationFailedException {
+        compile(Phases.ALL);
+    }
+
+    /**
+     * Compiles the compilation unit from sources.
+     */
+    public void compile(int throughPhase) throws CompilationFailedException {
+        //
+        // To support delta compilations, we always restart
+        // the compiler.  The individual passes are responsible
+        // for not reprocessing old code.
+        gotoPhase(Phases.INITIALIZATION);
+        throughPhase = Math.min(throughPhase, Phases.ALL);
+
+        while (throughPhase >= phase && phase <= Phases.ALL) {
+
+            if (phase == Phases.SEMANTIC_ANALYSIS) {
+                doPhaseOperation(resolve);
+                if (dequeued()) continue;
+            }
+
+            processPhaseOperations(phase);
+            // Grab processing may have brought in new AST transforms into various phases, process them as well
+            processNewPhaseOperations(phase);
+
+            if (progressCallback != null) progressCallback.call(this, phase);
+            completePhase();
+            applyToSourceUnits(mark);
+
+            if (dequeued()) continue;
+
+            gotoPhase(phase + 1);
+
+            if (phase == Phases.CLASS_GENERATION) {
+                sortClasses();
+            }
+        }
+
+        errorCollector.failIfErrors();
+    }
+
+    private void processPhaseOperations(int ph) {
+        LinkedList ops = phaseOperations[ph];
+        for (Object next : ops) {
+            doPhaseOperation(next);
+        }
+    }
+
+    private void processNewPhaseOperations(int currPhase) {
+        recordPhaseOpsInAllOtherPhases(currPhase);
+        LinkedList currentPhaseNewOps = newPhaseOperations[currPhase];
+        while (!currentPhaseNewOps.isEmpty()) {
+            Object operation = currentPhaseNewOps.removeFirst();
+            // push this operation to master list and then process it.
+            phaseOperations[currPhase].add(operation);
+            doPhaseOperation(operation);
+            // if this operation has brought in more phase ops for ast transforms, keep recording them
+            // in master list of other phases and keep processing them for this phase.
+            recordPhaseOpsInAllOtherPhases(currPhase);
+            currentPhaseNewOps = newPhaseOperations[currPhase];
+        }
+
+    }
+
+    private void doPhaseOperation(Object operation) {
+        if (operation instanceof PrimaryClassNodeOperation) {
+            applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation);
+        } else if (operation instanceof SourceUnitOperation) {
+            applyToSourceUnits((SourceUnitOperation) operation);
+        } else {
+            applyToGeneratedGroovyClasses((GroovyClassOperation) operation);
+        }
+    }
+
+    private void recordPhaseOpsInAllOtherPhases(int currPhase) {
+        // apart from current phase, push new operations for every other phase in the master phase ops list
+        for (int ph = Phases.INITIALIZATION; ph <= Phases.ALL; ph++) {
+            if (ph != currPhase && !newPhaseOperations[ph].isEmpty()) {
+                phaseOperations[ph].addAll(newPhaseOperations[ph]);
+                newPhaseOperations[ph].clear();
+            }
+        }
+    }
+
+    private void sortClasses() throws CompilationFailedException {
+        for (ModuleNode module : this.ast.getModules()) {
+            module.sortClasses();
+        }
+    }
+
+
+    /**
+     * Dequeues any source units add through addSource and resets the compiler phase
+     * to initialization.
+     * <p>
+     * Note: this does not mean a file is recompiled. If a SourceUnit has already passed
+     * a phase it is skipped until a higher phase is reached.
+     *
+     * @return true if there was a queued source
+     * @throws CompilationFailedException
+     */
+    protected boolean dequeued() throws CompilationFailedException {
+        boolean dequeue = !queuedSources.isEmpty();
+        while (!queuedSources.isEmpty()) {
+            SourceUnit su = queuedSources.removeFirst();
+            String name = su.getName();
+            names.add(name);
+            sources.put(name, su);
+        }
+        if (dequeue) {
+            gotoPhase(Phases.INITIALIZATION);
+        }
+        return dequeue;
+    }
+
+    /**
+     * Resolves all types
+     */
+    private final SourceUnitOperation resolve = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            List<ClassNode> classes = source.ast.getClasses();
+            for (ClassNode node : classes) {
+                VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
+                scopeVisitor.visitClass(node);
+
+                resolveVisitor.setClassNodeResolver(classNodeResolver);
+                resolveVisitor.startResolving(node, source);
+            }
+
+        }
+    };
+
+    private final PrimaryClassNodeOperation staticImport = new PrimaryClassNodeOperation() {
+        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+            staticImportVisitor.visitClass(classNode, source);
+        }
+    };
+
+    /**
+     * Runs convert() on a single SourceUnit.
+     */
+    private final SourceUnitOperation convert = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            source.convert();
+            CompilationUnit.this.ast.addModule(source.getAST());
+
+
+            if (CompilationUnit.this.progressCallback != null) {
+                CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
+            }
+        }
+    };
+
+    private final GroovyClassOperation output = new GroovyClassOperation() {
+        public void call(GroovyClass gclass) throws CompilationFailedException {
+            String name = gclass.getName().replace('.', File.separatorChar) + ".class";
+            File path = new File(configuration.getTargetDirectory(), name);
+
+            //
+            // Ensure the path is ready for the file
+            //
+            File directory = path.getParentFile();
+            if (directory != null && !directory.exists()) {
+                directory.mkdirs();
+            }
+
+            //
+            // Create the file and write out the data
+            //
+            byte[] bytes = gclass.getBytes();
+
+            FileOutputStream stream = null;
+            try {
+                stream = new FileOutputStream(path);
+                stream.write(bytes, 0, bytes.length);
+            } catch (IOException e) {
+                getErrorCollector().addError(Message.create(e.getMessage(), CompilationUnit.this));
+            } finally {
+                if (stream != null) {
+                    try {
+                        stream.close();
+                    } catch (Exception e) {
+                        // Ignore
+                    }
+                }
+            }
+        }
+    };
+
+    /* checks if all needed classes are compiled before generating the bytecode */
+    private final SourceUnitOperation compileCompleteCheck = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            List<ClassNode> classes = source.ast.getClasses();
+            for (ClassNode node : classes) {
+                CompileUnit cu = node.getCompileUnit();
+                for (Iterator iter = cu.iterateClassNodeToCompile(); iter.hasNext();) {
+                    String name = (String) iter.next();
+                    SourceUnit su = ast.getScriptSourceLocation(name);
+                    List<ClassNode> classesInSourceUnit = su.ast.getClasses();
+                    StringBuilder message = new StringBuilder();
+                    message
+                            .append("Compilation incomplete: expected to find the class ")
+                            .append(name)
+                            .append(" in ")
+                            .append(su.getName());
+                    if (classesInSourceUnit.isEmpty()) {
+                        message.append(", but the file seems not to contain any classes");
+                    } else {
+                        message.append(", but the file contains the classes: ");
+                        boolean first = true;
+                        for (ClassNode cn : classesInSourceUnit) {
+                            if (!first) {
+                                message.append(", ");
+                            } else {
+                                first = false;
+                            }
+                            message.append(cn.getName());
+                        }
+                    }
+
+                    getErrorCollector().addErrorAndContinue(
+                            new SimpleMessage(message.toString(), CompilationUnit.this)
+                    );
+                    iter.remove();
+                }
+            }
+        }
+    };
+
+
+    /**
+     * Runs classgen() on a single ClassNode.
+     */
+    private final PrimaryClassNodeOperation classgen = new PrimaryClassNodeOperation() {
+        public boolean needSortedInput() {
+            return true;
+        }
+
+        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+
+            optimizer.visitClass(classNode, source); // GROOVY-4272: repositioned it here from staticImport
+
+            //
+            // Run the Verifier on the outer class
+            //
+            try {
+                verifier.visitClass(classNode);
+            } catch (GroovyRuntimeException rpe) {
+                ASTNode node = rpe.getNode();
+                getErrorCollector().addError(
+                        new SyntaxException(rpe.getMessage(), node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()),
+                        source
+                );
+            }
+
+            LabelVerifier lv = new LabelVerifier(source);
+            lv.visitClass(classNode);
+
+            ClassCompletionVerifier completionVerifier = new ClassCompletionVerifier(source);
+            completionVerifier.visitClass(classNode);
+
+            ExtendedVerifier xverifier = new ExtendedVerifier(source);
+            xverifier.visitClass(classNode);
+
+            // because the class may be generated even if a error was found
+            // and that class may have an invalid format we fail here if needed
+            getErrorCollector().failIfErrors();
+
+            //
+            // Prep the generator machinery
+            //
+            ClassVisitor visitor = createClassVisitor();
+            
+            String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
+            // only show the file name and its extension like javac does in its stacktraces rather than the full path
+            // also takes care of both \ and / depending on the host compiling environment
+            if (sourceName != null)
+                sourceName = sourceName.substring(Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1);
+            AsmClassGenerator generator = new AsmClassGenerator(source, context, visitor, sourceName);
+
+            //
+            // Run the generation and create the class (if required)
+            //
+            generator.visitClass(classNode);
+
+            byte[] bytes = ((ClassWriter) visitor).toByteArray();
+            generatedClasses.add(new GroovyClass(classNode.getName(), bytes));
+
+            //
+            // Handle any callback that's been set
+            //
+            if (CompilationUnit.this.classgenCallback != null) {
+                classgenCallback.call(visitor, classNode);
+            }
+
+            //
+            // Recurse for inner classes
+            //
+            LinkedList innerClasses = generator.getInnerClasses();
+            while (!innerClasses.isEmpty()) {
+                classgen.call(source, context, (ClassNode) innerClasses.removeFirst());
+            }
+        }
+    };
+
+    protected ClassVisitor createClassVisitor() {
+        CompilerConfiguration config = getConfiguration();
+        int computeMaxStackAndFrames = ClassWriter.COMPUTE_MAXS;
+        if (CompilerConfiguration.isPostJDK7(config.getTargetBytecode())
+                || Boolean.TRUE.equals(config.getOptimizationOptions().get("indy"))) {
+            computeMaxStackAndFrames += ClassWriter.COMPUTE_FRAMES;
+        }
+        return new ClassWriter(computeMaxStackAndFrames) {
+            private ClassNode getClassNode(String name) {
+                // try classes under compilation
+                CompileUnit cu = getAST();
+                ClassNode cn = cu.getClass(name);
+                if (cn!=null) return cn;
+                // try inner classes
+                cn = cu.getGeneratedInnerClass(name);
+                if (cn!=null) return cn;
+                // try class loader classes
+                try {
+                    cn = ClassHelper.make(
+                            cu.getClassLoader().loadClass(name,false,true),
+                            false);
+                } catch (Exception e) {
+                    throw new GroovyBugError(e);
+                }
+                return cn;
+            }
+            private ClassNode getCommonSuperClassNode(ClassNode c, ClassNode d) {
+                // adapted from ClassWriter code
+                if (c.isDerivedFrom(d)) return d;
+                if (d.isDerivedFrom(c)) return c;
+                if (c.isInterface() || d.isInterface()) return ClassHelper.OBJECT_TYPE;
+                do {
+                    c = c.getSuperClass();
+                } while (c!=null && !d.isDerivedFrom(c));
+                if (c==null) return ClassHelper.OBJECT_TYPE;
+                return c;
+            }
+            @Override
+            protected String getCommonSuperClass(String arg1, String arg2) {
+                ClassNode a = getClassNode(arg1.replace('/', '.')); 
+                ClassNode b = getClassNode(arg2.replace('/', '.'));
+                return getCommonSuperClassNode(a,b).getName().replace('.','/');
+            }
+
+        };
+    }
+    
+    //---------------------------------------------------------------------------
+    // PHASE HANDLING
+
+    /**
+     * Updates the phase marker on all sources.
+     */
+    protected void mark() throws CompilationFailedException {
+        applyToSourceUnits(mark);
+    }
+
+
+    /**
+     * Marks a single SourceUnit with the current phase,
+     * if it isn't already there yet.
+     */
+    private final SourceUnitOperation mark = new SourceUnitOperation() {
+        public void call(SourceUnit source) throws CompilationFailedException {
+            if (source.phase < phase) {
+                source.gotoPhase(phase);
+            }
+
+            if (source.phase == phase && phaseComplete && !source.phaseComplete) {
+                source.completePhase();
+            }
+        }
+    };
+
+    //---------------------------------------------------------------------------
+    // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS
+
+
+    /**
+     * An callback interface for use in the applyToSourceUnits loop driver.
+     */
+    public abstract static class SourceUnitOperation {
+        public abstract void call(SourceUnit source) throws CompilationFailedException;
+    }
+
+
+    /**
+     * A loop driver for applying operations to all SourceUnits.
+     * Automatically skips units that have already been processed
+     * through the current phase.
+     */
+    public void applyToSourceUnits(SourceUnitOperation body) throws CompilationFailedException {
+        for (String name : names) {
+            SourceUnit source = sources.get(name);
+            if ((source.phase < phase) || (source.phase == phase && !source.phaseComplete)) {
+                try {
+                    body.call(source);
+                } catch (CompilationFailedException e) {
+                    throw e;
+                } catch (Exception e) {
+                    GroovyBugError gbe = new GroovyBugError(e);
+                    changeBugText(gbe, source);
+                    throw gbe;
+                } catch (GroovyBugError e) {
+                    changeBugText(e, source);
+                    throw e;
+                }
+            }
+        }
+
+
+        getErrorCollector().failIfErrors();
+    }
+
+    //---------------------------------------------------------------------------
+    // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS
+
+
+    /**
+     * An callback interface for use in the applyToPrimaryClassNodes loop driver.
+     */
+    public abstract static class PrimaryClassNodeOperation {
+        public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
+
+        public boolean needSortedInput() {
+            return false;
+        }
+    }
+
+    public abstract static class GroovyClassOperation {
+        public abstract void call(GroovyClass gclass) throws CompilationFailedException;
+    }
+
+    private static int getSuperClassCount(ClassNode element) {
+        int count = 0;
+        while (element != null) {
+            count++;
+            element = element.getSuperClass();
+        }
+        return count;
+    }
+
+    private int getSuperInterfaceCount(ClassNode element) {
+        int count = 1;
+        ClassNode[] interfaces = element.getInterfaces();
+        for (ClassNode anInterface : interfaces) {
+            count = Math.max(count, getSuperInterfaceCount(anInterface) + 1);
+        }
+        return count;
+    }
+
+    private List<ClassNode> getPrimaryClassNodes(boolean sort) {
+        List<ClassNode> unsorted = new ArrayList<ClassNode>();
+        for (ModuleNode module : this.ast.getModules()) {
+            for (ClassNode classNode : module.getClasses()) {
+                unsorted.add(classNode);
+            }
+        }
+
+        if (!sort) return unsorted;
+
+        int unsortedSize = unsorted.size();
+        int[] indexClass = new int[unsortedSize];
+        int[] indexInterface = new int[unsortedSize];
+        {
+            int i = 0;
+            for (Iterator<ClassNode> iter = unsorted.iterator(); iter.hasNext(); i++) {
+                ClassNode element = iter.next();
+                if (element.isInterface()) {
+                    indexInterface[i] = getSuperInterfaceCount(element);
+                    indexClass[i] = -1;
+                } else {
+                    indexClass[i] = getSuperClassCount(element);
+                    indexInterface[i] = -1;
+                }
+            }
+        }
+
+        List<ClassNode> sorted = getSorted(indexInterface, unsorted);
+        sorted.addAll(getSorted(indexClass, unsorted));
+        return sorted;
+    }
+
+    private static List<ClassNode> getSorted(int[] index, List<ClassNode> unsorted) {
+        int unsortedSize = unsorted.size();
+        List<ClassNode> sorted = new ArrayList<ClassNode>(unsortedSize);
+        for (int i = 0; i < unsortedSize; i++) {
+            int min = -1;
+            for (int j = 0; j < unsortedSize; j++) {
+                if (index[j] == -1) continue;
+                if (min == -1 || index[j] < index[min]) {
+                    min = j;
+                }
+            }
+            if (min == -1) break;
+            sorted.add(unsorted.get(min));
+            index[min] = -1;
+        }
+        return sorted;
+    }
+
+    /**
+     * A loop driver for applying operations to all primary ClassNodes in
+     * our AST.  Automatically skips units that have already been processed
+     * through the current phase.
+     */
+    public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body) throws CompilationFailedException {
+        for (ClassNode classNode : getPrimaryClassNodes(body.needSortedInput())) {
+            SourceUnit context = null;
+            try {
+                context = classNode.getModule().getContext();
+                if (context == null || context.phase < phase || (context.phase == phase && !context.phaseComplete)) {
+                    int offset = 1;
+                    for (Iterator<InnerClassNode> iterator = classNode.getInnerClasses(); iterator.hasNext(); ) {
+                        iterator.next();
+                        offset++;
+                    }
+                    body.call(context, new GeneratorContext(this.ast, offset), classNode);
+                }
+            } catch (CompilationFailedException e) {
+                // fall through, getErrorReporter().failIfErrors() will trigger
+            } catch (NullPointerException npe) {
+                GroovyBugError gbe = new GroovyBugError("unexpected NullpointerException", npe);
+                changeBugText(gbe, context);
+                throw gbe;
+            } catch (GroovyBugError e) {
+                changeBugText(e, context);
+                throw e;
+            } catch (NoClassDefFoundError e) {
+                // effort to get more logging in case a dependency of a class is loaded
+                // although it shouldn't have
+                convertUncaughtExceptionToCompilationError(e);
+            } catch (Exception e) {
+                convertUncaughtExceptionToCompilationError(e);
+            }
+        }
+
+        getErrorCollector().failIfErrors();
+    }
+
+    private void convertUncaughtExceptionToCompilationError(final Throwable e) {
+        // check the exception for a nested compilation exception
+        ErrorCollector nestedCollector = null;
+        for (Throwable next = e.getCause(); next != e && next != null; next = next.getCause()) {
+            if (!(next instanceof MultipleCompilationErrorsException)) continue;
+            MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next;
+            nestedCollector = mcee.collector;
+            break;
+        }
+
+        if (nestedCollector != null) {
+            getErrorCollector().addCollectorContents(nestedCollector);
+        } else {
+            Exception err = e instanceof Exception?((Exception)e):new RuntimeException(e);
+            getErrorCollector().addError(new ExceptionMessage(err, configuration.getDebug(), this));
+        }
+    }
+
+    public void applyToGeneratedGroovyClasses(GroovyClassOperation body) throws CompilationFailedException {
+        if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
+            throw new GroovyBugError("CompilationUnit not ready for output(). Current phase=" + getPhaseDescription());
+        }
+
+        for (GroovyClass gclass : this.generatedClasses) {
+            //
+            // Get the class and calculate its filesystem name
+            //
+            try {
+                body.call(gclass);
+            } catch (CompilationFailedException e) {
+                // fall through, getErrorReporter().failIfErrors() will trigger
+            } catch (NullPointerException npe) {
+                throw npe;
+            } catch (GroovyBugError e) {
+                changeBugText(e, null);
+                throw e;
+            } catch (Exception e) {
+                throw new GroovyBugError(e);
+            }
+        }
+
+        getErrorCollector().failIfErrors();
+    }
+
+    private void changeBugText(GroovyBugError e, SourceUnit context) {
+        e.setBugText("exception in phase '" + getPhaseDescription() + "' in source unit '" + ((context != null) ? context.getName() : "?") + "' " + e.getBugText());
+    }
+    
+    public ClassNodeResolver getClassNodeResolver() {
+        return classNodeResolver;
+    }
+
+
+    public void setClassNodeResolver(ClassNodeResolver classNodeResolver) {
+        this.classNodeResolver = classNodeResolver;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilePhase.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilePhase.java b/src/main/java/org/codehaus/groovy/control/CompilePhase.java
new file mode 100644
index 0000000..7b25fed
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilePhase.java
@@ -0,0 +1,118 @@
+/*
+ *  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.control;
+
+/**
+* The phases of the GroovyCompiler. This is an enum facade on top of the 
+* Phases object. In general, prefer using this object over Phases. 
+*
+* @author Hamlet D'Arcy
+*/ 
+public enum CompilePhase {
+
+    /**
+    * source files are opened and environment configured
+    */ 
+    INITIALIZATION(Phases.INITIALIZATION),
+    
+    /**
+    * the grammar is used to to produce tree of tokens representing the source code
+    */ 
+    PARSING(Phases.PARSING),
+    
+    /**
+    * An abstract syntax tree (AST) is created from token trees
+    */ 
+    CONVERSION(Phases.CONVERSION),
+    
+    /**
+    * Performs consistency and validity checks that the grammar can't check for, and resolves classes
+    */ 
+    SEMANTIC_ANALYSIS(Phases.SEMANTIC_ANALYSIS),
+    
+    /**
+    * Complete building the AST
+    */ 
+    CANONICALIZATION(Phases.CANONICALIZATION),
+    
+    /**
+    * instruction set is chosen, for example java5 or pre java5
+    */ 
+    INSTRUCTION_SELECTION(Phases.INSTRUCTION_SELECTION),
+    
+    /**
+    * creates the binary output in memory
+    */ 
+    CLASS_GENERATION(Phases.CLASS_GENERATION),
+    
+    /**
+    * write the binary output to the file system
+    */ 
+    OUTPUT(Phases.OUTPUT),
+    
+    /**
+    * Perform any last cleanup
+    */ 
+    FINALIZATION(Phases.FINALIZATION),
+    ;
+
+    /**
+    * The phases as an array, with a null entry. 
+    */ 
+    public static CompilePhase[] phases = {
+        null,
+        INITIALIZATION,
+        PARSING,
+        CONVERSION,
+        SEMANTIC_ANALYSIS,
+        CANONICALIZATION,
+        INSTRUCTION_SELECTION,
+        CLASS_GENERATION,
+        OUTPUT,
+        FINALIZATION,
+    };
+
+    int phaseNumber;
+    CompilePhase(int phaseNumber) {
+        this.phaseNumber = phaseNumber;
+    }
+
+    /**
+    * Returns the underlieng integer Phase number. 
+    */ 
+    public int getPhaseNumber() {
+        return phaseNumber;
+    }
+
+    /**
+     * Returns the CompilePhase for the given integer phase number.
+     * @param phaseNumber
+     *      the phase number
+     * @return
+     *      the CompilePhase or null if not found
+     */
+    public static CompilePhase fromPhaseNumber(int phaseNumber) {
+        for (CompilePhase phase : values()) {
+            if (phase.phaseNumber == phaseNumber) {
+                return phase;
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java b/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
new file mode 100644
index 0000000..9f6babe
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilerConfiguration.java
@@ -0,0 +1,934 @@
+/*
+ *  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.control;
+
+import org.apache.groovy.util.Maps;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+import org.codehaus.groovy.control.io.NullWriter;
+import org.codehaus.groovy.control.messages.WarningMessage;
+import org.objectweb.asm.Opcodes;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * Compilation control flags and coordination stuff.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @author <a href="mailto:jim@pagesmiths.com">Jim White</a>
+ * @author <a href="mailto:cedric.champeau@gmail.com">Cedric Champeau</a>
+ */
+
+public class CompilerConfiguration {
+
+    /** This (<code>"indy"</code>) is the Optimization Option value for enabling <code>invokedynamic</code> complilation. */
+    public static final String INVOKEDYNAMIC = "indy";
+
+    /** This (<code>"1.4"</code>) is the value for targetBytecode to compile for a JDK 1.4. **/
+    public static final String JDK4 = "1.4";
+    /** This (<code>"1.5"</code>) is the value for targetBytecode to compile for a JDK 1.5. **/
+    public static final String JDK5 = "1.5";
+    /** This (<code>"1.6"</code>) is the value for targetBytecode to compile for a JDK 1.6. **/
+    public static final String JDK6 = "1.6";
+    /** This (<code>"1.7"</code>) is the value for targetBytecode to compile for a JDK 1.7. **/
+    public static final String JDK7 = "1.7";
+    /** This (<code>"1.8"</code>) is the value for targetBytecode to compile for a JDK 1.8. **/
+    public static final String JDK8 = "1.8";
+
+    /** This (<code>"1.5"</code>) is the value for targetBytecode to compile for a JDK 1.5 or later JVM. **/
+    public static final String POST_JDK5 = JDK5; // for backwards compatibility
+
+    /** This (<code>"1.4"</code>) is the value for targetBytecode to compile for a JDK 1.4 JVM. **/
+    public static final String PRE_JDK5 = JDK4;
+
+    /**
+     * JDK version to bytecode version mapping
+     */
+    public static final Map<String, Integer> JDK_TO_BYTECODE_VERSION_MAP = Maps.of(
+            JDK4, Opcodes.V1_4,
+            JDK5, Opcodes.V1_5,
+            JDK6, Opcodes.V1_6,
+            JDK7, Opcodes.V1_7,
+            JDK8, Opcodes.V1_8
+    );
+
+    /** An array of the valid targetBytecode values **/
+    public static final String[] ALLOWED_JDKS = JDK_TO_BYTECODE_VERSION_MAP.keySet().toArray(new String[0]);
+
+    // Just call getVMVersion() once.
+    public static final String CURRENT_JVM_VERSION = getVMVersion();
+
+    private static final String GROOVY_ANTLR4_OPT = "groovy.antlr4";
+
+    /**
+     * The default source encoding
+     */
+    public static final String DEFAULT_SOURCE_ENCODING = "UTF-8";
+
+    // Static initializers are executed in text order,
+    // therefore we must do this one last!
+    /**
+     *  A convenience for getting a default configuration.  Do not modify it!
+     *  See {@link #CompilerConfiguration(Properties)} for an example on how to
+     *  make a suitable copy to modify.  But if you're really starting from a
+     *  default context, then you probably just want <code>new CompilerConfiguration()</code>. 
+     */
+    public static final CompilerConfiguration DEFAULT = new CompilerConfiguration();
+
+    /**
+     * See {@link WarningMessage} for levels.
+     */
+    private int warningLevel;
+
+    /**
+     * Encoding for source files
+     */
+    private String sourceEncoding;
+
+    /**
+     * The <code>PrintWriter</code> does nothing.
+     */
+    private PrintWriter output;
+
+    /**
+     * Directory into which to write classes
+     */
+    private File targetDirectory;
+
+    /**
+     * Classpath for use during compilation
+     */
+    private LinkedList<String> classpath;
+
+    /**
+     * If true, the compiler should produce action information
+     */
+    private boolean verbose;
+
+    /**
+     * If true, debugging code should be activated
+     */
+    private boolean debug;
+
+    /**
+     * If true, generates metadata for reflection on method parameters
+     */
+    private boolean parameters = false;
+
+    /**
+     * The number of non-fatal errors to allow before bailing
+     */
+    private int tolerance;
+
+    /**
+     * Base class name for scripts (must derive from Script)
+     */
+    private String scriptBaseClass;
+
+    private ParserPluginFactory pluginFactory;
+
+    /**
+     * extension used to find a groovy file
+     */
+    private String defaultScriptExtension;
+
+    /**
+     * extensions used to find a groovy files
+     */
+    private Set<String> scriptExtensions = new LinkedHashSet<String>();
+
+    /**
+     * if set to true recompilation is enabled
+     */
+    private boolean recompileGroovySource;
+
+    /**
+     * sets the minimum of time after a script can be recompiled.
+     */
+    private int minimumRecompilationInterval;
+
+    /**
+     * sets the bytecode version target
+     */
+    private String targetBytecode;
+
+    /**
+     * options for joint compilation (null by default == no joint compilation)
+     */
+    private Map<String, Object> jointCompilationOptions;
+
+    /**
+     * options for optimizations (empty map by default)
+     */
+    private Map<String, Boolean> optimizationOptions;
+
+    private final List<CompilationCustomizer> compilationCustomizers = new LinkedList<CompilationCustomizer>();
+
+    /**
+     * Sets a list of global AST transformations which should not be loaded even if they are
+     * defined in META-INF/org.codehaus.groovy.transform.ASTTransformation files. By default,
+     * none is disabled.
+     */
+    private Set<String> disabledGlobalASTTransformations;
+
+    private BytecodeProcessor bytecodePostprocessor;
+
+    /**
+     * defines if antlr2 parser should be used or the antlr4 one if
+     * no factory is set yet
+     */
+    private ParserVersion parserVersion = ParserVersion.V_2;
+
+    /**
+     * Sets the Flags to defaults.
+     */
+    public CompilerConfiguration() {
+        //
+        // Set in safe defaults
+
+        setWarningLevel(WarningMessage.LIKELY_ERRORS);
+        setOutput(null);
+        setTargetDirectory((File) null);
+        setClasspath("");
+        setVerbose(false);
+        setDebug(false);
+        setParameters(safeGetSystemProperty("groovy.parameters") != null);
+        setTolerance(10);
+        setScriptBaseClass(null);
+        setRecompileGroovySource(false);
+        setMinimumRecompilationInterval(100);
+        setTargetBytecode(safeGetSystemProperty("groovy.target.bytecode", getVMVersion()));
+        setDefaultScriptExtension(safeGetSystemProperty("groovy.default.scriptExtension", ".groovy"));
+
+        // Source file encoding
+        String encoding = safeGetSystemProperty("file.encoding", DEFAULT_SOURCE_ENCODING);
+        encoding = safeGetSystemProperty("groovy.source.encoding", encoding);
+        setSourceEncoding(encoding);
+
+        try {
+            setOutput(new PrintWriter(System.err));
+        } catch (Exception e) {
+            // IGNORE
+        }
+
+
+        String target = safeGetSystemProperty("groovy.target.directory");
+        if (target != null) {
+            setTargetDirectory(target);
+        }
+
+        boolean indy = false;
+        try {
+            indy = Boolean.getBoolean("groovy.target.indy");
+        } catch (Exception e) {
+            // IGNORE
+        }
+        if (DEFAULT!=null && Boolean.TRUE.equals(DEFAULT.getOptimizationOptions().get(INVOKEDYNAMIC))) {
+            indy = true;
+        }
+        Map options = new HashMap<String,Boolean>(3);
+        if (indy) {
+            options.put(INVOKEDYNAMIC, Boolean.TRUE);
+        }
+        setOptimizationOptions(options);
+
+        try {
+            String groovyAntlr4Opt = System.getProperty(GROOVY_ANTLR4_OPT);
+
+            this.parserVersion = !Boolean.valueOf(groovyAntlr4Opt)
+                            ? ParserVersion.V_2
+                            : ParserVersion.V_4;
+        } catch (Exception e) {
+            // IGNORE
+        }
+    }
+
+    /**
+     * Retrieves a System property, or null if any of the following exceptions occur.
+     * <ul>
+     *     <li>SecurityException - if a security manager exists and its checkPropertyAccess method doesn't allow access to the specified system property.</li>
+     *     <li>NullPointerException - if key is null.</li>
+     *     <li>IllegalArgumentException - if key is empty.</li>
+     * </ul>
+     * @param key the name of the system property.
+     * @return value of the system property or null
+     */
+    private static String safeGetSystemProperty(String key){
+        return safeGetSystemProperty(key, null);
+    }
+
+    /**
+     * Retrieves a System property, or null if any of the following exceptions occur (Warning: Exception messages are
+     * suppressed).
+     * <ul>
+     *     <li>SecurityException - if a security manager exists and its checkPropertyAccess method doesn't allow access to the specified system property.</li>
+     *     <li>NullPointerException - if key is null.</li>
+     *     <li>IllegalArgumentException - if key is empty.</li>
+     * </ul>
+     * @param key the name of the system property.
+     * @param def a default value.
+     * @return  value of the system property or null
+     */
+    private static String safeGetSystemProperty(String key, String def){
+        try {
+            return System.getProperty(key, def);
+        } catch (SecurityException t){
+            // suppress exception
+        } catch (NullPointerException t){
+            // suppress exception
+        } catch (IllegalArgumentException t){
+            // suppress exception
+        }
+        return def;
+    }
+
+    /**
+     * Copy constructor.  Use this if you have a mostly correct configuration
+     * for your compilation but you want to make a some changes programatically.
+     * An important reason to prefer this approach is that your code will most
+     * likely be forward compatible with future changes to this configuration API.
+     * <p>
+     * An example of this copy constructor at work:
+     * <pre>
+     *    // In all likelihood there is already a configuration in your code's context
+     *    // for you to copy, but for the sake of this example we'll use the global default.
+     *    CompilerConfiguration myConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
+     *    myConfiguration.setDebug(true);
+     *</pre>
+     *
+     * @param configuration The configuration to copy.
+     */
+    public CompilerConfiguration(CompilerConfiguration configuration) {
+        setWarningLevel(configuration.getWarningLevel());
+        setOutput(configuration.getOutput());
+        setTargetDirectory(configuration.getTargetDirectory());
+        setClasspathList(new LinkedList<String>(configuration.getClasspath()));
+        setVerbose(configuration.getVerbose());
+        setDebug(configuration.getDebug());
+        setParameters(configuration.getParameters());
+        setTolerance(configuration.getTolerance());
+        setScriptBaseClass(configuration.getScriptBaseClass());
+        setRecompileGroovySource(configuration.getRecompileGroovySource());
+        setMinimumRecompilationInterval(configuration.getMinimumRecompilationInterval());
+        setTargetBytecode(configuration.getTargetBytecode());
+        setDefaultScriptExtension(configuration.getDefaultScriptExtension());
+        setSourceEncoding(configuration.getSourceEncoding());
+        setTargetDirectory(configuration.getTargetDirectory());
+        Map<String, Object> jointCompilationOptions = configuration.getJointCompilationOptions();
+        if (jointCompilationOptions != null) {
+            jointCompilationOptions = new HashMap<String, Object>(jointCompilationOptions);
+        }
+        setJointCompilationOptions(jointCompilationOptions);
+        setPluginFactory(configuration.getPluginFactory());
+        setScriptExtensions(configuration.getScriptExtensions());
+        setOptimizationOptions(new HashMap<String, Boolean>(configuration.getOptimizationOptions()));
+    }
+
+    /**
+     * Sets the Flags to the specified configuration, with defaults
+     * for those not supplied.
+     * Note that those "defaults" here do <em>not</em> include checking the
+     * settings in {@link System#getProperties()} in general, only file.encoding, 
+     * groovy.target.directory and groovy.source.encoding are.
+     * <p>
+     * If you want to set a few flags but keep Groovy's default
+     * configuration behavior then be sure to make your settings in
+     * a Properties that is backed by <code>System.getProperties()</code> (which
+     * is done using this constructor). That might be done like this:
+     * <pre>
+     * Properties myProperties = new Properties(System.getProperties());
+     * myProperties.setProperty("groovy.output.debug", "true");
+     * myConfiguration = new CompilerConfiguration(myProperties);
+     * </pre>
+     * And you also have to contend with a possible SecurityException when
+     * getting the system properties (See {@link java.lang.System#getProperties()}).
+     * A safer approach would be to copy a default
+     * CompilerConfiguration and make your changes there using the setter:
+     * <pre>
+     * // In all likelihood there is already a configuration for you to copy,
+     * // but for the sake of this example we'll use the global default.
+     * CompilerConfiguration myConfiguration = new CompilerConfiguration(CompilerConfiguration.DEFAULT);
+     * myConfiguration.setDebug(true);
+     * </pre>
+     * <p>
+     * <table summary="Groovy Compiler Configuration Properties">
+     *   <tr>
+     *      <th>Property Key</th><th>Get/Set Property Name</th>
+     *   </tr>
+     *      <tr>
+     *      <td><code>"groovy.warnings"</code></td><td>{@link #getWarningLevel}</td></tr>
+     *      <tr><td><code>"groovy.source.encoding"</code></td><td>{@link #getSourceEncoding}</td></tr>
+     *      <tr><td><code>"groovy.target.directory"</code></td><td>{@link #getTargetDirectory}</td></tr>
+     *      <tr><td><code>"groovy.target.bytecode"</code></td><td>{@link #getTargetBytecode}</td></tr>
+     *      <tr><td><code>"groovy.classpath"</code></td><td>{@link #getClasspath}</td></tr>
+     *      <tr><td><code>"groovy.output.verbose"</code></td><td>{@link #getVerbose}</td></tr>
+     *      <tr><td><code>"groovy.output.debug"</code></td><td>{@link #getDebug}</td></tr>
+     *      <tr><td><code>"groovy.errors.tolerance"</code></td><td>{@link #getTolerance}</td></tr>
+     *      <tr><td><code>"groovy.script.extension"</code></td><td>{@link #getDefaultScriptExtension}</td></tr>
+     *      <tr><td><code>"groovy.script.base"</code></td><td>{@link #getScriptBaseClass}</td></tr>
+     *      <tr><td><code>"groovy.recompile"</code></td><td>{@link #getRecompileGroovySource}</td></tr>
+     *      <tr><td><code>"groovy.recompile.minimumInterval"</code></td><td>{@link #getMinimumRecompilationInterval}</td></tr>
+     *      <tr><td>
+     *   </tr>
+     * </table>
+     *
+     * @param configuration The properties to get flag values from.
+     */
+    public CompilerConfiguration(Properties configuration) throws ConfigurationException {
+        this();
+        configure(configuration);
+    }
+
+    /**
+     * Checks if the specified bytecode version string represents a JDK 1.5+ compatible
+     * bytecode version.
+     * @param bytecodeVersion the bytecode version string (1.4, 1.5, 1.6, 1.7 or 1.8)
+     * @return true if the bytecode version is JDK 1.5+
+     */
+    public static boolean isPostJDK5(String bytecodeVersion) {
+        return new BigDecimal(bytecodeVersion).compareTo(new BigDecimal(JDK5)) >= 0;
+    }
+
+    /**
+     * Checks if the specified bytecode version string represents a JDK 1.7+ compatible
+     * bytecode version.
+     * @param bytecodeVersion the bytecode version string (1.4, 1.5, 1.6, 1.7 or 1.8)
+     * @return true if the bytecode version is JDK 1.7+
+     */
+    public static boolean isPostJDK7(String bytecodeVersion) {
+        return new BigDecimal(bytecodeVersion).compareTo(new BigDecimal(JDK7)) >= 0;
+    }
+
+    /**
+     * Method to configure a CompilerConfiguration by using Properties.
+     * For a list of available properties look at {@link #CompilerConfiguration(Properties)}.
+     * @param configuration The properties to get flag values from.
+     */
+    public void configure(Properties configuration) throws ConfigurationException {
+        String text = null;
+        int numeric = 0;
+
+        //
+        // Warning level
+
+        numeric = getWarningLevel();
+        try {
+            text = configuration.getProperty("groovy.warnings", "likely errors");
+            numeric = Integer.parseInt(text);
+        } catch (NumberFormatException e) {
+            text = text.toLowerCase();
+            if (text.equals("none")) {
+                numeric = WarningMessage.NONE;
+            }
+            else if (text.startsWith("likely")) {
+                numeric = WarningMessage.LIKELY_ERRORS;
+            }
+            else if (text.startsWith("possible")) {
+                numeric = WarningMessage.POSSIBLE_ERRORS;
+            }
+            else if (text.startsWith("paranoia")) {
+                numeric = WarningMessage.PARANOIA;
+            }
+            else {
+                throw new ConfigurationException("unrecognized groovy.warnings: " + text);
+            }
+        }
+        setWarningLevel(numeric);
+
+        //
+        // Source file encoding
+        //
+        text = configuration.getProperty("groovy.source.encoding");
+        if (text == null) {
+            text = configuration.getProperty("file.encoding", "US-ASCII");
+        }
+        setSourceEncoding(text);
+
+        //
+        // Target directory for classes
+        //
+        text = configuration.getProperty("groovy.target.directory");
+        if (text != null) setTargetDirectory(text);
+
+        text = configuration.getProperty("groovy.target.bytecode");
+        if (text != null) setTargetBytecode(text);
+
+        //
+        // Classpath
+        //
+        text = configuration.getProperty("groovy.classpath");
+        if (text != null) setClasspath(text);
+
+        //
+        // Verbosity
+        //
+        text = configuration.getProperty("groovy.output.verbose");
+        if (text != null && text.equalsIgnoreCase("true")) setVerbose(true);
+
+        //
+        // Debugging
+        //
+        text = configuration.getProperty("groovy.output.debug");
+        if (text != null && text.equalsIgnoreCase("true")) setDebug(true);
+
+        //
+        // Parameters
+        //
+        setParameters(configuration.getProperty("groovy.parameters") != null);
+
+        //
+        // Tolerance
+        //
+        numeric = 10;
+        try {
+            text = configuration.getProperty("groovy.errors.tolerance", "10");
+            numeric = Integer.parseInt(text);
+        } catch (NumberFormatException e) {
+            throw new ConfigurationException(e);
+        }
+        setTolerance(numeric);
+
+        //
+        // Script Base Class
+        //
+        text = configuration.getProperty("groovy.script.base");
+        if (text!=null) setScriptBaseClass(text);
+
+        //
+        // recompilation options
+        //
+        text = configuration.getProperty("groovy.recompile");
+        if (text != null) {
+            setRecompileGroovySource(text.equalsIgnoreCase("true"));
+        }
+
+        numeric = 100;
+        try {
+            text = configuration.getProperty("groovy.recompile.minimumIntervall");
+            if (text==null) text = configuration.getProperty("groovy.recompile.minimumInterval");
+            if (text!=null) {
+                numeric = Integer.parseInt(text);
+            } else {
+                numeric = 100;
+            }
+        } catch (NumberFormatException e) {
+            throw new ConfigurationException(e);
+        }
+        setMinimumRecompilationInterval(numeric);
+
+        // disabled global AST transformations
+        text = configuration.getProperty("groovy.disabled.global.ast.transformations");
+        if (text!=null) {
+            String[] classNames = text.split(",\\s*}");
+            Set<String> blacklist = new HashSet<String>(Arrays.asList(classNames));
+            setDisabledGlobalASTTransformations(blacklist);
+        }
+    }
+
+    /**
+     * Gets the currently configured warning level. See {@link WarningMessage}
+     * for level details.
+     */
+    public int getWarningLevel() {
+        return this.warningLevel;
+    }
+
+    /**
+     * Sets the warning level. See {@link WarningMessage} for level details.
+     */
+    public void setWarningLevel(int level) {
+        if (level < WarningMessage.NONE || level > WarningMessage.PARANOIA) {
+            this.warningLevel = WarningMessage.LIKELY_ERRORS;
+        }
+        else {
+            this.warningLevel = level;
+        }
+    }
+
+    /**
+     * Gets the currently configured source file encoding.
+     */
+    public String getSourceEncoding() {
+        return this.sourceEncoding;
+    }
+
+    /**
+     * Sets the encoding to be used when reading source files.
+     */
+    public void setSourceEncoding(String encoding) {
+        if (encoding == null) encoding = DEFAULT_SOURCE_ENCODING;
+        this.sourceEncoding = encoding;
+    }
+
+    /**
+     * Gets the currently configured output writer.
+     * @deprecated not used anymore
+     */
+    @Deprecated
+    public PrintWriter getOutput() {
+        return this.output;
+    }
+
+    /**
+     * Sets the output writer.
+     * @deprecated not used anymore, has no effect
+     */
+    @Deprecated
+    public void setOutput(PrintWriter output) {
+        if (output == null) {
+            this.output = new PrintWriter(NullWriter.DEFAULT);
+        }
+        else {
+            this.output = output;
+        }
+    }
+
+    /**
+     * Gets the target directory for writing classes.
+     */
+    public File getTargetDirectory() {
+        return this.targetDirectory;
+    }
+
+    /**
+     * Sets the target directory.
+     */
+    public void setTargetDirectory(String directory) {
+        if (directory != null && directory.length() > 0) {
+            this.targetDirectory = new File(directory);
+        } else {
+            this.targetDirectory = null;
+        }
+    }
+
+    /**
+     * Sets the target directory.
+     */
+    public void setTargetDirectory(File directory) {
+        this.targetDirectory = directory;
+    }
+
+    /**
+     * @return the classpath
+     */
+    public List<String> getClasspath() {
+        return this.classpath;
+    }
+
+    /**
+     * Sets the classpath.
+     */
+    public void setClasspath(String classpath) {
+        this.classpath = new LinkedList<String>();
+        StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator);
+        while (tokenizer.hasMoreTokens()) {
+            this.classpath.add(tokenizer.nextToken());
+        }
+    }
+
+    /**
+     * sets the classpath using a list of Strings
+     * @param parts list of strings containing the classpath parts
+     */
+    public void setClasspathList(List<String> parts) {
+        this.classpath = new LinkedList<String>(parts);
+    }
+
+    /**
+     * Returns true if verbose operation has been requested.
+     */
+    public boolean getVerbose() {
+        return this.verbose;
+    }
+
+    /**
+     * Turns verbose operation on or off.
+     */
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+
+    /**
+     * Returns true if debugging operation has been requested.
+     */
+    public boolean getDebug() {
+        return this.debug;
+    }
+
+    /**
+     * Returns true if parameter metadata generation has been enabled.
+     */
+    public boolean getParameters() {
+        return this.parameters;
+    }
+
+    /**
+     * Turns debugging operation on or off.
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Turns parameter metadata generation on or off.
+     */
+    public void setParameters(boolean parameters) {
+        this.parameters = parameters;
+    }
+
+    /**
+     * Returns the requested error tolerance.
+     */
+    public int getTolerance() {
+        return this.tolerance;
+    }
+
+    /**
+     * Sets the error tolerance, which is the number of
+     * non-fatal errors (per unit) that should be tolerated before
+     * compilation is aborted.
+     */
+    public void setTolerance(int tolerance) {
+        this.tolerance = tolerance;
+    }
+
+    /**
+     * Gets the name of the base class for scripts.  It must be a subclass
+     * of Script.
+     */
+    public String getScriptBaseClass() {
+        return this.scriptBaseClass;
+    }
+
+    /**
+     * Sets the name of the base class for scripts.  It must be a subclass
+     * of Script.
+     */
+    public void setScriptBaseClass(String scriptBaseClass) {
+        this.scriptBaseClass = scriptBaseClass;
+    }
+
+    public ParserPluginFactory getPluginFactory() {
+        if (pluginFactory == null) {
+            pluginFactory = ParserVersion.V_2 == parserVersion
+                                ? ParserPluginFactory.antlr2()
+                                : ParserPluginFactory.antlr4();
+        }
+        return pluginFactory;
+    }
+
+    public void setPluginFactory(ParserPluginFactory pluginFactory) {
+        this.pluginFactory = pluginFactory;
+    }
+
+    public void setScriptExtensions(Set<String> scriptExtensions) {
+        if(scriptExtensions == null) scriptExtensions = new LinkedHashSet<String>();
+        this.scriptExtensions = scriptExtensions;
+    }
+
+    public Set<String> getScriptExtensions() {
+        if(scriptExtensions == null || scriptExtensions.isEmpty()) {
+            /*
+             *  this happens
+             *  *    when groovyc calls FileSystemCompiler in forked mode, or
+             *  *    when FileSystemCompiler is run from the command line directly, or
+             *  *    when groovy was not started using groovyc or FileSystemCompiler either
+             */
+            scriptExtensions = SourceExtensionHandler.getRegisteredExtensions(
+                    this.getClass().getClassLoader());
+        }
+        return scriptExtensions;
+    }
+
+    public String getDefaultScriptExtension() {
+        return defaultScriptExtension;
+    }
+
+
+    public void setDefaultScriptExtension(String defaultScriptExtension) {
+        this.defaultScriptExtension = defaultScriptExtension;
+    }
+
+    public void setRecompileGroovySource(boolean recompile) {
+        recompileGroovySource = recompile;
+    }
+
+    public boolean getRecompileGroovySource(){
+        return recompileGroovySource;
+    }
+
+    public void setMinimumRecompilationInterval(int time) {
+        minimumRecompilationInterval = Math.max(0,time);
+    }
+
+    public int getMinimumRecompilationInterval() {
+        return minimumRecompilationInterval;
+    }
+
+    /**
+     * Allow setting the bytecode compatibility. The parameter can take
+     * one of the values <tt>1.7</tt>, <tt>1.6</tt>, <tt>1.5</tt> or <tt>1.4</tt>.
+     * If wrong parameter then the value will default to VM determined version.
+     *
+     * @param version the bytecode compatibility mode
+     */
+    public void setTargetBytecode(String version) {
+        for (String allowedJdk : ALLOWED_JDKS) {
+            if (allowedJdk.equals(version)) {
+                this.targetBytecode = version;
+            }
+        }
+    }
+
+    /**
+     * Retrieves the compiler bytecode compatibility mode.
+     *
+     * @return bytecode compatibility mode. Can be either <tt>1.5</tt> or <tt>1.4</tt>.
+     */
+    public String getTargetBytecode() {
+        return this.targetBytecode;
+    }
+
+    private static String getVMVersion() {
+        return POST_JDK5;
+    }
+
+    /**
+     * Gets the joint compilation options for this configuration.
+     * @return the options
+     */
+    public Map<String, Object> getJointCompilationOptions() {
+        return jointCompilationOptions;
+    }
+
+    /**
+     * Sets the joint compilation options for this configuration.
+     * Using null will disable joint compilation.
+     * @param options the options
+     */
+    public void setJointCompilationOptions(Map<String, Object> options) {
+        jointCompilationOptions = options;
+    }
+
+    /**
+     * Gets the optimization options for this configuration.
+     * @return the options (always not null)
+     */
+    public Map<String, Boolean> getOptimizationOptions() {
+        return optimizationOptions;
+    }
+
+    /**
+     * Sets the optimization options for this configuration.
+     * No entry or a true for that entry means to enable that optimization,
+     * a false means the optimization is disabled.
+     * Valid keys are "all" and "int".
+     * @param options the options.
+     * @throws IllegalArgumentException if the options are null
+     */
+    public void setOptimizationOptions(Map<String, Boolean> options) {
+        if (options==null) throw new IllegalArgumentException("provided option map must not be null");
+        optimizationOptions = options;
+    }
+
+    /**
+     * Adds compilation customizers to the compilation process. A compilation customizer is a class node
+     * operation which performs various operations going from adding imports to access control.
+     * @param customizers the list of customizers to be added
+     * @return this configuration instance
+     */
+    public CompilerConfiguration addCompilationCustomizers(CompilationCustomizer... customizers) {
+        if (customizers==null) throw new IllegalArgumentException("provided customizers list must not be null");
+        compilationCustomizers.addAll(Arrays.asList(customizers));
+        return this;
+    }
+
+    /**
+     * Returns the list of compilation customizers.
+     * @return the customizers (always not null)
+     */
+    public List<CompilationCustomizer> getCompilationCustomizers() {
+        return compilationCustomizers;
+    }
+
+    /**
+     * Returns the list of disabled global AST transformation class names.
+     * @return a list of global AST transformation fully qualified class names
+     */
+    public Set<String> getDisabledGlobalASTTransformations() {
+        return disabledGlobalASTTransformations;
+    }
+
+    /**
+     * Disables global AST transformations. In order to avoid class loading side effects, it is not recommended
+     * to use MyASTTransformation.class.getName() by directly use the class name as a string. Disabled AST transformations
+     * only apply to automatically loaded global AST transformations, that is to say transformations defined in a
+     * META-INF/org.codehaus.groovy.transform.ASTTransformation file. If you explicitly add a global AST transformation
+     * in your compilation process, for example using the {@link org.codehaus.groovy.control.customizers.ASTTransformationCustomizer} or
+     * using a {@link org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation}, then nothing will prevent
+     * the transformation from being loaded.
+     * @param disabledGlobalASTTransformations a set of fully qualified class names of global AST transformations
+     * which should not be loaded.
+     */
+    public void setDisabledGlobalASTTransformations(final Set<String> disabledGlobalASTTransformations) {
+        this.disabledGlobalASTTransformations = disabledGlobalASTTransformations;
+    }
+
+    public BytecodeProcessor getBytecodePostprocessor() {
+        return bytecodePostprocessor;
+    }
+
+    public void setBytecodePostprocessor(final BytecodeProcessor bytecodePostprocessor) {
+        this.bytecodePostprocessor = bytecodePostprocessor;
+    }
+
+    public ParserVersion getParserVersion() {
+        return this.parserVersion;
+    }
+
+    public void setParserVersion(ParserVersion parserVersion) {
+        this.parserVersion = parserVersion;
+    }
+
+    /**
+     * Check whether invoke dynamic enabled
+     * @return the result
+     */
+    public boolean isIndyEnabled() {
+        Boolean indyEnabled = this.getOptimizationOptions().get(INVOKEDYNAMIC);
+
+        if (null == indyEnabled) {
+            return false;
+        }
+
+        return indyEnabled;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ConfigurationException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ConfigurationException.java b/src/main/java/org/codehaus/groovy/control/ConfigurationException.java
new file mode 100644
index 0000000..3d0658a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ConfigurationException.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.control;
+
+import org.codehaus.groovy.GroovyExceptionInterface;
+
+
+
+
+/**
+ *  Thrown when configuration data is invalid.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class ConfigurationException extends RuntimeException implements GroovyExceptionInterface
+{
+    
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND SUCH
+
+    protected Exception cause;   // The phase in which the failures occurred
+
+    
+   /**
+    *  Initializes the exception from a cause exception.
+    */
+    
+    public ConfigurationException( Exception cause ) 
+    {
+        super( cause.getMessage() );
+        this.cause = cause;
+    }
+    
+    
+   /**
+    *  Initializes the exception with just a message.
+    */
+    
+    public ConfigurationException( String message )
+    {
+        super( message );
+    }
+
+    
+    
+   /**
+    *  Returns the causing exception, if available.
+    */
+    
+    public Throwable getCause()
+    {
+        return cause;
+    }
+    
+    
+   /**
+    *  Its always fatal.
+    */
+    
+    public boolean isFatal()
+    {
+        return true;
+    }
+    
+    
+    
+   /**
+    *  Set fatal is just ignored.
+    */
+    
+    public void setFatal( boolean fatal )
+    {
+    }
+    
+}


[54/62] [abbrv] groovy git commit: Avoid copying unprocessed release-info file into jar (then overwriting)

Posted by cc...@apache.org.
Avoid copying unprocessed release-info file into jar (then overwriting)


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/5abfec71
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/5abfec71
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/5abfec71

Branch: refs/heads/GROOVY_2_6_X
Commit: 5abfec710bda06f43876a7ad1ba52e4ce3743dda
Parents: 9edb31f
Author: Cedric Champeau <cc...@apache.org>
Authored: Thu Dec 14 12:41:00 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:51:50 2017 +0100

----------------------------------------------------------------------
 build.gradle                                    | 12 ++-
 .../groovy/gradle/ReleaseInfoGenerator.groovy   | 78 ++++++++++++++++++++
 gradle/assemble.gradle                          |  7 +-
 gradle/docs.gradle                              |  4 +-
 gradle/filter.gradle                            | 33 ---------
 .../META-INF/groovy-release-info.properties     | 23 ------
 6 files changed, 91 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/5abfec71/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index 4b96673..c24073e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,6 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
+import org.codehaus.groovy.gradle.ReleaseInfoGenerator
 
 buildscript {
     repositories {
@@ -69,6 +70,7 @@ buildScanRecipes {
 ext.modules = {
     subprojects.findAll{ !['performance', 'tests-vm8'].contains(it.name) }
 }
+ext.isReleaseVersion = !groovyVersion.toLowerCase().endsWith("snapshot")
 
 apply from: 'gradle/filter.gradle'
 apply from: 'gradle/indy.gradle'
@@ -97,6 +99,15 @@ allprojects {
         maven { url 'http://dl.bintray.com/melix/thirdparty-apache' } // openbeans
     }
 
+    ext.buildDate = isReleaseVersion?new Date():new Date(0)
+
+    task generateReleaseInfo(type: ReleaseInfoGenerator) {
+        version = rootProject.groovyVersion
+        bundleVersion = rootProject.groovyBundleVersion
+        buildDate = rootProject.buildDate
+        outputFile = file("$buildDir/release-info/groovy-release-info.properties")
+    }
+
     apply plugin: 'groovy'
     apply from: "${rootProject.projectDir}/gradle/indy.gradle"
     if (JavaVersion.current().java7Compatible) {
@@ -169,7 +180,6 @@ ext {
     spockVersion = '1.2-groovy-2.4-SNAPSHOT'
     antlr4Version = '4.7'
     jsr305Version = '3.0.2'
-    isReleaseVersion = !groovyVersion.toLowerCase().endsWith("snapshot")
 }
 
 dependencies {

http://git-wip-us.apache.org/repos/asf/groovy/blob/5abfec71/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/ReleaseInfoGenerator.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/ReleaseInfoGenerator.groovy b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/ReleaseInfoGenerator.groovy
new file mode 100644
index 0000000..b29193c
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/ReleaseInfoGenerator.groovy
@@ -0,0 +1,78 @@
+/*
+ *  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.gradle
+
+import groovy.transform.CompileStatic
+import org.gradle.api.DefaultTask
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.OutputFile
+
+import java.text.SimpleDateFormat
+
+@CompileStatic
+class ReleaseInfoGenerator extends DefaultTask {
+    String description = "Generates the release info properties file"
+
+    @Input
+    String version
+
+    @Input
+    String bundleVersion
+
+    @Input
+    Date buildDate
+
+    @OutputFile
+    File outputFile
+
+    @TaskAction
+    void generateDescriptor() {
+        String date = new SimpleDateFormat('dd-MMM-yyyy').format(buildDate)
+        String time = new SimpleDateFormat('hh:mm aa').format(buildDate)
+
+        outputFile.withWriter('utf-8') {
+            it.write("""#
+#  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.
+#
+
+ImplementationVersion=$version
+BundleVersion=$bundleVersion
+BuildDate=$date
+BuildTime=$time
+""")
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/5abfec71/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index d60fab4..706953f 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -166,9 +166,7 @@ allprojects {
                 include('antlr4-license.txt')
             }
             from("$projectDir/notices/NOTICE-JARJAR")
-            from('src/resources/META-INF/groovy-release-info.properties') {
-                filter(rootProject.propertiesFilter, org.apache.tools.ant.filters.ReplaceTokens)
-            }
+            from(generateReleaseInfo)
             rename { String filename -> filename == 'LICENSE-JARJAR' ? 'LICENSE' : filename == 'NOTICE-JARJAR' ? 'NOTICE' : filename }
         }
         arch.exclude '**/package-info.class'
@@ -317,9 +315,6 @@ subprojects { sp ->
             } else {
                 from "${rootProject.projectDir}/notices/NOTICE-BASE"
             }
-            from("${rootProject.projectDir}/src/resources/META-INF/groovy-release-info.properties") {
-                filter(rootProject.propertiesFilter, org.apache.tools.ant.filters.ReplaceTokens)
-            }
             rename { String filename -> filename == 'LICENSE-BASE' ? 'LICENSE' : filename == 'NOTICE-BASE' ? 'NOTICE' : filename }
         }
         exclude '**/package-info.class'

http://git-wip-us.apache.org/repos/asf/groovy/blob/5abfec71/gradle/docs.gradle
----------------------------------------------------------------------
diff --git a/gradle/docs.gradle b/gradle/docs.gradle
index d10b9d5..483bb23 100644
--- a/gradle/docs.gradle
+++ b/gradle/docs.gradle
@@ -113,9 +113,7 @@ groovydocAll groovydocSpec
 task docProjectVersionInfo(type: Copy) {
     destinationDir = file("${project(':groovy-docgenerator').sourceSets.main.java.outputDir}")
     into('META-INF') {
-        from('src/resources/META-INF/groovy-release-info.properties') {
-            filter(rootProject.propertiesFilter, org.apache.tools.ant.filters.ReplaceTokens)
-        }
+        from(generateReleaseInfo)
     }
     from('subprojects/groovy-docgenerator/src/main/resources')
 }

http://git-wip-us.apache.org/repos/asf/groovy/blob/5abfec71/gradle/filter.gradle
----------------------------------------------------------------------
diff --git a/gradle/filter.gradle b/gradle/filter.gradle
deleted file mode 100644
index 4a5575b..0000000
--- a/gradle/filter.gradle
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-import java.text.SimpleDateFormat
-
-// do not use a timestamp during development, to avoid unnecessary rebuilds and cache misses
-ext.buildTime = rootProject.groovyVersion.endsWith('SNAPSHOT')?new Date(0):new Date()
-
-ext.propertiesFilter = [
-        beginToken: '#',
-        endToken: '#',
-        tokens: [
-                ImplementationVersion: rootProject.groovyVersion,
-                BundleVersion: rootProject.groovyBundleVersion,
-                BuildDate: new SimpleDateFormat('dd-MMM-yyyy').format(rootProject.buildTime),
-                BuildTime: new SimpleDateFormat('hh:mm aa').format(rootProject.buildTime)
-        ]
-]

http://git-wip-us.apache.org/repos/asf/groovy/blob/5abfec71/src/resources/META-INF/groovy-release-info.properties
----------------------------------------------------------------------
diff --git a/src/resources/META-INF/groovy-release-info.properties b/src/resources/META-INF/groovy-release-info.properties
deleted file mode 100644
index d33358c..0000000
--- a/src/resources/META-INF/groovy-release-info.properties
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-#  Licensed to the Apache Software Foundation (ASF) under one
-#  or more contributor license agreements.  See the NOTICE file
-#  distributed with this work for additional information
-#  regarding copyright ownership.  The ASF licenses this file
-#  to you under the Apache License, Version 2.0 (the
-#  "License"); you may not use this file except in compliance
-#  with the License.  You may obtain a copy of the License at
-#
-#    http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing,
-#  software distributed under the License is distributed on an
-#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-#  KIND, either express or implied.  See the License for the
-#  specific language governing permissions and limitations
-#  under the License.
-#
-
-ImplementationVersion=#ImplementationVersion#
-BundleVersion=#BundleVersion#
-BuildDate=#BuildDate#
-BuildTime=#BuildTime#
\ No newline at end of file


[57/62] [abbrv] groovy git commit: Remove unnecessary `mustRunAfter`

Posted by cc...@apache.org.
Remove unnecessary `mustRunAfter`

Now that we generate separate jars for jar and jarjar, we don't need to make sure it's run after tests.


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/e3dfcfd7
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/e3dfcfd7
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/e3dfcfd7

Branch: refs/heads/GROOVY_2_6_X
Commit: e3dfcfd7530824e6695e5edcc6923285ccd498a4
Parents: 52b67fc
Author: Cedric Champeau <cc...@apache.org>
Authored: Thu Dec 14 22:46:19 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:52:42 2017 +0100

----------------------------------------------------------------------
 gradle/assemble.gradle | 4 ----
 1 file changed, 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/e3dfcfd7/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index 97ec669..d51a8d1 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -320,10 +320,6 @@ subprojects { sp ->
     }
 }
 
-allprojects {
-    rootProject.jarjar.mustRunAfter(test)
-}
-
 task sourceAllJar(type: Jar, dependsOn: { modules()*.sourceJar + rootProject.sourceJar }) {
     with sourceJar.rootSpec
     modules()*.sourceJar.each {


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
new file mode 100644
index 0000000..5e13cd7
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/ExtendedVerifier.java
@@ -0,0 +1,342 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.tools.ParameterUtils;
+import org.codehaus.groovy.control.AnnotationConstantsVisitor;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.ErrorCollector;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+
+/**
+ * A specialized Groovy AST visitor meant to perform additional verifications upon the
+ * current AST. Currently it does checks on annotated nodes and annotations itself.
+ * <p>
+ * Current limitations:
+ * - annotations on local variables are not supported
+ */
+public class ExtendedVerifier extends ClassCodeVisitorSupport {
+    public static final String JVM_ERROR_MESSAGE = "Please make sure you are running on a JVM >= 1.5";
+
+    private final SourceUnit source;
+    private ClassNode currentClass;
+
+    public ExtendedVerifier(SourceUnit sourceUnit) {
+        this.source = sourceUnit;
+    }
+
+    public void visitClass(ClassNode node) {
+        AnnotationConstantsVisitor acv = new AnnotationConstantsVisitor();
+        acv.visitClass(node, this.source);
+        this.currentClass = node;
+        if (node.isAnnotationDefinition()) {
+            visitAnnotations(node, AnnotationNode.ANNOTATION_TARGET);
+        } else {
+            visitAnnotations(node, AnnotationNode.TYPE_TARGET);
+        }
+        PackageNode packageNode = node.getPackage();
+        if (packageNode != null) {
+            visitAnnotations(packageNode, AnnotationNode.PACKAGE_TARGET);
+        }
+        node.visitContents(this);
+    }
+
+    public void visitField(FieldNode node) {
+        visitAnnotations(node, AnnotationNode.FIELD_TARGET);
+    }
+
+    @Override
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        visitAnnotations(expression, AnnotationNode.LOCAL_VARIABLE_TARGET);
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+        visitConstructorOrMethod(node, AnnotationNode.CONSTRUCTOR_TARGET);
+    }
+
+    public void visitMethod(MethodNode node) {
+        visitConstructorOrMethod(node, AnnotationNode.METHOD_TARGET);
+    }
+
+    private void visitConstructorOrMethod(MethodNode node, int methodTarget) {
+        visitAnnotations(node, methodTarget);
+        for (int i = 0; i < node.getParameters().length; i++) {
+            Parameter parameter = node.getParameters()[i];
+            visitAnnotations(parameter, AnnotationNode.PARAMETER_TARGET);
+        }
+
+        if (this.currentClass.isAnnotationDefinition() && !node.isStaticConstructor()) {
+            ErrorCollector errorCollector = new ErrorCollector(this.source.getConfiguration());
+            AnnotationVisitor visitor = new AnnotationVisitor(this.source, errorCollector);
+            visitor.setReportClass(currentClass);
+            visitor.checkReturnType(node.getReturnType(), node);
+            if (node.getParameters().length > 0) {
+                addError("Annotation members may not have parameters.", node.getParameters()[0]);
+            }
+            if (node.getExceptions().length > 0) {
+                addError("Annotation members may not have a throws clause.", node.getExceptions()[0]);
+            }
+            ReturnStatement code = (ReturnStatement) node.getCode();
+            if (code != null) {
+                visitor.visitExpression(node.getName(), code.getExpression(), node.getReturnType());
+                visitor.checkCircularReference(currentClass, node.getReturnType(), code.getExpression());
+            }
+            this.source.getErrorCollector().addCollectorContents(errorCollector);
+        }
+        Statement code = node.getCode();
+        if (code != null) {
+            code.visit(this);
+        }
+
+    }
+
+    public void visitProperty(PropertyNode node) {
+    }
+
+    protected void visitAnnotations(AnnotatedNode node, int target) {
+        if (node.getAnnotations().isEmpty()) {
+            return;
+        }
+        this.currentClass.setAnnotated(true);
+        if (!isAnnotationCompatible()) {
+            addError("Annotations are not supported in the current runtime. " + JVM_ERROR_MESSAGE, node);
+            return;
+        }
+        Map<String, List<AnnotationNode>> runtimeAnnotations = new LinkedHashMap<String, List<AnnotationNode>>();
+        for (AnnotationNode unvisited : node.getAnnotations()) {
+            AnnotationNode visited = visitAnnotation(unvisited);
+            String name = visited.getClassNode().getName();
+            if (visited.hasRuntimeRetention()) {
+                List<AnnotationNode> seen = runtimeAnnotations.get(name);
+                if (seen == null) {
+                    seen = new ArrayList<AnnotationNode>();
+                }
+                seen.add(visited);
+                runtimeAnnotations.put(name, seen);
+            }
+            boolean isTargetAnnotation = name.equals("java.lang.annotation.Target");
+
+            // Check if the annotation target is correct, unless it's the target annotating an annotation definition
+            // defining on which target elements the annotation applies
+            if (!isTargetAnnotation && !visited.isTargetAllowed(target)) {
+                addError("Annotation @" + name + " is not allowed on element "
+                        + AnnotationNode.targetToName(target), visited);
+            }
+            visitDeprecation(node, visited);
+            visitOverride(node, visited);
+        }
+        checkForDuplicateAnnotations(node, runtimeAnnotations);
+    }
+
+    private void checkForDuplicateAnnotations(AnnotatedNode node, Map<String, List<AnnotationNode>> runtimeAnnotations) {
+        for (Map.Entry<String, List<AnnotationNode>> next : runtimeAnnotations.entrySet()) {
+            if (next.getValue().size() > 1) {
+                ClassNode repeatable = null;
+                AnnotationNode repeatee = next.getValue().get(0);
+                List<AnnotationNode> repeateeAnnotations = repeatee.getClassNode().getAnnotations();
+                for (AnnotationNode anno : repeateeAnnotations) {
+                    ClassNode annoClassNode = anno.getClassNode();
+                    if (annoClassNode.getName().equals("java.lang.annotation.Repeatable")) {
+                        Expression value = anno.getMember("value");
+                        if (value instanceof ClassExpression) {
+                            ClassExpression ce = (ClassExpression) value;
+                            if (ce.getType() != null && ce.getType().isAnnotationDefinition()) {
+                                repeatable = ce.getType();
+                                break;
+                            }
+                        }
+                    }
+                }
+                if (repeatable != null) {
+                    AnnotationNode collector = new AnnotationNode(repeatable);
+                    collector.setRuntimeRetention(true); // checked earlier
+                    List<Expression> annos = new ArrayList<Expression>();
+                    for (AnnotationNode an : next.getValue()) {
+                        annos.add(new AnnotationConstantExpression(an));
+                    }
+                    collector.addMember("value", new ListExpression(annos));
+                    node.addAnnotation(collector);
+                    node.getAnnotations().removeAll(next.getValue());
+                }
+            }
+        }
+    }
+
+    private static void visitDeprecation(AnnotatedNode node, AnnotationNode visited) {
+        if (visited.getClassNode().isResolved() && visited.getClassNode().getName().equals("java.lang.Deprecated")) {
+            if (node instanceof MethodNode) {
+                MethodNode mn = (MethodNode) node;
+                mn.setModifiers(mn.getModifiers() | Opcodes.ACC_DEPRECATED);
+            } else if (node instanceof FieldNode) {
+                FieldNode fn = (FieldNode) node;
+                fn.setModifiers(fn.getModifiers() | Opcodes.ACC_DEPRECATED);
+            } else if (node instanceof ClassNode) {
+                ClassNode cn = (ClassNode) node;
+                cn.setModifiers(cn.getModifiers() | Opcodes.ACC_DEPRECATED);
+            }
+        }
+    }
+
+    // TODO GROOVY-5011 handle case of @Override on a property
+    private void visitOverride(AnnotatedNode node, AnnotationNode visited) {
+        ClassNode annotationClassNode = visited.getClassNode();
+        if (annotationClassNode.isResolved() && annotationClassNode.getName().equals("java.lang.Override")) {
+            if (node instanceof MethodNode && !Boolean.TRUE.equals(node.getNodeMetaData(Verifier.DEFAULT_PARAMETER_GENERATED))) {
+                boolean override = false;
+                MethodNode origMethod = (MethodNode) node;
+                ClassNode cNode = origMethod.getDeclaringClass();
+                if (origMethod.hasDefaultValue()) {
+                    List<MethodNode> variants = cNode.getDeclaredMethods(origMethod.getName());
+                    for (MethodNode m : variants) {
+                        if (m.getAnnotations().contains(visited) && isOverrideMethod(m)) {
+                            override = true;
+                            break;
+                        }
+                    }
+                } else {
+                    override = isOverrideMethod(origMethod);
+                }
+
+                if (!override) {
+                    addError("Method '" + origMethod.getName() + "' from class '" + cNode.getName() + "' does not override " +
+                            "method from its superclass or interfaces but is annotated with @Override.", visited);
+                }
+            }
+        }
+    }
+
+    private static boolean isOverrideMethod(MethodNode method) {
+        ClassNode cNode = method.getDeclaringClass();
+        ClassNode next = cNode;
+        outer:
+        while (next != null) {
+            Map genericsSpec = createGenericsSpec(next);
+            MethodNode mn = correctToGenericsSpec(genericsSpec, method);
+            if (next != cNode) {
+                ClassNode correctedNext = correctToGenericsSpecRecurse(genericsSpec, next);
+                MethodNode found = getDeclaredMethodCorrected(genericsSpec, mn, correctedNext);
+                if (found != null) break;
+            }
+            List<ClassNode> ifaces = new ArrayList<ClassNode>();
+            ifaces.addAll(Arrays.asList(next.getInterfaces()));
+            Map updatedGenericsSpec = new HashMap(genericsSpec);
+            while (!ifaces.isEmpty()) {
+                ClassNode origInterface = ifaces.remove(0);
+                if (!origInterface.equals(ClassHelper.OBJECT_TYPE)) {
+                    updatedGenericsSpec = createGenericsSpec(origInterface, updatedGenericsSpec);
+                    ClassNode iNode = correctToGenericsSpecRecurse(updatedGenericsSpec, origInterface);
+                    MethodNode found2 = getDeclaredMethodCorrected(updatedGenericsSpec, mn, iNode);
+                    if (found2 != null) break outer;
+                    ifaces.addAll(Arrays.asList(iNode.getInterfaces()));
+                }
+            }
+            ClassNode superClass = next.getUnresolvedSuperClass();
+            if (superClass != null) {
+                next =  correctToGenericsSpecRecurse(updatedGenericsSpec, superClass);
+            } else {
+                next = null;
+            }
+        }
+        return next != null;
+    }
+
+    private static MethodNode getDeclaredMethodCorrected(Map genericsSpec, MethodNode mn, ClassNode correctedNext) {
+        for (MethodNode orig :  correctedNext.getDeclaredMethods(mn.getName())) {
+            MethodNode method = correctToGenericsSpec(genericsSpec, orig);
+            if (ParameterUtils.parametersEqual(method.getParameters(), mn.getParameters())) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Resolve metadata and details of the annotation.
+     *
+     * @param unvisited the node to visit
+     * @return the visited node
+     */
+    private AnnotationNode visitAnnotation(AnnotationNode unvisited) {
+        ErrorCollector errorCollector = new ErrorCollector(this.source.getConfiguration());
+        AnnotationVisitor visitor = new AnnotationVisitor(this.source, errorCollector);
+        AnnotationNode visited = visitor.visit(unvisited);
+        this.source.getErrorCollector().addCollectorContents(errorCollector);
+        return visited;
+    }
+
+    /**
+     * Check if the current runtime allows Annotation usage.
+     *
+     * @return true if running on a 1.5+ runtime
+     */
+    protected boolean isAnnotationCompatible() {
+        return CompilerConfiguration.isPostJDK5(this.source.getConfiguration().getTargetBytecode());
+    }
+
+    public void addError(String msg, ASTNode expr) {
+        this.source.getErrorCollector().addErrorAndContinue(
+                new SyntaxErrorMessage(
+                        new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), this.source)
+        );
+    }
+
+    @Override
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    // TODO use it or lose it
+    public void visitGenericType(GenericsType genericsType) {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java b/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java
new file mode 100644
index 0000000..76c4e1f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/FinalVariableAnalyzer.java
@@ -0,0 +1,363 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PostfixExpression;
+import org.codehaus.groovy.ast.expr.PrefixExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+
+import java.lang.reflect.Modifier;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+public class FinalVariableAnalyzer extends ClassCodeVisitorSupport {
+
+    private final SourceUnit sourceUnit;
+    private final VariableNotFinalCallback callback;
+
+    private Set<VariableExpression> declaredFinalVariables = null;
+    private boolean inAssignment = false;
+
+    private enum VariableState {
+        is_uninitialized(false),
+        is_final(true),
+        is_var(false);
+
+        private final boolean isFinal;
+
+        VariableState(final boolean isFinal) {
+            this.isFinal = isFinal;
+        }
+
+        public VariableState getNext() {
+            switch (this) {
+                case is_uninitialized:
+                    return is_final;
+                default:
+                    return is_var;
+            }
+        }
+
+        public boolean isFinal() {
+            return isFinal;
+        }
+    }
+
+    private final Deque<Map<Variable, VariableState>> assignmentTracker = new LinkedList<Map<Variable, VariableState>>();
+
+    public FinalVariableAnalyzer(final SourceUnit sourceUnit) {
+        this(sourceUnit, null);
+    }
+
+    public FinalVariableAnalyzer(final SourceUnit sourceUnit, final VariableNotFinalCallback callback) {
+        this.callback = callback;
+        this.sourceUnit = sourceUnit;
+        pushState();
+    }
+
+    private Map<Variable, VariableState> pushState() {
+        Map<Variable, VariableState> state = new StateMap();
+        assignmentTracker.add(state);
+        return state;
+    }
+
+    private static Variable getTarget(Variable v) {
+        if (v instanceof VariableExpression) {
+            Variable t = ((VariableExpression) v).getAccessedVariable();
+            if (t == v) return t;
+            return getTarget(t);
+        }
+        return v;
+    }
+
+    private Map<Variable, VariableState> popState() {
+        return assignmentTracker.removeLast();
+    }
+
+    private Map<Variable, VariableState> getState() {
+        return assignmentTracker.getLast();
+    }
+
+    @Override
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
+    }
+
+    public boolean isEffectivelyFinal(Variable v) {
+        VariableState state = getState().get(v);
+        return (v instanceof Parameter && state == null)
+                || (state != null && state.isFinal());
+    }
+
+    @Override
+    public void visitBlockStatement(final BlockStatement block) {
+        Set<VariableExpression> old = declaredFinalVariables;
+        declaredFinalVariables = new HashSet<VariableExpression>();
+        super.visitBlockStatement(block);
+        if (callback != null) {
+            Map<Variable, VariableState> state = getState();
+            for (VariableExpression declaredFinalVariable : declaredFinalVariables) {
+                VariableState variableState = state.get(declaredFinalVariable.getAccessedVariable());
+                if (variableState == null || variableState != VariableState.is_final) {
+                    callback.variableNotAlwaysInitialized(declaredFinalVariable);
+                }
+            }
+        }
+        declaredFinalVariables = old;
+    }
+
+    @Override
+    public void visitBinaryExpression(final BinaryExpression expression) {
+        boolean assignment = StaticTypeCheckingSupport.isAssignment(expression.getOperation().getType());
+        boolean isDeclaration = expression instanceof DeclarationExpression;
+        Expression leftExpression = expression.getLeftExpression();
+        Expression rightExpression = expression.getRightExpression();
+        if (isDeclaration && leftExpression instanceof VariableExpression) {
+            VariableExpression var = (VariableExpression) leftExpression;
+            if (Modifier.isFinal(var.getModifiers())) {
+                declaredFinalVariables.add(var);
+            }
+        }
+        leftExpression.visit(this);
+        inAssignment = assignment;
+        rightExpression.visit(this);
+        inAssignment = false;
+        if (assignment) {
+            if (leftExpression instanceof Variable) {
+                boolean uninitialized =
+                        isDeclaration && rightExpression == EmptyExpression.INSTANCE;
+                recordAssignment((Variable) leftExpression, isDeclaration, uninitialized, false, expression);
+            } else if (leftExpression instanceof TupleExpression) {
+                TupleExpression te = (TupleExpression) leftExpression;
+                for (Expression next : te.getExpressions()) {
+                    if (next instanceof Variable) {
+                        recordAssignment((Variable) next, isDeclaration, false, false, next);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void visitClosureExpression(final ClosureExpression expression) {
+        boolean old = inAssignment;
+        inAssignment = false;
+        super.visitClosureExpression(expression);
+        inAssignment = old;
+    }
+
+    @Override
+    public void visitPrefixExpression(final PrefixExpression expression) {
+        inAssignment = expression.getExpression() instanceof VariableExpression;
+        super.visitPrefixExpression(expression);
+        inAssignment = false;
+        checkPrePostfixOperation(expression.getExpression(), expression);
+    }
+
+    @Override
+    public void visitPostfixExpression(final PostfixExpression expression) {
+        inAssignment = expression.getExpression() instanceof VariableExpression;
+        super.visitPostfixExpression(expression);
+        inAssignment = false;
+        checkPrePostfixOperation(expression.getExpression(), expression);
+    }
+
+    private void checkPrePostfixOperation(final Expression variable, final Expression originalExpression) {
+        if (variable instanceof Variable) {
+            recordAssignment((Variable) variable, false, false, true, originalExpression);
+            if (variable instanceof VariableExpression) {
+                Variable accessed = ((VariableExpression) variable).getAccessedVariable();
+                if (accessed != variable) {
+                    recordAssignment(accessed, false, false, true, originalExpression);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void visitVariableExpression(final VariableExpression expression) {
+        super.visitVariableExpression(expression);
+        if (inAssignment) {
+            Map<Variable, VariableState> state = getState();
+            Variable key = expression.getAccessedVariable();
+            VariableState variableState = state.get(key);
+            if (variableState == VariableState.is_uninitialized) {
+                variableState = VariableState.is_var;
+                state.put(key, variableState);
+            }
+        }
+    }
+
+    @Override
+    public void visitIfElse(final IfStatement ifElse) {
+        visitStatement(ifElse);
+        ifElse.getBooleanExpression().visit(this);
+        Map<Variable, VariableState> ifState = pushState();
+        ifElse.getIfBlock().visit(this);
+        popState();
+        Statement elseBlock = ifElse.getElseBlock();
+        Map<Variable, VariableState> elseState = pushState();
+        if (elseBlock instanceof EmptyStatement) {
+            // dispatching to EmptyStatement will not call back visitor,
+            // must call our visitEmptyStatement explicitly
+            visitEmptyStatement((EmptyStatement) elseBlock);
+        } else {
+            elseBlock.visit(this);
+        }
+        popState();
+
+        // merge if/else branches
+        Map<Variable, VariableState> curState = getState();
+        Set<Variable> allVars = new HashSet<Variable>();
+        allVars.addAll(curState.keySet());
+        allVars.addAll(ifState.keySet());
+        allVars.addAll(elseState.keySet());
+        for (Variable var : allVars) {
+            VariableState beforeValue = curState.get(var);
+            VariableState ifValue = ifState.get(var);
+            VariableState elseValue = elseState.get(var);
+            // merge if and else values
+            VariableState mergedIfElse;
+            mergedIfElse = ifValue != null && ifValue.isFinal
+                    && elseValue != null && elseValue.isFinal ? VariableState.is_final : VariableState.is_var;
+            if (beforeValue == null) {
+                curState.put(var, mergedIfElse);
+            } else {
+                if (beforeValue == VariableState.is_uninitialized) {
+                    curState.put(var, mergedIfElse);
+                } else if (ifValue != null || elseValue != null) {
+                    curState.put(var, VariableState.is_var);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void visitTryCatchFinally(final TryCatchStatement statement) {
+        visitStatement(statement);
+        Map<Variable, VariableState> beforeTryCatch = new HashMap<Variable, VariableState>(getState());
+        statement.getTryStatement().visit(this);
+        for (CatchStatement catchStatement : statement.getCatchStatements()) {
+            catchStatement.visit(this);
+        }
+        Statement finallyStatement = statement.getFinallyStatement();
+        // we need to recall which final variables are unassigned so cloning the current state
+        Map<Variable, VariableState> afterTryCatchState = new HashMap<Variable, VariableState>(getState());
+        if (finallyStatement instanceof EmptyStatement) {
+            // dispatching to EmptyStatement will not call back visitor,
+            // must call our visitEmptyStatement explicitly
+            visitEmptyStatement((EmptyStatement) finallyStatement);
+        } else {
+            finallyStatement.visit(this);
+        }
+        // and now we must reset to uninitialized state variables which were only initialized during try/catch
+        Map<Variable, VariableState> afterFinally = new HashMap<Variable, VariableState>(getState());
+        for (Map.Entry<Variable, VariableState> entry : afterFinally.entrySet()) {
+            Variable var = entry.getKey();
+            VariableState afterFinallyState = entry.getValue();
+            VariableState beforeTryCatchState = beforeTryCatch.get(var);
+            if (afterFinallyState == VariableState.is_final
+                    && beforeTryCatchState != VariableState.is_final
+                    && afterTryCatchState.get(var) != beforeTryCatchState) {
+                getState().put(var, beforeTryCatchState == null ? VariableState.is_uninitialized : beforeTryCatchState);
+            }
+        }
+    }
+
+    private void recordAssignment(
+            Variable var,
+            boolean isDeclaration,
+            boolean uninitialized,
+            boolean forceVariable,
+            Expression expression) {
+        if (var == null) {
+            return;
+        }
+        if (!isDeclaration && var.isClosureSharedVariable()) {
+            getState().put(var, VariableState.is_var);
+        }
+        VariableState variableState = getState().get(var);
+        if (variableState == null) {
+            variableState = uninitialized ? VariableState.is_uninitialized : VariableState.is_final;
+            if (getTarget(var) instanceof Parameter) {
+                variableState = VariableState.is_var;
+            }
+        } else {
+            variableState = variableState.getNext();
+        }
+        if (forceVariable) {
+            variableState = VariableState.is_var;
+        }
+        getState().put(var, variableState);
+        if (variableState == VariableState.is_var && callback != null) {
+            callback.variableNotFinal(var, expression);
+        }
+    }
+
+    public interface VariableNotFinalCallback {
+        /**
+         * Callback called whenever an assignment transforms an effectively final variable into a non final variable
+         * (aka, breaks the "final" modifier contract)
+         *
+         * @param var  the variable detected as not final
+         * @param bexp the expression responsible for the contract to be broken
+         */
+        void variableNotFinal(Variable var, Expression bexp);
+
+        /**
+         * Callback used whenever a variable is declared as final, but can remain in an uninitialized state
+         *
+         * @param var the variable detected as potentially uninitialized
+         */
+        void variableNotAlwaysInitialized(VariableExpression var);
+    }
+
+    private static class StateMap extends HashMap<Variable, VariableState> {
+        @Override
+        public VariableState get(final Object key) {
+            return super.get(getTarget((Variable) key));
+        }
+
+        @Override
+        public VariableState put(final Variable key, final VariableState value) {
+            return super.put(getTarget(key), value);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
new file mode 100644
index 0000000..8b8a510
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/GeneratorContext.java
@@ -0,0 +1,113 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.MethodNode;
+
+
+/**
+ * A context shared across generations of a class and its inner classes
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class GeneratorContext {
+
+    private int innerClassIdx = 1;
+    private int closureClassIdx = 1;
+    private final CompileUnit compileUnit;
+    
+    public GeneratorContext(CompileUnit compileUnit) {
+        this.compileUnit = compileUnit;
+    }
+
+    public GeneratorContext(CompileUnit compileUnit, int innerClassOffset) {
+        this.compileUnit = compileUnit;
+        this.innerClassIdx = innerClassOffset;
+    }
+
+    public int getNextInnerClassIdx() {
+        return innerClassIdx++;
+    }
+
+    public CompileUnit getCompileUnit() {
+        return compileUnit;
+    }
+
+    public String getNextClosureInnerName(ClassNode owner, ClassNode enclosingClass, MethodNode enclosingMethod) {
+        String methodName = "";
+        if (enclosingMethod != null) {
+            methodName = enclosingMethod.getName();
+
+            if (enclosingClass.isDerivedFrom(ClassHelper.CLOSURE_TYPE)) {
+                methodName = "";
+            } else {
+                methodName = "_"+encodeAsValidClassName(methodName);
+            }
+        }
+        return methodName + "_closure" + closureClassIdx++;
+    }
+
+
+    private static final int MIN_ENCODING = ' ';
+    private static final int MAX_ENCODING = ']';
+    private static final boolean[] CHARACTERS_TO_ENCODE = new boolean[MAX_ENCODING-MIN_ENCODING+1];
+    static {
+        CHARACTERS_TO_ENCODE[' '-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['!'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['/'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['.'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE[';'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['$'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['<'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['>'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['['-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE[']'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE[':'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['\\'-MIN_ENCODING] = true;
+    }
+
+    public static String encodeAsValidClassName(String name) {
+        final int l = name.length();
+        StringBuilder b = null;
+        int lastEscape = -1;
+        for(int i = 0; i < l; ++i) {
+            final int encodeIndex = name.charAt(i) - MIN_ENCODING;
+            if (encodeIndex >= 0 && encodeIndex < CHARACTERS_TO_ENCODE.length) {
+                if (CHARACTERS_TO_ENCODE[encodeIndex]) {
+                    if(b == null) {
+                        b = new StringBuilder(name.length() + 3);
+                        b.append(name, 0, i);
+                    } else {
+                        b.append(name, lastEscape + 1, i);
+                    }
+                    b.append('_');
+                    lastEscape = i;
+                }
+            }
+        }
+        if(b == null) return name.toString();
+        if (lastEscape == -1) throw new GroovyBugError("unexpected escape char control flow in "+name);
+        b.append(name, lastEscape + 1, l);
+        return b.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
new file mode 100644
index 0000000..a8d84c8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
@@ -0,0 +1,454 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+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.asm.BytecodeHelper;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.List;
+
+import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+
+public class InnerClassCompletionVisitor extends InnerClassVisitorHelper implements Opcodes {
+
+    private final SourceUnit sourceUnit;
+    private ClassNode classNode;
+    private FieldNode thisField = null;
+
+    private static final String
+            CLOSURE_INTERNAL_NAME   = BytecodeHelper.getClassInternalName(CLOSURE_TYPE),
+            CLOSURE_DESCRIPTOR      = BytecodeHelper.getTypeDescription(CLOSURE_TYPE);
+
+    public InnerClassCompletionVisitor(CompilationUnit cu, SourceUnit su) {
+        sourceUnit = su;
+    }
+
+    @Override
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
+    }
+
+    @Override
+    public void visitClass(ClassNode node) {
+        this.classNode = node;
+        thisField = null;
+        InnerClassNode innerClass = null;
+        if (!node.isEnum() && !node.isInterface() && node instanceof InnerClassNode) {
+            innerClass = (InnerClassNode) node;
+            thisField = innerClass.getField("this$0");
+            if (innerClass.getVariableScope() == null && innerClass.getDeclaredConstructors().isEmpty()) {
+                // add dummy constructor
+                innerClass.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, null, null);
+            }
+        }
+        if (node.isEnum() || node.isInterface()) return;
+        // use Iterator.hasNext() to check for available inner classes
+        if (node.getInnerClasses().hasNext()) addDispatcherMethods(node);
+        if (innerClass == null) return;
+        super.visitClass(node);
+        addDefaultMethods(innerClass);
+    }
+
+    @Override
+    public void visitConstructor(ConstructorNode node) {
+        addThisReference(node);
+        super.visitConstructor(node);
+    }
+
+    private static String getTypeDescriptor(ClassNode node, boolean isStatic) {
+        return BytecodeHelper.getTypeDescription(getClassNode(node, isStatic));
+    }
+
+    private static String getInternalName(ClassNode node, boolean isStatic) {
+        return BytecodeHelper.getClassInternalName(getClassNode(node, isStatic));
+    }
+
+    private static void addDispatcherMethods(ClassNode classNode) {
+        final int objectDistance = getObjectDistance(classNode);
+
+        // since we added an anonymous inner class we should also
+        // add the dispatcher methods
+
+        // add method dispatcher
+        Parameter[] parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name"),
+                new Parameter(ClassHelper.OBJECT_TYPE, "args")
+        };
+        MethodNode method = classNode.addSyntheticMethod(
+                "this$dist$invoke$" + objectDistance,
+                ACC_PUBLIC + ACC_SYNTHETIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        BlockStatement block = new BlockStatement();
+        setMethodDispatcherCode(block, VariableExpression.THIS_EXPRESSION, parameters);
+        method.setCode(block);
+
+        // add property setter
+        parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name"),
+                new Parameter(ClassHelper.OBJECT_TYPE, "value")
+        };
+        method = classNode.addSyntheticMethod(
+                "this$dist$set$" + objectDistance,
+                ACC_PUBLIC + ACC_SYNTHETIC,
+                ClassHelper.VOID_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertySetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
+        method.setCode(block);
+
+        // add property getter
+        parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name")
+        };
+        method = classNode.addSyntheticMethod(
+                "this$dist$get$" + objectDistance,
+                ACC_PUBLIC + ACC_SYNTHETIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertyGetterDispatcher(block, VariableExpression.THIS_EXPRESSION, parameters);
+        method.setCode(block);
+    }
+
+    private void getThis(MethodVisitor mv, String classInternalName, String outerClassDescriptor, String innerClassInternalName) {
+        mv.visitVarInsn(ALOAD, 0);
+        if (CLOSURE_TYPE.equals(thisField.getType())) {
+            mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", CLOSURE_DESCRIPTOR);
+            mv.visitMethodInsn(INVOKEVIRTUAL, CLOSURE_INTERNAL_NAME, "getThisObject", "()Ljava/lang/Object;", false);
+            mv.visitTypeInsn(CHECKCAST, innerClassInternalName);
+        } else {
+            mv.visitFieldInsn(GETFIELD, classInternalName, "this$0", outerClassDescriptor);
+        }
+    }
+    
+    private void addDefaultMethods(InnerClassNode node) {
+        final boolean isStatic = isStatic(node);
+
+        ClassNode outerClass = node.getOuterClass();
+        final String classInternalName = org.codehaus.groovy.classgen.asm.BytecodeHelper.getClassInternalName(node);
+        final String outerClassInternalName = getInternalName(outerClass, isStatic);
+        final String outerClassDescriptor = getTypeDescriptor(outerClass, isStatic);
+        final int objectDistance = getObjectDistance(outerClass);
+
+        // add missing method dispatcher
+        Parameter[] parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name"),
+                new Parameter(ClassHelper.OBJECT_TYPE, "args")
+        };
+
+        String methodName = "methodMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        MethodNode method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        BlockStatement block = new BlockStatement();
+        if (isStatic) {
+            setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
+        } else {
+            block.addStatement(
+                    new BytecodeSequence(new BytecodeInstruction() {
+                        public void visit(MethodVisitor mv) {
+                            getThis(mv,classInternalName,outerClassDescriptor,outerClassInternalName);
+                            mv.visitVarInsn(ALOAD, 1);
+                            mv.visitVarInsn(ALOAD, 2);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$invoke$" + objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", false);
+                            mv.visitInsn(ARETURN);
+                        }
+                    })
+            );
+        }
+        method.setCode(block);
+
+        // add static missing method dispatcher
+        methodName = "$static_methodMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setMethodDispatcherCode(block, new ClassExpression(outerClass), parameters);
+        method.setCode(block);
+
+        // add property setter dispatcher
+        parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name"),
+                new Parameter(ClassHelper.OBJECT_TYPE, "val")
+        };
+
+        methodName = "propertyMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC,
+                ClassHelper.VOID_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        if (isStatic) {
+            setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
+        } else {
+            block.addStatement(
+                    new BytecodeSequence(new BytecodeInstruction() {
+                        public void visit(MethodVisitor mv) {
+                            getThis(mv,classInternalName,outerClassDescriptor,outerClassInternalName);
+                            mv.visitVarInsn(ALOAD, 1);
+                            mv.visitVarInsn(ALOAD, 2);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$set$" + objectDistance, "(Ljava/lang/String;Ljava/lang/Object;)V", false);
+                            mv.visitInsn(RETURN);
+                        }
+                    })
+            );
+        }
+        method.setCode(block);
+
+        // add static property missing setter dispatcher
+        methodName = "$static_propertyMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
+                ClassHelper.VOID_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertySetterDispatcher(block, new ClassExpression(outerClass), parameters);
+        method.setCode(block);
+
+        // add property getter dispatcher
+        parameters = new Parameter[]{
+                new Parameter(ClassHelper.STRING_TYPE, "name")
+        };
+
+        methodName = "propertyMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        if (isStatic) {
+            setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
+        } else {
+            block.addStatement(
+                    new BytecodeSequence(new BytecodeInstruction() {
+                        public void visit(MethodVisitor mv) {
+                            getThis(mv,classInternalName,outerClassDescriptor,outerClassInternalName);
+                            mv.visitVarInsn(ALOAD, 1);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, outerClassInternalName, "this$dist$get$" + objectDistance, "(Ljava/lang/String;)Ljava/lang/Object;", false);
+                            mv.visitInsn(ARETURN);
+                        }
+                    })
+            );
+        }
+        method.setCode(block);
+
+        // add static property missing getter dispatcher
+        methodName = "$static_propertyMissing";
+        if (isStatic)
+            addCompilationErrorOnCustomMethodNode(node, methodName, parameters);
+
+        method = node.addSyntheticMethod(
+                methodName,
+                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
+                ClassHelper.OBJECT_TYPE,
+                parameters,
+                ClassNode.EMPTY_ARRAY,
+                null
+        );
+
+        block = new BlockStatement();
+        setPropertyGetterDispatcher(block, new ClassExpression(outerClass), parameters);
+        method.setCode(block);
+    }
+
+    /**
+     * Adds a compilation error if a {@link MethodNode} with the given <tt>methodName</tt> and
+     * <tt>parameters</tt> exists in the {@link InnerClassNode}.
+     */
+    private void addCompilationErrorOnCustomMethodNode(InnerClassNode node, String methodName, Parameter[] parameters) {
+        MethodNode existingMethodNode = node.getMethod(methodName, parameters);
+        // if there is a user-defined methodNode, add compiler error msg and continue
+        if (existingMethodNode != null && !existingMethodNode.isSynthetic())  {
+            addError("\"" +methodName + "\" implementations are not supported on static inner classes as " +
+                    "a synthetic version of \"" + methodName + "\" is added during compilation for the purpose " +
+                    "of outer class delegation.",
+                    existingMethodNode);
+        }
+    }
+
+    private void addThisReference(ConstructorNode node) {
+        if (!shouldHandleImplicitThisForInnerClass(classNode)) return;
+        Statement code = node.getCode();
+
+        // add "this$0" field init
+
+        //add this parameter to node
+        Parameter[] params = node.getParameters();
+        Parameter[] newParams = new Parameter[params.length + 1];
+        System.arraycopy(params, 0, newParams, 1, params.length);
+        String name = getUniqueName(params, node);
+
+        Parameter thisPara = new Parameter(classNode.getOuterClass().getPlainNodeReference(), name);
+        newParams[0] = thisPara;
+        node.setParameters(newParams);
+
+        BlockStatement block = null;
+        if (code == null) {
+            block = new BlockStatement();
+        } else if (!(code instanceof BlockStatement)) {
+            block = new BlockStatement();
+            block.addStatement(code);
+        } else {
+            block = (BlockStatement) code;
+        }
+        BlockStatement newCode = new BlockStatement();
+        addFieldInit(thisPara, thisField, newCode);
+        ConstructorCallExpression cce = getFirstIfSpecialConstructorCall(block);
+        if (cce == null) {
+            cce = new ConstructorCallExpression(ClassNode.SUPER, new TupleExpression());
+            block.getStatements().add(0, new ExpressionStatement(cce));
+        }
+        if (shouldImplicitlyPassThisPara(cce)) {
+            // add thisPara to this(...)
+            TupleExpression args = (TupleExpression) cce.getArguments();
+            List<Expression> expressions = args.getExpressions();
+            VariableExpression ve = new VariableExpression(thisPara.getName());
+            ve.setAccessedVariable(thisPara);
+            expressions.add(0, ve);
+        }
+        if (cce.isSuperCall()) {
+            // we have a call to super here, so we need to add
+            // our code after that
+            block.getStatements().add(1, newCode);
+        }
+        node.setCode(block);
+    }
+
+    private boolean shouldImplicitlyPassThisPara(ConstructorCallExpression cce) {
+        boolean pass = false;
+        ClassNode superCN = classNode.getSuperClass();
+        if (cce.isThisCall()) {
+            pass = true;
+        } else if (cce.isSuperCall()) {
+            // if the super class is another non-static inner class in the same outer class hierarchy, implicit this
+            // needs to be passed
+            if (!superCN.isEnum() && !superCN.isInterface() && superCN instanceof InnerClassNode) {
+                InnerClassNode superInnerCN = (InnerClassNode) superCN;
+                if (!isStatic(superInnerCN) && classNode.getOuterClass().isDerivedFrom(superCN.getOuterClass())) {
+                    pass = true;
+                }
+            }
+        }
+        return pass;
+    }
+
+    private String getUniqueName(Parameter[] params, ConstructorNode node) {
+        String namePrefix = "$p";
+        outer:
+        for (int i = 0; i < 100; i++) {
+            namePrefix = namePrefix + "$";
+            for (Parameter p : params) {
+                if (p.getName().equals(namePrefix)) continue outer;
+            }
+            return namePrefix;
+        }
+        addError("unable to find a unique prefix name for synthetic this reference in inner class constructor", node);
+        return namePrefix;
+    }
+
+    private static ConstructorCallExpression getFirstIfSpecialConstructorCall(BlockStatement code) {
+        if (code == null) return null;
+
+        final List<Statement> statementList = code.getStatements();
+        if (statementList.isEmpty()) return null;
+
+        final Statement statement = statementList.get(0);
+        if (!(statement instanceof ExpressionStatement)) return null;
+
+        Expression expression = ((ExpressionStatement) statement).getExpression();
+        if (!(expression instanceof ConstructorCallExpression)) return null;
+        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
+        if (cce.isSpecialCall()) return cce;
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
new file mode 100644
index 0000000..87815a8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitor.java
@@ -0,0 +1,288 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+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.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class InnerClassVisitor extends InnerClassVisitorHelper implements Opcodes {
+
+    private final SourceUnit sourceUnit;
+    private ClassNode classNode;
+    private static final int PUBLIC_SYNTHETIC = Opcodes.ACC_PUBLIC + Opcodes.ACC_SYNTHETIC;
+    private FieldNode thisField = null;
+    private MethodNode currentMethod;
+    private FieldNode currentField;
+    private boolean processingObjInitStatements = false;
+    private boolean inClosure = false;
+
+    public InnerClassVisitor(CompilationUnit cu, SourceUnit su) {
+        sourceUnit = su;
+    }
+
+    @Override
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
+    }
+
+    @Override
+    public void visitClass(ClassNode node) {
+        this.classNode = node;
+        thisField = null;
+        InnerClassNode innerClass = null;
+        if (!node.isEnum() && !node.isInterface() && node instanceof InnerClassNode) {
+            innerClass = (InnerClassNode) node;
+            if (!isStatic(innerClass) && innerClass.getVariableScope() == null) {
+                thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, node.getOuterClass().getPlainNodeReference(), null);
+            }
+        }
+
+        super.visitClass(node);
+
+        if (node.isEnum() || node.isInterface()) return;
+        if (innerClass == null) return;
+
+        if (node.getSuperClass().isInterface()) {
+            node.addInterface(node.getUnresolvedSuperClass());
+            node.setUnresolvedSuperClass(ClassHelper.OBJECT_TYPE);
+        }
+    }
+    
+    @Override
+    public void visitClosureExpression(ClosureExpression expression) {
+        boolean inClosureOld = inClosure;
+        inClosure = true;
+        super.visitClosureExpression(expression);
+        inClosure = inClosureOld;
+    }
+
+    @Override
+    protected void visitObjectInitializerStatements(ClassNode node) {
+        processingObjInitStatements = true;
+        super.visitObjectInitializerStatements(node);
+        processingObjInitStatements = false;
+    }
+
+    @Override
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        this.currentMethod = node;
+        visitAnnotations(node);
+        visitClassCodeContainer(node.getCode());
+        // GROOVY-5681: initial expressions should be visited too!
+        for (Parameter param : node.getParameters()) {
+            if (param.hasInitialExpression()) {
+                param.getInitialExpression().visit(this);
+            }
+            visitAnnotations(param);
+        }
+        this.currentMethod = null;
+    }
+
+    @Override
+    public void visitField(FieldNode node) {
+        this.currentField = node;
+        super.visitField(node);
+        this.currentField = null;
+    }
+
+    @Override
+    public void visitProperty(PropertyNode node) {
+        final FieldNode field = node.getField();
+        final Expression init = field.getInitialExpression();
+        field.setInitialValueExpression(null);
+        super.visitProperty(node);
+        field.setInitialValueExpression(init);
+    }
+
+    @Override
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        super.visitConstructorCallExpression(call);
+        if (!call.isUsingAnonymousInnerClass()) {
+            passThisReference(call);
+            return;
+        }
+
+        InnerClassNode innerClass = (InnerClassNode) call.getType();
+        ClassNode outerClass = innerClass.getOuterClass();
+        ClassNode superClass = innerClass.getSuperClass();
+        if (superClass instanceof InnerClassNode
+                && !superClass.isInterface()
+                && !(superClass.isStaticClass()||((superClass.getModifiers()&ACC_STATIC)==ACC_STATIC))) {
+            insertThis0ToSuperCall(call, innerClass);
+        }
+        if (!innerClass.getDeclaredConstructors().isEmpty()) return;
+        if ((innerClass.getModifiers() & ACC_STATIC) != 0) return;
+
+        VariableScope scope = innerClass.getVariableScope();
+        if (scope == null) return;
+
+        // expressions = constructor call arguments
+        List<Expression> expressions = ((TupleExpression) call.getArguments()).getExpressions();
+        // block = init code for the constructor we produce
+        BlockStatement block = new BlockStatement();
+        // parameters = parameters of the constructor
+        final int additionalParamCount = 1 + scope.getReferencedLocalVariablesCount();
+        List<Parameter> parameters = new ArrayList<Parameter>(expressions.size() + additionalParamCount);
+        // superCallArguments = arguments for the super call == the constructor call arguments
+        List<Expression> superCallArguments = new ArrayList<Expression>(expressions.size());
+
+        // first we add a super() call for all expressions given in the 
+        // constructor call expression
+        int pCount = additionalParamCount;
+        for (Expression expr : expressions) {
+            pCount++;
+            // add one parameter for each expression in the
+            // constructor call
+            Parameter param = new Parameter(ClassHelper.OBJECT_TYPE, "p" + pCount);
+            parameters.add(param);
+            // add to super call
+            superCallArguments.add(new VariableExpression(param));
+        }
+
+        // add the super call
+        ConstructorCallExpression cce = new ConstructorCallExpression(
+                ClassNode.SUPER,
+                new TupleExpression(superCallArguments)
+        );
+
+        block.addStatement(new ExpressionStatement(cce));
+
+        // we need to add "this" to access unknown methods/properties
+        // this is saved in a field named this$0
+        pCount = 0;
+        expressions.add(pCount, VariableExpression.THIS_EXPRESSION);
+        boolean isStatic = isStaticThis(innerClass,scope);
+        ClassNode outerClassType = getClassNode(outerClass, isStatic);
+        if (!isStatic && inClosure) outerClassType = ClassHelper.CLOSURE_TYPE;
+        outerClassType = outerClassType.getPlainNodeReference();
+        Parameter thisParameter = new Parameter(outerClassType, "p" + pCount);
+        parameters.add(pCount, thisParameter);
+
+        thisField = innerClass.addField("this$0", PUBLIC_SYNTHETIC, outerClassType, null);
+        addFieldInit(thisParameter, thisField, block);
+
+        // for each shared variable we add a reference and save it as field
+        for (Iterator it = scope.getReferencedLocalVariablesIterator(); it.hasNext();) {
+            pCount++;
+            org.codehaus.groovy.ast.Variable var = (org.codehaus.groovy.ast.Variable) it.next();
+            VariableExpression ve = new VariableExpression(var);
+            ve.setClosureSharedVariable(true);
+            ve.setUseReferenceDirectly(true);
+            expressions.add(pCount, ve);
+
+            ClassNode rawReferenceType = ClassHelper.REFERENCE_TYPE.getPlainNodeReference();
+            Parameter p = new Parameter(rawReferenceType, "p" + pCount);
+            parameters.add(pCount, p);
+            p.setOriginType(var.getOriginType());
+            final VariableExpression initial = new VariableExpression(p);
+            initial.setSynthetic(true);
+            initial.setUseReferenceDirectly(true);
+            final FieldNode pField = innerClass.addFieldFirst(ve.getName(), PUBLIC_SYNTHETIC,rawReferenceType, initial);
+            pField.setHolder(true);
+            pField.setOriginType(ClassHelper.getWrapper(var.getOriginType()));
+        }
+
+        innerClass.addConstructor(ACC_SYNTHETIC, parameters.toArray(new Parameter[parameters.size()]), ClassNode.EMPTY_ARRAY, block);
+    }
+
+    private boolean isStaticThis(InnerClassNode innerClass, VariableScope scope) {
+        if (inClosure) return false;
+        boolean ret = innerClass.isStaticClass();
+        if (    innerClass.getEnclosingMethod()!=null) {
+            ret = ret || innerClass.getEnclosingMethod().isStatic();
+        } else if (currentField!=null) {
+            ret = ret || currentField.isStatic();
+        } else if (currentMethod!=null && "<clinit>".equals(currentMethod.getName())) {
+            ret = true;
+        }
+        return ret;
+    }
+
+    // this is the counterpart of addThisReference(). To non-static inner classes, outer this should be
+    // passed as the first argument implicitly.
+    private void passThisReference(ConstructorCallExpression call) {
+        ClassNode cn = call.getType().redirect();
+        if (!shouldHandleImplicitThisForInnerClass(cn)) return;
+
+        boolean isInStaticContext = true;
+        if (currentMethod != null)
+            isInStaticContext = currentMethod.getVariableScope().isInStaticContext();
+        else if (currentField != null)
+            isInStaticContext = currentField.isStatic();
+        else if (processingObjInitStatements)
+            isInStaticContext = false;
+
+        // if constructor call is not in static context, return
+        if (isInStaticContext) {
+            // constructor call is in static context and the inner class is non-static - 1st arg is supposed to be 
+            // passed as enclosing "this" instance
+            //
+            Expression args = call.getArguments();
+            if (args instanceof TupleExpression && ((TupleExpression) args).getExpressions().isEmpty()) {
+                addError("No enclosing instance passed in constructor call of a non-static inner class", call);
+            }
+            return;
+        }
+        insertThis0ToSuperCall(call, cn);
+
+    }
+
+    private void insertThis0ToSuperCall(final ConstructorCallExpression call, final ClassNode cn) {
+        // calculate outer class which we need for this$0
+        ClassNode parent = classNode;
+        int level = 0;
+        for (; parent != null && parent != cn.getOuterClass(); parent = parent.getOuterClass()) {
+            level++;
+        }
+
+        // if constructor call is not in outer class, don't pass 'this' implicitly. Return.
+        if (parent == null) return;
+
+        //add this parameter to node
+        Expression argsExp = call.getArguments();
+        if (argsExp instanceof TupleExpression) {
+            TupleExpression argsListExp = (TupleExpression) argsExp;
+            Expression this0 = VariableExpression.THIS_EXPRESSION;
+            for (int i = 0; i != level; ++i)
+                this0 = new PropertyExpression(this0, "this$0");
+            argsListExp.getExpressions().add(0, this0);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
new file mode 100644
index 0000000..7ed0629
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/InnerClassVisitorHelper.java
@@ -0,0 +1,143 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+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.ReturnStatement;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class InnerClassVisitorHelper extends ClassCodeVisitorSupport {
+    protected static void setPropertyGetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
+        List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
+        gStringStrings.add(new ConstantExpression(""));
+        gStringStrings.add(new ConstantExpression(""));
+        List<Expression> gStringValues = new ArrayList<Expression>();
+        gStringValues.add(new VariableExpression(parameters[0]));
+        block.addStatement(
+                new ReturnStatement(
+                        new PropertyExpression(
+                                thiz,
+                                new GStringExpression("$name", gStringStrings, gStringValues)
+                        )
+                )
+        );
+    }
+
+    protected static void setPropertySetterDispatcher(BlockStatement block, Expression thiz, Parameter[] parameters) {
+        List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
+        gStringStrings.add(new ConstantExpression(""));
+        gStringStrings.add(new ConstantExpression(""));
+        List<Expression> gStringValues = new ArrayList<Expression>();
+        gStringValues.add(new VariableExpression(parameters[0]));
+        block.addStatement(
+                new ExpressionStatement(
+                        new BinaryExpression(
+                                new PropertyExpression(
+                                        thiz,
+                                        new GStringExpression("$name", gStringStrings, gStringValues)
+                                ),
+                                Token.newSymbol(Types.ASSIGN, -1, -1),
+                                new VariableExpression(parameters[1])
+                        )
+                )
+        );
+    }
+
+    protected static void setMethodDispatcherCode(BlockStatement block, Expression thiz, Parameter[] parameters) {
+        List<ConstantExpression> gStringStrings = new ArrayList<ConstantExpression>();
+        gStringStrings.add(new ConstantExpression(""));
+        gStringStrings.add(new ConstantExpression(""));
+        List<Expression> gStringValues = new ArrayList<Expression>();
+        gStringValues.add(new VariableExpression(parameters[0]));
+        block.addStatement(
+                new ReturnStatement(
+                        new MethodCallExpression(
+                                thiz,
+                                new GStringExpression("$name", gStringStrings, gStringValues),
+                                new ArgumentListExpression(
+                                        new SpreadExpression(new VariableExpression(parameters[1]))
+                                )
+                        )
+                )
+        );
+    }
+
+    protected static boolean isStatic(InnerClassNode node) {
+        VariableScope scope = node.getVariableScope();
+        if (scope != null) return scope.isInStaticContext();
+        return (node.getModifiers() & Opcodes.ACC_STATIC) != 0;
+    }
+
+    protected static ClassNode getClassNode(ClassNode node, boolean isStatic) {
+        if (isStatic) node = ClassHelper.CLASS_Type;
+        return node;
+    }
+
+    protected static int getObjectDistance(ClassNode node) {
+        int count = 0;
+        while (node != null && node != ClassHelper.OBJECT_TYPE) {
+            count++;
+            node = node.getSuperClass();
+        }
+        return count;
+    }
+
+    protected static void addFieldInit(Parameter p, FieldNode fn, BlockStatement block) {
+        VariableExpression ve = new VariableExpression(p);
+        FieldExpression fe = new FieldExpression(fn);
+        block.addStatement(new ExpressionStatement(
+                new BinaryExpression(fe, Token.newSymbol(Types.ASSIGN, -1, -1), ve)
+        ));
+    }
+
+    protected static boolean shouldHandleImplicitThisForInnerClass(ClassNode cn) {
+        if (cn.isEnum() || cn.isInterface()) return false;
+        if ((cn.getModifiers() & Opcodes.ACC_STATIC) != 0) return false;
+
+        if (!(cn instanceof InnerClassNode)) return false;
+        InnerClassNode innerClass = (InnerClassNode) cn;
+        // scope != null means aic, we don't handle that here
+        if (innerClass.getVariableScope() != null) return false;
+        // static inner classes don't need this$0
+        return (innerClass.getModifiers() & Opcodes.ACC_STATIC) == 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java b/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java
new file mode 100644
index 0000000..22f3059
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/ReturnAdder.java
@@ -0,0 +1,279 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+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.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.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 java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class to add return statements.
+ * Extracted from Verifier as it can be useful for some AST transformations
+ */
+public class ReturnAdder {
+
+    private static final ReturnStatementListener DEFAULT_LISTENER = new ReturnStatementListener() {
+        public void returnStatementAdded(final ReturnStatement returnStatement) {
+        }
+    };
+
+    /**
+     * If set to 'true', then returns are effectively added. This is useful whenever you just want
+     * to check what returns are produced without eventually adding them.
+     */
+    private final boolean doAdd;
+
+    private final ReturnStatementListener listener;
+
+    public ReturnAdder() {
+        doAdd = true;
+        listener = DEFAULT_LISTENER;
+    }
+
+    public ReturnAdder(ReturnStatementListener listener) {
+        this.listener = listener;
+        this.doAdd = false;
+    }
+
+    /**
+     * Adds return statements in method code whenever an implicit return is detected.
+     * @param node the method node where to add return statements
+     * @deprecated Use {@link #visitMethod(org.codehaus.groovy.ast.MethodNode)} instead
+     */
+    @Deprecated
+    public static void addReturnIfNeeded(MethodNode node) {
+        ReturnAdder adder = new ReturnAdder();
+        adder.visitMethod(node);
+    }
+
+    public void visitMethod(MethodNode node) {
+        Statement statement = node.getCode();
+        if (!node.isVoidMethod()) {
+            if (statement != null) // it happens with @interface methods
+            {
+                final Statement code = addReturnsIfNeeded(statement, node.getVariableScope());
+                if (doAdd) node.setCode(code);
+            }
+        } else if (!node.isAbstract() && node.getReturnType().redirect()!=ClassHelper.VOID_TYPE) {
+            if (!(statement instanceof BytecodeSequence)) {
+                BlockStatement newBlock = new BlockStatement();
+                Statement code = node.getCode();
+                if (code instanceof BlockStatement) {
+                    newBlock.setVariableScope(((BlockStatement) code).getVariableScope());
+                }
+                if (statement instanceof BlockStatement) {
+                    newBlock.addStatements(((BlockStatement)statement).getStatements());
+                } else {
+                    newBlock.addStatement(statement);
+                }
+                final ReturnStatement returnStatement = ReturnStatement.RETURN_NULL_OR_VOID;
+                listener.returnStatementAdded(returnStatement);
+                newBlock.addStatement(returnStatement);
+                newBlock.setSourcePosition(statement);
+                if (doAdd) node.setCode(newBlock);
+            }
+        }
+    }
+
+    private Statement addReturnsIfNeeded(Statement statement, VariableScope scope) {
+        if (  statement instanceof ReturnStatement
+           || statement instanceof BytecodeSequence
+           || statement instanceof ThrowStatement)
+        {
+            return statement;
+        }
+
+        if (statement instanceof EmptyStatement) {
+            final ReturnStatement returnStatement = new ReturnStatement(ConstantExpression.NULL);
+            listener.returnStatementAdded(returnStatement);
+            return returnStatement;
+        }
+
+        if (statement instanceof ExpressionStatement) {
+            ExpressionStatement expStmt = (ExpressionStatement) statement;
+            Expression expr = expStmt.getExpression();
+            ReturnStatement ret = new ReturnStatement(expr);
+            ret.setSourcePosition(expr);
+            ret.setStatementLabel(statement.getStatementLabel());
+            listener.returnStatementAdded(ret);
+            return ret;
+        }
+
+        if (statement instanceof SynchronizedStatement) {
+            SynchronizedStatement sync = (SynchronizedStatement) statement;
+            final Statement code = addReturnsIfNeeded(sync.getCode(), scope);
+            if (doAdd) sync.setCode(code);
+            return sync;
+        }
+
+        if (statement instanceof IfStatement) {
+            IfStatement ifs = (IfStatement) statement;
+            final Statement ifBlock = addReturnsIfNeeded(ifs.getIfBlock(), scope);
+            final Statement elseBlock = addReturnsIfNeeded(ifs.getElseBlock(), scope);
+            if (doAdd) {
+                ifs.setIfBlock(ifBlock);
+                ifs.setElseBlock(elseBlock);
+            }
+            return ifs;
+        }
+
+        if (statement instanceof SwitchStatement) {
+            SwitchStatement swi = (SwitchStatement) statement;
+            for (CaseStatement caseStatement : swi.getCaseStatements()) {
+                final Statement code = adjustSwitchCaseCode(caseStatement.getCode(), scope, false);
+                if (doAdd) caseStatement.setCode(code);
+            }
+            final Statement defaultStatement = adjustSwitchCaseCode(swi.getDefaultStatement(), scope, true);
+            if (doAdd) swi.setDefaultStatement(defaultStatement);
+            return swi;
+        }
+
+        if (statement instanceof TryCatchStatement) {
+            TryCatchStatement trys = (TryCatchStatement) statement;
+            final boolean[] missesReturn = new boolean[1];
+            new ReturnAdder(new ReturnStatementListener() {
+                @Override
+                public void returnStatementAdded(ReturnStatement returnStatement) {
+                    missesReturn[0] = true;
+                }
+            }).addReturnsIfNeeded(trys.getFinallyStatement(), scope);
+            boolean hasFinally = !(trys.getFinallyStatement() instanceof EmptyStatement);
+
+            // if there is no missing return in the finally block and the block exists
+            // there is nothing to do
+            if (hasFinally && !missesReturn[0]) return trys;
+
+            // add returns to try and catch blocks
+            final Statement tryStatement = addReturnsIfNeeded(trys.getTryStatement(), scope);
+            if (doAdd) trys.setTryStatement(tryStatement);
+            final int len = trys.getCatchStatements().size();
+            for (int i = 0; i != len; ++i) {
+                final CatchStatement catchStatement = trys.getCatchStatement(i);
+                final Statement code = addReturnsIfNeeded(catchStatement.getCode(), scope);
+                if (doAdd) catchStatement.setCode(code);
+            }
+            return trys;
+        }
+
+        if (statement instanceof BlockStatement) {
+            BlockStatement block = (BlockStatement) statement;
+
+            final List list = block.getStatements();
+            if (!list.isEmpty()) {
+                int idx = list.size() - 1;
+                Statement last = addReturnsIfNeeded((Statement) list.get(idx), block.getVariableScope());
+                if (doAdd) list.set(idx, last);
+                if (!statementReturns(last)) {
+                    final ReturnStatement returnStatement = new ReturnStatement(ConstantExpression.NULL);
+                    listener.returnStatementAdded(returnStatement);
+                    if (doAdd) list.add(returnStatement);
+                }
+            } else {
+                ReturnStatement ret = new ReturnStatement(ConstantExpression.NULL);
+                ret.setSourcePosition(block);
+                listener.returnStatementAdded(ret);
+                return ret;
+            }
+
+            BlockStatement newBlock = new BlockStatement(list, block.getVariableScope());
+            newBlock.setSourcePosition(block);
+            return newBlock;
+        }
+
+        if (statement == null) {
+            final ReturnStatement returnStatement = new ReturnStatement(ConstantExpression.NULL);
+            listener.returnStatementAdded(returnStatement);
+            return returnStatement;
+        } else {
+            final List list = new ArrayList();
+            list.add(statement);
+            final ReturnStatement returnStatement = new ReturnStatement(ConstantExpression.NULL);
+            listener.returnStatementAdded(returnStatement);
+            list.add(returnStatement);
+
+            BlockStatement newBlock = new BlockStatement(list, new VariableScope(scope));
+            newBlock.setSourcePosition(statement);
+            return newBlock;
+        }
+    }
+
+    private Statement adjustSwitchCaseCode(Statement statement, VariableScope scope, boolean defaultCase) {
+        if(statement instanceof BlockStatement) {
+            final List list = ((BlockStatement)statement).getStatements();
+            if (!list.isEmpty()) {
+                int idx = list.size() - 1;
+                Statement last = (Statement) list.get(idx);
+                if(last instanceof BreakStatement) {
+                    if (doAdd) {
+                        list.remove(idx);
+                        return addReturnsIfNeeded(statement, scope);
+                    } else {
+                        BlockStatement newStmt = new BlockStatement();
+                        for (int i=0;i<idx; i++) {
+                            newStmt.addStatement((Statement) list.get(i));
+                        }
+                        return addReturnsIfNeeded(newStmt, scope);
+                    }
+                } else if(defaultCase) {
+                    return addReturnsIfNeeded(statement, scope);
+                }
+            }
+        }
+        return statement;
+    }
+
+    private static boolean statementReturns(Statement last) {
+        return (
+                last instanceof ReturnStatement ||
+                last instanceof BlockStatement ||
+                last instanceof IfStatement ||
+                last instanceof ExpressionStatement ||
+                last instanceof EmptyStatement ||
+                last instanceof TryCatchStatement ||
+                last instanceof BytecodeSequence ||
+                last instanceof ThrowStatement ||
+                last instanceof SynchronizedStatement
+                );
+    }
+
+    /**
+     * Implement this method in order to be notified whenever a return statement is generated.
+     */
+    public interface ReturnStatementListener {
+        void returnStatementAdded(ReturnStatement returnStatement);
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java
new file mode 100644
index 0000000..dcae1a8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/TraversalHelper.java
@@ -0,0 +1,557 @@
+/*
+ *  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.antlr.treewalker;
+
+import antlr.collections.AST;
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper Class for Antlr AST traversal and visitation.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+public abstract class TraversalHelper implements AntlrASTProcessor {
+    protected List<GroovySourceAST> unvisitedNodes;
+    private final Visitor v;
+
+    public TraversalHelper(Visitor visitor) {
+        this.unvisitedNodes = new ArrayList<GroovySourceAST>();
+        this.v = visitor;
+    }
+
+    protected void setUp(GroovySourceAST ast) {
+        v.setUp();
+    }
+
+    protected void tearDown(GroovySourceAST ast) {
+        v.tearDown();
+    }
+
+    protected void push(GroovySourceAST ast) {
+        v.push(ast);
+    }
+
+    protected GroovySourceAST pop() {
+        return v.pop();
+    }
+
+    protected void visitNode(GroovySourceAST ast, int n) {
+        if (ast != null) {
+            switch (ast.getType()) {
+                case GroovyTokenTypes.ABSTRACT                      :   v.visitAbstract(ast,n);                     break;
+                case GroovyTokenTypes.ANNOTATION                    :   v.visitAnnotation(ast,n);                   break;
+                case GroovyTokenTypes.ANNOTATIONS                   :   v.visitAnnotations(ast,n);                  break;
+                case GroovyTokenTypes.ANNOTATION_ARRAY_INIT         :   v.visitAnnotationArrayInit(ast,n);          break; // obsolete?
+                case GroovyTokenTypes.ANNOTATION_DEF                :   v.visitAnnotationDef(ast,n);                break;
+                case GroovyTokenTypes.ANNOTATION_FIELD_DEF          :   v.visitAnnotationFieldDef(ast,n);           break;
+                case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR  :   v.visitAnnotationMemberValuePair(ast,n);    break;
+                case GroovyTokenTypes.ARRAY_DECLARATOR              :   v.visitArrayDeclarator(ast,n);              break;
+                case GroovyTokenTypes.ASSIGN                        :   v.visitAssign(ast,n);                       break;
+                case GroovyTokenTypes.AT                            :   v.visitAt(ast,n);                           break;
+                case GroovyTokenTypes.BAND                          :   v.visitBand(ast,n);                         break;
+                case GroovyTokenTypes.BAND_ASSIGN                   :   v.visitBandAssign(ast,n);                   break;
+                case GroovyTokenTypes.BIG_SUFFIX                    :   v.visitBigSuffix(ast,n);                    break;
+                case GroovyTokenTypes.BLOCK                         :   v.visitBlock(ast,n);                        break;
+                case GroovyTokenTypes.BNOT                          :   v.visitBnot(ast,n);                         break;
+                case GroovyTokenTypes.BOR                           :   v.visitBor(ast,n);                          break;
+                case GroovyTokenTypes.BOR_ASSIGN                    :   v.visitBorAssign(ast,n);                    break;
+                case GroovyTokenTypes.BSR                           :   v.visitBsr(ast,n);                          break;
+                case GroovyTokenTypes.BSR_ASSIGN                    :   v.visitBsrAssign(ast,n);                    break;
+                case GroovyTokenTypes.BXOR                          :   v.visitBxor(ast,n);                         break;
+                case GroovyTokenTypes.BXOR_ASSIGN                   :   v.visitBxorAssign(ast,n);                   break;
+                case GroovyTokenTypes.CASE_GROUP                    :   v.visitCaseGroup(ast,n);                    break;
+                case GroovyTokenTypes.CLASS_DEF                     :   v.visitClassDef(ast,n);                     break;
+                case GroovyTokenTypes.CLOSABLE_BLOCK                :   v.visitClosedBlock(ast,n);                  break;
+                case GroovyTokenTypes.CLOSABLE_BLOCK_OP             :   v.visitClosureOp(ast,n);                    break;
+                case GroovyTokenTypes.CLOSURE_LIST                  :   v.visitClosureList(ast,n);                  break;
+                case GroovyTokenTypes.COLON                         :   v.visitColon(ast,n);                        break;
+                case GroovyTokenTypes.COMMA                         :   v.visitComma(ast,n);                        break;
+                case GroovyTokenTypes.COMPARE_TO                    :   v.visitCompareTo(ast,n);                    break;
+                case GroovyTokenTypes.CTOR_CALL                     :   v.visitCtorCall(ast,n);                     break;
+                case GroovyTokenTypes.CTOR_IDENT                    :   v.visitCtorIdent(ast,n);                    break;
+                case GroovyTokenTypes.DEC                           :   v.visitDec(ast,n);                          break;
+                case GroovyTokenTypes.DIGIT                         :   v.visitDigit(ast,n);                        break;
+                case GroovyTokenTypes.DIV                           :   v.visitDiv(ast,n);                          break;
+                case GroovyTokenTypes.DIV_ASSIGN                    :   v.visitDivAssign(ast,n);                    break;
+                case GroovyTokenTypes.DOLLAR                        :   v.visitDollar(ast,n);                       break;
+                case GroovyTokenTypes.DOLLAR_REGEXP_CTOR_END        :   v.visitRegexpCtorEnd(ast,n);                break;
+                case GroovyTokenTypes.DOLLAR_REGEXP_LITERAL         :   v.visitRegexpLiteral(ast,n);                break;
+                case GroovyTokenTypes.DOLLAR_REGEXP_SYMBOL          :   v.visitRegexpSymbol(ast,n);                 break;
+                case GroovyTokenTypes.DOT                           :   v.visitDot(ast,n);                          break;
+                case GroovyTokenTypes.DYNAMIC_MEMBER                :   v.visitDynamicMember(ast,n);                break;
+                case GroovyTokenTypes.ELIST                         :   v.visitElist(ast,n);                        break;
+                case GroovyTokenTypes.EMPTY_STAT                    :   v.visitEmptyStat(ast,n);                    break;
+                case GroovyTokenTypes.ENUM_CONSTANT_DEF             :   v.visitEnumConstantDef(ast,n);              break;
+                case GroovyTokenTypes.ENUM_DEF                      :   v.visitEnumDef(ast,n);                      break;
+                case GroovyTokenTypes.EOF                           :   v.visitEof(ast,n);                          break;
+                case GroovyTokenTypes.EQUAL                         :   v.visitEqual(ast,n);                        break;
+                case GroovyTokenTypes.ESC                           :   v.visitEsc(ast,n);                          break;
+                case GroovyTokenTypes.EXPONENT                      :   v.visitExponent(ast,n);                     break;
+                case GroovyTokenTypes.EXPR                          :   v.visitExpr(ast,n);                         break;
+                case GroovyTokenTypes.EXTENDS_CLAUSE                :   v.visitExtendsClause(ast,n);                break;
+                case GroovyTokenTypes.FINAL                         :   v.visitFinal(ast,n);                        break;
+                case GroovyTokenTypes.FLOAT_SUFFIX                  :   v.visitFloatSuffix(ast,n);                  break;
+                case GroovyTokenTypes.FOR_CONDITION                 :   v.visitForCondition(ast,n);                 break;
+                case GroovyTokenTypes.FOR_EACH_CLAUSE               :   v.visitForEachClause(ast,n);                break;
+                case GroovyTokenTypes.FOR_INIT                      :   v.visitForInit(ast,n);                      break;
+                case GroovyTokenTypes.FOR_IN_ITERABLE               :   v.visitForInIterable(ast,n);                break;
+                case GroovyTokenTypes.FOR_ITERATOR                  :   v.visitForIterator(ast,n);                  break;
+                case GroovyTokenTypes.GE                            :   v.visitGe(ast,n);                           break;
+                case GroovyTokenTypes.GT                            :   v.visitGt(ast,n);                           break;
+                case GroovyTokenTypes.HEX_DIGIT                     :   v.visitHexDigit(ast,n);                     break;
+                case GroovyTokenTypes.IDENT                         :   v.visitIdent(ast,n);                        break;
+                case GroovyTokenTypes.IMPLEMENTS_CLAUSE             :   v.visitImplementsClause(ast,n);             break;
+                case GroovyTokenTypes.IMPLICIT_PARAMETERS           :   v.visitImplicitParameters(ast,n);           break;
+                case GroovyTokenTypes.IMPORT                        :   v.visitImport(ast,n);                       break;
+                case GroovyTokenTypes.INC                           :   v.visitInc(ast,n);                          break;
+                case GroovyTokenTypes.INDEX_OP                      :   v.visitIndexOp(ast,n);                      break;
+                case GroovyTokenTypes.INSTANCE_INIT                 :   v.visitInstanceInit(ast,n);                 break;
+                case GroovyTokenTypes.INTERFACE_DEF                 :   v.visitInterfaceDef(ast,n);                 break;
+                case GroovyTokenTypes.LABELED_ARG                   :   v.visitLabeledArg(ast,n);                   break;
+                case GroovyTokenTypes.LABELED_STAT                  :   v.visitLabeledStat(ast,n);                  break;
+                case GroovyTokenTypes.LAND                          :   v.visitLand(ast,n);                         break;
+                case GroovyTokenTypes.LBRACK                        :   v.visitLbrack(ast,n);                       break;
+                case GroovyTokenTypes.LCURLY                        :   v.visitLcurly(ast,n);                       break;
+                case GroovyTokenTypes.LE                            :   v.visitLe(ast,n);                           break;
+                case GroovyTokenTypes.LETTER                        :   v.visitLetter(ast,n);                       break;
+                case GroovyTokenTypes.LIST_CONSTRUCTOR              :   v.visitListConstructor(ast,n);              break;
+                case GroovyTokenTypes.LITERAL_as                    :   v.visitLiteralAs(ast,n);                    break;
+                case GroovyTokenTypes.LITERAL_assert                :   v.visitLiteralAssert(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_boolean               :   v.visitLiteralBoolean(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_break                 :   v.visitLiteralBreak(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_byte                  :   v.visitLiteralByte(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_case                  :   v.visitLiteralCase(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_catch                 :   v.visitLiteralCatch(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_char                  :   v.visitLiteralChar(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_class                 :   v.visitLiteralClass(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_continue              :   v.visitLiteralContinue(ast,n);              break;
+                case GroovyTokenTypes.LITERAL_def                   :   v.visitLiteralDef(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_default               :   v.visitLiteralDefault(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_double                :   v.visitLiteralDouble(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_else                  :   v.visitLiteralElse(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_enum                  :   v.visitLiteralEnum(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_extends               :   v.visitLiteralExtends(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_false                 :   v.visitLiteralFalse(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_finally               :   v.visitLiteralFinally(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_float                 :   v.visitLiteralFloat(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_for                   :   v.visitLiteralFor(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_if                    :   v.visitLiteralIf(ast,n);                    break;
+                case GroovyTokenTypes.LITERAL_implements            :   v.visitLiteralImplements(ast,n);            break;
+                case GroovyTokenTypes.LITERAL_import                :   v.visitLiteralImport(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_in                    :   v.visitLiteralIn(ast,n);                    break;
+                case GroovyTokenTypes.LITERAL_instanceof            :   v.visitLiteralInstanceof(ast,n);            break;
+                case GroovyTokenTypes.LITERAL_int                   :   v.visitLiteralInt(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_interface             :   v.visitLiteralInterface(ast,n);             break;
+                case GroovyTokenTypes.LITERAL_long                  :   v.visitLiteralLong(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_native                :   v.visitLiteralNative(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_new                   :   v.visitLiteralNew(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_null                  :   v.visitLiteralNull(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_package               :   v.visitLiteralPackage(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_private               :   v.visitLiteralPrivate(ast,n);               break;
+                case GroovyTokenTypes.LITERAL_protected             :   v.visitLiteralProtected(ast,n);             break;
+                case GroovyTokenTypes.LITERAL_public                :   v.visitLiteralPublic(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_return                :   v.visitLiteralReturn(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_short                 :   v.visitLiteralShort(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_static                :   v.visitLiteralStatic(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_super                 :   v.visitLiteralSuper(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_switch                :   v.visitLiteralSwitch(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_synchronized          :   v.visitLiteralSynchronized(ast,n);          break;
+                case GroovyTokenTypes.LITERAL_this                  :   v.visitLiteralThis(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_threadsafe            :   v.visitLiteralThreadsafe(ast,n);            break;
+                case GroovyTokenTypes.LITERAL_throw                 :   v.visitLiteralThrow(ast,n);                 break;
+                case GroovyTokenTypes.LITERAL_throws                :   v.visitLiteralThrows(ast,n);                break;
+                case GroovyTokenTypes.LITERAL_transient             :   v.visitLiteralTransient(ast,n);             break;
+                case GroovyTokenTypes.LITERAL_true                  :   v.visitLiteralTrue(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_try                   :   v.visitLiteralTry(ast,n);                   break;
+                case GroovyTokenTypes.LITERAL_void                  :   v.visitLiteralVoid(ast,n);                  break;
+                case GroovyTokenTypes.LITERAL_volatile              :   v.visitLiteralVolatile(ast,n);              break;
+                case GroovyTokenTypes.LITERAL_while                 :   v.visitLiteralWhile(ast,n);                 break;
+                case GroovyTokenTypes.LNOT                          :   v.visitLnot(ast,n);                         break;
+                case GroovyTokenTypes.LOR                           :   v.visitLor(ast,n);                          break;
+                case GroovyTokenTypes.LPAREN                        :   v.visitLparen(ast,n);                       break;
+                case GroovyTokenTypes.LT                            :   v.visitLt(ast,n);                           break;
+                case GroovyTokenTypes.MAP_CONSTRUCTOR               :   v.visitMapConstructor(ast,n);               break;
+                case GroovyTokenTypes.MEMBER_POINTER                :   v.visitMemberPointer(ast,n);                break;
+                case GroovyTokenTypes.METHOD_CALL                   :   v.visitMethodCall(ast,n);                   break;
+                case GroovyTokenTypes.METHOD_DEF                    :   v.visitMethodDef(ast,n);                    break;
+                case GroovyTokenTypes.MINUS                         :   v.visitMinus(ast,n);                        break;
+                case GroovyTokenTypes.MINUS_ASSIGN                  :   v.visitMinusAssign(ast,n);                  break;
+                case GroovyTokenTypes.ML_COMMENT                    :   v.visitMlComment(ast,n);                    break;
+                case GroovyTokenTypes.MOD                           :   v.visitMod(ast,n);                          break;
+                case GroovyTokenTypes.MODIFIERS                     :   v.visitModifiers(ast,n);                    break;
+                case GroovyTokenTypes.MOD_ASSIGN                    :   v.visitModAssign(ast,n);                    break;
+                case GroovyTokenTypes.NLS                           :   v.visitNls(ast,n);                          break;
+                case GroovyTokenTypes.NOT_EQUAL                     :   v.visitNotEqual(ast,n);                     break;
+                case GroovyTokenTypes.NULL_TREE_LOOKAHEAD           :   v.visitNullTreeLookahead(ast,n);            break;
+                case GroovyTokenTypes.MULTICATCH                    :   v.visitMultiCatch(ast,n);                   break;
+                case GroovyTokenTypes.MULTICATCH_TYPES              :   v.visitMultiCatchTypes(ast,n);              break;
+                case GroovyTokenTypes.NUM_BIG_DECIMAL               :   v.visitNumBigDecimal(ast,n);                break;
+                case GroovyTokenTypes.NUM_BIG_INT                   :   v.visitNumBigInt(ast,n);                    break;
+                case GroovyTokenTypes.NUM_DOUBLE                    :   v.visitNumDouble(ast,n);                    break;
+                case GroovyTokenTypes.NUM_FLOAT                     :   v.visitNumFloat(ast,n);                     break;
+                case GroovyTokenTypes.NUM_INT                       :   v.visitNumInt(ast,n);                       break;
+                case GroovyTokenTypes.NUM_LONG                      :   v.visitNumLong(ast,n);                      break;
+                case GroovyTokenTypes.OBJBLOCK                      :   v.visitObjblock(ast,n);                     break;
+                case GroovyTokenTypes.ONE_NL                        :   v.visitOneNl(ast,n);                        break;
+                case GroovyTokenTypes.OPTIONAL_DOT                  :   v.visitOptionalDot(ast,n);                  break;
+                case GroovyTokenTypes.PACKAGE_DEF                   :   v.visitPackageDef(ast,n);                   break;
+                case GroovyTokenTypes.PARAMETERS                    :   v.visitParameters(ast,n);                   break;
+                case GroovyTokenTypes.PARAMETER_DEF                 :   v.visitParameterDef(ast,n);                 break;
+                case GroovyTokenTypes.PLUS                          :   v.visitPlus(ast,n);                         break;
+                case GroovyTokenTypes.PLUS_ASSIGN                   :   v.visitPlusAssign(ast,n);                   break;
+                case GroovyTokenTypes.POST_DEC                      :   v.visitPostDec(ast,n);                      break;
+                case GroovyTokenTypes.POST_INC                      :   v.visitPostInc(ast,n);                      break;
+                case GroovyTokenTypes.QUESTION                      :   v.visitQuestion(ast,n);                     break;
+                case GroovyTokenTypes.RANGE_EXCLUSIVE               :   v.visitRangeExclusive(ast,n);               break;
+                case GroovyTokenTypes.RANGE_INCLUSIVE               :   v.visitRangeInclusive(ast,n);               break;
+                case GroovyTokenTypes.RBRACK                        :   v.visitRbrack(ast,n);                       break;
+                case GroovyTokenTypes.RCURLY                        :   v.visitRcurly(ast,n);                       break;
+                case GroovyTokenTypes.REGEXP_CTOR_END               :   v.visitRegexpCtorEnd(ast,n);                break;
+                case GroovyTokenTypes.REGEXP_LITERAL                :   v.visitRegexpLiteral(ast,n);                break;
+                case GroovyTokenTypes.REGEXP_SYMBOL                 :   v.visitRegexpSymbol(ast,n);                 break;
+                case GroovyTokenTypes.REGEX_FIND                    :   v.visitRegexFind(ast,n);                    break;
+                case GroovyTokenTypes.REGEX_MATCH                   :   v.visitRegexMatch(ast,n);                   break;
+                case GroovyTokenTypes.RPAREN                        :   v.visitRparen(ast,n);                       break;
+                case GroovyTokenTypes.SELECT_SLOT                   :   v.visitSelectSlot(ast,n);                   break;
+                case GroovyTokenTypes.SEMI                          :   v.visitSemi(ast,n);                         break;
+                case GroovyTokenTypes.SH_COMMENT                    :   v.visitShComment(ast,n);                    break;
+                case GroovyTokenTypes.SL                            :   v.visitSl(ast,n);                           break;
+                case GroovyTokenTypes.SLIST                         :   v.visitSlist(ast,n);                        break;
+                case GroovyTokenTypes.SL_ASSIGN                     :   v.visitSlAssign(ast,n);                     break;
+                case GroovyTokenTypes.SL_COMMENT                    :   v.visitSlComment(ast,n);                    break;
+                case GroovyTokenTypes.SPREAD_ARG                    :   v.visitSpreadArg(ast,n);                    break;
+                case GroovyTokenTypes.SPREAD_DOT                    :   v.visitSpreadDot(ast,n);                    break;
+                case GroovyTokenTypes.SPREAD_MAP_ARG                :   v.visitSpreadMapArg(ast,n);                 break;
+                case GroovyTokenTypes.SR                            :   v.visitSr(ast,n);                           break;
+                case GroovyTokenTypes.SR_ASSIGN                     :   v.visitSrAssign(ast,n);                     break;
+                case GroovyTokenTypes.STAR                          :   v.visitStar(ast,n);                         break;
+                case GroovyTokenTypes.STAR_ASSIGN                   :   v.visitStarAssign(ast,n);                   break;
+                case GroovyTokenTypes.STAR_STAR                     :   v.visitStarStar(ast,n);                     break;
+                case GroovyTokenTypes.STAR_STAR_ASSIGN              :   v.visitStarStarAssign(ast,n);               break;
+                case GroovyTokenTypes.STATIC_IMPORT                 :   v.visitStaticImport(ast,n);                 break;
+                case GroovyTokenTypes.STATIC_INIT                   :   v.visitStaticInit(ast,n);                   break;
+                case GroovyTokenTypes.STRICTFP                      :   v.visitStrictfp(ast,n);                     break;
+                case GroovyTokenTypes.STRING_CH                     :   v.visitStringCh(ast,n);                     break;
+                case GroovyTokenTypes.STRING_CONSTRUCTOR            :   v.visitStringConstructor(ast,n);            break;
+                case GroovyTokenTypes.STRING_CTOR_END               :   v.visitStringCtorEnd(ast,n);                break;
+                case GroovyTokenTypes.STRING_CTOR_MIDDLE            :   v.visitStringCtorMiddle(ast,n);             break;
+                case GroovyTokenTypes.STRING_CTOR_START             :   v.visitStringCtorStart(ast,n);              break;
+                case GroovyTokenTypes.STRING_LITERAL                :   v.visitStringLiteral(ast,n);                break;
+                case GroovyTokenTypes.STRING_NL                     :   v.visitStringNl(ast,n);                     break;
+                case GroovyTokenTypes.SUPER_CTOR_CALL               :   v.visitSuperCtorCall(ast,n);                break;
+                case GroovyTokenTypes.TRAIT_DEF                     :   v.visitTraitDef(ast,n);                     break;
+                case GroovyTokenTypes.TRIPLE_DOT                    :   v.visitTripleDot(ast,n);                    break;
+                case GroovyTokenTypes.TYPE                          :   v.visitType(ast,n);                         break;
+                case GroovyTokenTypes.TYPECAST                      :   v.visitTypecast(ast,n);                     break;
+                case GroovyTokenTypes.TYPE_ARGUMENT                 :   v.visitTypeArgument(ast,n);                 break;
+                case GroovyTokenTypes.TYPE_ARGUMENTS                :   v.visitTypeArguments(ast,n);                break;
+                case GroovyTokenTypes.TYPE_LOWER_BOUNDS             :   v.visitTypeLowerBounds(ast,n);              break;
+                case GroovyTokenTypes.TYPE_PARAMETER                :   v.visitTypeParameter(ast,n);                break;
+                case GroovyTokenTypes.TYPE_PARAMETERS               :   v.visitTypeParameters(ast,n);               break;
+                case GroovyTokenTypes.TYPE_UPPER_BOUNDS             :   v.visitTypeUpperBounds(ast,n);              break;
+                case GroovyTokenTypes.UNARY_MINUS                   :   v.visitUnaryMinus(ast,n);                   break;
+                case GroovyTokenTypes.UNARY_PLUS                    :   v.visitUnaryPlus(ast,n);                    break;
+                case GroovyTokenTypes.UNUSED_CONST                  :   v.visitUnusedConst(ast,n);                  break;
+                case GroovyTokenTypes.UNUSED_DO                     :   v.visitUnusedDo(ast,n);                     break;
+                case GroovyTokenTypes.UNUSED_GOTO                   :   v.visitUnusedGoto(ast,n);                   break;
+                case GroovyTokenTypes.VARIABLE_DEF                  :   v.visitVariableDef(ast,n);                  break;
+                case GroovyTokenTypes.VARIABLE_PARAMETER_DEF        :   v.visitVariableParameterDef(ast,n);         break;
+                case GroovyTokenTypes.VOCAB                         :   v.visitVocab(ast,n);                        break;
+                case GroovyTokenTypes.WILDCARD_TYPE                 :   v.visitWildcardType(ast,n);                 break;
+                case GroovyTokenTypes.WS                            :   v.visitWs(ast,n);                           break;
+
+
+                default                                             :   v.visitDefault(ast,n);                      break;
+            }
+        } else {
+            // the supplied AST was null
+            v.visitDefault(null,n);
+        }
+    }
+
+    protected abstract void accept(GroovySourceAST currentNode);
+
+    protected void accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST expr2 = t.childAt(0);
+        skip(expr2);
+        accept(expr2.childAt(0));
+        closingVisit(t);
+
+        GroovySourceAST sibling = (GroovySourceAST) expr2.getNextSibling();
+        boolean firstSList = true;
+        while (sibling != null) {
+            if (!firstSList) {
+                subsequentVisit(t);
+            }
+            firstSList = false;
+            accept(sibling);
+            sibling = (GroovySourceAST) sibling.getNextSibling();
+        }
+    }
+
+    protected void accept_v_FirstChildsFirstChild_v_RestOfTheChildren(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST expr = t.childAt(0);
+        skip(expr);
+        accept(expr.childAt(0));
+        closingVisit(t);
+        acceptSiblings(expr);
+    }
+
+    protected void accept_FirstChild_v_SecondChild(GroovySourceAST t) {
+        accept(t.childAt(0));
+        subsequentVisit(t);
+        accept(t.childAt(1));
+    }
+
+    protected void accept_FirstChild_v_SecondChild_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        accept(t.childAt(1));
+        closingVisit(t);
+    }
+
+    protected void accept_SecondChild_v_ThirdChild_v(GroovySourceAST t) {
+        accept(t.childAt(1));
+        openingVisit(t);
+        accept(t.childAt(2));
+        closingVisit(t);
+    }
+
+    protected void accept_FirstChild_v_SecondChildsChildren_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+
+        openingVisit(t);
+        GroovySourceAST secondChild = t.childAt(1);
+        if (secondChild != null) {
+            acceptChildren(secondChild);
+        }
+        closingVisit(t);
+    }
+
+
+    protected void accept_v_FirstChild_SecondChild_v_ThirdChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        accept(t.childAt(0));
+        accept(t.childAt(1));
+        subsequentVisit(t);
+        accept(t.childAt(2));
+        closingVisit(t);
+    }
+
+    protected void accept_FirstChild_v_SecondChild_v_ThirdChild_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        accept(t.childAt(1));
+        subsequentVisit(t);
+        accept(t.childAt(2));
+        closingVisit(t);
+    }
+
+    protected void accept_FirstSecondAndThirdChild_v_v_ForthChild(GroovySourceAST t) {
+        GroovySourceAST child1 = (GroovySourceAST) t.getFirstChild();
+        if (child1 != null) {
+            accept(child1);
+            GroovySourceAST child2 = (GroovySourceAST) child1.getNextSibling();
+            if (child2 != null) {
+                accept(child2);
+                GroovySourceAST child3 = (GroovySourceAST) child2.getNextSibling();
+                if (child3 != null) {
+                    accept(child3);
+                    openingVisit(t);
+                    GroovySourceAST child4 = (GroovySourceAST) child3.getNextSibling();
+                    if (child4 != null) {
+                        subsequentVisit(t);
+                        accept(child4);
+                    }
+                }
+            }
+        }
+    }
+
+    protected void accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST child = (GroovySourceAST) t.getFirstChild();
+        if (child != null) {
+            accept(child);
+            GroovySourceAST sibling = (GroovySourceAST) child.getNextSibling();
+            if (sibling != null) {
+                secondVisit(t);
+                accept(sibling);
+                sibling = (GroovySourceAST) sibling.getNextSibling();
+                while (sibling != null) {
+                    subsequentVisit(t);
+                    accept(sibling);
+                    sibling = (GroovySourceAST) sibling.getNextSibling();
+                }
+            }
+        }
+        closingVisit(t);
+    }
+
+    protected void accept_v_FirstChild_v_SecondChild_v___LastChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        GroovySourceAST child = (GroovySourceAST) t.getFirstChild();
+        if (child != null) {
+            accept(child);
+            GroovySourceAST sibling = (GroovySourceAST) child.getNextSibling();
+            while (sibling != null) {
+                subsequentVisit(t);
+                accept(sibling);
+                sibling = (GroovySourceAST) sibling.getNextSibling();
+            }
+        }
+        closingVisit(t);
+    }
+
+    protected void accept_v_FirstChild_v(GroovySourceAST t) {
+        openingVisit(t);
+        accept(t.childAt(0));
+        closingVisit(t);
+    }
+
+    protected void accept_v_Siblings_v(GroovySourceAST t) {
+        openingVisit(t);
+        acceptSiblings(t);
+        closingVisit(t);
+    }
+
+    protected void accept_v_AllChildren_v_Siblings(GroovySourceAST t) {
+        openingVisit(t);
+        acceptChildren(t);
+        closingVisit(t);
+        acceptSiblings(t);
+    }
+
+    protected void accept_v_AllChildren_v(GroovySourceAST t) {
+        openingVisit(t);
+        acceptChildren(t);
+        closingVisit(t);
+    }
+
+    protected void accept_FirstChild_v_RestOfTheChildren(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        closingVisit(t);
+        acceptSiblings(t.childAt(0));
+    }
+
+    protected void accept_FirstChild_v_RestOfTheChildren_v_LastChild(GroovySourceAST t) {
+        int count = 0;
+        accept(t.childAt(0));
+        count++;
+        openingVisit(t);
+        if (t.childAt(0) != null) {
+            GroovySourceAST sibling = (GroovySourceAST) t.childAt(0).getNextSibling();
+            while (sibling != null) {
+                if (count == t.getNumberOfChildren() - 1) {
+                    closingVisit(t);
+                }
+                accept(sibling);
+                count++;
+                sibling = (GroovySourceAST) sibling.getNextSibling();
+            }
+        }
+
+
+    }
+
+    protected void accept_FirstChild_v_RestOfTheChildren_v(GroovySourceAST t) {
+        accept(t.childAt(0));
+        openingVisit(t);
+        acceptSiblings(t.childAt(0));
+        closingVisit(t);
+    }
+
+    protected void accept_v_FirstChild_v_RestOfTheChildren(GroovySourceAST t) {
+        accept_v_FirstChild_v(t);
+        acceptSiblings(t.childAt(0));
+    }
+
+    protected void accept_v_FirstChild_v_RestOfTheChildren_v(GroovySourceAST t) {
+        openingVisit(t);
+        accept(t.childAt(0));
+        subsequentVisit(t);
+        acceptSiblings(t.childAt(0));
+        closingVisit(t);
+    }
+
+    protected void acceptSiblings(GroovySourceAST t) {
+        if (t != null) {
+            GroovySourceAST sibling = (GroovySourceAST) t.getNextSibling();
+            while (sibling != null) {
+                accept(sibling);
+                sibling = (GroovySourceAST) sibling.getNextSibling();
+            }
+        }
+    }
+
+    protected void acceptChildren(GroovySourceAST t) {
+        if (t != null) {
+            GroovySourceAST child = (GroovySourceAST) t.getFirstChild();
+            if (child != null) {
+                accept(child);
+                acceptSiblings(child);
+            }
+        }
+    }
+
+    protected void skip(GroovySourceAST expr) {
+        unvisitedNodes.remove(expr);
+    }
+
+    protected void openingVisit(GroovySourceAST t) {
+        unvisitedNodes.remove(t);
+
+        int n = Visitor.OPENING_VISIT;
+        visitNode(t, n);
+    }
+
+    protected void secondVisit(GroovySourceAST t) {
+        int n = Visitor.SECOND_VISIT;
+        visitNode(t, n);
+    }
+
+    protected void subsequentVisit(GroovySourceAST t) {
+        int n = Visitor.SUBSEQUENT_VISIT;
+        visitNode(t, n);
+    }
+
+    protected void closingVisit(GroovySourceAST t) {
+        int n = Visitor.CLOSING_VISIT;
+        visitNode(t, n);
+    }
+
+    public AST process(AST t) {
+        GroovySourceAST node = (GroovySourceAST) t;
+
+        // process each node in turn
+        setUp(node);
+        accept(node);
+        acceptSiblings(node);
+        tearDown(node);
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/Visitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/Visitor.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/Visitor.java
new file mode 100644
index 0000000..841e4ca
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/Visitor.java
@@ -0,0 +1,260 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+/**
+ * An interface for visiting a GroovySourceAST node.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public interface Visitor {
+    int OPENING_VISIT = 1;
+    int SECOND_VISIT = 2; // only used on rare occasions, e.g. the '(' in this snippet...   @Foo  (  a=1, b=2, c=3)
+    int SUBSEQUENT_VISIT = 3;
+    int CLOSING_VISIT = 4;
+
+    void setUp();
+    void visitAbstract(GroovySourceAST t, int visit);
+    void visitAnnotation(GroovySourceAST t, int visit);
+    void visitAnnotations(GroovySourceAST t, int visit);
+    void visitAnnotationArrayInit(GroovySourceAST t, int visit);
+    void visitAnnotationDef(GroovySourceAST t, int visit);
+    void visitAnnotationFieldDef(GroovySourceAST t, int visit);
+    void visitAnnotationMemberValuePair(GroovySourceAST t, int visit);
+    void visitArrayDeclarator(GroovySourceAST t, int visit);
+    void visitAssign(GroovySourceAST t, int visit);
+    void visitAt(GroovySourceAST t, int visit);
+    void visitBand(GroovySourceAST t, int visit);
+    void visitBandAssign(GroovySourceAST t, int visit);
+    void visitBigSuffix(GroovySourceAST t, int visit);
+    void visitBlock(GroovySourceAST t, int visit);
+    void visitBnot(GroovySourceAST t, int visit);
+    void visitBor(GroovySourceAST t, int visit);
+    void visitBorAssign(GroovySourceAST t, int visit);
+    void visitBsr(GroovySourceAST t, int visit);
+    void visitBsrAssign(GroovySourceAST t, int visit);
+    void visitBxor(GroovySourceAST t, int visit);
+    void visitBxorAssign(GroovySourceAST t, int visit);
+    void visitCaseGroup(GroovySourceAST t, int visit);
+    void visitClassDef(GroovySourceAST t, int visit);
+    void visitClosedBlock(GroovySourceAST t, int visit);
+    void visitClosureList(GroovySourceAST t, int visit);
+    void visitClosureOp(GroovySourceAST t, int visit);
+    void visitColon(GroovySourceAST t, int visit);
+    void visitComma(GroovySourceAST t, int visit);
+    void visitCompareTo(GroovySourceAST t, int visit);
+    void visitCtorCall(GroovySourceAST t, int visit);
+    void visitCtorIdent(GroovySourceAST t, int visit);
+    void visitDec(GroovySourceAST t, int visit);
+    void visitDigit(GroovySourceAST t, int visit);
+    void visitDiv(GroovySourceAST t, int visit);
+    void visitDivAssign(GroovySourceAST t, int visit);
+    void visitDollar(GroovySourceAST t, int visit);
+    void visitDot(GroovySourceAST t, int visit);
+    void visitDynamicMember(GroovySourceAST t, int visit);
+    void visitElist(GroovySourceAST t, int visit);
+    void visitEmptyStat(GroovySourceAST t, int visit);
+    void visitEnumConstantDef(GroovySourceAST t, int visit);
+    void visitEnumDef(GroovySourceAST t, int visit);
+    void visitEof(GroovySourceAST t, int visit);
+    void visitEqual(GroovySourceAST t, int visit);
+    void visitEsc(GroovySourceAST t, int visit);
+    void visitExponent(GroovySourceAST t, int visit);
+    void visitExpr(GroovySourceAST t, int visit);
+    void visitExtendsClause(GroovySourceAST t, int visit);
+    void visitFinal(GroovySourceAST t, int visit);
+    void visitFloatSuffix(GroovySourceAST t, int visit);
+    void visitForCondition(GroovySourceAST t, int visit);
+    void visitForEachClause(GroovySourceAST t, int visit);
+    void visitForInit(GroovySourceAST t, int visit);
+    void visitForInIterable(GroovySourceAST t, int visit);
+    void visitForIterator(GroovySourceAST t, int visit);
+    void visitGe(GroovySourceAST t, int visit);
+    void visitGt(GroovySourceAST t, int visit);
+    void visitHexDigit(GroovySourceAST t, int visit);
+    void visitIdent(GroovySourceAST t, int visit);
+    void visitImplementsClause(GroovySourceAST t, int visit);
+    void visitImplicitParameters(GroovySourceAST t, int visit);
+    void visitImport(GroovySourceAST t, int visit);
+    void visitInc(GroovySourceAST t, int visit);
+    void visitIndexOp(GroovySourceAST t, int visit);
+    void visitInstanceInit(GroovySourceAST t, int visit);
+    void visitInterfaceDef(GroovySourceAST t, int visit);
+    void visitLabeledArg(GroovySourceAST t, int visit);
+    void visitLabeledStat(GroovySourceAST t, int visit);
+    void visitLand(GroovySourceAST t, int visit);
+    void visitLbrack(GroovySourceAST t, int visit);
+    void visitLcurly(GroovySourceAST t, int visit);
+    void visitLe(GroovySourceAST t, int visit);
+    void visitLetter(GroovySourceAST t, int visit);
+    void visitListConstructor(GroovySourceAST t, int visit);
+    void visitLiteralAs(GroovySourceAST t, int visit);
+    void visitLiteralAssert(GroovySourceAST t, int visit);
+    void visitLiteralBoolean(GroovySourceAST t, int visit);
+    void visitLiteralBreak(GroovySourceAST t, int visit);
+    void visitLiteralByte(GroovySourceAST t, int visit);
+    void visitLiteralCase(GroovySourceAST t, int visit);
+    void visitLiteralCatch(GroovySourceAST t, int visit);
+    void visitLiteralChar(GroovySourceAST t, int visit);
+    void visitLiteralClass(GroovySourceAST t, int visit);
+    void visitLiteralContinue(GroovySourceAST t, int visit);
+    void visitLiteralDef(GroovySourceAST t, int visit);
+    void visitLiteralDefault(GroovySourceAST t, int visit);
+    void visitLiteralDouble(GroovySourceAST t, int visit);
+    void visitLiteralElse(GroovySourceAST t, int visit);
+    void visitLiteralEnum(GroovySourceAST t, int visit);
+    void visitLiteralExtends(GroovySourceAST t, int visit);
+    void visitLiteralFalse(GroovySourceAST t, int visit);
+    void visitLiteralFinally(GroovySourceAST t, int visit);
+    void visitLiteralFloat(GroovySourceAST t, int visit);
+    void visitLiteralFor(GroovySourceAST t, int visit);
+    void visitLiteralIf(GroovySourceAST t, int visit);
+    void visitLiteralImplements(GroovySourceAST t, int visit);
+    void visitLiteralImport(GroovySourceAST t, int visit);
+    void visitLiteralIn(GroovySourceAST t, int visit);
+    void visitLiteralInstanceof(GroovySourceAST t, int visit);
+    void visitLiteralInt(GroovySourceAST t, int visit);
+    void visitLiteralInterface(GroovySourceAST t, int visit);
+    void visitLiteralLong(GroovySourceAST t, int visit);
+    void visitLiteralNative(GroovySourceAST t, int visit);
+    void visitLiteralNew(GroovySourceAST t, int visit);
+    void visitLiteralNull(GroovySourceAST t, int visit);
+    void visitLiteralPackage(GroovySourceAST t, int visit);
+    void visitLiteralPrivate(GroovySourceAST t, int visit);
+    void visitLiteralProtected(GroovySourceAST t, int visit);
+    void visitLiteralPublic(GroovySourceAST t, int visit);
+    void visitLiteralReturn(GroovySourceAST t, int visit);
+    void visitLiteralShort(GroovySourceAST t, int visit);
+    void visitLiteralStatic(GroovySourceAST t, int visit);
+    void visitLiteralSuper(GroovySourceAST t, int visit);
+    void visitLiteralSwitch(GroovySourceAST t, int visit);
+    void visitLiteralSynchronized(GroovySourceAST t, int visit);
+    void visitLiteralThis(GroovySourceAST t, int visit);
+    void visitLiteralThreadsafe(GroovySourceAST t, int visit);
+    void visitLiteralThrow(GroovySourceAST t, int visit);
+    void visitLiteralThrows(GroovySourceAST t, int visit);
+    void visitLiteralTransient(GroovySourceAST t, int visit);
+    void visitLiteralTrue(GroovySourceAST t, int visit);
+    void visitLiteralTry(GroovySourceAST t, int visit);
+    void visitLiteralVoid(GroovySourceAST t, int visit);
+    void visitLiteralVolatile(GroovySourceAST t, int visit);
+    void visitLiteralWhile(GroovySourceAST t, int visit);
+    void visitLnot(GroovySourceAST t, int visit);
+    void visitLor(GroovySourceAST t, int visit);
+    void visitLparen(GroovySourceAST t, int visit);
+    void visitLt(GroovySourceAST t, int visit);
+    void visitMapConstructor(GroovySourceAST t, int visit);
+    void visitMemberPointer(GroovySourceAST t, int visit);
+    void visitMethodCall(GroovySourceAST t, int visit);
+    void visitMethodDef(GroovySourceAST t, int visit);
+    void visitMinus(GroovySourceAST t, int visit);
+    void visitMinusAssign(GroovySourceAST t, int visit);
+    void visitMlComment(GroovySourceAST t, int visit);
+    void visitMod(GroovySourceAST t, int visit);
+    void visitModifiers(GroovySourceAST t, int visit);
+    void visitModAssign(GroovySourceAST t, int visit);
+    void visitMultiCatch(GroovySourceAST t, int visit);
+    void visitMultiCatchTypes(GroovySourceAST t, int visit);
+    void visitNls(GroovySourceAST t, int visit);
+    void visitNotEqual(GroovySourceAST t, int visit);
+    void visitNullTreeLookahead(GroovySourceAST t, int visit);
+    void visitNumBigDecimal(GroovySourceAST t, int visit);
+    void visitNumBigInt(GroovySourceAST t, int visit);
+    void visitNumDouble(GroovySourceAST t, int visit);
+    void visitNumFloat(GroovySourceAST t, int visit);
+    void visitNumInt(GroovySourceAST t, int visit);
+    void visitNumLong(GroovySourceAST t, int visit);
+    void visitObjblock(GroovySourceAST t, int visit);
+    void visitOneNl(GroovySourceAST t, int visit);
+    void visitOptionalDot(GroovySourceAST t, int visit);
+    void visitPackageDef(GroovySourceAST t, int visit);
+    void visitParameters(GroovySourceAST t, int visit);
+    void visitParameterDef(GroovySourceAST t, int visit);
+    void visitPlus(GroovySourceAST t, int visit);
+    void visitPlusAssign(GroovySourceAST t, int visit);
+    void visitPostDec(GroovySourceAST t, int visit);
+    void visitPostInc(GroovySourceAST t, int visit);
+    void visitQuestion(GroovySourceAST t, int visit);
+    void visitRangeExclusive(GroovySourceAST t, int visit);
+    void visitRangeInclusive(GroovySourceAST t, int visit);
+    void visitRbrack(GroovySourceAST t, int visit);
+    void visitRcurly(GroovySourceAST t, int visit);
+    void visitRegexpCtorEnd(GroovySourceAST t, int visit);
+    void visitRegexpLiteral(GroovySourceAST t, int visit);
+    void visitRegexpSymbol(GroovySourceAST t, int visit);
+    void visitRegexFind(GroovySourceAST t, int visit);
+    void visitRegexMatch(GroovySourceAST t, int visit);
+    void visitRparen(GroovySourceAST t, int visit);
+    void visitSelectSlot(GroovySourceAST t, int visit);
+    void visitSemi(GroovySourceAST t, int visit);
+    void visitShComment(GroovySourceAST t, int visit);
+    void visitSl(GroovySourceAST t, int visit);
+    void visitSlist(GroovySourceAST t, int visit);
+    void visitSlAssign(GroovySourceAST t, int visit);
+    void visitSlComment(GroovySourceAST t, int visit);
+    void visitSpreadArg(GroovySourceAST t, int visit);
+    void visitSpreadDot(GroovySourceAST t, int visit);
+    void visitSpreadMapArg(GroovySourceAST t, int visit);
+    void visitSr(GroovySourceAST t, int visit);
+    void visitSrAssign(GroovySourceAST t, int visit);
+    void visitStar(GroovySourceAST t, int visit);
+    void visitStarAssign(GroovySourceAST t, int visit);
+    void visitStarStar(GroovySourceAST t, int visit);
+    void visitStarStarAssign(GroovySourceAST t, int visit);
+    void visitStaticImport(GroovySourceAST t, int visit);
+    void visitStaticInit(GroovySourceAST t, int visit);
+    void visitStrictfp(GroovySourceAST t, int visit);
+    void visitStringCh(GroovySourceAST t, int visit);
+    void visitStringConstructor(GroovySourceAST t, int visit);
+    void visitStringCtorEnd(GroovySourceAST t, int visit);
+    void visitStringCtorMiddle(GroovySourceAST t, int visit);
+    void visitStringCtorStart(GroovySourceAST t, int visit);
+    void visitStringLiteral(GroovySourceAST t, int visit);
+    void visitStringNl(GroovySourceAST t, int visit);
+    void visitSuperCtorCall(GroovySourceAST t, int visit);
+    void visitTraitDef(GroovySourceAST t, int visit);
+    void visitTripleDot(GroovySourceAST t, int visit);
+    void visitType(GroovySourceAST t, int visit);
+    void visitTypecast(GroovySourceAST t, int visit);
+    void visitTypeArgument(GroovySourceAST t, int visit);
+    void visitTypeArguments(GroovySourceAST t, int visit);
+    void visitTypeLowerBounds(GroovySourceAST t, int visit);
+    void visitTypeParameter(GroovySourceAST t, int visit);
+    void visitTypeParameters(GroovySourceAST t, int visit);
+    void visitTypeUpperBounds(GroovySourceAST t, int visit);
+    void visitUnaryMinus(GroovySourceAST t, int visit);
+    void visitUnaryPlus(GroovySourceAST t, int visit);
+    void visitUnusedConst(GroovySourceAST t, int visit);
+    void visitUnusedDo(GroovySourceAST t, int visit);
+    void visitUnusedGoto(GroovySourceAST t, int visit);
+    void visitVariableDef(GroovySourceAST t, int visit);
+    void visitVariableParameterDef(GroovySourceAST t, int visit);
+    void visitVocab(GroovySourceAST t, int visit);
+    void visitWildcardType(GroovySourceAST t, int visit);
+    void visitWs(GroovySourceAST t, int visit);
+
+    void visitDefault(GroovySourceAST t,int visit);
+    void tearDown();
+
+    void push(GroovySourceAST t);
+    GroovySourceAST pop();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java
new file mode 100644
index 0000000..a6e8063
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/VisitorAdapter.java
@@ -0,0 +1,258 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+
+/**
+ * A default implementation of all visitor methods.
+ * If you extend this class, any un-overridden visit methods will
+ * call visitDefault.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public class VisitorAdapter implements Visitor {
+    public void setUp() {}
+    public void visitAbstract(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotation(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotations(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationArrayInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationFieldDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAnnotationMemberValuePair(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitArrayDeclarator(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitAt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBand(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBandAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBigSuffix(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBlock(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBnot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBorAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBsr(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBsrAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBxor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitBxorAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCaseGroup(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitClassDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitClosedBlock(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitClosureOp(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitClosureList(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitColon(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitComma(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCompareTo(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCtorCall(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitCtorIdent(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDec(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDigit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDiv(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDivAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDollar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitDynamicMember(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitElist(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEmptyStat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEnumConstantDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEnumDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEof(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEqual(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitEsc(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitExponent(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitExpr(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitExtendsClause(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitFinal(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitFloatSuffix(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForCondition(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForEachClause(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForInIterable(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitForIterator(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitGe(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitGt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitHexDigit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitIdent(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitImplementsClause(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitImplicitParameters(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitImport(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitInc(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitIndexOp(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitInstanceInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitInterfaceDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLabeledArg(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLabeledStat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLand(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLbrack(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLcurly(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLe(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLetter(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitListConstructor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralAs(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralAssert(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralBoolean(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralBreak(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralByte(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralCase(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralCatch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralChar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralClass(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralContinue(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralDefault(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralDouble(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralElse(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralEnum(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralExtends(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFalse(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFinally(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFloat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralFor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralIf(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralImplements(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralImport(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralIn(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralInstanceof(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralInt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralInterface(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralLong(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralNative(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralNew(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralNull(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralPackage(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralPrivate(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralProtected(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralPublic(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralReturn(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralShort(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralStatic(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralSuper(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralSwitch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralSynchronized(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThis(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThreadsafe(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThrow(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralThrows(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralTransient(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralTrue(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralTry(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralVoid(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralVolatile(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLiteralWhile(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLnot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLparen(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitLt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMapConstructor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMemberPointer(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMethodCall(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMethodDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMinus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMinusAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMlComment(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMod(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitModifiers(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitModAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMultiCatch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitMultiCatchTypes(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNls(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNotEqual(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNullTreeLookahead(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumBigDecimal(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumBigInt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumDouble(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumFloat(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumInt(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitNumLong(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitObjblock(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitOneNl(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitOptionalDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPackageDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitParameters(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitParameterDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPlus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPlusAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPostDec(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitPostInc(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitQuestion(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRangeExclusive(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRangeInclusive(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRbrack(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRcurly(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexpCtorEnd(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexpLiteral(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexpSymbol(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexFind(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRegexMatch(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitRparen(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSelectSlot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSemi(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitShComment(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSl(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSlist(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSlAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSlComment(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSpreadArg(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSpreadDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSpreadMapArg(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSr(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSrAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStarAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStarStar(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStarStarAssign(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStaticImport(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStaticInit(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStrictfp(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCh(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringConstructor(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCtorEnd(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCtorMiddle(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringCtorStart(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringLiteral(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitStringNl(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitSuperCtorCall(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTraitDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTripleDot(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitType(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypecast(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeArgument(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeArguments(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeLowerBounds(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeParameter(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeParameters(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitTypeUpperBounds(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnaryMinus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnaryPlus(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnusedConst(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnusedDo(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitUnusedGoto(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitVariableDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitVariableParameterDef(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitVocab(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitWildcardType(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+    public void visitWs(GroovySourceAST t,int visit) {visitDefault(t,visit);}
+
+    public void visitDefault(GroovySourceAST t,int visit) {}
+    public void tearDown() {}
+
+    public void push(GroovySourceAST t) {}
+    public GroovySourceAST pop() {return null;}
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/package.html b/src/main/java/org/codehaus/groovy/antlr/treewalker/package.html
new file mode 100644
index 0000000..9fca823
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.antlr.treewalker.*</title>
+  </head>
+  <body>
+    <p>Classes for walking the AST.</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ASTNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ASTNode.java b/src/main/java/org/codehaus/groovy/ast/ASTNode.java
new file mode 100644
index 0000000..b5b7200
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ASTNode.java
@@ -0,0 +1,158 @@
+/*
+ *  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.util.ListHashMap;
+
+import java.util.Map;
+
+/**
+ * Base class for any AST node. This class supports basic information used in all nodes of the AST:
+ * <ul>
+ * <li> line and column number information. Usually a node represents a certain
+ * area in a text file determined by a starting position and an ending position.
+ * For nodes that do not represent this, this information will be -1. A node can
+ * also be configured in its line/col information using another node through 
+ * setSourcePosition(otherNode).</li>
+ * <li> every node can store meta data. A phase operation or transform can use 
+ * this to transport arbitrary information to another phase operation or 
+ * transform. The only requirement is that the other phase operation or transform
+ * runs after the part storing the information. If the information transport is 
+ * done it is strongly recommended to remove that meta data.</li> 
+ * <li> a text representation of this node trough getText(). This was in the
+ * past used for assertion messages. Since the usage of power asserts this 
+ * method will not be called for this purpose anymore and might be removed in
+ * future versions of Groovy</li>
+ * </ul>
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class ASTNode implements NodeMetaDataHandler {
+
+    private int lineNumber = -1;
+    private int columnNumber = -1;
+    private int lastLineNumber = -1;
+    private int lastColumnNumber = -1;
+    private Map metaDataMap = null;
+    private NodeMetaDataHandlerHelper helper = new NodeMetaDataHandlerHelper(this);
+
+    public void visit(GroovyCodeVisitor visitor) {
+        throw new RuntimeException("No visit() method implemented for class: " + getClass().getName());
+    }
+
+    public String getText() {
+        return "<not implemented yet for class: " + getClass().getName() + ">";
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    public void setColumnNumber(int columnNumber) {
+        this.columnNumber = columnNumber;
+    }
+
+    public int getLastLineNumber() {
+        return lastLineNumber;
+    }
+
+    public void setLastLineNumber(int lastLineNumber) {
+        this.lastLineNumber = lastLineNumber;
+    }
+
+    public int getLastColumnNumber() {
+        return lastColumnNumber;
+    }
+
+    public void setLastColumnNumber(int lastColumnNumber) {
+        this.lastColumnNumber = lastColumnNumber;
+    }
+    
+    /**
+     * Sets the source position using another ASTNode.
+     * The sourcePosition consists of a line/column pair for
+     * the start and a line/column pair for the end of the
+     * expression or statement 
+     * 
+     * @param node - the node used to configure the position information
+     */
+    public void setSourcePosition(ASTNode node) {
+        this.columnNumber = node.getColumnNumber();
+        this.lastLineNumber = node.getLastLineNumber();
+        this.lastColumnNumber = node.getLastColumnNumber();
+        this.lineNumber = node.getLineNumber();
+    }
+
+    /**
+     * Copies all node meta data from the other node to this one
+     * @param other - the other node
+     */
+    public void copyNodeMetaData(ASTNode other) {
+        copyNodeMetaData((NodeMetaDataHandler) other);
+    }
+
+    @Override
+    public <T> T getNodeMetaData(Object key) {
+        return helper.getNodeMetaData(key);
+    }
+
+    @Override
+    public void copyNodeMetaData(NodeMetaDataHandler other) {
+        helper.copyNodeMetaData(other);
+    }
+
+    @Override
+    public void setNodeMetaData(Object key, Object value) {
+        helper.setNodeMetaData(key, value);
+    }
+
+    @Override
+    public Object putNodeMetaData(Object key, Object value) {
+        return helper.putNodeMetaData(key, value);
+    }
+
+    @Override
+    public void removeNodeMetaData(Object key) {
+        helper.removeNodeMetaData(key);
+    }
+
+    @Override
+    public Map<?, ?> getNodeMetaData() {
+        return helper.getNodeMetaData();
+    }
+
+    @Override
+    public ListHashMap getMetaDataMap() {
+        return (ListHashMap) metaDataMap;
+    }
+
+    @Override
+    public void setMetaDataMap(Map<?, ?> metaDataMap) {
+        this.metaDataMap = metaDataMap;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/AnnotatedNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/AnnotatedNode.java b/src/main/java/org/codehaus/groovy/ast/AnnotatedNode.java
new file mode 100644
index 0000000..ab5f2eb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/AnnotatedNode.java
@@ -0,0 +1,112 @@
+/*
+ *  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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Base class for any AST node which is capable of being annotated
+ *
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ */
+public class AnnotatedNode extends ASTNode {
+    private List<AnnotationNode> annotations = Collections.emptyList();
+    private boolean synthetic;
+    ClassNode declaringClass;
+    private boolean hasNoRealSourcePositionFlag;
+
+    public AnnotatedNode() {
+    }
+
+    public List<AnnotationNode> getAnnotations() {
+        return annotations;
+    }
+
+    public List<AnnotationNode> getAnnotations(ClassNode type) {
+        List<AnnotationNode> ret = new ArrayList<AnnotationNode>(annotations.size());
+        for (AnnotationNode node: annotations) {
+            if (type.equals(node.getClassNode())) ret.add(node);
+        }
+        return ret;
+    }
+
+    public void addAnnotation(AnnotationNode value) {
+        checkInit();
+        annotations.add(value);
+    }
+
+    private void checkInit() {
+        if (annotations == Collections.EMPTY_LIST)
+            annotations = new ArrayList<AnnotationNode>(3);
+    }
+
+    public void addAnnotations(List<AnnotationNode> annotations) {
+        for (AnnotationNode node : annotations) {
+            addAnnotation(node);
+        }
+    }
+
+    /**
+     * returns true if this node is added by the compiler.
+     * <b>NOTE</b>: 
+     * This method has nothing to do with the synthetic flag
+     * for fields, methods or classes.              
+     * @return true if this node is added by the compiler
+     */
+    public boolean isSynthetic() {
+        return synthetic;
+    }
+
+    /**
+     * sets this node as a node added by the compiler.
+     * <b>NOTE</b>: 
+     * This method has nothing to do with the synthetic flag
+     * for fields, methods or classes.              
+     * @param synthetic - if true this node is marked as
+     *                    added by the compiler
+     */
+    public void setSynthetic(boolean synthetic) {
+        this.synthetic = synthetic;
+    }
+
+    public ClassNode getDeclaringClass() {
+        return declaringClass;
+    }
+
+    /**
+     * @param declaringClass - The declaringClass to set.
+     */
+    public void setDeclaringClass(ClassNode declaringClass) {
+        this.declaringClass = declaringClass;
+    }
+
+    /**
+     * Currently only ever returns true for default constructors
+     * added by the compiler. See GROOVY-4161.
+     */
+    public boolean hasNoRealSourcePosition() {
+        return hasNoRealSourcePositionFlag;
+    }
+
+    public void setHasNoRealSourcePosition(boolean value) {
+        this.hasNoRealSourcePositionFlag = value;
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
new file mode 100644
index 0000000..3838fdc
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
@@ -0,0 +1,383 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.EmptyRange;
+import groovy.lang.IntRange;
+import groovy.lang.Range;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Properties;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.Stack;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+import java.util.WeakHashMap;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.SynchronousQueue;
+import java.util.logging.Logger;
+
+/**
+ * Support methods for DefaultGroovyMethods and PluginDefaultMethods.
+ */
+public class DefaultGroovyMethodsSupport {
+
+    private static final Logger LOG = Logger.getLogger(DefaultGroovyMethodsSupport.class.getName());
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+    // helper method for getAt and putAt
+    protected static RangeInfo subListBorders(int size, Range range) {
+        if (range instanceof IntRange) {
+            return ((IntRange)range).subListBorders(size);
+        }
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), size);
+        int to = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getTo()), size);
+        boolean reverse = range.isReverse();
+        if (from > to) {
+            // support list[1..-1]
+            int tmp = to;
+            to = from;
+            from = tmp;
+            reverse = !reverse;
+        }
+        return new RangeInfo(from, to + 1, reverse);
+    }
+
+    // helper method for getAt and putAt
+    protected static RangeInfo subListBorders(int size, EmptyRange range) {
+        int from = normaliseIndex(DefaultTypeTransformation.intUnbox(range.getFrom()), size);
+        return new RangeInfo(from, from, false);
+    }
+
+    /**
+     * This converts a possibly negative index to a real index into the array.
+     *
+     * @param i    the unnormalized index
+     * @param size the array size
+     * @return the normalised index
+     */
+    protected static int normaliseIndex(int i, int size) {
+        int temp = i;
+        if (i < 0) {
+            i += size;
+        }
+        if (i < 0) {
+            throw new ArrayIndexOutOfBoundsException("Negative array index [" + temp + "] too large for array size " + size);
+        }
+        return i;
+    }
+
+    /**
+     * Close the Closeable. Logging a warning if any problems occur.
+     *
+     * @param closeable the thing to close
+     */
+    public static void closeWithWarning(Closeable closeable) {
+        tryClose(closeable, true); // ignore result
+    }
+
+    /**
+     * Attempts to close the closeable returning rather than throwing
+     * any Exception that may occur.
+     *
+     * @param closeable the thing to close
+     * @param logWarning if true will log a warning if an exception occurs
+     * @return throwable Exception from the close method, else null
+     */
+    static Throwable tryClose(AutoCloseable closeable, boolean logWarning) {
+        Throwable thrown = null;
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (Exception e) {
+                thrown = e;
+                if (logWarning) {
+                    LOG.warning("Caught exception during close(): " + e);
+                }
+            }
+        }
+        return thrown;
+    }
+
+    /**
+     * Close the Closeable. Ignore any problems that might occur.
+     *
+     * @param c the thing to close
+     */
+    public static void closeQuietly(Closeable c) {
+        if (c != null) {
+            try {
+                c.close();
+            } catch (IOException e) {
+                /* ignore */
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> Collection<T> cloneSimilarCollection(Collection<T> orig, int newCapacity) {
+        Collection<T> answer = (Collection<T>) cloneObject(orig);
+        if (answer != null) return answer;
+
+        // fall back to creation
+        answer = createSimilarCollection(orig, newCapacity);
+        answer.addAll(orig);
+        return answer;
+    }
+
+    private static Object cloneObject(Object orig) {
+        if (orig instanceof Cloneable) {
+            try {
+                return InvokerHelper.invokeMethod(orig, "clone", EMPTY_OBJECT_ARRAY);
+            } catch (Exception ex) {
+                // ignore
+            }
+        }
+        return null;
+    }
+
+    protected static Collection createSimilarOrDefaultCollection(Object object) {
+        if (object instanceof Collection) {
+            return createSimilarCollection((Collection<?>) object);
+        }
+        return new ArrayList();
+    }
+
+    protected static <T> Collection<T> createSimilarCollection(Iterable<T> iterable) {
+        if (iterable instanceof Collection) {
+            return createSimilarCollection((Collection<T>) iterable);
+        } else {
+            return new ArrayList<T>();
+        }
+    }
+
+    protected static <T> Collection<T> createSimilarCollection(Collection<T> collection) {
+        return createSimilarCollection(collection, collection.size());
+    }
+
+    protected static <T> Collection<T> createSimilarCollection(Collection<T> orig, int newCapacity) {
+        if (orig instanceof Set) {
+            return createSimilarSet((Set<T>) orig);
+        }
+        if (orig instanceof List) {
+            return createSimilarList((List<T>) orig, newCapacity);
+        }
+        if (orig instanceof Queue) {
+            return createSimilarQueue((Queue<T>) orig);
+        }
+        return new ArrayList<T>(newCapacity);
+    }
+
+    protected static <T> List<T> createSimilarList(List<T> orig, int newCapacity) {
+        if (orig instanceof LinkedList)
+            return new LinkedList<T>();
+
+        if (orig instanceof Stack)
+            return new Stack<T>();
+
+        if (orig instanceof Vector)
+            return new Vector<T>();
+
+        if (orig instanceof CopyOnWriteArrayList)
+            return new CopyOnWriteArrayList<T>();
+
+        return new ArrayList<T>(newCapacity);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> T[] createSimilarArray(T[] orig, int newCapacity) {
+        Class<T> componentType = (Class<T>) orig.getClass().getComponentType();
+        return (T[]) Array.newInstance(componentType, newCapacity);
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> Set<T> createSimilarSet(Set<T> orig) {
+        if (orig instanceof SortedSet) {
+            Comparator comparator = ((SortedSet) orig).comparator();
+            if (orig instanceof ConcurrentSkipListSet) {
+                return new ConcurrentSkipListSet<T>(comparator);
+            } else {
+                return new TreeSet<T>(comparator);
+            }
+        } else {
+            if (orig instanceof CopyOnWriteArraySet) {
+                return new CopyOnWriteArraySet<T>();
+            } else {
+                // Do not use HashSet
+                return new LinkedHashSet<T>();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <T> Queue<T> createSimilarQueue(Queue<T> orig) {
+        if (orig instanceof ArrayBlockingQueue) {
+            ArrayBlockingQueue queue = (ArrayBlockingQueue) orig;
+            return new ArrayBlockingQueue<T>(queue.size() + queue.remainingCapacity());
+        } else if (orig instanceof ArrayDeque) {
+            return new ArrayDeque<T>();
+        } else if (orig instanceof ConcurrentLinkedQueue) {
+            return new ConcurrentLinkedQueue<T>();
+        } else if (orig instanceof DelayQueue) {
+            return new DelayQueue();
+        } else if (orig instanceof LinkedBlockingDeque) {
+            return new LinkedBlockingDeque<T>();
+        } else if (orig instanceof LinkedBlockingQueue) {
+            return new LinkedBlockingQueue<T>();
+        } else if (orig instanceof PriorityBlockingQueue) {
+            return new PriorityBlockingQueue<T>();
+        } else if (orig instanceof PriorityQueue) {
+            return new PriorityQueue<T>(11, ((PriorityQueue) orig).comparator());
+        } else if (orig instanceof SynchronousQueue) {
+            return new SynchronousQueue<T>();
+        } else {
+            return new LinkedList<T>();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <K, V> Map<K, V> createSimilarMap(Map<K, V> orig) {
+        if (orig instanceof SortedMap) {
+            Comparator comparator = ((SortedMap) orig).comparator();
+            if (orig instanceof ConcurrentSkipListMap) {
+                return new ConcurrentSkipListMap<K, V>(comparator);
+            } else {
+                return new TreeMap<K, V>(comparator);
+            }
+        } else {
+            if (orig instanceof ConcurrentHashMap) {
+                return new ConcurrentHashMap<K, V>();
+            } else if (orig instanceof Hashtable) {
+                if (orig instanceof Properties) {
+                    return (Map<K, V>) new Properties();
+                } else {
+                    return new Hashtable<K, V>();
+                }
+            } else if (orig instanceof IdentityHashMap) {
+                return new IdentityHashMap<K, V>();
+            } else if (orig instanceof WeakHashMap) {
+                return new WeakHashMap<K, V>();
+            } else {
+                // Do not use HashMap
+                return new LinkedHashMap<K, V>();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    protected static <K, V> Map<K ,V> cloneSimilarMap(Map<K, V> orig) {
+        Map<K, V> answer = (Map<K, V>) cloneObject(orig);
+        if (answer != null) return answer;
+
+        // fall back to some defaults
+        if (orig instanceof SortedMap) {
+            if (orig instanceof ConcurrentSkipListMap) {
+                return new ConcurrentSkipListMap<K, V>(orig);
+            } else {
+                return new TreeMap<K, V>(orig);
+            }
+        } else {
+            if (orig instanceof ConcurrentHashMap) {
+                return new ConcurrentHashMap<K, V>(orig);
+            } else if (orig instanceof Hashtable) {
+                if (orig instanceof Properties) {
+                    Map<K, V> map = (Map<K, V>) new Properties();
+                    map.putAll(orig);
+                    return map;
+                } else {
+                    return new Hashtable<K, V>(orig);
+                }
+            } else if (orig instanceof IdentityHashMap) {
+                return new IdentityHashMap<K, V>(orig);
+            } else if (orig instanceof WeakHashMap) {
+                return new WeakHashMap<K, V>(orig);
+            } else {
+                // Do not use HashMap
+                return new LinkedHashMap<K, V>(orig);
+            }
+        }
+    }
+
+    /**
+     * Determines if all items of this array are of the same type.
+     *
+     * @param cols an array of collections
+     * @return true if the collections are all of the same type
+     */
+    @SuppressWarnings("unchecked")
+    protected static boolean sameType(Collection[] cols) {
+        List all = new LinkedList();
+        for (Collection col : cols) {
+            all.addAll(col);
+        }
+        if (all.isEmpty())
+            return true;
+
+        Object first = all.get(0);
+
+        //trying to determine the base class of the collections
+        //special case for Numbers
+        Class baseClass;
+        if (first instanceof Number) {
+            baseClass = Number.class;
+        } else if (first == null) {
+            baseClass = NullObject.class;
+        } else {
+            baseClass = first.getClass();
+        }
+
+        for (Collection col : cols) {
+            for (Object o : col) {
+                if (!baseClass.isInstance(o)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
new file mode 100644
index 0000000..1c85e91
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
@@ -0,0 +1,314 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.reflection.ReflectionUtils;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+
+/**
+ * This class defines all the new static groovy methods which appear on normal
+ * JDK classes inside the Groovy environment. Static methods are used with the
+ * first parameter as the destination class.
+ *
+ * @author Guillaume Laforge
+ * @author Dierk Koenig
+ * @author Joachim Baumann
+ * @author Paul King
+ * @author Kent Inge Fagerland Simonsen
+ */
+public class DefaultGroovyStaticMethods {
+
+    /**
+     * Start a Thread with the given closure as a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.0
+     */
+    public static Thread start(Thread self, Closure closure) {
+        return createThread(null, false, closure);
+    }
+
+    /**
+     * Start a Thread with a given name and the given closure
+     * as a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param name    the name to give the thread
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.6
+     */
+    public static Thread start(Thread self, String name, Closure closure) {
+        return createThread(name, false, closure);
+    }
+
+    /**
+     * Start a daemon Thread with the given closure as a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.0
+     */
+    public static Thread startDaemon(Thread self, Closure closure) {
+        return createThread(null, true, closure);
+    }
+
+    /**
+     * Start a daemon Thread with a given name and the given closure as
+     * a Runnable instance.
+     *
+     * @param self    placeholder variable used by Groovy categories; ignored for default static methods
+     * @param name    the name to give the thread
+     * @param closure the Runnable closure
+     * @return the started thread
+     * @since 1.6
+     */
+    public static Thread startDaemon(Thread self, String name, Closure closure) {
+        return createThread(name, true, closure);
+    }
+
+    private static Thread createThread(String name, boolean daemon, Closure closure) {
+        Thread thread = name != null ? new Thread(closure, name) : new Thread(closure);
+        if (daemon) thread.setDaemon(true);
+        thread.start();
+        return thread;
+    }
+
+    /**
+     * Get the last hidden matcher that the system used to do a match.
+     *
+     * @param self placeholder variable used by Groovy categories; ignored for default static methods
+     * @return the last regex matcher
+     * @since 1.0
+     */
+    public static Matcher getLastMatcher(Matcher self) {
+        return RegexSupport.getLastMatcher();
+    }
+
+    /**
+     * This method is used by both sleep() methods to implement sleeping
+     * for the given time even if interrupted
+     *
+     * @param millis  the number of milliseconds to sleep
+     * @param closure optional closure called when interrupted
+     *                as long as the closure returns false the sleep continues
+     */
+    private static void sleepImpl(long millis, Closure closure) {
+        long start = System.currentTimeMillis();
+        long rest = millis;
+        long current;
+        while (rest > 0) {
+            try {
+                Thread.sleep(rest);
+                rest = 0;
+            } catch (InterruptedException e) {
+                if (closure != null) {
+                    if (DefaultTypeTransformation.castToBoolean(closure.call(e))) {
+                        return;
+                    }
+                }
+                current = System.currentTimeMillis(); // compensate for closure's time
+                rest = millis + start - current;
+            }
+        }
+    }
+
+    /**
+     * Sleep for so many milliseconds, even if interrupted.
+     *
+     * @param self         placeholder variable used by Groovy categories; ignored for default static methods
+     * @param milliseconds the number of milliseconds to sleep
+     * @since 1.0
+     */
+    public static void sleep(Object self, long milliseconds) {
+        sleepImpl(milliseconds, null);
+    }
+
+    /**
+     * Sleep for so many milliseconds, using a given closure for interrupt processing.
+     *
+     * @param self         placeholder variable used by Groovy categories; ignored for default static methods
+     * @param milliseconds the number of milliseconds to sleep
+     * @param onInterrupt  interrupt handler, InterruptedException is passed to the Closure
+     *                     as long as it returns false, the sleep continues
+     * @since 1.0
+     */
+    public static void sleep(Object self, long milliseconds, Closure onInterrupt) {
+        sleepImpl(milliseconds, onInterrupt);
+    }
+
+    /**
+     * Parse a String into a Date instance using the given pattern.
+     * This convenience method acts as a wrapper for {@link java.text.SimpleDateFormat}.
+     * <p>
+     * Note that a new SimpleDateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+     * @param format pattern used to parse the input string.
+     * @param input  String to be parsed to create the date instance
+     * @return a new Date instance representing the parsed input string
+     * @throws ParseException if there is a parse error
+     * @see java.text.SimpleDateFormat#parse(java.lang.String)
+     * @since 1.5.7
+     */
+    public static Date parse(Date self, String format, String input) throws ParseException {
+        return new SimpleDateFormat(format).parse(input);
+    }
+
+    /**
+     * Parse a String into a Date instance using the given pattern and TimeZone.
+     * This convenience method acts as a wrapper for {@link java.text.SimpleDateFormat}.
+     * <p>
+     * Note that a new SimpleDateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+     * @param format pattern used to parse the input string.
+     * @param input  String to be parsed to create the date instance
+     * @param zone   TimeZone to use when parsing
+     * @return a new Date instance representing the parsed input string
+     * @throws ParseException if there is a parse error
+     * @see java.text.SimpleDateFormat#parse(java.lang.String)
+     * @since 2.4.1
+     */
+    public static Date parse(Date self, String format, String input, TimeZone zone) throws ParseException {
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        sdf.setTimeZone(zone);
+        return sdf.parse(input);
+    }
+
+    /**
+     * Parse a String matching the pattern EEE MMM dd HH:mm:ss zzz yyyy
+     * containing US-locale-constants only (e.g. Sat for Saturdays).
+     * Such a string is generated by the toString method of {@link java.util.Date}
+     * <p>
+     * Note that a new SimpleDateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self          placeholder variable used by Groovy categories; ignored for default static methods
+     * @param dateToString  String to be parsed to create the date instance. Must match the pattern EEE MMM dd HH:mm:ss zzz yyyy with US-locale symbols
+     * @return a new Date instance representing the parsed input string
+     * @throws ParseException if there is a parse error
+     */
+    public static Date parseToStringDate(Date self, String dateToString) throws ParseException {
+        return new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US).parse(dateToString);
+    }
+
+    /**
+     * Works exactly like ResourceBundle.getBundle(String).  This is needed
+     * because the java method depends on a particular stack configuration that
+     * is not guaranteed in Groovy when calling the Java method.
+     *
+     * @param self       placeholder variable used by Groovy categories; ignored for default static methods
+     * @param bundleName the name of the bundle.
+     * @return the resource bundle
+     * @see java.util.ResourceBundle#getBundle(java.lang.String)
+     * @since 1.6.0
+     */
+    public static ResourceBundle getBundle(ResourceBundle self, String bundleName) {
+        return getBundle(self, bundleName, Locale.getDefault());
+    }
+
+    /**
+     * Works exactly like ResourceBundle.getBundle(String, Locale).  This is needed
+     * because the java method depends on a particular stack configuration that
+     * is not guaranteed in Groovy when calling the Java method.
+     *
+     * @param self       placeholder variable used by Groovy categories; ignored for default static methods
+     * @param bundleName the name of the bundle.
+     * @param locale     the specific locale
+     * @return the resource bundle
+     * @see java.util.ResourceBundle#getBundle(java.lang.String, java.util.Locale)
+     * @since 1.6.0
+     */
+    public static ResourceBundle getBundle(ResourceBundle self, String bundleName, Locale locale) {
+        Class c = ReflectionUtils.getCallingClass();
+        ClassLoader targetCL = c != null ? c.getClassLoader() : null;
+        if (targetCL == null) targetCL = ClassLoader.getSystemClassLoader();
+        return ResourceBundle.getBundle(bundleName, locale, targetCL);
+    }
+
+    public static File createTempDir(File self) throws IOException {
+        return createTempDir(self, "groovy-generated-", "-tmpdir");
+    }
+
+    public static File createTempDir(File self, final String prefix, final String suffix) throws IOException {
+        final int MAXTRIES = 3;
+        int accessDeniedCounter = 0;
+        File tempFile=null;
+        for (int i=0; i<MAXTRIES; i++) {
+            try {
+                tempFile = File.createTempFile(prefix, suffix);
+                tempFile.delete();
+                tempFile.mkdirs();
+                break;
+            } catch (IOException ioe) {
+                if (ioe.getMessage().startsWith("Access is denied")) {
+                    accessDeniedCounter++;
+                    try { Thread.sleep(100); } catch (InterruptedException e) {}
+                }
+                if (i==MAXTRIES-1) {
+                    if (accessDeniedCounter==MAXTRIES) {
+                        String msg =
+                                "Access is denied.\nWe tried " +
+                                        + accessDeniedCounter+
+                                        " times to create a temporary directory"+
+                                        " and failed each time. If you are on Windows"+
+                                        " you are possibly victim to"+
+                                        " http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6325169. "+
+                                        " this is no bug in Groovy.";
+                        throw new IOException(msg);
+                    } else {
+                        throw ioe;
+                    }
+                }
+                continue;
+            }
+        }
+        return tempFile;
+    }
+
+  /**
+   * Get the current time in seconds
+   *
+   * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+   * @return  the difference, measured in seconds, between
+   *          the current time and midnight, January 1, 1970 UTC.
+   * @see     System#currentTimeMillis()
+   */
+  public static long currentTimeSeconds(System self){
+    return System.currentTimeMillis() / 1000;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java b/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java
new file mode 100644
index 0000000..96612ff
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultMethodKey.java
@@ -0,0 +1,44 @@
+/*
+ *  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.runtime;
+
+/**
+ * A default implementation of MethodKey
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class DefaultMethodKey extends MethodKey{
+
+    private final Class[] parameterTypes;
+
+    public DefaultMethodKey(Class sender, String name, Class[] parameterTypes, boolean isCallToSuper) {
+        super(sender, name,isCallToSuper);
+        this.parameterTypes = parameterTypes;
+    }
+
+    public int getParameterCount() {
+        return parameterTypes.length;
+    }
+
+    public Class getParameterType(int index) {
+        Class c = parameterTypes[index];
+        if (c==null) return Object.class;
+        return c;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java
new file mode 100644
index 0000000..62b6eeb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethods.java
@@ -0,0 +1,367 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.StringWriterIOException;
+import groovy.lang.Writable;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import static org.codehaus.groovy.runtime.EncodingGroovyMethodsSupport.TRANSLATE_TABLE;
+import static org.codehaus.groovy.runtime.EncodingGroovyMethodsSupport.TRANSLATE_TABLE_URLSAFE;
+
+/**
+ * This class defines all the encoding/decoding groovy methods which enhance
+ * the normal JDK classes when inside the Groovy environment.
+ * Static methods are used with the first parameter the destination class.
+ */
+public class EncodingGroovyMethods {
+
+    private static final char[] T_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
+
+    private static final char[] T_TABLE_URLSAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=".toCharArray();
+
+    private static final String CHUNK_SEPARATOR = "\r\n";
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data Byte array to be encoded
+     * @param chunked whether or not the Base64 encoded data should be MIME chunked
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.5.1
+     */
+    public static Writable encodeBase64(Byte[] data, final boolean chunked) {
+        return encodeBase64(DefaultTypeTransformation.convertToByteArray(data), chunked);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data Byte array to be encoded
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.0
+     */
+    public static Writable encodeBase64(Byte[] data) {
+        return encodeBase64(DefaultTypeTransformation.convertToByteArray(data), false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data byte array to be encoded
+     * @param chunked whether or not the Base64 encoded data should be MIME chunked
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.5.7
+     */
+    public static Writable encodeBase64(final byte[] data, final boolean chunked) {
+        return encodeBase64(data, chunked, false, true);
+    }
+
+    private static Writable encodeBase64(final byte[] data, final boolean chunked, final boolean urlSafe, final boolean pad) {
+        return new Writable() {
+            public Writer writeTo(final Writer writer) throws IOException {
+                int charCount = 0;
+                final int dLimit = (data.length / 3) * 3;
+                final char[] table = urlSafe ? T_TABLE_URLSAFE : T_TABLE;
+                for (int dIndex = 0; dIndex != dLimit; dIndex += 3) {
+                    int d = ((data[dIndex] & 0XFF) << 16) | ((data[dIndex + 1] & 0XFF) << 8) | (data[dIndex + 2] & 0XFF);
+
+                    writer.write(table[d >> 18]);
+                    writer.write(table[(d >> 12) & 0X3F]);
+                    writer.write(table[(d >> 6) & 0X3F]);
+                    writer.write(table[d & 0X3F]);
+
+                    if (chunked && ++charCount == 19) {
+                        writer.write(CHUNK_SEPARATOR);
+                        charCount = 0;
+                    }
+                }
+
+                if (dLimit != data.length) {
+                    int d = (data[dLimit] & 0XFF) << 16;
+
+                    if (dLimit + 1 != data.length) {
+                        d |= (data[dLimit + 1] & 0XFF) << 8;
+                    }
+
+                    writer.write(table[d >> 18]);
+                    writer.write(table[(d >> 12) & 0X3F]);
+                    if (pad) {
+                        writer.write((dLimit + 1 < data.length) ? table[(d >> 6) & 0X3F] : '=');
+                        writer.write('=');
+                    } else {
+                        if (dLimit + 1 < data.length) {
+                            writer.write(table[(d >> 6) & 0X3F]);
+                        }
+                    }
+                    if (chunked && charCount != 0) {
+                        writer.write(CHUNK_SEPARATOR);
+                    }
+                }
+
+                return writer;
+            }
+
+            public String toString() {
+                StringWriter buffer = new StringWriter();
+
+                try {
+                    writeTo(buffer);
+                } catch (IOException e) {
+                    throw new StringWriterIOException(e);
+                }
+
+                return buffer.toString();
+            }
+        };
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 encoding and chunking see <code>RFC 4648</code>.
+     *
+     * @param data byte array to be encoded
+     * @return object which will write the Base64 encoding of the byte array
+     * @since 1.0
+     */
+    public static Writable encodeBase64(final byte[] data) {
+        return encodeBase64(data, false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     * <p>
+     * The method omits padding and is equivalent to calling
+     * {@link org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(Byte[], boolean)} with a
+     * value of {@code false}.
+     *
+     * @param data Byte array to be encoded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @see org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(Byte[], boolean)
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(Byte[] data) {
+        return encodeBase64Url(data, false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     *
+     * @param data Byte array to be encoded
+     * @param pad whether or not the encoded data should be padded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(Byte[] data, boolean pad) {
+        return encodeBase64Url(DefaultTypeTransformation.convertToByteArray(data), pad);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     * <p>
+     * The method omits padding and is equivalent to calling
+     * {@link org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(byte[], boolean)} with a
+     * value of {@code false}.
+     *
+     * @param data Byte array to be encoded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @see org.codehaus.groovy.runtime.EncodingGroovyMethods#encodeBase64Url(byte[], boolean)
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(final byte[] data) {
+        return encodeBase64Url(data, false);
+    }
+
+    /**
+     * Produce a Writable object which writes the Base64 URL and Filename Safe encoding of the byte array.
+     * Calling toString() on the result returns the encoding as a String. For more
+     * information on Base64 URL and Filename Safe encoding see <code>RFC 4648 - Section 5
+     * Base 64 Encoding with URL and Filename Safe Alphabet</code>.
+     *
+     * @param data Byte array to be encoded
+     * @param pad whether or not the encoded data should be padded
+     * @return object which will write the Base64 URL and Filename Safe encoding of the byte array
+     * @since 2.5.0
+     */
+    public static Writable encodeBase64Url(final byte[] data, final boolean pad) {
+        return encodeBase64(data, false, true, pad);
+    }
+
+    /**
+     * Decode the String from Base64 into a byte array.
+     *
+     * @param value the string to be decoded
+     * @return the decoded bytes as an array
+     * @since 1.0
+     */
+    public static byte[] decodeBase64(String value) {
+        return decodeBase64(value, false);
+    }
+
+    /**
+     * Decodes a Base64 URL and Filename Safe encoded String into a byte array.
+     *
+     * @param value the string to be decoded
+     * @return the decoded bytes as an array
+     * @since 2.5.0
+     */
+    public static byte[] decodeBase64Url(String value) {
+        return decodeBase64(value, true);
+    }
+
+    private static byte[] decodeBase64(String value, boolean urlSafe) {
+        int byteShift = 4;
+        int tmp = 0;
+        boolean done = false;
+        final StringBuilder buffer = new StringBuilder();
+        final byte[] table = urlSafe ? TRANSLATE_TABLE_URLSAFE : TRANSLATE_TABLE;
+        for (int i = 0; i != value.length(); i++) {
+            final char c = value.charAt(i);
+            final int sixBit = (c < 123) ? table[c] : 66;
+
+            if (sixBit < 64) {
+                if (done)
+                    throw new RuntimeException("= character not at end of base64 value"); // TODO: change this exception type
+
+                tmp = (tmp << 6) | sixBit;
+
+                if (byteShift-- != 4) {
+                    buffer.append((char) ((tmp >> (byteShift * 2)) & 0XFF));
+                }
+
+            } else if (sixBit == 64) {
+
+                byteShift--;
+                done = true;
+
+            } else if (sixBit == 66) {
+                // RFC 2045 says that I'm allowed to take the presence of
+                // these characters as evidence of data corruption
+                // So I will
+                throw new RuntimeException("bad character in base64 value"); // TODO: change this exception type
+            }
+
+            if (byteShift == 0) byteShift = 4;
+        }
+
+        try {
+            return buffer.toString().getBytes("ISO-8859-1");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("Base 64 decode produced byte values > 255"); // TODO: change this exception type
+        }
+    }
+
+    /**
+     * Produces a Writable that writes the hex encoding of the Byte[]. Calling
+     * toString() on this Writable returns the hex encoding as a String. The hex
+     * encoding includes two characters for each byte and all letters are lower case.
+     *
+     * @param data byte array to be encoded
+     * @return object which will write the hex encoding of the byte array
+     * @see Integer#toHexString(int)
+     */
+    public static Writable encodeHex(final Byte[] data) {
+        return encodeHex(DefaultTypeTransformation.convertToByteArray(data));
+    }
+
+    /**
+     * Produces a Writable that writes the hex encoding of the byte[]. Calling
+     * toString() on this Writable returns the hex encoding as a String. The hex
+     * encoding includes two characters for each byte and all letters are lower case.
+     *
+     * @param data byte array to be encoded
+     * @return object which will write the hex encoding of the byte array
+     * @see Integer#toHexString(int)
+     */
+    public static Writable encodeHex(final byte[] data) {
+        return new Writable() {
+            public Writer writeTo(Writer out) throws IOException {
+                for (int i = 0; i < data.length; i++) {
+                    // convert byte into unsigned hex string
+                    String hexString = Integer.toHexString(data[i] & 0xFF);
+
+                    // add leading zero if the length of the string is one
+                    if (hexString.length() < 2) {
+                        out.write("0");
+                    }
+
+                    // write hex string to writer
+                    out.write(hexString);
+                }
+                return out;
+            }
+
+            public String toString() {
+                StringWriter buffer = new StringWriter();
+
+                try {
+                    writeTo(buffer);
+                } catch (IOException e) {
+                    throw new StringWriterIOException(e);
+                }
+
+                return buffer.toString();
+            }
+        };
+    }
+
+    /**
+     * Decodes a hex string to a byte array. The hex string can contain either upper
+     * case or lower case letters.
+     *
+     * @param value string to be decoded
+     * @return decoded byte array
+     * @throws NumberFormatException If the string contains an odd number of characters
+     *                               or if the characters are not valid hexadecimal values.
+     */
+    public static byte[] decodeHex(final String value) {
+        // if string length is odd then throw exception
+        if (value.length() % 2 != 0) {
+            throw new NumberFormatException("odd number of characters in hex string");
+        }
+
+        byte[] bytes = new byte[value.length() / 2];
+        for (int i = 0; i < value.length(); i += 2) {
+            bytes[i / 2] = (byte) Integer.parseInt(value.substring(i, i + 2), 16);
+        }
+
+        return bytes;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
new file mode 100644
index 0000000..24929a8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/EncodingGroovyMethodsSupport.java
@@ -0,0 +1,90 @@
+/*
+ *  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.runtime;
+
+/**
+ * Keep this constant in a separate file as it is troublesome for Antlr to parse for doc purposes.
+ */
+public class EncodingGroovyMethodsSupport {
+    static final byte[] TRANSLATE_TABLE = (
+            "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //           \t    \n                \r
+                    + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //     sp     !     "     #     $     %     &     '
+                    + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //      (     )     *     +     ,     -     .     /
+                    + "\u0042\u0042\u0042\u003E\u0042\u0042\u0042\u003F"
+                    //      0     1     2     3     4     5     6     7
+                    + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
+                    //      8     9     :     ;     <     =     >     ?
+                    + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
+                    //      @     A     B     C     D     E     F     G
+                    + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
+                    //      H     I J K     L     M N     O
+                    + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
+                    //      P     Q     R     S     T     U     V     W
+                    + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
+                    //      X     Y     Z     [     \     ]     ^     _
+                    + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u0042"
+                    //      '     a     b     c     d     e     f     g
+                    + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
+                    //      h i     j     k     l     m     n     o
+                    + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
+                    //      p     q     r     s     t     u     v     w
+                    + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
+                    //      x     y     z
+                    + "\u0031\u0032\u0033").getBytes();
+
+    static final byte[] TRANSLATE_TABLE_URLSAFE = (
+            "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //           \t    \n                \r
+                    + "\u0042\u0041\u0041\u0042\u0042\u0041\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //
+                    + "\u0042\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //     sp     !     "     #     $     %     &     '
+                    + "\u0041\u0042\u0042\u0042\u0042\u0042\u0042\u0042"
+                    //      (     )     *     +     ,     -     .     /
+                    + "\u0042\u0042\u0042\u0042\u0042\u003E\u0042\u0042"
+                    //      0     1     2     3     4     5     6     7
+                    + "\u0034\u0035\u0036\u0037\u0038\u0039\u003A\u003B"
+                    //      8     9     :     ;     <     =     >     ?
+                    + "\u003C\u003D\u0042\u0042\u0042\u0040\u0042\u0042"
+                    //      @     A     B     C     D     E     F     G
+                    + "\u0042\u0000\u0001\u0002\u0003\u0004\u0005\u0006"
+                    //      H     I J K     L     M N     O
+                    + "\u0007\u0008\t\n\u000B\u000C\r\u000E"
+                    //      P     Q     R     S     T     U     V     W
+                    + "\u000F\u0010\u0011\u0012\u0013\u0014\u0015\u0016"
+                    //      X     Y     Z     [     \     ]     ^     _
+                    + "\u0017\u0018\u0019\u0042\u0042\u0042\u0042\u003F"
+                    //      '     a     b     c     d     e     f     g
+                    + "\u0042\u001A\u001B\u001C\u001D\u001E\u001F\u0020"
+                    //      h i     j     k     l     m     n     o
+                    + "\u0021\"\u0023\u0024\u0025\u0026\u0027\u0028"
+                    //      p     q     r     s     t     u     v     w
+                    + "\u0029\u002A\u002B\u002C\u002D\u002E\u002F\u0030"
+                    //      x     y     z
+                    + "\u0031\u0032\u0033").getBytes();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java b/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java
new file mode 100644
index 0000000..6fb77b7
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/FlushingStreamWriter.java
@@ -0,0 +1,50 @@
+/*
+ *  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.runtime;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+/**
+ * Stream writer which flushes after each write operation.
+ *
+ * @author Guillaume Laforge
+ */
+public class FlushingStreamWriter extends OutputStreamWriter {
+
+    public FlushingStreamWriter(OutputStream out) {
+        super(out);
+    }
+
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        super.write(cbuf, off, len);
+        flush();
+    }
+
+    public void write(int c) throws IOException {
+        super.write(c);
+        flush();
+    }
+
+    public void write(String str, int off, int len) throws IOException {
+        super.write(str, off, len);
+        flush();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java b/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
new file mode 100644
index 0000000..d4cd857
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/GStringImpl.java
@@ -0,0 +1,64 @@
+/*
+ * 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.runtime;
+
+import groovy.lang.GString;
+
+/**
+ * Default implementation of a GString used by the compiler. A GString
+ * consist of a list of values and strings which can be combined to
+ * create a new String.
+ *
+ * @author Jochen Theodorou
+ * @see groovy.lang.GString
+ */
+public class GStringImpl extends GString {
+    private final String[] strings;
+
+    /**
+     * Create a new GString with values and strings.
+     * <p>
+     * Each value is prefixed by a string, after the last value
+     * an additional String might be used. This means
+     * <code>strings.length == values.length  ||  strings.length == values.length + 1</code>.
+     * <p>
+     * <b>NOTE:</b> The lengths are <b>not</b> checked. Using different lengths might result
+     * in unpredictable behaviour.
+     *
+     * @param values  the value parts
+     * @param strings the string parts
+     */
+    public GStringImpl(Object[] values, String[] strings) {
+        super(values);
+        this.strings = strings;
+    }
+
+    /**
+     * Get the strings of this GString.
+     * <p>
+     * This methods returns the same array as used in the constructor. Changing
+     * the values will result in changes of the GString. It is not recommended
+     * to do so.
+     */
+    public String[] getStrings() {
+        return strings;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java b/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java
new file mode 100644
index 0000000..50da843
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/GeneratedClosure.java
@@ -0,0 +1,29 @@
+/*
+ *  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.runtime;
+
+/**
+ * Marker interface to identify closures generated by the groovy compiler.
+ * For internal use only!
+ * 
+ * @author Jochen Theodorou
+ * @since 1.5
+ * @see org.codehaus.groovy.runtime.metaclass.ClosureMetaClass
+ */
+public interface GeneratedClosure {}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
new file mode 100644
index 0000000..19f53d2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/GroovyCategorySupport.java
@@ -0,0 +1,365 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.CachedMethod;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.metaclass.DefaultMetaClassInfo;
+import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author sam
+ * @author Paul King
+ * @author Alex Tkachman
+ */
+public class GroovyCategorySupport {
+
+    private static int categoriesInUse = 0;
+
+    public static class CategoryMethodList extends ArrayList<CategoryMethod> {
+        public final int level;
+        final CategoryMethodList previous;
+        final AtomicInteger usage;
+
+        public CategoryMethodList(String name, int level, CategoryMethodList previous) {
+            this.level = level;
+            this.previous = previous;
+            if (previous != null) {
+                addAll(previous);
+                usage = previous.usage;
+            }
+            else {
+                usage = getCategoryNameUsage (name);
+            }
+        }
+
+        public boolean add(CategoryMethod o) {
+            usage.incrementAndGet();
+            return super.add(o);
+        }
+    }
+
+    public static class ThreadCategoryInfo extends HashMap<String, CategoryMethodList>{
+
+        private static final Object LOCK = new Object();
+
+        int level;
+
+        private Map<String, String> propertyGetterMap;
+        private Map<String, String> propertySetterMap;
+
+        private void newScope () {
+            synchronized (LOCK) {
+                categoriesInUse++;
+                DefaultMetaClassInfo.setCategoryUsed(true);
+            }
+            VMPluginFactory.getPlugin().invalidateCallSites();
+            level++;
+        }
+
+        private void endScope () {
+            for (Iterator<Map.Entry<String, CategoryMethodList>> it = entrySet().iterator(); it.hasNext(); ) {
+                final Map.Entry<String, CategoryMethodList> e = it.next();
+                final CategoryMethodList list = e.getValue();
+                if (list.level == level) {
+                    final CategoryMethodList prev = list.previous;
+                    if (prev == null) {
+                      it.remove();
+                      list.usage.addAndGet(-list.size());
+                    }
+                    else {
+                      e.setValue(prev);
+                      list.usage.addAndGet(prev.size()-list.size());
+                    }
+                }
+            }
+            level--;
+            VMPluginFactory.getPlugin().invalidateCallSites();
+            synchronized (LOCK) {
+                if (--categoriesInUse == 0) {
+                    DefaultMetaClassInfo.setCategoryUsed(false);
+                }
+            }
+            if (level == 0) {
+                THREAD_INFO.remove();
+            }
+        }
+
+        private <T> T use(Class categoryClass, Closure<T> closure) {
+            newScope();
+            try {
+                use(categoryClass);
+                return closure.call();
+            } finally {
+                endScope();
+            }
+        }
+
+        public <T> T use(List<Class> categoryClasses, Closure<T> closure) {
+            newScope();
+            try {
+                for (Class categoryClass : categoryClasses) {
+                    use(categoryClass);
+                }
+                return closure.call();
+            } finally {
+                endScope();
+            }
+        }
+
+        private void applyUse(CachedClass cachedClass) {
+            CachedMethod[] methods = cachedClass.getMethods();
+            for (CachedMethod cachedMethod : methods) {
+                if (cachedMethod.isStatic() && cachedMethod.isPublic()) {
+                    CachedClass[] paramTypes = cachedMethod.getParameterTypes();
+                    if (paramTypes.length > 0) {
+                        CachedClass metaClass = paramTypes[0];
+                        CategoryMethod mmethod = new CategoryMethod(cachedMethod, metaClass.getTheClass());
+                        final String name = cachedMethod.getName();
+                        CategoryMethodList list = get(name);
+                        if (list == null || list.level != level) {
+                            list = new CategoryMethodList(name, level, list);
+                            put(name, list);
+                        }
+                        list.add(mmethod);
+                        Collections.sort(list);
+                        cachePropertyAccessor(mmethod);
+                    }
+                }
+            }
+        }
+
+        private void cachePropertyAccessor(CategoryMethod method) {
+             String name = method.getName();
+             int parameterLength = method.getParameterTypes().length;
+
+             if (name.startsWith("get") && name.length() > 3 && parameterLength == 0) {
+                 propertyGetterMap = putPropertyAccessor(3, name, propertyGetterMap);
+             }
+             else if (name.startsWith("set") && name.length() > 3 && parameterLength == 1) {
+                 propertySetterMap = putPropertyAccessor(3, name, propertySetterMap);
+             }
+        }
+
+        // Precondition: accessorName.length() > prefixLength
+        private Map<String, String> putPropertyAccessor(int prefixLength, String accessorName, Map<String, String> map) {
+            if (map == null) {
+              map = new HashMap<String, String>();
+            }
+            String property = accessorName.substring(prefixLength, prefixLength+1).toLowerCase() + accessorName.substring(prefixLength+1);
+            map.put(property, accessorName);
+            return map;
+        }
+
+        private void use(Class categoryClass) {
+            CachedClass cachedClass = ReflectionCache.getCachedClass(categoryClass);
+            LinkedList<CachedClass> classStack = new LinkedList<CachedClass>();
+            for (CachedClass superClass = cachedClass; superClass.getTheClass()!=Object.class; superClass = superClass.getCachedSuperClass()) {
+                classStack.add(superClass);
+            }
+
+            while (!classStack.isEmpty()) {
+                CachedClass klazz = classStack.removeLast();
+                applyUse(klazz);
+            }
+        }
+
+        public CategoryMethodList getCategoryMethods(String name) {
+            return level == 0 ? null : get(name);
+        }
+
+
+        String getPropertyCategoryGetterName(String propertyName){
+            return propertyGetterMap != null ? propertyGetterMap.get(propertyName) : null;
+        }
+
+        String getPropertyCategorySetterName(String propertyName){
+            return propertySetterMap != null ? propertySetterMap.get(propertyName) : null;
+        }
+    }
+
+    private static final MyThreadLocal THREAD_INFO = new MyThreadLocal();
+
+    public static class CategoryMethod extends NewInstanceMetaMethod implements Comparable {
+        private final Class metaClass;
+
+        public CategoryMethod(CachedMethod metaMethod, Class metaClass) {
+            super(metaMethod);
+            this.metaClass = metaClass;
+        }
+
+        public boolean isCacheable() { return false; }
+
+        /**
+         * Sort by most specific to least specific.
+         *
+         * @param o the object to compare against
+         */
+        public int compareTo(Object o) {
+            CategoryMethod thatMethod = (CategoryMethod) o;
+            Class thisClass = metaClass;
+            Class thatClass = thatMethod.metaClass;
+            if (thisClass == thatClass) return 0;
+            if (isChildOfParent(thisClass, thatClass)) return -1;
+            if (isChildOfParent(thatClass, thisClass)) return 1;
+            return 0;
+        }
+
+        private boolean isChildOfParent(Class candidateChild, Class candidateParent) {
+            Class loop = candidateChild;
+            while(loop != null && loop != Object.class) {
+                loop = loop.getSuperclass();
+                if (loop == candidateParent) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    public static AtomicInteger getCategoryNameUsage (String name) {
+        return THREAD_INFO.getUsage (name);
+    }
+
+    /**
+     * Create a scope based on given categoryClass and invoke closure within that scope.
+     *
+     * @param categoryClass the class containing category methods
+     * @param closure the closure during which to make the category class methods available
+     * @return the value returned from the closure
+     */
+    public static <T> T use(Class categoryClass, Closure<T> closure) {
+        return THREAD_INFO.getInfo().use(categoryClass, closure);
+    }
+
+    /**
+     * Create a scope based on given categoryClasses and invoke closure within that scope.
+     *
+     * @param categoryClasses the list of classes containing category methods
+     * @param closure the closure during which to make the category class methods available
+     * @return the value returned from the closure
+     */
+    public static <T> T use(List<Class> categoryClasses, Closure<T> closure) {
+        return THREAD_INFO.getInfo().use(categoryClasses, closure);
+    }
+
+    public static boolean hasCategoryInCurrentThread() {
+        /*
+         * Synchronization is avoided here for performance reasons since
+         * this method is called frequently from callsite locations. For
+         * a typical case when no Categories are in use the initialized
+         * value of 0 will be correctly read. For cases where multiple
+         * Threads are using Categories it is possible that a stale
+         * non-zero value may be read but in that case the ThreadLocal
+         * check will produce the correct result. When the current Thread
+         * is using Categories, it would have incremented the counter
+         * so whatever version of the value it observes here should be
+         * non-zero and good enough for the purposes of this quick exit
+         * check.
+         */
+        if (categoriesInUse == 0) {
+            return false;
+        }
+        ThreadCategoryInfo infoNullable = THREAD_INFO.getInfoNullable();
+        return infoNullable != null && infoNullable.level != 0;
+    }
+
+    /**
+     * @deprecated use {@link #hasCategoryInCurrentThread()}
+     */
+    @Deprecated
+    public static boolean hasCategoryInAnyThread() {
+        synchronized (ThreadCategoryInfo.LOCK) {
+            return categoriesInUse != 0;
+        }
+    }
+
+    /**
+     * This method is used to pull all the new methods out of the local thread context with a particular name.
+     *
+     * @param name the method name of interest
+     * @return the list of methods
+     */
+    public static CategoryMethodList getCategoryMethods(String name) {
+        final ThreadCategoryInfo categoryInfo = THREAD_INFO.getInfoNullable();
+        return categoryInfo == null ? null : categoryInfo.getCategoryMethods(name);
+    }
+
+    public static String getPropertyCategoryGetterName(String propertyName) {
+         final ThreadCategoryInfo categoryInfo = THREAD_INFO.getInfoNullable();
+         return categoryInfo == null ? null : categoryInfo.getPropertyCategoryGetterName(propertyName);
+    }
+
+    public static String getPropertyCategorySetterName(String propertyName) {
+         final ThreadCategoryInfo categoryInfo = THREAD_INFO.getInfoNullable();
+         return categoryInfo == null ? null : categoryInfo.getPropertyCategorySetterName(propertyName);
+   }
+
+    private static class MyThreadLocal extends ThreadLocal<SoftReference> {
+
+        final ConcurrentHashMap<String,AtomicInteger> usage = new ConcurrentHashMap<String,AtomicInteger> ();
+
+        public ThreadCategoryInfo getInfo() {
+            final SoftReference reference = get();
+            ThreadCategoryInfo tcinfo;
+            if (reference != null) {
+                tcinfo = (ThreadCategoryInfo) reference.get();
+                if( tcinfo == null ) {
+                    tcinfo = new ThreadCategoryInfo();
+                    set(new SoftReference(tcinfo));
+                }
+            }
+            else {
+                tcinfo = new ThreadCategoryInfo();
+                set(new SoftReference(tcinfo));
+            }
+            return tcinfo;
+        }
+
+        public ThreadCategoryInfo getInfoNullable() {
+            final SoftReference reference = get();
+            return reference == null ? null : (ThreadCategoryInfo) reference.get();
+        }
+
+        public AtomicInteger getUsage (String name) {
+            AtomicInteger u = usage.get(name);
+            if (u != null) {
+                return u;
+            }
+
+            final AtomicInteger ai = new AtomicInteger();
+            final AtomicInteger prev = usage.putIfAbsent(name, ai);
+            return prev == null ? ai : prev;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java b/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java
new file mode 100644
index 0000000..a838c28
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/HandleMetaClass.java
@@ -0,0 +1,122 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.DelegatingMetaClass;
+import groovy.lang.ExpandoMetaClass;
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaBeanProperty;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaMethod;
+
+import java.lang.reflect.Method;
+
+public class HandleMetaClass extends DelegatingMetaClass {
+    private Object object;
+    private static final Object NONE = new Object();
+
+    public HandleMetaClass(MetaClass mc) {
+        this(mc, null);
+    }
+
+    public HandleMetaClass(MetaClass mc, Object obj) {
+        super(mc);
+        if (obj != null) {
+            if (InvokerHelper.getMetaClass(obj.getClass()) == mc || !(mc instanceof ExpandoMetaClass))
+              object = obj; // object has default meta class, so we need to replace it on demand
+            else
+              object = NONE; // object already has per instance meta class
+        }
+    }
+
+    public void initialize() {
+        replaceDelegate();
+        delegate.initialize();
+    }
+
+    public GroovyObject replaceDelegate() {
+        if (object == null) {
+            if (!(delegate instanceof ExpandoMetaClass)) {
+              delegate = new ExpandoMetaClass(delegate.getTheClass(), true, true);
+              delegate.initialize();
+            }
+            DefaultGroovyMethods.setMetaClass(delegate.getTheClass(), delegate);
+        }
+        else {
+          if (object != NONE) {
+              final MetaClass metaClass = delegate;
+              delegate = new ExpandoMetaClass(delegate.getTheClass(), false, true);
+              if (metaClass instanceof ExpandoMetaClass) {
+                  ExpandoMetaClass emc = (ExpandoMetaClass) metaClass;
+                  for (MetaMethod method : emc.getExpandoMethods())
+                    ((ExpandoMetaClass)delegate).registerInstanceMethod(method);
+              }
+              delegate.initialize();
+              MetaClassHelper.doSetMetaClass(object, delegate);
+              object = NONE;
+          }
+        }
+        return (GroovyObject)delegate;
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        return replaceDelegate().invokeMethod(name, args);
+    }
+
+    // this method mimics EMC behavior
+    public Object getProperty(String property) {
+        if(ExpandoMetaClass.isValidExpandoProperty(property)) {
+            if(property.equals(ExpandoMetaClass.STATIC_QUALIFIER) ||
+               property.equals(ExpandoMetaClass.CONSTRUCTOR) ||
+               Holder.META_CLASS.hasProperty(this, property) == null) {
+                  return replaceDelegate().getProperty(property);
+            }
+        }
+        return Holder.META_CLASS.getProperty(this, property);
+    }
+
+    public void setProperty(String property, Object newValue) {
+        replaceDelegate().setProperty(property, newValue);
+    }
+
+    public void addNewInstanceMethod(Method method) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addNewStaticMethod(Method method) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addMetaMethod(MetaMethod metaMethod) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void addMetaBeanProperty(MetaBeanProperty metaBeanProperty) {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean equals(Object obj) {
+        return super.equals(obj) || getAdaptee().equals(obj) || (obj instanceof HandleMetaClass && equals(((HandleMetaClass)obj).getAdaptee()));
+    }
+
+    // Lazily initialize the single instance of the HandleMetaClass metaClass
+    private static class Holder {
+        static final MetaClass META_CLASS = InvokerHelper.getMetaClass(HandleMetaClass.class);
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
new file mode 100644
index 0000000..b2beb96
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GeneralUtils.java
@@ -0,0 +1,805 @@
+/*
+ *  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.tools;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+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.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TernaryExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.runtime.GeneratedClosure;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.AbstractASTTransformation;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_IDENTICAL;
+
+/**
+ * Handy methods when working with the Groovy AST
+ */
+public class GeneralUtils {
+    public static final Token ASSIGN = Token.newSymbol(Types.ASSIGN, -1, -1);
+    public static final Token EQ = Token.newSymbol(Types.COMPARE_EQUAL, -1, -1);
+    public static final Token NE = Token.newSymbol(Types.COMPARE_NOT_EQUAL, -1, -1);
+    public static final Token NOT_IDENTICAL = Token.newSymbol(COMPARE_NOT_IDENTICAL, -1, -1);
+    public static final Token LT = Token.newSymbol(Types.COMPARE_LESS_THAN, -1, -1);
+    public static final Token AND = Token.newSymbol(Types.LOGICAL_AND, -1, -1);
+    public static final Token OR = Token.newSymbol(Types.LOGICAL_OR, -1, -1);
+    public static final Token CMP = Token.newSymbol(Types.COMPARE_TO, -1, -1);
+    private static final Token INSTANCEOF = Token.newSymbol(Types.KEYWORD_INSTANCEOF, -1, -1);
+    private static final Token PLUS = Token.newSymbol(Types.PLUS, -1, -1);
+    private static final Token INDEX = Token.newSymbol("[", -1, -1);
+
+    public static BinaryExpression andX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, AND, rhv);
+    }
+
+    public static ArgumentListExpression args(Expression... expressions) {
+        List<Expression> args = new ArrayList<Expression>();
+        Collections.addAll(args, expressions);
+        return new ArgumentListExpression(args);
+    }
+
+    public static ArgumentListExpression args(List<Expression> expressions) {
+        return new ArgumentListExpression(expressions);
+    }
+
+    public static ArgumentListExpression args(Parameter[] parameters) {
+        return new ArgumentListExpression(parameters);
+    }
+
+    public static ArgumentListExpression args(String... names) {
+        List<Expression> vars = new ArrayList<Expression>();
+        for (String name : names) {
+            vars.add(varX(name));
+        }
+        return new ArgumentListExpression(vars);
+    }
+
+    public static Statement assignS(Expression target, Expression value) {
+        return new ExpressionStatement(assignX(target, value));
+    }
+
+    public static Expression assignX(Expression target, Expression value) {
+        return new BinaryExpression(target, ASSIGN, value);
+    }
+
+    public static Expression attrX(Expression oe, Expression prop) {
+        return new AttributeExpression(oe, prop);
+    }
+
+    public static BinaryExpression binX(Expression left, Token token, Expression right) {
+        return new BinaryExpression(left, token, right);
+    }
+
+    public static BlockStatement block(VariableScope varScope, Statement... stmts) {
+        BlockStatement block = new BlockStatement();
+        block.setVariableScope(varScope);
+        for (Statement stmt : stmts) block.addStatement(stmt);
+        return block;
+    }
+
+    public static BlockStatement block(VariableScope varScope, List<Statement> stmts) {
+        BlockStatement block = new BlockStatement();
+        block.setVariableScope(varScope);
+        for (Statement stmt : stmts) block.addStatement(stmt);
+        return block;
+    }
+
+    public static BlockStatement block(Statement... stmts) {
+        BlockStatement block = new BlockStatement();
+        for (Statement stmt : stmts) block.addStatement(stmt);
+        return block;
+    }
+
+    public static MethodCallExpression callSuperX(String methodName, Expression args) {
+        return callX(varX("super"), methodName, args);
+    }
+
+    public static MethodCallExpression callSuperX(String methodName) {
+        return callSuperX(methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static MethodCallExpression callThisX(String methodName, Expression args) {
+        return callX(varX("this"), methodName, args);
+    }
+
+    public static MethodCallExpression callThisX(String methodName) {
+        return callThisX(methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static MethodCallExpression callX(Expression receiver, String methodName, Expression args) {
+        return new MethodCallExpression(receiver, methodName, args);
+    }
+
+    public static MethodCallExpression callX(Expression receiver, Expression method, Expression args) {
+        return new MethodCallExpression(receiver, method, args);
+    }
+
+    public static MethodCallExpression callX(Expression receiver, String methodName) {
+        return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static StaticMethodCallExpression callX(ClassNode receiver, String methodName, Expression args) {
+        return new StaticMethodCallExpression(receiver, methodName, args);
+    }
+
+    public static StaticMethodCallExpression callX(ClassNode receiver, String methodName) {
+        return callX(receiver, methodName, MethodCallExpression.NO_ARGUMENTS);
+    }
+
+    public static CastExpression castX(ClassNode type, Expression expression) {
+        return new CastExpression(type, expression);
+    }
+
+    public static CastExpression castX(ClassNode type, Expression expression, boolean ignoreAutoboxing) {
+        return new CastExpression(type, expression, ignoreAutoboxing);
+    }
+
+    public static ClassExpression classX(ClassNode clazz) {
+        return new ClassExpression(clazz);
+    }
+
+    public static ClassExpression classX(Class clazz) {
+        return classX(ClassHelper.make(clazz).getPlainNodeReference());
+    }
+
+    public static ClosureExpression closureX(Parameter[] params, Statement code) {
+        return new ClosureExpression(params, code);
+    }
+
+    public static ClosureExpression closureX(Statement code) {
+        return closureX(Parameter.EMPTY_ARRAY, code);
+    }
+
+    public static Parameter[] cloneParams(Parameter[] source) {
+        Parameter[] result = new Parameter[source.length];
+        for (int i = 0; i < source.length; i++) {
+            Parameter srcParam = source[i];
+            Parameter dstParam = new Parameter(srcParam.getOriginType(), srcParam.getName());
+            result[i] = dstParam;
+        }
+        return result;
+    }
+
+    /**
+     * Build a binary expression that compares two values
+     * @param lhv expression for the value to compare from
+     * @param rhv expression for the value value to compare to
+     * @return the expression comparing two values
+     */
+    public static BinaryExpression cmpX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, CMP, rhv);
+    }
+
+    public static ConstantExpression constX(Object val) {
+        return new ConstantExpression(val);
+    }
+
+    public static ConstantExpression constX(Object val, boolean keepPrimitive) {
+        return new ConstantExpression(val, keepPrimitive);
+    }
+
+    /**
+     * Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
+     * and {@link java.lang.annotation.RetentionPolicy#CLASS}.
+     * <p>
+     * Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported at present.
+     */
+    public static void copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, final List<AnnotationNode> copied, List<AnnotationNode> notCopied) {
+        List<AnnotationNode> annotationList = annotatedNode.getAnnotations();
+        for (AnnotationNode annotation : annotationList)  {
+
+            List<AnnotationNode> annotations = annotation.getClassNode().getAnnotations(AbstractASTTransformation.RETENTION_CLASSNODE);
+            if (annotations.isEmpty()) continue;
+
+            if (hasClosureMember(annotation)) {
+                notCopied.add(annotation);
+                continue;
+            }
+
+            AnnotationNode retentionPolicyAnnotation = annotations.get(0);
+            Expression valueExpression = retentionPolicyAnnotation.getMember("value");
+            if (!(valueExpression instanceof PropertyExpression)) continue;
+
+            PropertyExpression propertyExpression = (PropertyExpression) valueExpression;
+            boolean processAnnotation =
+                    propertyExpression.getProperty() instanceof ConstantExpression &&
+                            (
+                                    "RUNTIME".equals(((ConstantExpression) (propertyExpression.getProperty())).getValue()) ||
+                                            "CLASS".equals(((ConstantExpression) (propertyExpression.getProperty())).getValue())
+                            );
+
+            if (processAnnotation)  {
+                AnnotationNode newAnnotation = new AnnotationNode(annotation.getClassNode());
+                for (Map.Entry<String, Expression> member : annotation.getMembers().entrySet())  {
+                    newAnnotation.addMember(member.getKey(), member.getValue());
+                }
+                newAnnotation.setSourcePosition(annotatedNode);
+
+                copied.add(newAnnotation);
+            }
+        }
+    }
+
+    public static Statement createConstructorStatementDefault(FieldNode fNode) {
+        final String name = fNode.getName();
+        final ClassNode fType = fNode.getType();
+        final Expression fieldExpr = propX(varX("this"), name);
+        Expression initExpr = fNode.getInitialValueExpression();
+        Statement assignInit;
+        if (initExpr == null || (initExpr instanceof ConstantExpression && ((ConstantExpression)initExpr).isNullExpression())) {
+            if (ClassHelper.isPrimitiveType(fType)) {
+                assignInit = EmptyStatement.INSTANCE;
+            } else {
+                assignInit = assignS(fieldExpr, ConstantExpression.EMPTY_EXPRESSION);
+            }
+        } else {
+            assignInit = assignS(fieldExpr, initExpr);
+        }
+        fNode.setInitialValueExpression(null);
+        Expression value = findArg(name);
+        return ifElseS(equalsNullX(value), assignInit, assignS(fieldExpr, castX(fType, value)));
+    }
+
+    public static ConstructorCallExpression ctorX(ClassNode type, Expression args) {
+        return new ConstructorCallExpression(type, args);
+    }
+
+    public static ConstructorCallExpression ctorX(ClassNode type) {
+        return new ConstructorCallExpression(type, ArgumentListExpression.EMPTY_ARGUMENTS);
+    }
+
+    public static Statement ctorSuperS(Expression args) {
+        return stmt(ctorX(ClassNode.SUPER, args));
+    }
+
+    public static Statement ctorThisS(Expression args) {
+        return stmt(ctorX(ClassNode.THIS, args));
+    }
+
+    public static Statement ctorSuperS() {
+        return stmt(ctorX(ClassNode.SUPER));
+    }
+
+    public static Statement ctorThisS() {
+        return stmt(ctorX(ClassNode.THIS));
+    }
+
+    public static Statement declS(Expression target, Expression init) {
+        return new ExpressionStatement(new DeclarationExpression(target, ASSIGN, init));
+    }
+
+    public static BinaryExpression eqX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, EQ, rhv);
+    }
+
+    public static BooleanExpression equalsNullX(Expression argExpr) {
+        return new BooleanExpression(eqX(argExpr, new ConstantExpression(null)));
+    }
+
+    public static FieldExpression fieldX(FieldNode fieldNode) {
+        return new FieldExpression(fieldNode);
+    }
+
+    public static FieldExpression fieldX(ClassNode owner, String fieldName) {
+        return new FieldExpression(owner.getField(fieldName));
+    }
+
+    public static Expression findArg(String argName) {
+        return new PropertyExpression(new VariableExpression("args"), argName);
+    }
+
+    public static List<MethodNode> getAllMethods(ClassNode type) {
+        ClassNode node = type;
+        List<MethodNode> result = new ArrayList<MethodNode>();
+        while (node != null) {
+            result.addAll(node.getMethods());
+            node = node.getSuperClass();
+        }
+        return result;
+    }
+
+    public static List<PropertyNode> getAllProperties(ClassNode type) {
+        ClassNode node = type;
+        List<PropertyNode> result = new ArrayList<PropertyNode>();
+        while (node != null) {
+            result.addAll(node.getProperties());
+            node = node.getSuperClass();
+        }
+        return result;
+    }
+
+    public static String getGetterName(PropertyNode pNode) {
+        return "get" + Verifier.capitalize(pNode.getName());
+    }
+
+    public static List<FieldNode> getInstanceNonPropertyFields(ClassNode cNode) {
+        final List<FieldNode> result = new ArrayList<FieldNode>();
+        for (FieldNode fNode : cNode.getFields()) {
+            if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
+                result.add(fNode);
+            }
+        }
+        return result;
+    }
+
+    public static List<String> getInstanceNonPropertyFieldNames(ClassNode cNode) {
+        List<FieldNode> fList = getInstanceNonPropertyFields(cNode);
+        List<String> result = new ArrayList<String>(fList.size());
+        for (FieldNode fNode : fList) {
+            result.add(fNode.getName());
+        }
+        return result;
+    }
+
+    public static List<PropertyNode> getInstanceProperties(ClassNode cNode) {
+        final List<PropertyNode> result = new ArrayList<PropertyNode>();
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (!pNode.isStatic()) {
+                result.add(pNode);
+            }
+        }
+        return result;
+    }
+
+    public static List<String> getInstancePropertyNames(ClassNode cNode) {
+        List<PropertyNode> pList = BeanUtils.getAllProperties(cNode, false, false, true);
+        List<String> result = new ArrayList<String>(pList.size());
+        for (PropertyNode pNode : pList) {
+            result.add(pNode.getName());
+        }
+        return result;
+    }
+
+    public static List<FieldNode> getInstancePropertyFields(ClassNode cNode) {
+        final List<FieldNode> result = new ArrayList<FieldNode>();
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (!pNode.isStatic()) {
+                result.add(pNode.getField());
+            }
+        }
+        return result;
+    }
+
+    public static Set<ClassNode> getInterfacesAndSuperInterfaces(ClassNode type) {
+        Set<ClassNode> res = new LinkedHashSet<ClassNode>();
+        if (type.isInterface()) {
+            res.add(type);
+            return res;
+        }
+        ClassNode next = type;
+        while (next != null) {
+            res.addAll(next.getAllInterfaces());
+            next = next.getSuperClass();
+        }
+        return res;
+    }
+
+    public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) {
+        final List<FieldNode> result;
+        if (cNode == ClassHelper.OBJECT_TYPE) {
+            result = new ArrayList<FieldNode>();
+        } else {
+            result = getSuperNonPropertyFields(cNode.getSuperClass());
+        }
+        for (FieldNode fNode : cNode.getFields()) {
+            if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
+                result.add(fNode);
+            }
+        }
+        return result;
+    }
+
+    public static List<FieldNode> getSuperPropertyFields(ClassNode cNode) {
+        final List<FieldNode> result;
+        if (cNode == ClassHelper.OBJECT_TYPE) {
+            result = new ArrayList<FieldNode>();
+        } else {
+            result = getSuperPropertyFields(cNode.getSuperClass());
+        }
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (!pNode.isStatic()) {
+                result.add(pNode.getField());
+            }
+        }
+        return result;
+    }
+
+    public static BinaryExpression hasClassX(Expression instance, ClassNode cNode) {
+        return eqX(classX(cNode), callX(instance, "getClass"));
+    }
+
+    private static boolean hasClosureMember(AnnotationNode annotation) {
+
+        Map<String, Expression> members = annotation.getMembers();
+        for (Map.Entry<String, Expression> member : members.entrySet())  {
+            if (member.getValue() instanceof ClosureExpression) return true;
+
+            if (member.getValue() instanceof ClassExpression)  {
+                ClassExpression classExpression = (ClassExpression) member.getValue();
+                Class<?> typeClass = classExpression.getType().isResolved() ? classExpression.getType().redirect().getTypeClass() : null;
+                if (typeClass != null && GeneratedClosure.class.isAssignableFrom(typeClass)) return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static boolean hasDeclaredMethod(ClassNode cNode, String name, int argsCount) {
+        List<MethodNode> ms = cNode.getDeclaredMethods(name);
+        for (MethodNode m : ms) {
+            Parameter[] paras = m.getParameters();
+            if (paras != null && paras.length == argsCount) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static BinaryExpression hasEqualFieldX(FieldNode fNode, Expression other) {
+        return eqX(varX(fNode), propX(other, fNode.getName()));
+    }
+
+    public static BinaryExpression hasEqualPropertyX(ClassNode annotatedNode, PropertyNode pNode, VariableExpression other) {
+        return eqX(getterThisX(annotatedNode, pNode), getterX(other.getOriginType(), other, pNode));
+    }
+
+    @Deprecated
+    public static BinaryExpression hasEqualPropertyX(PropertyNode pNode, Expression other) {
+        String getterName = getGetterName(pNode);
+        return eqX(callThisX(getterName), callX(other, getterName));
+    }
+
+    public static BooleanExpression hasSameFieldX(FieldNode fNode, Expression other) {
+        return sameX(varX(fNode), propX(other, fNode.getName()));
+    }
+
+    public static BooleanExpression hasSamePropertyX(PropertyNode pNode, Expression other) {
+        ClassNode cNode = pNode.getDeclaringClass();
+        return sameX(getterThisX(cNode, pNode), getterX(cNode, other, pNode));
+    }
+
+    public static Statement ifElseS(Expression cond, Statement thenStmt, Statement elseStmt) {
+        return new IfStatement(
+                cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond),
+                thenStmt,
+                elseStmt
+        );
+    }
+
+    public static Statement ifS(Expression cond, Expression trueExpr) {
+        return ifS(cond, new ExpressionStatement(trueExpr));
+    }
+
+    public static Statement ifS(Expression cond, Statement trueStmt) {
+        return new IfStatement(
+                cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond),
+                trueStmt,
+                EmptyStatement.INSTANCE
+        );
+    }
+
+    public static Expression indexX(Expression target, Expression value) {
+        return new BinaryExpression(target, INDEX, value);
+    }
+
+    public static BooleanExpression isInstanceOfX(Expression objectExpression, ClassNode cNode) {
+        return new BooleanExpression(new BinaryExpression(objectExpression, INSTANCEOF, classX(cNode)));
+    }
+
+    public static BooleanExpression isOneX(Expression expr) {
+        return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(1)));
+    }
+
+    public static boolean isOrImplements(ClassNode type, ClassNode interfaceType) {
+        return type.equals(interfaceType) || type.implementsInterface(interfaceType);
+    }
+
+    public static BooleanExpression isTrueX(Expression argExpr) {
+        return new BooleanExpression(new BinaryExpression(argExpr, EQ, new ConstantExpression(Boolean.TRUE)));
+    }
+
+    public static BooleanExpression isZeroX(Expression expr) {
+        return new BooleanExpression(new BinaryExpression(expr, EQ, new ConstantExpression(0)));
+    }
+
+    public static BinaryExpression ltX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, LT, rhv);
+    }
+
+    public static BinaryExpression notIdenticalX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, NOT_IDENTICAL, rhv);
+    }
+
+    /**
+     * @deprecated use MethodNodeUtils#methodDescriptorWithoutReturnType(MethodNode) instead
+     */
+    @Deprecated
+    public static String makeDescriptorWithoutReturnType(MethodNode mn) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(mn.getName()).append(':');
+        for (Parameter p : mn.getParameters()) {
+            sb.append(p.getType()).append(',');
+        }
+        return sb.toString();
+    }
+
+    public static BinaryExpression neX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, NE, rhv);
+    }
+
+    public static BooleanExpression notNullX(Expression argExpr) {
+        return new BooleanExpression(new BinaryExpression(argExpr, NE, new ConstantExpression(null)));
+    }
+
+    public static NotExpression notX(Expression expr) {
+        return new NotExpression(expr instanceof BooleanExpression ? expr : new BooleanExpression(expr));
+    }
+
+    public static BinaryExpression orX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, OR, rhv);
+    }
+
+    public static Parameter param(ClassNode type, String name) {
+        return param(type, name, null);
+    }
+
+    public static Parameter param(ClassNode type, String name, Expression initialExpression) {
+        Parameter param = new Parameter(type, name);
+        if (initialExpression != null) {
+            param.setInitialExpression(initialExpression);
+        }
+        return param;
+    }
+
+    public static Parameter[] params(Parameter... params) {
+        return params != null ? params : Parameter.EMPTY_ARRAY;
+    }
+
+    public static BinaryExpression plusX(Expression lhv, Expression rhv) {
+        return new BinaryExpression(lhv, PLUS, rhv);
+    }
+
+    public static Expression propX(Expression owner, String property) {
+        return new PropertyExpression(owner, property);
+    }
+
+    public static Expression propX(Expression owner, Expression property) {
+        return new PropertyExpression(owner, property);
+    }
+
+    public static Statement returnS(Expression expr) {
+        return new ReturnStatement(new ExpressionStatement(expr));
+    }
+
+    public static Statement safeExpression(Expression fieldExpr, Expression expression) {
+        return new IfStatement(
+                equalsNullX(fieldExpr),
+                new ExpressionStatement(fieldExpr),
+                new ExpressionStatement(expression));
+    }
+
+    public static BooleanExpression sameX(Expression self, Expression other) {
+        return new BooleanExpression(callX(self, "is", args(other)));
+    }
+
+    public static Statement stmt(Expression expr) {
+        return new ExpressionStatement(expr);
+    }
+
+    public static TernaryExpression ternaryX(Expression cond, Expression trueExpr, Expression elseExpr) {
+        return new TernaryExpression(
+                cond instanceof BooleanExpression ? (BooleanExpression) cond : new BooleanExpression(cond),
+                trueExpr,
+                elseExpr);
+    }
+
+    public static VariableExpression varX(String name) {
+        return new VariableExpression(name);
+    }
+
+    public static VariableExpression varX(Variable variable) {
+        return new VariableExpression(variable);
+    }
+
+    public static VariableExpression varX(String name, ClassNode type) {
+        return new VariableExpression(name, type);
+    }
+
+    public static ThrowStatement throwS(Expression expr) {
+        return new ThrowStatement(expr);
+    }
+
+    public static CatchStatement catchS(Parameter variable, Statement code) {
+        return new CatchStatement(variable, code);
+    }
+
+    /**
+     * This method is similar to {@link #propX(Expression, Expression)} but will make sure that if the property
+     * being accessed is defined inside the classnode provided as a parameter, then a getter call is generated
+     * instead of a field access.
+     * @param annotatedNode the class node where the property node is accessed from
+     * @param pNode the property being accessed
+     * @return a method call expression or a property expression
+     */
+    public static Expression getterThisX(ClassNode annotatedNode, PropertyNode pNode) {
+        ClassNode owner = pNode.getDeclaringClass();
+        if (annotatedNode.equals(owner)) {
+            return callThisX(getterName(annotatedNode, pNode));
+        }
+        return propX(new VariableExpression("this"), pNode.getName());
+    }
+
+    private static String getterName(ClassNode annotatedNode, PropertyNode pNode) {
+        String getterName = "get" + MetaClassHelper.capitalize(pNode.getName());
+        boolean existingExplicitGetter = annotatedNode.getMethod(getterName, Parameter.EMPTY_ARRAY) != null;
+        if (ClassHelper.boolean_TYPE.equals(pNode.getOriginType()) && !existingExplicitGetter) {
+            getterName = "is" + MetaClassHelper.capitalize(pNode.getName());
+        }
+        return getterName;
+    }
+
+    /**
+     * This method is similar to {@link #propX(Expression, Expression)} but will make sure that if the property
+     * being accessed is defined inside the classnode provided as a parameter, then a getter call is generated
+     * instead of a field access.
+     * @param annotatedNode the class node where the property node is accessed from
+     * @param receiver the object having the property
+     * @param pNode the property being accessed
+     * @return a method call expression or a property expression
+     */
+    public static Expression getterX(ClassNode annotatedNode, Expression receiver, PropertyNode pNode) {
+        ClassNode owner = pNode.getDeclaringClass();
+        if (annotatedNode.equals(owner)) {
+            return callX(receiver, getterName(annotatedNode, pNode));
+        }
+        return propX(receiver, pNode.getName());
+    }
+
+    /**
+     * Converts an expression into the String source. Only some specific expressions like closure expression
+     * support this.
+     *
+     * @param readerSource a source
+     * @param expression an expression. Can't be null
+     * @return the source the closure was created from
+     * @throws java.lang.IllegalArgumentException when expression is null
+     * @throws java.lang.Exception when closure can't be read from source
+     */
+    public static String convertASTToSource(ReaderSource readerSource, ASTNode expression) throws Exception {
+        if (expression == null) throw new IllegalArgumentException("Null: expression");
+
+        StringBuilder result = new StringBuilder();
+        for (int x = expression.getLineNumber(); x <= expression.getLastLineNumber(); x++) {
+            String line = readerSource.getLine(x, null);
+            if (line == null) {
+                throw new Exception(
+                        "Error calculating source code for expression. Trying to read line " + x + " from " + readerSource.getClass()
+                );
+            }
+            if (x == expression.getLastLineNumber()) {
+                line = line.substring(0, expression.getLastColumnNumber() - 1);
+            }
+            if (x == expression.getLineNumber()) {
+                line = line.substring(expression.getColumnNumber() - 1);
+            }
+            //restoring line breaks is important b/c of lack of semicolons
+            result.append(line).append('\n');
+        }
+
+
+        String source = result.toString().trim();
+
+        return source;
+    }
+
+    public static boolean copyStatementsWithSuperAdjustment(ClosureExpression pre, BlockStatement body) {
+        Statement preCode = pre.getCode();
+        boolean changed = false;
+        if (preCode instanceof BlockStatement) {
+            BlockStatement block = (BlockStatement) preCode;
+            List<Statement> statements = block.getStatements();
+            for (int i = 0; i < statements.size(); i++) {
+                Statement statement = statements.get(i);
+                // adjust the first statement if it's a super call
+                if (i == 0 && statement instanceof ExpressionStatement) {
+                    ExpressionStatement es = (ExpressionStatement) statement;
+                    Expression preExp = es.getExpression();
+                    if (preExp instanceof MethodCallExpression) {
+                        MethodCallExpression mce = (MethodCallExpression) preExp;
+                        String name = mce.getMethodAsString();
+                        if ("super".equals(name)) {
+                            es.setExpression(new ConstructorCallExpression(ClassNode.SUPER, mce.getArguments()));
+                            changed = true;
+                        }
+                    }
+                }
+                body.addStatement(statement);
+            }
+        }
+        return changed;
+    }
+
+    public static String getSetterName(String name) {
+        return "set" + Verifier.capitalize(name);
+    }
+
+    public static boolean isDefaultVisibility(int modifiers) {
+        return (modifiers & (Modifier.PRIVATE | Modifier.PUBLIC | Modifier.PROTECTED)) == 0;
+    }
+
+    public static boolean inSamePackage(ClassNode first, ClassNode second) {
+        PackageNode firstPackage = first.getPackage();
+        PackageNode secondPackage = second.getPackage();
+        return ((firstPackage == null && secondPackage == null) ||
+                        firstPackage != null && secondPackage != null && firstPackage.getName().equals(secondPackage.getName()));
+    }
+
+    public static boolean inSamePackage(Class first, Class second) {
+        Package firstPackage = first.getPackage();
+        Package secondPackage = second.getPackage();
+        return ((firstPackage == null && secondPackage == null) ||
+                        firstPackage != null && secondPackage != null && firstPackage.getName().equals(secondPackage.getName()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
new file mode 100644
index 0000000..653f327
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -0,0 +1,614 @@
+/*
+ *  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.tools;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import groovy.transform.stc.IncorrectTypeHintException;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.antlr.AntlrParserPlugin;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.ResolveVisitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.ParserException;
+import org.codehaus.groovy.syntax.Reduction;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Utility methods to deal with generic types.
+ *
+ * @author Cedric Champeau
+ * @author Paul King
+ */
+public class GenericsUtils {
+    public static final GenericsType[] EMPTY_GENERICS_ARRAY = new GenericsType[0];
+
+    /**
+     * Given a parameterized type and a generic type information, aligns actual type parameters. For example, if a
+     * class uses generic type <pre>&lt;T,U,V&gt;</pre> (redirectGenericTypes), is used with actual type parameters
+     * <pre>&lt;java.lang.String, U,V&gt;</pre>, then a class or interface using generic types <pre>&lt;T,V&gt;</pre>
+     * will be aligned to <pre>&lt;java.lang.String,V&gt;</pre>
+     * @param redirectGenericTypes the type arguments or the redirect class node
+     * @param parameterizedTypes the actual type arguments used on this class node
+     * @param alignmentTarget the generic type arguments to which we want to align to
+     * @return aligned type arguments
+     * @deprecated You shouldn't call this method because it is inherently unreliable
+     */
+    @Deprecated
+    public static GenericsType[] alignGenericTypes(final GenericsType[] redirectGenericTypes, final GenericsType[] parameterizedTypes, final GenericsType[] alignmentTarget) {
+        if (alignmentTarget==null) return EMPTY_GENERICS_ARRAY;
+        if (parameterizedTypes==null || parameterizedTypes.length==0) return alignmentTarget;
+        GenericsType[] generics = new GenericsType[alignmentTarget.length];
+        for (int i = 0, scgtLength = alignmentTarget.length; i < scgtLength; i++) {
+            final GenericsType currentTarget = alignmentTarget[i];
+            GenericsType match = null;
+            if (redirectGenericTypes!=null) {
+                for (int j = 0; j < redirectGenericTypes.length && match == null; j++) {
+                    GenericsType redirectGenericType = redirectGenericTypes[j];
+                    if (redirectGenericType.isCompatibleWith(currentTarget.getType())) {
+                        if (currentTarget.isPlaceholder() && redirectGenericType.isPlaceholder() && !currentTarget.getName().equals(redirectGenericType.getName())) {
+                            // check if there's a potential better match
+                            boolean skip = false;
+                            for (int k=j+1; k<redirectGenericTypes.length && !skip; k++) {
+                                GenericsType ogt = redirectGenericTypes[k];
+                                if (ogt.isPlaceholder() && ogt.isCompatibleWith(currentTarget.getType()) && ogt.getName().equals(currentTarget.getName())) {
+                                    skip = true;
+                                }
+                            }
+                            if (skip) continue;
+                        }
+                        match = parameterizedTypes[j];
+                        if (currentTarget.isWildcard()) {
+                            // if alignment target is a wildcard type
+                            // then we must make best effort to return a parameterized
+                            // wildcard
+                            ClassNode lower = currentTarget.getLowerBound()!=null?match.getType():null;
+                            ClassNode[] currentUpper = currentTarget.getUpperBounds();
+                            ClassNode[] upper = currentUpper !=null?new ClassNode[currentUpper.length]:null;
+                            if (upper!=null) {
+                                for (int k = 0; k < upper.length; k++) {
+                                    upper[k] = currentUpper[k].isGenericsPlaceHolder()?match.getType():currentUpper[k];
+                                }
+                            }
+                            match = new GenericsType(ClassHelper.makeWithoutCaching("?"), upper, lower);
+                            match.setWildcard(true);
+                        }
+                    }
+                }
+            }
+            if (match == null) {
+                match = currentTarget;
+            }
+            generics[i]=match;
+        }
+        return generics;
+    }
+
+    /**
+     * Generates a wildcard generic type in order to be used for checks against class nodes.
+     * See {@link GenericsType#isCompatibleWith(org.codehaus.groovy.ast.ClassNode)}.
+     * @param types the type to be used as the wildcard upper bound
+     * @return a wildcard generics type
+     */
+    public static GenericsType buildWildcardType(final ClassNode... types) {
+        ClassNode base = ClassHelper.makeWithoutCaching("?");
+        GenericsType gt = new GenericsType(base, types, null);
+        gt.setWildcard(true);
+        return gt;
+    }
+
+    public static Map<String, GenericsType> extractPlaceholders(ClassNode cn) {
+        Map<String, GenericsType> ret = new HashMap<String, GenericsType>();
+        extractPlaceholders(cn, ret);
+        return ret;
+    }
+
+    /**
+     * For a given classnode, fills in the supplied map with the parameterized
+     * types it defines.
+     * @param node
+     * @param map
+     */
+    public static void extractPlaceholders(ClassNode node, Map<String, GenericsType> map) {
+        if (node == null) return;
+
+        if (node.isArray()) {
+            extractPlaceholders(node.getComponentType(), map);
+            return;
+        }
+
+        if (!node.isUsingGenerics() || !node.isRedirectNode()) return;
+        GenericsType[] parameterized = node.getGenericsTypes();
+        if (parameterized == null || parameterized.length == 0) return;
+        GenericsType[] redirectGenericsTypes = node.redirect().getGenericsTypes();
+        if (redirectGenericsTypes==null) redirectGenericsTypes = parameterized;
+        for (int i = 0; i < redirectGenericsTypes.length; i++) {
+            GenericsType redirectType = redirectGenericsTypes[i];
+            if (redirectType.isPlaceholder()) {
+                String name = redirectType.getName();
+                if (!map.containsKey(name)) {
+                    GenericsType value = parameterized[i];
+                    map.put(name, value);
+                    if (value.isWildcard()) {
+                        ClassNode lowerBound = value.getLowerBound();
+                        if (lowerBound!=null) {
+                            extractPlaceholders(lowerBound, map);
+                        }
+                        ClassNode[] upperBounds = value.getUpperBounds();
+                        if (upperBounds!=null) {
+                            for (ClassNode upperBound : upperBounds) {
+                                extractPlaceholders(upperBound, map);
+                            }
+                        }
+                    } else if (!value.isPlaceholder()) {
+                        extractPlaceholders(value.getType(), map);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Interface class nodes retrieved from {@link org.codehaus.groovy.ast.ClassNode#getInterfaces()}
+     * or {@link org.codehaus.groovy.ast.ClassNode#getAllInterfaces()} are returned with generic type
+     * arguments. This method allows returning a parameterized interface given the parameterized class
+     * node which implements this interface.
+     * @param hint the class node where generics types are parameterized
+     * @param target the interface we want to parameterize generics types
+     * @return a parameterized interface class node
+     * @deprecated Use #parameterizeType instead
+     */
+    @Deprecated
+    public static ClassNode parameterizeInterfaceGenerics(final ClassNode hint, final ClassNode target) {
+        return parameterizeType(hint, target);
+    }
+
+    /**
+     * Interface class nodes retrieved from {@link org.codehaus.groovy.ast.ClassNode#getInterfaces()}
+     * or {@link org.codehaus.groovy.ast.ClassNode#getAllInterfaces()} are returned with generic type
+     * arguments. This method allows returning a parameterized interface given the parameterized class
+     * node which implements this interface.
+     * @param hint the class node where generics types are parameterized
+     * @param target the interface we want to parameterize generics types
+     * @return a parameterized interface class node
+     */
+    public static ClassNode parameterizeType(final ClassNode hint, final ClassNode target) {
+        if (hint.isArray()) {
+            if (target.isArray()) {
+                return parameterizeType(hint.getComponentType(), target.getComponentType()).makeArray();
+            }
+            return target;
+        }
+        if (!target.equals(hint) && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(target, hint)) {
+            ClassNode nextSuperClass = ClassHelper.getNextSuperClass(target, hint);
+            if (!hint.equals(nextSuperClass)) {
+                Map<String, ClassNode> genericsSpec = createGenericsSpec(hint);
+                extractSuperClassGenerics(hint, nextSuperClass, genericsSpec);
+                ClassNode result = correctToGenericsSpecRecurse(genericsSpec, nextSuperClass);
+                return parameterizeType(result, target);
+            }
+        }
+        Map<String, ClassNode> genericsSpec = createGenericsSpec(hint);
+        ClassNode targetRedirect = target.redirect();
+        genericsSpec = createGenericsSpec(targetRedirect, genericsSpec);
+        extractSuperClassGenerics(hint, targetRedirect, genericsSpec);
+        return correctToGenericsSpecRecurse(genericsSpec, targetRedirect);
+
+    }
+
+    public static ClassNode nonGeneric(ClassNode type) {
+        if (type.isUsingGenerics()) {
+            final ClassNode nonGen = ClassHelper.makeWithoutCaching(type.getName());
+            nonGen.setRedirect(type);
+            nonGen.setGenericsTypes(null);
+            nonGen.setUsingGenerics(false);
+            return nonGen;
+        }
+        if (type.isArray() && type.getComponentType().isUsingGenerics()) {
+            return type.getComponentType().getPlainNodeReference().makeArray();
+        }
+        return type;
+    }
+
+    public static ClassNode newClass(ClassNode type) {
+        return type.getPlainNodeReference();
+    }
+
+    public static ClassNode makeClassSafe(Class klass) {
+        return makeClassSafeWithGenerics(ClassHelper.make(klass));
+    }
+
+    public static ClassNode makeClassSafeWithGenerics(Class klass, ClassNode genericsType) {
+        GenericsType[] genericsTypes = new GenericsType[1];
+        genericsTypes[0] = new GenericsType(genericsType);
+        return makeClassSafeWithGenerics(ClassHelper.make(klass), genericsTypes);
+    }
+
+    public static ClassNode makeClassSafe0(ClassNode type, GenericsType... genericTypes) {
+        ClassNode plainNodeReference = newClass(type);
+        if (genericTypes != null && genericTypes.length > 0) {
+            plainNodeReference.setGenericsTypes(genericTypes);
+            if (type.isGenericsPlaceHolder()) plainNodeReference.setGenericsPlaceHolder(true);
+        }
+        return plainNodeReference;
+    }
+
+    public static ClassNode makeClassSafeWithGenerics(ClassNode type, GenericsType... genericTypes) {
+        if (type.isArray()) {
+            return makeClassSafeWithGenerics(type.getComponentType(), genericTypes).makeArray();
+        }
+        GenericsType[] gtypes = new GenericsType[0];
+        if (genericTypes != null) {
+            gtypes = new GenericsType[genericTypes.length];
+            System.arraycopy(genericTypes, 0, gtypes, 0, gtypes.length);
+        }
+        return makeClassSafe0(type, gtypes);
+    }
+
+    public static MethodNode correctToGenericsSpec(Map<String,ClassNode> genericsSpec, MethodNode mn) {
+        ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, mn.getReturnType());
+        Parameter[] origParameters = mn.getParameters();
+        Parameter[] newParameters = new Parameter[origParameters.length];
+        for (int i = 0; i < origParameters.length; i++) {
+            Parameter origParameter = origParameters[i];
+            newParameters[i] = new Parameter(correctToGenericsSpecRecurse(genericsSpec, origParameter.getType()), origParameter.getName(), origParameter.getInitialExpression());
+        }
+        return new MethodNode(mn.getName(), mn.getModifiers(), correctedType, newParameters, mn.getExceptions(), mn.getCode());
+    }
+
+    public static ClassNode correctToGenericsSpecRecurse(Map<String,ClassNode> genericsSpec, ClassNode type) {
+        return correctToGenericsSpecRecurse(genericsSpec, type, new ArrayList<String>());
+    }
+
+    /**
+     * @since 2.4.1
+     */
+    public static ClassNode[] correctToGenericsSpecRecurse(Map<String,ClassNode> genericsSpec, ClassNode[] types) {
+        if (types==null || types.length==1) return types;
+        ClassNode[] newTypes = new ClassNode[types.length];
+        boolean modified = false;
+        for (int i=0; i<types.length; i++) {
+            newTypes[i] = correctToGenericsSpecRecurse(genericsSpec, types[i], new ArrayList<String>());
+            modified = modified || (types[i]!=newTypes[i]);
+        }
+        if (!modified) return types;
+        return newTypes;
+    }
+
+    public static ClassNode correctToGenericsSpecRecurse(Map<String,ClassNode> genericsSpec, ClassNode type, List<String> exclusions) {
+        if (type.isArray()) {
+            return correctToGenericsSpecRecurse(genericsSpec, type.getComponentType(), exclusions).makeArray();
+        }
+        if (type.isGenericsPlaceHolder() && !exclusions.contains(type.getUnresolvedName())) {
+            String name = type.getGenericsTypes()[0].getName();
+            type = genericsSpec.get(name);
+            if (type != null && type.isGenericsPlaceHolder() && type.getGenericsTypes() == null) {
+                ClassNode placeholder = ClassHelper.makeWithoutCaching(type.getUnresolvedName());
+                placeholder.setGenericsPlaceHolder(true);
+                type = makeClassSafeWithGenerics(type, new GenericsType(placeholder));
+            }
+        }
+        if (type == null) type = ClassHelper.OBJECT_TYPE;
+        GenericsType[] oldgTypes = type.getGenericsTypes();
+        GenericsType[] newgTypes = GenericsType.EMPTY_ARRAY;
+        if (oldgTypes != null) {
+            newgTypes = new GenericsType[oldgTypes.length];
+            for (int i = 0; i < newgTypes.length; i++) {
+                GenericsType oldgType = oldgTypes[i];
+                if (oldgType.isPlaceholder() ) {
+                    if (genericsSpec.get(oldgType.getName())!=null) {
+                        newgTypes[i] = new GenericsType(genericsSpec.get(oldgType.getName()));
+                    } else {
+                        newgTypes[i] = new GenericsType(ClassHelper.OBJECT_TYPE);
+                    }
+                } else if (oldgType.isWildcard()) {
+                    ClassNode oldLower = oldgType.getLowerBound();
+                    ClassNode lower = oldLower!=null?correctToGenericsSpecRecurse(genericsSpec, oldLower, exclusions):null;
+                    ClassNode[] oldUpper = oldgType.getUpperBounds();
+                    ClassNode[] upper = null;
+                    if (oldUpper!=null) {
+                        upper = new ClassNode[oldUpper.length];
+                        for (int j = 0; j < oldUpper.length; j++) {
+                            upper[j] = correctToGenericsSpecRecurse(genericsSpec,oldUpper[j], exclusions);
+                        }
+                    }
+                    GenericsType fixed = new GenericsType(oldgType.getType(), upper, lower);
+                    fixed.setName(oldgType.getName());
+                    fixed.setWildcard(true);
+                    newgTypes[i] = fixed;
+                } else {
+                    newgTypes[i] = new GenericsType(correctToGenericsSpecRecurse(genericsSpec,correctToGenericsSpec(genericsSpec, oldgType), exclusions));
+                }
+            }
+        }
+        return makeClassSafeWithGenerics(type, newgTypes);
+    }
+
+    public static ClassNode correctToGenericsSpec(Map<String, ClassNode> genericsSpec, GenericsType type) {
+        ClassNode ret = null;
+        if (type.isPlaceholder()) {
+            String name = type.getName();
+            ret = genericsSpec.get(name);
+        }
+        if (ret == null) ret = type.getType();
+        return ret;
+    }
+
+    public static ClassNode correctToGenericsSpec(Map<String,ClassNode> genericsSpec, ClassNode type) {
+        if (type.isArray()) {
+            return correctToGenericsSpec(genericsSpec, type.getComponentType()).makeArray();
+        }
+        if (type.isGenericsPlaceHolder()) {
+            String name = type.getGenericsTypes()[0].getName();
+            type = genericsSpec.get(name);
+        }
+        if (type == null) type = ClassHelper.OBJECT_TYPE;
+        return type;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Map<String,ClassNode> createGenericsSpec(ClassNode current) {
+        return createGenericsSpec(current, Collections.EMPTY_MAP);
+    }
+
+    public static Map<String,ClassNode> createGenericsSpec(ClassNode current, Map<String,ClassNode> oldSpec) {
+        Map<String,ClassNode> ret = new HashMap<String,ClassNode>(oldSpec);
+        // ret contains the type specs, what we now need is the type spec for the
+        // current class. To get that we first apply the type parameters to the
+        // current class and then use the type names of the current class to reset
+        // the map. Example:
+        //   class A<V,W,X>{}
+        //   class B<T extends Number> extends A<T,Long,String> {}
+        // first we have:    T->Number
+        // we apply it to A<T,Long,String> -> A<Number,Long,String>
+        // resulting in:     V->Number,W->Long,X->String
+
+        GenericsType[] sgts = current.getGenericsTypes();
+        if (sgts != null) {
+            ClassNode[] spec = new ClassNode[sgts.length];
+            for (int i = 0; i < spec.length; i++) {
+                spec[i] = correctToGenericsSpec(ret, sgts[i]);
+            }
+            GenericsType[] newGts = current.redirect().getGenericsTypes();
+            if (newGts == null) return ret;
+            ret.clear();
+            for (int i = 0; i < spec.length; i++) {
+                ret.put(newGts[i].getName(), spec[i]);
+            }
+        }
+        return ret;
+    }
+
+    public static Map<String,ClassNode> addMethodGenerics(MethodNode current, Map<String,ClassNode> oldSpec) {
+        Map<String,ClassNode> ret = new HashMap<String,ClassNode>(oldSpec);
+        // ret starts with the original type specs, now add gts for the current method if any
+        GenericsType[] sgts = current.getGenericsTypes();
+        if (sgts != null) {
+            for (GenericsType sgt : sgts) {
+                ret.put(sgt.getName(), sgt.getType());
+            }
+        }
+        return ret;
+    }
+
+    public static void extractSuperClassGenerics(ClassNode type, ClassNode target, Map<String,ClassNode> spec) {
+        // TODO: this method is very similar to StaticTypesCheckingSupport#extractGenericsConnections,
+        // but operates on ClassNodes instead of GenericsType
+        if (target==null || type==target) return;
+        if (type.isArray() && target.isArray()) {
+            extractSuperClassGenerics(type.getComponentType(), target.getComponentType(), spec);
+        } else if (type.isArray() && target.getName().equals("java.lang.Object")) {
+            // Object is superclass of arrays but no generics involved
+        } else if (target.isGenericsPlaceHolder() || type.equals(target) || !StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(type, target)) {
+            // structural match route
+            if (target.isGenericsPlaceHolder()) {
+                spec.put(target.getGenericsTypes()[0].getName(),type);
+            } else {
+                extractSuperClassGenerics(type.getGenericsTypes(), target.getGenericsTypes(), spec);
+            }
+        } else {
+            // have first to find matching super class or interface
+            Map <String,ClassNode> genSpec = createGenericsSpec(type);
+            ClassNode superClass = ClassHelper.getNextSuperClass(type,target);
+            if (superClass!=null){
+                ClassNode corrected = GenericsUtils.correctToGenericsSpecRecurse(genSpec, superClass);
+                extractSuperClassGenerics(corrected, target, spec);
+            } else {
+                // if we reach here, we have an unhandled case 
+                throw new GroovyBugError("The type "+type+" seems not to normally extend "+target+". Sorry, I cannot handle this.");
+            }
+        }
+    }
+
+    private static void extractSuperClassGenerics(GenericsType[] usage, GenericsType[] declaration, Map<String, ClassNode> spec) {
+        // if declaration does not provide generics, there is no connection to make 
+        if (usage==null || declaration==null || declaration.length==0) return;
+        if (usage.length!=declaration.length) return;
+
+        // both have generics
+        for (int i=0; i<usage.length; i++) {
+            GenericsType ui = usage[i];
+            GenericsType di = declaration[i];
+            if (di.isPlaceholder()) {
+                spec.put(di.getName(), ui.getType());
+            } else if (di.isWildcard()){
+                if (ui.isWildcard()) {
+                    extractSuperClassGenerics(ui.getLowerBound(), di.getLowerBound(), spec);
+                    extractSuperClassGenerics(ui.getUpperBounds(), di.getUpperBounds(), spec);
+                } else {
+                    ClassNode cu = ui.getType();
+                    extractSuperClassGenerics(cu, di.getLowerBound(), spec);
+                    ClassNode[] upperBounds = di.getUpperBounds();
+                    if (upperBounds!=null) {
+                        for (ClassNode cn : upperBounds) {
+                            extractSuperClassGenerics(cu, cn, spec);
+                        }
+                    }
+                }
+            } else {
+                extractSuperClassGenerics(ui.getType(), di.getType(), spec);
+            }
+        }
+    }
+
+    private static void extractSuperClassGenerics(ClassNode[] usage, ClassNode[] declaration, Map<String, ClassNode> spec) {
+        if (usage==null || declaration==null || declaration.length==0) return;
+        // both have generics
+        for (int i=0; i<usage.length; i++) {
+            ClassNode ui = usage[i];
+            ClassNode di = declaration[i];
+            if (di.isGenericsPlaceHolder()) {
+                spec.put(di.getGenericsTypes()[0].getName(), di);
+            } else if (di.isUsingGenerics()){
+                extractSuperClassGenerics(ui.getGenericsTypes(), di.getGenericsTypes(), spec);
+            }
+        }
+    }
+
+    public static ClassNode[] parseClassNodesFromString(
+            final String option,
+            final SourceUnit sourceUnit,
+            final CompilationUnit compilationUnit,
+            final MethodNode mn,
+            final ASTNode usage) {
+        GroovyLexer lexer = new GroovyLexer(new StringReader("DummyNode<" + option + ">"));
+        final GroovyRecognizer rn = GroovyRecognizer.make(lexer);
+        try {
+            rn.classOrInterfaceType(true);
+            final AtomicReference<ClassNode> ref = new AtomicReference<ClassNode>();
+            AntlrParserPlugin plugin = new AntlrParserPlugin() {
+                @Override
+                public ModuleNode buildAST(final SourceUnit sourceUnit, final ClassLoader classLoader, final Reduction cst) throws ParserException {
+                    ref.set(makeTypeWithArguments(rn.getAST()));
+                    return null;
+                }
+            };
+            plugin.buildAST(null, null, null);
+            ClassNode parsedNode = ref.get();
+            // the returned node is DummyNode<Param1, Param2, Param3, ...)
+            GenericsType[] parsedNodeGenericsTypes = parsedNode.getGenericsTypes();
+            if (parsedNodeGenericsTypes == null) {
+                return null;
+            }
+            ClassNode[] signature = new ClassNode[parsedNodeGenericsTypes.length];
+            for (int i = 0; i < parsedNodeGenericsTypes.length; i++) {
+                final GenericsType genericsType = parsedNodeGenericsTypes[i];
+                signature[i] = resolveClassNode(sourceUnit, compilationUnit, mn, usage, genericsType.getType());
+            }
+            return signature;
+        } catch (RecognitionException e) {
+            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
+        } catch (TokenStreamException e) {
+            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
+        } catch (ParserException e) {
+            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
+        }
+        return null;
+    }
+
+    private static ClassNode resolveClassNode(final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final MethodNode mn, final ASTNode usage, final ClassNode parsedNode) {
+        ClassNode dummyClass = new ClassNode("dummy",0, ClassHelper.OBJECT_TYPE);
+        dummyClass.setModule(new ModuleNode(sourceUnit));
+        dummyClass.setGenericsTypes(mn.getDeclaringClass().getGenericsTypes());
+        MethodNode dummyMN = new MethodNode(
+                "dummy",
+                0,
+                parsedNode,
+                Parameter.EMPTY_ARRAY,
+                ClassNode.EMPTY_ARRAY,
+                EmptyStatement.INSTANCE
+        );
+        dummyMN.setGenericsTypes(mn.getGenericsTypes());
+        dummyClass.addMethod(dummyMN);
+        ResolveVisitor visitor = new ResolveVisitor(compilationUnit) {
+            @Override
+            public void addError(final String msg, final ASTNode expr) {
+                sourceUnit.addError(new IncorrectTypeHintException(mn, msg, usage.getLineNumber(), usage.getColumnNumber()));
+            }
+        };
+        visitor.startResolving(dummyClass, sourceUnit);
+        return dummyMN.getReturnType();
+    }
+
+    /**
+     * transforms generics types from an old context to a new context using the given spec. This method assumes
+     * all generics types will be placeholders. WARNING: The resulting generics types may or may not be placeholders
+     * after the transformation.
+     * @param genericsSpec the generics context information spec
+     * @param oldPlaceHolders the old placeholders
+     * @return the new generics types
+     */
+    public static GenericsType[] applyGenericsContextToPlaceHolders(Map<String, ClassNode> genericsSpec, GenericsType[] oldPlaceHolders) {
+        if (oldPlaceHolders==null || oldPlaceHolders.length==0) return oldPlaceHolders;
+        if (genericsSpec.isEmpty()) return oldPlaceHolders;
+        GenericsType[] newTypes = new GenericsType[oldPlaceHolders.length];
+        for (int i=0; i<oldPlaceHolders.length; i++) {
+            GenericsType old = oldPlaceHolders[i];
+            if (!old.isPlaceholder()) throw new GroovyBugError("Given generics type "+old+" must be a placeholder!");
+            ClassNode fromSpec = genericsSpec.get(old.getName());
+            if (fromSpec!=null) {
+                if (fromSpec.isGenericsPlaceHolder()) {
+                    ClassNode[] upper = new ClassNode[]{fromSpec.redirect()};
+                    newTypes[i] = new GenericsType(fromSpec, upper, null);
+                } else {
+                    newTypes[i] = new GenericsType(fromSpec);
+                }
+            } else {
+                ClassNode[] upper = old.getUpperBounds();
+                ClassNode[] newUpper = upper;
+                if (upper!=null && upper.length>0) {
+                    ClassNode[] upperCorrected = new ClassNode[upper.length];
+                    for (int j=0;j<upper.length;j++) {
+                        upperCorrected[i] = correctToGenericsSpecRecurse(genericsSpec,upper[j]);
+                    }
+                    upper = upperCorrected;
+                }
+                ClassNode lower = old.getLowerBound();
+                ClassNode newLower = correctToGenericsSpecRecurse(genericsSpec,lower);
+                if (lower==newLower && upper==newUpper) {
+                    newTypes[i] = oldPlaceHolders[i];
+                } else {
+                    ClassNode newPlaceHolder = ClassHelper.make(old.getName());
+                    GenericsType gt = new GenericsType(newPlaceHolder, newUpper, newLower);
+                    gt.setPlaceholder(true);
+                    newTypes[i] = gt;
+                }
+            }
+        }
+        return newTypes;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
new file mode 100644
index 0000000..4edf92e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/ParameterUtils.java
@@ -0,0 +1,39 @@
+/*
+ * 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.tools;
+
+import org.codehaus.groovy.ast.Parameter;
+
+public class ParameterUtils {
+    public static boolean parametersEqual(Parameter[] a, Parameter[] b) {
+        if (a.length == b.length) {
+            boolean answer = true;
+            for (int i = 0; i < a.length; i++) {
+                if (!a[i].getType().equals(b[i].getType())) {
+                    answer = false;
+                    break;
+                }
+            }
+            return answer;
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java
new file mode 100644
index 0000000..513144a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/PropertyNodeUtils.java
@@ -0,0 +1,43 @@
+/*
+ *  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.tools;
+
+import org.codehaus.groovy.ast.PropertyNode;
+
+import java.lang.reflect.Modifier;
+
+public class PropertyNodeUtils {
+    /**
+     * Fields within the AST that have no explicit visibility are deemed to be properties
+     * and represented by a PropertyNode. The Groovy compiler creates accessor methods and
+     * a backing field for such property nodes. During this process, all modifiers
+     * from the property are carried over to the backing field (so a property marked as
+     * {@code transient} will have a {@code transient} backing field) but when creating
+     * the accessor methods we don't carry over modifier values which don't make sense for
+     * methods (this includes VOLATILE and TRANSIENT) but other modifiers are carried over,
+     * for example {@code static}.
+     *
+     * @param propNode the original property node
+     * @return the modifiers which make sense for an accessor method
+     */
+    public static int adjustPropertyModifiersForMethod(PropertyNode propNode) {
+        // GROOVY-3726: clear volatile, transient modifiers so that they don't get applied to methods
+        return ~(Modifier.TRANSIENT | Modifier.VOLATILE) & propNode.getModifiers();
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
new file mode 100644
index 0000000..1489a56
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -0,0 +1,746 @@
+/*
+ *  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.tools;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.codehaus.groovy.ast.ClassHelper.BigDecimal_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.BigInteger_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.Number_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.char_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
+import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
+import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.isNumberType;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
+import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
+
+/**
+ * This class provides helper methods to determine the type from a widening
+ * operation for example for a plus operation.
+ * <p>
+ * To determine the resulting type of for example a=exp1+exp2 we look at the
+ * conditions {@link #isIntCategory(ClassNode)}, {@link #isLongCategory(ClassNode)},
+ * {@link #isBigIntCategory(ClassNode)}, {@link #isDoubleCategory(ClassNode)} and
+ * {@link #isBigDecCategory(ClassNode)} in that order. The first case applying to
+ * exp1 and exp2 is defining the result type of the expression.
+ * <p>
+ * If for example you look at x = 1 + 2l we have the first category applying to
+ * the number 1 being int, since the 1 is an int. The 2l is a long, therefore the
+ * int category will not apply and the result type can't be int. The next category
+ * in the list is long, and since both apply to long, the result type is a long.
+ *
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ * @author Cedric Champeau
+ */
+public class WideningCategories {
+
+    private static final List<ClassNode> EMPTY_CLASSNODE_LIST = Collections.emptyList();
+
+    private static final Map<ClassNode, Integer> NUMBER_TYPES_PRECEDENCE = Collections.unmodifiableMap(new HashMap<ClassNode, Integer>() {{
+        put(ClassHelper.double_TYPE, 0);
+        put(ClassHelper.float_TYPE, 1);
+        put(ClassHelper.long_TYPE, 2);
+        put(ClassHelper.int_TYPE, 3);
+        put(ClassHelper.short_TYPE, 4);
+        put(ClassHelper.byte_TYPE, 5);
+    }});
+
+    /**
+     * A comparator which is used in case we generate a virtual lower upper bound class node. In that case,
+     * since a concrete implementation should be used at compile time, we must ensure that interfaces are
+     * always sorted. It is not important what sort is used, as long as the result is constant.
+     */
+    private static final Comparator<ClassNode> INTERFACE_CLASSNODE_COMPARATOR = new Comparator<ClassNode>() {
+        public int compare(final ClassNode o1, final ClassNode o2) {
+            int interfaceCountForO1 = o1.getInterfaces().length;
+            int interfaceCountForO2 = o2.getInterfaces().length;
+            if (interfaceCountForO1 > interfaceCountForO2) return -1;
+            if (interfaceCountForO1 < interfaceCountForO2) return 1;
+            int methodCountForO1 = o1.getMethods().size();
+            int methodCountForO2 = o2.getMethods().size();
+            if (methodCountForO1 > methodCountForO2) return -1;
+            if (methodCountForO1 < methodCountForO2) return 1;
+            return o1.getName().compareTo(o2.getName());
+        }
+    };
+
+    /**
+     * Used to check if a type is an int or Integer.
+     * @param type the type to check
+     */
+    public static boolean isInt(ClassNode type) {
+        return int_TYPE == type;
+    }
+
+    /**
+     * Used to check if a type is an double or Double.
+     * @param type the type to check
+     */
+    public static boolean isDouble(ClassNode type) {
+        return double_TYPE == type;
+    }
+
+    /**
+     * Used to check if a type is a float or Float.
+     * @param type the type to check
+     */
+    public static boolean isFloat(ClassNode type) {
+        return float_TYPE == type;
+    }
+
+    /**
+     * It is of an int category, if the provided type is a
+     * byte, char, short, int.
+     */
+    public static boolean isIntCategory(ClassNode type) {
+        return  type==byte_TYPE     ||  type==char_TYPE     ||
+                type==int_TYPE      ||  type==short_TYPE;
+    }
+    /**
+     * It is of a long category, if the provided type is a
+     * long, its wrapper or if it is a long category. 
+     */
+    public static boolean isLongCategory(ClassNode type) {
+        return  type==long_TYPE     ||  isIntCategory(type);
+    }
+    /**
+     * It is of a BigInteger category, if the provided type is a
+     * long category or a BigInteger. 
+     */
+    public static boolean isBigIntCategory(ClassNode type) {
+        return  type==BigInteger_TYPE || isLongCategory(type);
+    }
+    /**
+     * It is of a BigDecimal category, if the provided type is a
+     * BigInteger category or a BigDecimal. 
+     */
+    public static boolean isBigDecCategory(ClassNode type) {
+        return  type==BigDecimal_TYPE || isBigIntCategory(type);
+    }
+    /**
+     * It is of a double category, if the provided type is a
+     * BigDecimal, a float, double. C(type)=double
+     */
+    public static boolean isDoubleCategory(ClassNode type) {
+        return  type==float_TYPE    ||  type==double_TYPE   ||
+                isBigDecCategory(type);
+    }
+
+    /**
+     * It is of a floating category, if the provided type is a
+     * a float, double. C(type)=float
+     */
+    public static boolean isFloatingCategory(ClassNode type) {
+        return  type==float_TYPE    ||  type==double_TYPE;
+    }
+
+    public static boolean isNumberCategory(ClassNode type) {
+        return isBigDecCategory(type) || type.isDerivedFrom(Number_TYPE);
+    }
+
+    /**
+     * Given a list of class nodes, returns the first common supertype.
+     * For example, Double and Float would return Number, while
+     * Set and String would return Object.
+     * @param nodes the list of nodes for which to find the first common super type.
+     * @return first common supertype
+     */
+    public static ClassNode lowestUpperBound(List<ClassNode> nodes) {
+        if (nodes.size()==1) return nodes.get(0);
+        return lowestUpperBound(nodes.get(0), lowestUpperBound(nodes.subList(1, nodes.size())));
+    }
+
+    /**
+     * Given two class nodes, returns the first common supertype, or the class itself
+     * if there are equal. For example, Double and Float would return Number, while
+     * Set and String would return Object.
+     *
+     * This method is not guaranteed to return a class node which corresponds to a
+     * real type. For example, if two types have more than one interface in common
+     * and are not in the same hierarchy branch, then the returned type will be a
+     * virtual type implementing all those interfaces.
+     *
+     * Calls to this method are supposed to be made with resolved generics. This means
+     * that you can have wildcards, but no placeholder.
+     *
+     * @param a first class node
+     * @param b second class node
+     * @return first common supertype
+     */
+    public static ClassNode lowestUpperBound(ClassNode a, ClassNode b) {
+        ClassNode lub = lowestUpperBound(a, b, null, null);
+        if (lub==null || !lub.isUsingGenerics()) return lub;
+        // types may be parameterized. If so, we must ensure that generic type arguments
+        // are made compatible
+
+        if (lub instanceof LowestUpperBoundClassNode) {
+            // no parent super class representing both types could be found
+            // or both class nodes implement common interfaces which may have
+            // been parameterized differently.
+            // We must create a classnode for which the "superclass" is potentially parameterized
+            // plus the interfaces
+            ClassNode superClass = lub.getSuperClass();
+            ClassNode psc = superClass.isUsingGenerics()?parameterizeLowestUpperBound(superClass, a, b, lub):superClass;
+
+            ClassNode[] interfaces = lub.getInterfaces();
+            ClassNode[] pinterfaces = new ClassNode[interfaces.length];
+            for (int i = 0, interfacesLength = interfaces.length; i < interfacesLength; i++) {
+                final ClassNode icn = interfaces[i];
+                if (icn.isUsingGenerics()) {
+                    pinterfaces[i] = parameterizeLowestUpperBound(icn, a, b, lub);
+                } else {
+                    pinterfaces[i] = icn;
+                }
+            }
+
+            return new LowestUpperBoundClassNode(((LowestUpperBoundClassNode)lub).name, psc, pinterfaces);
+        } else {
+            return parameterizeLowestUpperBound(lub, a, b, lub);
+
+        }
+    }
+
+    /**
+     * Given a lowest upper bound computed without generic type information but which requires to be parameterized
+     * and the two implementing classnodes which are parameterized with potentially two different types, returns
+     * a parameterized lowest upper bound.
+     *
+     * For example, if LUB is Set&lt;T&gt; and a is Set&lt;String&gt; and b is Set&lt;StringBuffer&gt;, this
+     * will return a LUB which parameterized type matches Set&lt;? extends CharSequence&gt;
+     * @param lub the type to be parameterized
+     * @param a parameterized type a
+     * @param b parameterized type b
+     * @param fallback if we detect a recursive call, use this LUB as the parameterized type instead of computing a value
+     * @return the class node representing the parameterized lowest upper bound
+     */
+    private static ClassNode parameterizeLowestUpperBound(final ClassNode lub, final ClassNode a, final ClassNode b, final ClassNode fallback) {
+        if (!lub.isUsingGenerics()) return lub;
+        // a common super type exists, all we have to do is to parameterize
+        // it according to the types provided by the two class nodes
+        ClassNode holderForA = findGenericsTypeHolderForClass(a, lub);
+        ClassNode holderForB = findGenericsTypeHolderForClass(b, lub);
+        // let's compare their generics type
+        GenericsType[] agt = holderForA == null ? null : holderForA.getGenericsTypes();
+        GenericsType[] bgt = holderForB == null ? null : holderForB.getGenericsTypes();
+        if (agt==null || bgt==null || agt.length!=bgt.length) {
+            return lub;
+        }
+        GenericsType[] lubgt = new GenericsType[agt.length];
+        for (int i = 0; i < agt.length; i++) {
+            ClassNode t1 = agt[i].getType();
+            ClassNode t2 = bgt[i].getType();
+            ClassNode basicType;
+            if (areEqualWithGenerics(t1, a) && areEqualWithGenerics(t2,b)) {
+                // we are facing a self referencing type !
+                basicType = fallback;
+            } else {
+                 basicType = lowestUpperBound(t1, t2);
+            }
+            if (t1.equals(t2)) {
+                lubgt[i] = new GenericsType(basicType);
+            } else {
+                lubgt[i] = GenericsUtils.buildWildcardType(basicType);
+            }
+        }
+        ClassNode plain = lub.getPlainNodeReference();
+        plain.setGenericsTypes(lubgt);
+        return plain;
+    }
+
+    private static ClassNode findGenericsTypeHolderForClass(ClassNode source, ClassNode type) {
+        if (isPrimitiveType(source)) source = getWrapper(source);
+        if (source.equals(type)) return source;
+        if (type.isInterface()) {
+            for (ClassNode interfaceNode : source.getAllInterfaces()) {
+                if (interfaceNode.equals(type)) {
+                    ClassNode parameterizedInterface = GenericsUtils.parameterizeType(source, interfaceNode);
+                    return parameterizedInterface;
+                }
+            }
+        }
+        ClassNode superClass = source.getUnresolvedSuperClass();
+        // copy generic type information if available
+        if (superClass!=null && superClass.isUsingGenerics()) {
+            Map<String, GenericsType> genericsTypeMap = GenericsUtils.extractPlaceholders(source);
+            GenericsType[] genericsTypes = superClass.getGenericsTypes();
+            if (genericsTypes!=null) {
+                GenericsType[] copyTypes = new GenericsType[genericsTypes.length];
+                for (int i = 0; i < genericsTypes.length; i++) {
+                    GenericsType genericsType = genericsTypes[i];
+                    if (genericsType.isPlaceholder() && genericsTypeMap.containsKey(genericsType.getName())) {
+                        copyTypes[i] = genericsTypeMap.get(genericsType.getName());
+                    } else {
+                        copyTypes[i] = genericsType;
+                    }
+                }
+                superClass = superClass.getPlainNodeReference();
+                superClass.setGenericsTypes(copyTypes);
+            }
+        }
+        if (superClass!=null) return findGenericsTypeHolderForClass(superClass, type);
+        return null;
+    }
+
+    private static ClassNode lowestUpperBound(ClassNode a, ClassNode b, List<ClassNode> interfacesImplementedByA, List<ClassNode> interfacesImplementedByB) {
+        // first test special cases
+        if (a==null || b==null) {
+            // this is a corner case, you should not
+            // compare two class nodes if one of them is null
+            return null;
+        }
+        if (a.isArray() && b.isArray()) {
+            return lowestUpperBound(a.getComponentType(), b.getComponentType(), interfacesImplementedByA, interfacesImplementedByB).makeArray();
+        }
+        if (a.equals(OBJECT_TYPE) || b.equals(OBJECT_TYPE)) {
+            // one of the objects is at the top of the hierarchy
+            GenericsType[] gta = a.getGenericsTypes();
+            GenericsType[] gtb = b.getGenericsTypes();
+            if (gta !=null && gtb !=null && gta.length==1 && gtb.length==1) {
+                if (gta[0].getName().equals(gtb[0].getName())) {
+                    return a;
+                }
+            }
+            return OBJECT_TYPE;
+        }
+        if (a.equals(VOID_TYPE) || b.equals(VOID_TYPE)) {
+            if (!b.equals(a)) {
+                // one class is void, the other is not
+                return OBJECT_TYPE;
+            }
+            return VOID_TYPE;
+        }
+
+        // now handle primitive types
+        boolean isPrimitiveA = isPrimitiveType(a);
+        boolean isPrimitiveB = isPrimitiveType(b);
+        if (isPrimitiveA && !isPrimitiveB) {
+            return lowestUpperBound(getWrapper(a), b, null, null);
+        }
+        if (isPrimitiveB && !isPrimitiveA) {
+            return lowestUpperBound(a, getWrapper(b), null, null);
+        }
+        if (isPrimitiveA && isPrimitiveB) {
+            Integer pa = NUMBER_TYPES_PRECEDENCE.get(a);
+            Integer pb = NUMBER_TYPES_PRECEDENCE.get(b);
+            if (pa!=null && pb!=null) {
+                if (pa<=pb) return a;
+                return b;
+            }
+            return a.equals(b)?a:lowestUpperBound(getWrapper(a), getWrapper(b), null, null);
+        }
+        if (isNumberType(a.redirect()) && isNumberType(b.redirect())) {
+            ClassNode ua = getUnwrapper(a);
+            ClassNode ub = getUnwrapper(b);
+            Integer pa = NUMBER_TYPES_PRECEDENCE.get(ua);
+            Integer pb = NUMBER_TYPES_PRECEDENCE.get(ub);
+            if (pa!=null && pb!=null) {
+                if (pa<=pb) return a;
+                return b;
+            }
+        }
+
+        // handle interfaces
+        boolean isInterfaceA = a.isInterface();
+        boolean isInterfaceB = b.isInterface();
+        if (isInterfaceA && isInterfaceB) {
+            if (a.equals(b)) return a;
+            if (b.implementsInterface(a)) {
+                return a;
+            }
+            if (a.implementsInterface(b)) {
+                return b;
+            }
+            // each interface may have one or more "extends", so we must find those
+            // which are common
+            ClassNode[] interfacesFromA = a.getInterfaces();
+            ClassNode[] interfacesFromB = b.getInterfaces();
+            Set<ClassNode> common = new HashSet<ClassNode>();
+            Collections.addAll(common, interfacesFromA);
+            Set<ClassNode> fromB = new HashSet<ClassNode>();
+            Collections.addAll(fromB, interfacesFromB);
+            common.retainAll(fromB);
+
+            if (common.size()==1) {
+                return common.iterator().next();
+            } else if (common.size()>1) {
+                return buildTypeWithInterfaces(a, b, common);
+            }
+
+            // we have two interfaces, but none inherits from the other
+            // so the only possible return type is Object
+            return OBJECT_TYPE;
+        } else if (isInterfaceB) {
+            return lowestUpperBound(b, a, null, null);
+        } else if (isInterfaceA) {
+            // a is an interface, b is not
+
+            // a ClassNode superclass for an interface is not
+            // another interface but always Object. This implies that
+            // "extends" for an interface is understood as "implements"
+            // for a ClassNode. Therefore, even if b doesn't implement
+            // interface a, a could "implement" other interfaces that b
+            // implements too, so we must create a list of matching interfaces
+            List<ClassNode> matchingInterfaces = new LinkedList<ClassNode>();
+            extractMostSpecificImplementedInterfaces(b, a, matchingInterfaces);
+            if (matchingInterfaces.isEmpty()) {
+                // no interface in common
+                return OBJECT_TYPE;
+            }
+            if (matchingInterfaces.size()==1) {
+                // a single match, which should be returned
+                return matchingInterfaces.get(0);
+            }
+            return buildTypeWithInterfaces(a,b, matchingInterfaces);
+        }
+        // both classes do not represent interfaces
+        if (a.equals(b)) {
+            return buildTypeWithInterfaces(a,b, keepLowestCommonInterfaces(interfacesImplementedByA, interfacesImplementedByB));
+        }
+        // test if one class inherits from the other
+        if (a.isDerivedFrom(b) || b.isDerivedFrom(a)) {
+            return buildTypeWithInterfaces(a,b, keepLowestCommonInterfaces(interfacesImplementedByA, interfacesImplementedByB));
+        }
+
+        // Look at the super classes
+        ClassNode sa = a.getUnresolvedSuperClass();
+        ClassNode sb = b.getUnresolvedSuperClass();
+
+        // extract implemented interfaces before "going up"
+        Set<ClassNode> ifa = new HashSet<ClassNode>();
+        extractInterfaces(a, ifa);
+        Set<ClassNode> ifb = new HashSet<ClassNode>();
+        extractInterfaces(b, ifb);
+        interfacesImplementedByA = interfacesImplementedByA==null?new LinkedList<ClassNode>(ifa):interfacesImplementedByA;
+        interfacesImplementedByB = interfacesImplementedByB==null?new LinkedList<ClassNode>(ifb):interfacesImplementedByB;
+
+        // check if no superclass is defined
+        // meaning that we reached the top of the object hierarchy
+        if (sa==null || sb==null) return buildTypeWithInterfaces(OBJECT_TYPE, OBJECT_TYPE, keepLowestCommonInterfaces(interfacesImplementedByA, interfacesImplementedByB));
+
+
+        // if one superclass is derived (or equals) another
+        // then it is the common super type
+        if (sa.isDerivedFrom(sb) || sb.isDerivedFrom(sa)) {
+            return buildTypeWithInterfaces(sa, sb, keepLowestCommonInterfaces(interfacesImplementedByA, interfacesImplementedByB));
+        }
+        // superclasses are on distinct hierarchy branches, so we
+        // recurse on them
+        return lowestUpperBound(sa, sb, interfacesImplementedByA, interfacesImplementedByB);
+    }
+
+    private static void extractInterfaces(ClassNode node, Set<ClassNode> interfaces) {
+        if (node==null) return;
+        Collections.addAll(interfaces, node.getInterfaces());
+        extractInterfaces(node.getSuperClass(), interfaces);
+    }
+    
+    /**
+     * Given the list of interfaces implemented by two class nodes, returns the list of the most specific common
+     * implemented interfaces.
+     * @param fromA
+     * @param fromB
+     * @return the list of the most specific common implemented interfaces
+     */
+    private static List<ClassNode> keepLowestCommonInterfaces(List<ClassNode> fromA, List<ClassNode> fromB) {
+        if (fromA==null||fromB==null) return EMPTY_CLASSNODE_LIST;
+        Set<ClassNode> common = new HashSet<ClassNode>(fromA);
+        common.retainAll(fromB);
+        List<ClassNode> result = new ArrayList<ClassNode>(common.size());
+        for (ClassNode classNode : common) {
+            addMostSpecificInterface(classNode, result);
+        }
+        return result;
+    }
+
+    private static void addMostSpecificInterface(ClassNode interfaceNode, List<ClassNode> nodes) {
+        if (nodes.isEmpty()) nodes.add(interfaceNode);
+        for (int i = 0, nodesSize = nodes.size(); i < nodesSize; i++) {
+            final ClassNode node = nodes.get(i);
+            if (node.equals(interfaceNode)||node.implementsInterface(interfaceNode)) {
+                // a more specific interface exists in the list, keep it
+                return;
+            }
+            if (interfaceNode.implementsInterface(node)) {
+                // the interface beeing added is more specific than the one in the list, replace it
+                nodes.set(i, interfaceNode);
+                return;
+            }
+        }
+        // if we reach this point, this means the interface is new
+        nodes.add(interfaceNode);
+    }
+
+    private static void extractMostSpecificImplementedInterfaces(final ClassNode type, final ClassNode inode, final List<ClassNode> result) {
+        if (type.implementsInterface(inode)) result.add(inode);
+        else {
+            ClassNode[] interfaces = inode.getInterfaces();
+            for (ClassNode interfaceNode : interfaces) {
+                if (type.implementsInterface(interfaceNode)) result.add(interfaceNode);
+            }
+            if (result.isEmpty() && interfaces.length>0) {
+                // none if the direct interfaces match, but we must check "upper" in the hierarchy
+                for (ClassNode interfaceNode : interfaces) {
+                    extractMostSpecificImplementedInterfaces(type, interfaceNode, result);
+                }
+            }
+        }
+    }
+
+    /**
+     * Given two class nodes supposedly at the upper common level, returns a class node which is able to represent
+     * their lowest upper bound.
+     * @param baseType1
+     * @param baseType2
+     * @param interfaces interfaces both class nodes share, which their lowest common super class do not implement.
+     * @return the class node representing the lowest upper bound
+     */
+    private static ClassNode buildTypeWithInterfaces(ClassNode baseType1, ClassNode baseType2, Collection<ClassNode> interfaces) {
+        boolean noInterface = interfaces.isEmpty();
+        if (noInterface) {
+            if (baseType1.equals(baseType2)) return baseType1;
+            if (baseType1.isDerivedFrom(baseType2)) return baseType2;
+            if (baseType2.isDerivedFrom(baseType1)) return baseType1;
+        }
+        if (OBJECT_TYPE.equals(baseType1) && OBJECT_TYPE.equals(baseType2) && interfaces.size()==1) {
+            if (interfaces instanceof List) {
+                return ((List<ClassNode>) interfaces).get(0);
+            }
+            return interfaces.iterator().next();
+        }
+        LowestUpperBoundClassNode type;
+        ClassNode superClass;
+        String name;
+        if (baseType1.equals(baseType2)) {
+            if (OBJECT_TYPE.equals(baseType1)) {
+                superClass = baseType1;
+                name = "Virtual$Object";
+            } else {
+                superClass = baseType1;
+                name = "Virtual$"+baseType1.getName();
+            }
+        } else {
+            superClass = OBJECT_TYPE;
+            if (baseType1.isDerivedFrom(baseType2)) {
+                superClass = baseType2;
+            } else if (baseType2.isDerivedFrom(baseType1)) {
+                superClass = baseType1;
+            }
+            name = "CommonAssignOf$"+baseType1.getName()+"$"+baseType2.getName();
+        }
+        Iterator<ClassNode> itcn = interfaces.iterator();
+        while (itcn.hasNext()) {
+            ClassNode next = itcn.next();
+            if (superClass.isDerivedFrom(next) || superClass.implementsInterface(next)) {
+                itcn.remove();
+            }
+        }
+        ClassNode[] interfaceArray = interfaces.toArray(new ClassNode[interfaces.size()]);
+        Arrays.sort(interfaceArray, INTERFACE_CLASSNODE_COMPARATOR);
+        type = new LowestUpperBoundClassNode(name, superClass, interfaceArray);
+        return type;
+    }
+
+    /**
+     * This {@link ClassNode} specialization is used when the lowest upper bound of two types
+     * cannot be represented by an existing type. For example, if B extends A,  C extends A
+     * and both C & B implement a common interface not implemented by A, then we use this class
+     * to represent the bound.
+     *
+     * At compile time, some classes like {@link org.codehaus.groovy.classgen.AsmClassGenerator} need
+     * to know about a real class node, so we compute a "compile time" node which will be used
+     * to return a name and a type class.
+     *
+     */
+    public static class LowestUpperBoundClassNode extends ClassNode {
+        private static final Comparator<ClassNode> CLASS_NODE_COMPARATOR = new Comparator<ClassNode>() {
+            public int compare(final ClassNode o1, final ClassNode o2) {
+                String n1 = o1 instanceof LowestUpperBoundClassNode?((LowestUpperBoundClassNode)o1).name:o1.getName();
+                String n2 = o2 instanceof LowestUpperBoundClassNode?((LowestUpperBoundClassNode)o2).name:o2.getName();
+                return n1.compareTo(n2);
+            }
+        };
+        private final ClassNode compileTimeClassNode;
+        private final String name;
+        private final String text;
+
+        private final ClassNode upper;
+        private final ClassNode[] interfaces;
+
+        public LowestUpperBoundClassNode(String name, ClassNode upper, ClassNode... interfaces) {
+            super(name, ACC_PUBLIC|ACC_FINAL, upper, interfaces, null);
+            this.upper = upper;
+            this.interfaces = interfaces;
+            boolean usesGenerics;
+            Arrays.sort(interfaces, CLASS_NODE_COMPARATOR);
+            compileTimeClassNode = upper.equals(OBJECT_TYPE) && interfaces.length>0?interfaces[0]:upper;
+            this.name = name;
+            usesGenerics = upper.isUsingGenerics();
+            List<GenericsType[]> genericsTypesList = new LinkedList<GenericsType[]>();
+            genericsTypesList.add(upper.getGenericsTypes());
+			for (ClassNode anInterface : interfaces) {
+                usesGenerics |= anInterface.isUsingGenerics();
+                genericsTypesList.add(anInterface.getGenericsTypes());
+				for (MethodNode methodNode : anInterface.getMethods()) {
+                    MethodNode method = addMethod(methodNode.getName(), methodNode.getModifiers(), methodNode.getReturnType(), methodNode.getParameters(), methodNode.getExceptions(), methodNode.getCode());
+                    method.setDeclaringClass(anInterface); // important for static compilation!
+                }
+			}
+            setUsingGenerics(usesGenerics);
+            if (usesGenerics) {
+                List<GenericsType> asArrayList = new ArrayList<GenericsType>();
+                for (GenericsType[] genericsTypes : genericsTypesList) {
+                    if (genericsTypes!=null) {
+                        Collections.addAll(asArrayList, genericsTypes);
+                    }
+                }
+                setGenericsTypes(asArrayList.toArray(new GenericsType[asArrayList.size()]));
+            }
+            StringBuilder sb = new StringBuilder();
+            if (!upper.equals(OBJECT_TYPE)) sb.append(upper.getName());
+            for (ClassNode anInterface : interfaces) {
+                if (sb.length()>0) {
+                    sb.append(" or ");
+                }
+                sb.append(anInterface.getName());
+            }
+            this.text = sb.toString();
+        }
+
+        public String getLubName() {
+            return this.name;
+        }
+
+        @Override
+        public String getName() {
+            return compileTimeClassNode.getName();
+        }
+
+        @Override
+        public Class getTypeClass() {
+            return compileTimeClassNode.getTypeClass();
+        }
+
+        @Override
+        public int hashCode() {
+            int result = super.hashCode();
+//            result = 31 * result + (compileTimeClassNode != null ? compileTimeClassNode.hashCode() : 0);
+            result = 31 * result + (name != null ? name.hashCode() : 0);
+            return result;
+        }
+
+        @Override
+        public String getText() {
+            return text;
+        }
+
+        @Override
+        public ClassNode getPlainNodeReference() {
+            ClassNode[] intf = interfaces==null?null:new ClassNode[interfaces.length];
+            if (intf!=null) {
+                for (int i = 0; i < interfaces.length; i++) {
+                    intf[i] = interfaces[i].getPlainNodeReference();
+                }
+            }
+            LowestUpperBoundClassNode plain = new LowestUpperBoundClassNode(name, upper.getPlainNodeReference(), intf);
+            return plain;
+        }
+    }
+
+    /**
+     * Compares two class nodes, but including their generics types.
+     * @param a
+     * @param b
+     * @return true if the class nodes are equal, false otherwise
+     */
+    private static boolean areEqualWithGenerics(ClassNode a, ClassNode b) {
+        if (a==null) return b==null;
+        if (!a.equals(b)) return false;
+        if (a.isUsingGenerics() && !b.isUsingGenerics()) return false;
+        GenericsType[] gta = a.getGenericsTypes();
+        GenericsType[] gtb = b.getGenericsTypes();
+        if (gta==null && gtb!=null) return false;
+        if (gtb==null && gta!=null) return false;
+        if (gta!=null && gtb!=null) {
+            if (gta.length!=gtb.length) return false;
+            for (int i = 0; i < gta.length; i++) {
+                GenericsType ga = gta[i];
+                GenericsType gb = gtb[i];
+                boolean result = ga.isPlaceholder()==gb.isPlaceholder() && ga.isWildcard()==gb.isWildcard();
+                result = result && ga.isResolved() && gb.isResolved();
+                result = result && ga.getName().equals(gb.getName());
+                result = result && areEqualWithGenerics(ga.getType(), gb.getType());
+                result = result && areEqualWithGenerics(ga.getLowerBound(), gb.getLowerBound());
+                if (result) {
+                    ClassNode[] upA = ga.getUpperBounds();
+                    if (upA!=null) {
+                        ClassNode[] upB = gb.getUpperBounds();
+                        if (upB==null || upB.length!=upA.length) return false;
+                        for (int j = 0; j < upA.length; j++) {
+                            if (!areEqualWithGenerics(upA[j],upB[j])) return false;
+                        }
+                    }
+                }
+                if (!result) return false;
+            }
+        }
+        return true;
+    }
+    
+    /**
+     * Determines if the source class implements an interface or subclasses the target type.
+     * This method takes the {@link org.codehaus.groovy.ast.tools.WideningCategories.LowestUpperBoundClassNode lowest
+     * upper bound class node} type into account, allowing to remove unnecessary casts.
+     * @param source the type of interest
+     * @param targetType the target type of interest
+     */
+    public static boolean implementsInterfaceOrSubclassOf(final ClassNode source, final ClassNode targetType) {
+        if (source.isDerivedFrom(targetType) || source.implementsInterface(targetType)) return true;
+        if (targetType instanceof WideningCategories.LowestUpperBoundClassNode) {
+            WideningCategories.LowestUpperBoundClassNode lub = (WideningCategories.LowestUpperBoundClassNode) targetType;
+            if (implementsInterfaceOrSubclassOf(source, lub.getSuperClass())) return true;
+            for (ClassNode classNode : lub.getInterfaces()) {
+                if (source.implementsInterface(classNode)) return true;
+            }
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
new file mode 100644
index 0000000..e514b59
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/AnnotationVisitor.java
@@ -0,0 +1,344 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.control.ErrorCollector;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An Annotation visitor responsible for:
+ * <ul>
+ * <li>reading annotation metadata (@Retention, @Target, attribute types)</li>
+ * <li>verify that an <code>AnnotationNode</code> conforms to annotation meta</li>
+ * <li>enhancing an <code>AnnotationNode</code> AST to reflect real annotation meta</li>
+ * </ul>
+ */
+public class AnnotationVisitor {
+    private final SourceUnit source;
+    private final ErrorCollector errorCollector;
+    private AnnotationNode annotation;
+    private ClassNode reportClass;
+
+    public AnnotationVisitor(SourceUnit source, ErrorCollector errorCollector) {
+        this.source = source;
+        this.errorCollector = errorCollector;
+    }
+
+    public void setReportClass(ClassNode cn) {
+        reportClass = cn;
+    }
+
+    public AnnotationNode visit(AnnotationNode node) {
+        this.annotation = node;
+        this.reportClass = node.getClassNode();
+
+        if (!isValidAnnotationClass(node.getClassNode())) {
+            addError("class " + node.getClassNode().getName() + " is not an annotation");
+            return node;
+        }
+
+        // check if values have been passed for all annotation attributes that don't have defaults
+        if (!checkIfMandatoryAnnotationValuesPassed(node)) {
+            return node;
+        }
+
+        // if enum constants have been used, check if they are all valid
+        if (!checkIfValidEnumConstsAreUsed(node)) {
+            return node;
+        }
+        
+        Map<String, Expression> attributes = node.getMembers();
+        for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
+            String attrName = entry.getKey();
+            Expression attrExpr = transformInlineConstants(entry.getValue());
+            entry.setValue(attrExpr);
+            ClassNode attrType = getAttributeType(node, attrName);
+            visitExpression(attrName, attrExpr, attrType);
+        }
+        VMPluginFactory.getPlugin().configureAnnotation(node);
+        return this.annotation;
+    }
+    
+    private boolean checkIfValidEnumConstsAreUsed(AnnotationNode node) {
+        Map<String, Expression> attributes = node.getMembers();
+        for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
+            if (!validateEnumConstant(entry.getValue()))
+                return false;
+        }
+        return true;
+    }
+    
+    private boolean validateEnumConstant(Expression exp) {
+        if (exp instanceof PropertyExpression) {
+            PropertyExpression pe = (PropertyExpression) exp;
+            String name = pe.getPropertyAsString();
+            if (pe.getObjectExpression() instanceof ClassExpression && name != null) {
+                ClassExpression ce = (ClassExpression) pe.getObjectExpression();
+                ClassNode type = ce.getType();
+                if (type.isEnum()) {
+                    boolean ok = false;
+                    try {
+                        FieldNode enumField = type.getDeclaredField(name);
+                        ok = enumField != null && enumField.getType().equals(type);
+                    } catch(Exception ex) {
+                        // ignore
+                    }
+                    if(!ok) {
+                        addError("No enum const " + type.getName() + "." + name, pe);
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private Expression transformInlineConstants(Expression exp) {
+        if (exp instanceof PropertyExpression) {
+            PropertyExpression pe = (PropertyExpression) exp;
+            if (pe.getObjectExpression() instanceof ClassExpression) {
+                ClassExpression ce = (ClassExpression) pe.getObjectExpression();
+                ClassNode type = ce.getType();
+                if (type.isEnum() || !type.isResolved())
+                    return exp;
+
+                try {
+                    Field field = type.getTypeClass().getField(pe.getPropertyAsString());
+                    if (field != null && Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) {
+                        return new ConstantExpression(field.get(null));
+                    }
+                } catch(Exception e) {
+                    // ignore, leave property expression in place and we'll report later
+                }
+            }
+        } else if (exp instanceof ListExpression) {
+            ListExpression le = (ListExpression) exp;
+            ListExpression result = new ListExpression();
+            for (Expression e : le.getExpressions()) {
+                result.addExpression(transformInlineConstants(e));
+            }
+            return result;
+        }
+        return exp;
+    }
+
+    private boolean checkIfMandatoryAnnotationValuesPassed(AnnotationNode node) {
+        boolean ok = true;
+        Map attributes = node.getMembers();
+        ClassNode classNode = node.getClassNode();
+        for (MethodNode mn : classNode.getMethods()) {
+            String methodName = mn.getName();
+            // if the annotation attribute has a default, getCode() returns a ReturnStatement with the default value
+            if (mn.getCode() == null && !attributes.containsKey(methodName)) {
+                addError("No explicit/default value found for annotation attribute '" + methodName + "'", node);
+                ok = false;
+            }
+        }
+        return ok;
+    }
+
+    private ClassNode getAttributeType(AnnotationNode node, String attrName) {
+        ClassNode classNode = node.getClassNode();
+        List methods = classNode.getMethods(attrName);
+        // if size is >1, then the method was overwritten or something, we ignore that
+        // if it is an error, we have to test it at another place. But size==0 is
+        // an error, because it means that no such attribute exists.
+        if (methods.isEmpty()) {
+            addError("'" + attrName + "'is not part of the annotation " + classNode, node);
+            return ClassHelper.OBJECT_TYPE;
+        }
+        MethodNode method = (MethodNode) methods.get(0);
+        return method.getReturnType();
+    }
+
+    private static boolean isValidAnnotationClass(ClassNode node) {
+        return node.implementsInterface(ClassHelper.Annotation_TYPE);
+    }
+
+    protected void visitExpression(String attrName, Expression attrExp, ClassNode attrType) {
+        if (attrType.isArray()) {
+            // check needed as @Test(attr = {"elem"}) passes through the parser
+            if (attrExp instanceof ListExpression) {
+                ListExpression le = (ListExpression) attrExp;
+                visitListExpression(attrName, le, attrType.getComponentType());
+            } else if (attrExp instanceof ClosureExpression) {
+                addError("Annotation list attributes must use Groovy notation [el1, el2]", attrExp);
+            } else {
+                // treat like a singleton list as per Java
+                ListExpression listExp = new ListExpression();
+                listExp.addExpression(attrExp);
+                if (annotation != null) {
+                    annotation.setMember(attrName, listExp);
+                }
+                visitExpression(attrName, listExp, attrType);
+            }
+        } else if (ClassHelper.isPrimitiveType(attrType)) {
+            visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.getWrapper(attrType));
+        } else if (ClassHelper.STRING_TYPE.equals(attrType)) {
+            visitConstantExpression(attrName, getConstantExpression(attrExp, attrType), ClassHelper.STRING_TYPE);
+        } else if (ClassHelper.CLASS_Type.equals(attrType)) {
+            if (!(attrExp instanceof ClassExpression || attrExp instanceof ClosureExpression)) {
+                addError("Only classes and closures can be used for attribute '" + attrName + "'", attrExp);
+            }
+        } else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
+            if (attrExp instanceof PropertyExpression) {
+                visitEnumExpression(attrName, (PropertyExpression) attrExp, attrType);
+            } else {
+                addError("Expected enum value for attribute " + attrName, attrExp);
+            }
+        } else if (isValidAnnotationClass(attrType)) {
+            if (attrExp instanceof AnnotationConstantExpression) {
+                visitAnnotationExpression(attrName, (AnnotationConstantExpression) attrExp, attrType);
+            } else {
+                addError("Expected annotation of type '" + attrType.getName() + "' for attribute " + attrName, attrExp);
+            }
+        } else {
+            addError("Unexpected type " + attrType.getName(), attrExp);
+        }
+    }
+
+    public void checkReturnType(ClassNode attrType, ASTNode node) {
+        if (attrType.isArray()) {
+            checkReturnType(attrType.getComponentType(), node);
+        } else if (ClassHelper.isPrimitiveType(attrType)) {
+            return;
+        } else if (ClassHelper.STRING_TYPE.equals(attrType)) {
+            return;
+        } else if (ClassHelper.CLASS_Type.equals(attrType)) {
+            return;
+        } else if (attrType.isDerivedFrom(ClassHelper.Enum_Type)) {
+            return;
+        } else if (isValidAnnotationClass(attrType)) {
+            return;
+        } else {
+            addError("Unexpected return type " + attrType.getName(), node);
+        }
+    }
+
+    private ConstantExpression getConstantExpression(Expression exp, ClassNode attrType) {
+        if (exp instanceof ConstantExpression) {
+            return (ConstantExpression) exp;
+        }
+        String base = "Expected '" + exp.getText() + "' to be an inline constant of type " + attrType.getName();
+        if (exp instanceof PropertyExpression) {
+            addError(base + " not a property expression", exp);
+        } else if (exp instanceof VariableExpression && ((VariableExpression)exp).getAccessedVariable() instanceof FieldNode) {
+            addError(base + " not a field expression", exp);
+        } else {
+            addError(base, exp);
+        }
+        return ConstantExpression.EMPTY_EXPRESSION;
+    }
+
+    /**
+     * @param attrName   the name
+     * @param expression the expression
+     * @param attrType   the type
+     */
+    protected void visitAnnotationExpression(String attrName, AnnotationConstantExpression expression, ClassNode attrType) {
+        AnnotationNode annotationNode = (AnnotationNode) expression.getValue();
+        AnnotationVisitor visitor = new AnnotationVisitor(this.source, this.errorCollector);
+        // TODO track Deprecated usage and give a warning?
+        visitor.visit(annotationNode);
+    }
+
+    protected void visitListExpression(String attrName, ListExpression listExpr, ClassNode elementType) {
+        for (Expression expression : listExpr.getExpressions()) {
+            visitExpression(attrName, expression, elementType);
+        }
+    }
+
+    protected void visitConstantExpression(String attrName, ConstantExpression constExpr, ClassNode attrType) {
+        ClassNode constType = constExpr.getType();
+        ClassNode wrapperType = ClassHelper.getWrapper(constType);
+        if (!hasCompatibleType(attrType, wrapperType)) {
+            addError("Attribute '" + attrName + "' should have type '" + attrType.getName()
+                    + "'; but found type '" + constType.getName() + "'", constExpr);
+        }
+    }
+
+    private static boolean hasCompatibleType(ClassNode attrType, ClassNode wrapperType) {
+        return wrapperType.isDerivedFrom(ClassHelper.getWrapper(attrType));
+    }
+
+    protected void visitEnumExpression(String attrName, PropertyExpression propExpr, ClassNode attrType) {
+        if (!propExpr.getObjectExpression().getType().isDerivedFrom(attrType)) {
+            addError("Attribute '" + attrName + "' should have type '" + attrType.getName() + "' (Enum), but found "
+                    + propExpr.getObjectExpression().getType().getName(),
+                    propExpr);
+        }
+    }
+
+    protected void addError(String msg) {
+        addError(msg, this.annotation);
+    }
+
+    protected void addError(String msg, ASTNode expr) {
+        this.errorCollector.addErrorAndContinue(
+                new SyntaxErrorMessage(new SyntaxException(msg + " in @" + this.reportClass.getName() + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), this.source)
+        );
+    }
+
+    public void checkCircularReference(ClassNode searchClass, ClassNode attrType, Expression startExp) {
+        if (!isValidAnnotationClass(attrType)) return;
+        if (!(startExp instanceof AnnotationConstantExpression)) {
+            addError("Found '" + startExp.getText() + "' when expecting an Annotation Constant", startExp);
+            return;
+        }
+        AnnotationConstantExpression ace = (AnnotationConstantExpression) startExp;
+        AnnotationNode annotationNode = (AnnotationNode) ace.getValue();
+        if (annotationNode.getClassNode().equals(searchClass)) {
+            addError("Circular reference discovered in " + searchClass.getName(), startExp);
+            return;
+        }
+        ClassNode cn = annotationNode.getClassNode();
+        for (MethodNode method : cn.getMethods()) {
+            if (method.getReturnType().equals(searchClass)) {
+                addError("Circular reference discovered in " + cn.getName(), startExp);
+            }
+            ReturnStatement code = (ReturnStatement) method.getCode();
+            if (code == null) continue;
+            checkCircularReference(searchClass, method.getReturnType(), code.getExpression());
+        }
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/plugin/GroovyRunnerRegistry.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/plugin/GroovyRunnerRegistry.java b/src/main/java/org/apache/groovy/plugin/GroovyRunnerRegistry.java
new file mode 100644
index 0000000..4ed02e2
--- /dev/null
+++ b/src/main/java/org/apache/groovy/plugin/GroovyRunnerRegistry.java
@@ -0,0 +1,468 @@
+/*
+ *  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.apache.groovy.plugin;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Registry of services that implement the {@link GroovyRunner} interface.
+ * <p>
+ * This registry makes use of the {@link ServiceLoader} facility. The
+ * preferred method for registering new {@link GroovyRunner} providers
+ * is to place them in a provider-configuration file in the resource
+ * directory {@code META-INF/services}. The preferred method for accessing
+ * the registered runners is by making use of the {@code Iterable}
+ * interface using an enhanced for-loop.
+ * <p>
+ * For compatibility with previous versions, this registry implements the
+ * {@link Map} interface. All {@code null} keys and values will be ignored
+ * and no exception thrown, except where noted.
+ * <p>
+ * By default the registry contains runners that are capable of running
+ * {@code JUnit 3} and {@code JUnit 4} test classes if those libraries
+ * are available to the class loader.
+ *
+ * @since 2.5.0
+ */
+public class GroovyRunnerRegistry implements Map<String, GroovyRunner>, Iterable<GroovyRunner> {
+
+    /*
+     * Implementation notes
+     *
+     * GroovySystem stores a static reference to this instance so it is
+     * important to make it fast to create as possible. GroovyRunners are
+     * only used to run scripts that GroovyShell does not already know how
+     * to run so defer service loading until requested via the iterator or
+     * map access methods.
+     *
+     * The Map interface is for compatibility with the original definition
+     * of GroovySystem.RUNNER_REGISTRY. At some point it would probably
+     * make sense to dispense with associating a String key with a runner
+     * and provide register/unregister methods instead of the Map
+     * interface.
+     */
+
+    private static final GroovyRunnerRegistry INSTANCE = new GroovyRunnerRegistry();
+
+    private static final Logger LOG = Logger.getLogger(GroovyRunnerRegistry.class.getName());
+
+    // Lazily initialized and loaded, should be accessed internally using getMap()
+    private volatile Map<String, GroovyRunner> runnerMap;
+
+    /*
+     * Cached unmodifiable List used for iteration. Any method that mutates
+     * the runnerMap must set to null to invalidate the cache. Volatile is
+     * used because reads for DCL are faster than a lock/unlock.
+     * The values are cached in order to speed up iteration and avoid
+     * allocation of new collections on each call to the iterator.
+     */
+    private volatile List<GroovyRunner> cachedValues;
+
+    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
+    private final Lock readLock = rwLock.readLock();
+    private final Lock writeLock = rwLock.writeLock();
+
+    /**
+     * Returns a reference to the one and only registry instance.
+     *
+     * @return registry instance
+     */
+    public static GroovyRunnerRegistry getInstance() {
+        return INSTANCE;
+    }
+
+    // package-private for use in testing to avoid calling ServiceLoader.load
+    GroovyRunnerRegistry(Map<? extends String, ? extends GroovyRunner> runners) {
+        // Preserve insertion order
+        runnerMap = new LinkedHashMap<>();
+        putAll(runners);
+    }
+
+    private GroovyRunnerRegistry() {
+    }
+
+    /**
+     * Lazily initialize and load the backing Map. A {@link LinkedHashMap}
+     * is used to preserve insertion order.
+     * <p>
+     * Do not call while holding a read lock.
+     *
+     * @return backing registry map
+     */
+    private Map<String, GroovyRunner> getMap() {
+        Map<String, GroovyRunner> map = runnerMap;
+        if (map == null) {
+            writeLock.lock();
+            try {
+                if ((map = runnerMap) == null) {
+                    runnerMap = map = new LinkedHashMap<>();
+                    load(null);
+                }
+            } finally {
+                writeLock.unlock();
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Loads {@link GroovyRunner} instances using the {@link ServiceLoader} facility.
+     *
+     * @param classLoader used to locate provider-configuration files and classes
+     */
+    public void load(ClassLoader classLoader) {
+        Map<String, GroovyRunner> map = runnerMap; // direct read
+        if (map == null) {
+            map = getMap(); // initialize and load (recursive call), result ignored
+            if (classLoader == null) {
+                // getMap() already loaded using a null classloader
+                return;
+            }
+        }
+        writeLock.lock();
+        try {
+            if (classLoader == null) {
+                classLoader = Thread.currentThread().getContextClassLoader();
+            }
+            cachedValues = null;
+            loadDefaultRunners();
+            loadWithLock(classLoader);
+        } catch (SecurityException se) {
+            LOG.log(Level.WARNING, "Failed to get the context ClassLoader", se);
+        } catch (ServiceConfigurationError sce) {
+            LOG.log(Level.WARNING, "Failed to load GroovyRunner services from ClassLoader " + classLoader, sce);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    private void loadDefaultRunners() {
+        register(DefaultRunners.junit3TestRunner());
+        register(DefaultRunners.junit3SuiteRunner());
+        register(DefaultRunners.junit4TestRunner());
+    }
+
+    private void loadWithLock(ClassLoader classLoader) {
+        ServiceLoader<GroovyRunner> serviceLoader = ServiceLoader.load(GroovyRunner.class, classLoader);
+        for (GroovyRunner runner : serviceLoader) {
+            register(runner);
+        }
+    }
+
+    /**
+     * Registers the given instance with the registry. This is
+     * equivalent to {@link #put(String, GroovyRunner)} with a
+     * {@code key} being set to {@code runner.getClass().getName()}.
+     *
+     * @param runner the instance to add to the registry
+     */
+    private void register(GroovyRunner runner) {
+        put(runner.getClass().getName(), runner);
+    }
+
+    /**
+     * Returns an iterator for all runners that are registered.
+     * The returned iterator is a snapshot of the registry at
+     * the time the iterator is created. This iterator does not
+     * support removal.
+     *
+     * @return iterator for all registered runners
+     */
+    @Override
+    public Iterator<GroovyRunner> iterator() {
+        return values().iterator();
+    }
+
+    /**
+     * Returns the number of registered runners.
+     *
+     * @return number of registered runners
+     */
+    @Override
+    public int size() {
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            return map.size();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if the registry contains no runners, else
+     * {@code false}.
+     *
+     * @return {@code true} if no runners are registered
+     */
+    @Override
+    public boolean isEmpty() {
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            return map.isEmpty();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if a runner was registered with the
+     * specified key.
+     *
+     * @param key for the registered runner
+     * @return {@code true} if a runner was registered with given key
+     */
+    @Override
+    public boolean containsKey(Object key) {
+        if (key == null) {
+            return false;
+        }
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            return map.containsKey(key);
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if registry contains the given
+     * runner instance.
+     *
+     * @param runner instance of a GroovyRunner
+     * @return {@code true} if the given runner is registered
+     */
+    @Override
+    public boolean containsValue(Object runner) {
+        if (runner == null) {
+            return false;
+        }
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            return map.containsValue(runner);
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the registered runner for the specified key.
+     *
+     * @param key used to lookup the runner
+     * @return the runner registered with the given key
+     */
+    @Override
+    public GroovyRunner get(Object key) {
+        if (key == null) {
+            return null;
+        }
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            return map.get(key);
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Registers a runner with the specified key.
+     *
+     * @param key to associate with the runner
+     * @param runner the runner to register
+     * @return the previously registered runner for the given key,
+     *          if no runner was previously registered for the key
+     *          then {@code null}
+     */
+    @Override
+    public GroovyRunner put(String key, GroovyRunner runner) {
+        if (key == null || runner == null) {
+            return null;
+        }
+        Map<String, GroovyRunner> map = getMap();
+        writeLock.lock();
+        try {
+            cachedValues = null;
+            return map.put(key, runner);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Removes a registered runner from the registry.
+     *
+     * @param key of the runner to remove
+     * @return the runner instance that was removed, if no runner
+     *          instance was removed then {@code null}
+     */
+    @Override
+    public GroovyRunner remove(Object key) {
+        if (key == null) {
+            return null;
+        }
+        Map<String, GroovyRunner> map = getMap();
+        writeLock.lock();
+        try {
+            cachedValues = null;
+            return map.remove(key);
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Adds all entries from the given Map to the registry.
+     * Any entries in the provided Map that contain a {@code null}
+     * key or value will be ignored.
+     *
+     * @param m entries to add to the registry
+     * @throws NullPointerException if the given Map is {@code null}
+     */
+    @Override
+    public void putAll(Map<? extends String, ? extends GroovyRunner> m) {
+        Map<String, GroovyRunner> map = getMap();
+        writeLock.lock();
+        try {
+            cachedValues = null;
+            for (Map.Entry<? extends String, ? extends GroovyRunner> entry : m.entrySet()) {
+                if (entry.getKey() != null && entry.getValue() != null) {
+                    map.put(entry.getKey(), entry.getValue());
+                }
+            }
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Clears all registered runners from the registry and resets
+     * the registry so that it contains only the default set of
+     * runners.
+     */
+    @Override
+    public void clear() {
+        Map<String, GroovyRunner> map = getMap();
+        writeLock.lock();
+        try {
+            cachedValues = null;
+            map.clear();
+            loadDefaultRunners();
+        } finally {
+            writeLock.unlock();
+        }
+    }
+
+    /**
+     * Set of all keys associated with registered runners.
+     * This is a snapshot of the registry and any subsequent
+     * registry changes will not be reflected in the set.
+     *
+     * @return an unmodifiable set of keys for registered runners
+     */
+    @Override
+    public Set<String> keySet() {
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            if (map.isEmpty()) {
+                return Collections.emptySet();
+            }
+            return Collections.unmodifiableSet(new LinkedHashSet<>(map.keySet()));
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    /**
+     * Returns a collection of all registered runners.
+     * This is a snapshot of the registry and any subsequent
+     * registry changes will not be reflected in the collection.
+     *
+     * @return an unmodifiable collection of registered runner instances
+     */
+    @Override
+    public Collection<GroovyRunner> values() {
+        List<GroovyRunner> values = cachedValues;
+        if (values == null) {
+            Map<String, GroovyRunner> map = getMap();
+            // racy, multiple threads may set cachedValues but rather have that than take a write lock
+            readLock.lock();
+            try {
+                if ((values = cachedValues) == null) {
+                    cachedValues = values = Collections.unmodifiableList(new ArrayList<>(map.values()));
+                }
+            } finally {
+                readLock.unlock();
+            }
+        }
+        return values;
+    }
+
+    /**
+     * Returns a set of entries for registered runners.
+     * This is a snapshot of the registry and any subsequent
+     * registry changes will not be reflected in the set.
+     *
+     * @return an unmodifiable set of registered runner entries
+     */
+    @Override
+    public Set<Entry<String, GroovyRunner>> entrySet() {
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            if (map.isEmpty()) {
+                return Collections.emptySet();
+            }
+            return Collections.unmodifiableSet(new LinkedHashSet<>(map.entrySet()));
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    @Override
+    public String toString() {
+        Map<String, GroovyRunner> map = getMap();
+        readLock.lock();
+        try {
+            return map.toString();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java
new file mode 100644
index 0000000..c03515a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionWriter.java
@@ -0,0 +1,328 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.codehaus.groovy.syntax.Types.BITWISE_OR;
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_TO;
+import static org.codehaus.groovy.syntax.Types.LEFT_SHIFT;
+import static org.codehaus.groovy.syntax.Types.LEFT_SQUARE_BRACKET;
+import static org.codehaus.groovy.syntax.Types.MINUS_MINUS;
+import static org.codehaus.groovy.syntax.Types.PLUS;
+import static org.codehaus.groovy.syntax.Types.PLUS_PLUS;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.ICONST_0;
+import static org.objectweb.asm.Opcodes.ICONST_1;
+import static org.objectweb.asm.Opcodes.ICONST_M1;
+import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.IFGE;
+import static org.objectweb.asm.Opcodes.IFGT;
+import static org.objectweb.asm.Opcodes.IFLE;
+import static org.objectweb.asm.Opcodes.IFLT;
+import static org.objectweb.asm.Opcodes.IFNE;
+
+/**
+ * Base class for writing primitive typed operations
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public abstract class BinaryExpressionWriter {
+    
+    private final WriterController controller;
+    private MethodCaller arraySet, arrayGet;
+
+    public BinaryExpressionWriter(WriterController controller, MethodCaller arraySet, MethodCaller arrayGet) {
+        this.controller = controller;
+        this.arraySet = arraySet;
+        this.arrayGet = arrayGet;
+    }
+
+    /**
+     * return writer controller
+     * @since 2.5.0
+     */
+    public WriterController getController() {
+        return controller;
+    }
+    
+    protected static final int[] stdCompareCodes = {
+        IFEQ,      // COMPARE_NOT_EQUAL            120
+        IFNE,      // COMPARE_IDENTICAL            121 
+        IFEQ,      // COMPARE_NOT_IDENTICAL        122
+        IFNE,      // COMPARE_EQUAL                123
+        IFGE,      // COMPARE_LESS_THAN            124
+        IFGT,      // COMPARE_LESS_THAN_EQUAL      125
+        IFLE,      // COMPARE_GREATER_THAN         126
+        IFLT,      // COMPARE_GREATER_THAN_EQUAL   127
+    };
+    
+    protected abstract int getCompareCode();
+
+    /**
+     * writes some int standard operations for compares
+     * @param type the token type
+     * @return true if a successful std operator write
+     */
+    protected boolean writeStdCompare(int type, boolean simulate) {
+        type = type-COMPARE_NOT_EQUAL;
+        // look if really compare
+        if (type<0||type>7) return false;
+
+        if (!simulate) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            OperandStack operandStack = controller.getOperandStack();
+            // operands are on the stack already
+            int bytecode = stdCompareCodes[type];
+            mv.visitInsn(getCompareCode());
+            Label l1 = new Label();
+            mv.visitJumpInsn(bytecode,l1);
+            mv.visitInsn(ICONST_1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            mv.visitLabel(l1);
+            mv.visitInsn(ICONST_0);
+            mv.visitLabel(l2);
+            operandStack.replace(ClassHelper.boolean_TYPE, 2);
+        }
+        return true;
+    }
+    
+    protected abstract void doubleTwoOperands(MethodVisitor mv);
+    protected abstract void removeTwoOperands(MethodVisitor mv);
+    
+    protected boolean writeSpaceship(int type, boolean simulate) {
+        if (type != COMPARE_TO) return false;
+        /*  
+           we will actually do
+         
+          (x < y) ? -1 : ((x == y) ? 0 : 1)
+          which is the essence of what the call with Number would do
+          this compiles to something along
+          
+              <x>
+              <y>
+              LCMP
+              IFGE L1
+              ICONST_M1
+              GOTO L2
+          L1
+              <x>
+              <y>
+              LCMP
+              IFNE L3
+              ICONST_0
+              GOTO L2
+          L3
+              ICONST_1
+          L2
+          
+          since the operators are already on the stack and we don't want
+          to load them again, we will instead duplicate them. This will
+          require some pop actions in the branches!
+          
+              DUP4          (operands: L1L2L1L2)
+              LCMP          
+              IFGE L1       (operands: L1L2)
+              ICONST_M1     (operands: L1L2I)
+              GOTO L2
+          L1
+              -----         (operands: L1L2)
+              LCMP
+              IFNE L3       (operands: -)
+              ICONST_0      (operands: I)
+              GOTO L2
+          L3
+              - jump from L1 branch to here (operands: -)
+              ICONST_1      (operands: I)
+          L2  
+          - if jump from GOTO L2 we have LLI, but need only I
+          - if from L3 branch we get only I
+          
+          this means we have to pop of LL before loading -1
+          
+          since there is no DUP4 we have to do this:
+            DUP2_X1
+            POP2
+            DUP2_X1
+            DUP2_X1
+            POP2
+            DUP2_X1          
+        */
+        if (!simulate) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            // duplicate arguments
+            doubleTwoOperands(mv);
+            
+            Label l1 = new Label();
+            mv.visitInsn(getCompareCode());
+            mv.visitJumpInsn(IFGE,l1);
+            // no jump, so -1, need to pop off surplus LL
+            removeTwoOperands(mv);
+            mv.visitInsn(ICONST_M1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            
+            mv.visitLabel(l1);
+            Label l3 = new Label();
+            mv.visitInsn(getCompareCode());
+            mv.visitJumpInsn(IFNE,l3);
+            mv.visitInsn(ICONST_0);
+            mv.visitJumpInsn(GOTO,l2);
+            
+            mv.visitLabel(l3);
+            mv.visitInsn(ICONST_1);
+            
+            controller.getOperandStack().replace(ClassHelper.int_TYPE, 2);
+        }
+        return true;
+    }
+
+    protected abstract ClassNode getNormalOpResultType();
+    protected abstract int getStandardOperationBytecode(int type);
+    
+    protected boolean writeStdOperators(int type, boolean simulate) {
+        type = type-PLUS;
+        if (type<0 || type>5 || type == 3 /*DIV*/) return false;
+        
+        if (!simulate) {
+            int bytecode = getStandardOperationBytecode(type);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getNormalOpResultType(), 2);
+        }
+        return true;
+    }
+    
+    protected boolean writeDivision(boolean simulate) {
+        if (!supportsDivision()) return false;
+        if (!simulate) {
+            int bytecode = getStandardOperationBytecode(3 /*DIV*/);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getDevisionOpResultType(), 2);
+        }
+        return true;
+    }
+    
+    protected boolean supportsDivision() {
+        return false;
+    }
+
+    protected abstract ClassNode getDevisionOpResultType();
+
+    protected abstract int getBitwiseOperationBytecode(int type);
+    
+    /**
+     * writes some the bitwise operations. type is one of BITWISE_OR, 
+     * BITWISE_AND, BITWISE_XOR
+     * @param type the token type
+     * @return true if a successful bitwise operation write
+     */
+    protected boolean writeBitwiseOp(int type, boolean simulate) {
+        type = type-BITWISE_OR;
+        if (type<0 || type>2) return false;
+
+        if (!simulate) {
+            int bytecode = getBitwiseOperationBytecode(type);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getNormalOpResultType(), 2);
+        }
+        return true;
+    }
+    
+    protected abstract int getShiftOperationBytecode(int type);
+    
+    /**
+     * Write shifting operations.
+     * Type is one of LEFT_SHIFT, RIGHT_SHIFT, or RIGHT_SHIFT_UNSIGNED
+     *
+     * @param type the token type
+     * @return true on a successful shift operation write
+     */
+    protected boolean writeShiftOp(int type, boolean simulate) {
+        type = type - LEFT_SHIFT;
+        if (type < 0 || type > 2) return false;
+
+        if (!simulate) {
+            int bytecode = getShiftOperationBytecode(type);
+            controller.getMethodVisitor().visitInsn(bytecode);
+            controller.getOperandStack().replace(getNormalOpResultType(), 2);
+        }
+        return true;
+    }
+
+    public boolean write(int operation, boolean simulate) {
+        return  writeStdCompare(operation, simulate)         ||
+                writeSpaceship(operation, simulate)          ||
+                writeStdOperators(operation, simulate)       ||
+                writeBitwiseOp(operation, simulate)          ||
+                writeShiftOp(operation, simulate);
+    }
+    
+    protected MethodCaller getArrayGetCaller() {
+        return arrayGet;
+    }
+
+    protected ClassNode getArrayGetResultType(){
+        return getNormalOpResultType();
+    }
+    
+    protected MethodCaller getArraySetCaller() {
+        return arraySet;
+    }
+
+    public void setArraySetAndGet(MethodCaller arraySet, MethodCaller arrayGet) {
+        this.arraySet = arraySet;
+        this.arrayGet = arrayGet;
+    }
+    
+    public boolean arrayGet(int operation, boolean simulate) {
+        if (operation!=LEFT_SQUARE_BRACKET) return false;
+        
+        if (!simulate) {
+            getArrayGetCaller().call(controller.getMethodVisitor());
+        }
+        return true;
+    }
+
+    public boolean arraySet(boolean simulate) {        
+        if (!simulate) {
+            getArraySetCaller().call(controller.getMethodVisitor());
+        }
+        return true;
+    }
+
+    public boolean writePostOrPrefixMethod(int operation, boolean simulate) {
+        if (operation!=PLUS_PLUS && operation!=MINUS_MINUS) return false;
+        if (!simulate) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            if (operation==PLUS_PLUS) {
+                writePlusPlus(mv);
+            } else {
+                writeMinusMinus(mv);
+            }
+        }
+        return true;
+    }
+
+    protected abstract void writePlusPlus(MethodVisitor mv);
+    protected abstract void writeMinusMinus(MethodVisitor mv);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java
new file mode 100644
index 0000000..6a4552a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryFloatExpressionHelper.java
@@ -0,0 +1,111 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.objectweb.asm.Opcodes.DUP2;
+import static org.objectweb.asm.Opcodes.FADD;
+import static org.objectweb.asm.Opcodes.FCMPG;
+import static org.objectweb.asm.Opcodes.FCONST_1;
+import static org.objectweb.asm.Opcodes.FDIV;
+import static org.objectweb.asm.Opcodes.FMUL;
+import static org.objectweb.asm.Opcodes.FREM;
+import static org.objectweb.asm.Opcodes.FSUB;
+import static org.objectweb.asm.Opcodes.POP2;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryFloatExpressionHelper extends BinaryExpressionWriter {
+
+    public BinaryFloatExpressionHelper(WriterController controller) {
+        super(controller, floatArraySet, floatArrayGet);
+    }
+    
+    protected void doubleTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(DUP2);
+    }
+
+    private static final MethodCaller 
+        floatArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "fArrayGet"),
+        floatArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "fArraySet");
+
+    protected boolean writeBitwiseOp(int type, boolean simulate) {
+        if (!simulate) throw new GroovyBugError("should not reach here");
+        return false;   
+    }    
+    
+    protected int getBitwiseOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected int getCompareCode() {
+        return FCMPG;
+    }
+    
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.float_TYPE;
+    }
+    
+    protected boolean writeShiftOp(int type, boolean simulate) {
+        if (!simulate) throw new GroovyBugError("should not reach here");
+        return false;   
+    }    
+    
+    protected int getShiftOperationBytecode(int type) {
+        return -1;
+    }
+
+    private static final int[] stdOperations = {
+        FADD,           //  PLUS        200
+        FSUB,           //  MINUS       201
+        FMUL,           //  MULTIPLY    202
+        0,              //  DIV, (203) but we don't want that one
+        FDIV,           //  INTDIV      204
+        FREM,           //  MOD         203
+    };    
+    
+    protected int getStandardOperationBytecode(int type) {
+        return stdOperations[type];
+    }
+    
+    protected void removeTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(POP2);
+    }
+    
+    protected void writeMinusMinus(MethodVisitor mv) {
+        mv.visitInsn(FCONST_1);
+        mv.visitInsn(FSUB);
+    }
+    
+    protected void writePlusPlus(MethodVisitor mv) {
+        mv.visitInsn(FCONST_1);
+        mv.visitInsn(FADD);
+    }
+
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.BigDecimal_TYPE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java
new file mode 100644
index 0000000..dfa1245
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryIntExpressionHelper.java
@@ -0,0 +1,293 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_TO;
+import static org.objectweb.asm.Opcodes.DUP2;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IADD;
+import static org.objectweb.asm.Opcodes.IAND;
+import static org.objectweb.asm.Opcodes.ICONST_0;
+import static org.objectweb.asm.Opcodes.ICONST_1;
+import static org.objectweb.asm.Opcodes.ICONST_M1;
+import static org.objectweb.asm.Opcodes.IDIV;
+import static org.objectweb.asm.Opcodes.IF_ICMPEQ;
+import static org.objectweb.asm.Opcodes.IF_ICMPGE;
+import static org.objectweb.asm.Opcodes.IF_ICMPGT;
+import static org.objectweb.asm.Opcodes.IF_ICMPLE;
+import static org.objectweb.asm.Opcodes.IF_ICMPLT;
+import static org.objectweb.asm.Opcodes.IF_ICMPNE;
+import static org.objectweb.asm.Opcodes.IMUL;
+import static org.objectweb.asm.Opcodes.IOR;
+import static org.objectweb.asm.Opcodes.IREM;
+import static org.objectweb.asm.Opcodes.ISHL;
+import static org.objectweb.asm.Opcodes.ISHR;
+import static org.objectweb.asm.Opcodes.ISUB;
+import static org.objectweb.asm.Opcodes.IUSHR;
+import static org.objectweb.asm.Opcodes.IXOR;
+import static org.objectweb.asm.Opcodes.POP2;
+
+public class BinaryIntExpressionHelper extends BinaryExpressionWriter {
+    
+    private static final MethodCaller intArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "intArrayGet");
+    private static final MethodCaller intArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "intArraySet");
+
+    private static final int[] stdCompareCodes = {
+        IF_ICMPEQ,      // COMPARE_NOT_EQUAL            120
+        IF_ICMPNE,      // COMPARE_IDENTICAL            121 
+        IF_ICMPEQ,      // COMPARE_NOT_IDENTICAL        122
+        IF_ICMPNE,      // COMPARE_EQUAL                123
+        IF_ICMPGE,      // COMPARE_LESS_THAN            124
+        IF_ICMPGT,      // COMPARE_LESS_THAN_EQUAL      125
+        IF_ICMPLE,      // COMPARE_GREATER_THAN         126
+        IF_ICMPLT,      // COMPARE_GREATER_THAN_EQUAL   127
+    };
+    
+    private static final int[] stdOperations = {
+        IADD,           //  PLUS        200
+        ISUB,           //  MINUS       201
+        IMUL,           //  MULTIPLY    202
+        IDIV,           //  DIV         203
+        IDIV,           //  INTDIV      204
+        IREM,           //  MOD         203
+    };
+    
+    private static final int[] bitOp = {
+        IOR,            //  BITWISE_OR / PIPE   340
+        IAND,           //  BITWISE_AND         341
+        IXOR,           //  BIWISE_XOR          342
+    };    
+    
+    /* unhandled types from from org.codehaus.groovy.syntax.Types
+    public static final int LOGICAL_OR                  = 162;   // ||
+    public static final int LOGICAL_AND                 = 164;   // &&
+
+    public static final int DIVIDE                      = 203;   // /
+    public static final int STAR_STAR                   = 206;   // **
+    public static final int POWER                       = STAR_STAR;   //
+    
+    public static final int PLUS_EQUAL                  = 210;   // +=
+    public static final int MINUS_EQUAL                 = 211;   // -=
+    public static final int MULTIPLY_EQUAL              = 212;   // *=
+    public static final int DIVIDE_EQUAL                = 213;   // /=
+    public static final int INTDIV_EQUAL                = 214;   // \=
+    public static final int MOD_EQUAL                   = 215;   // %=
+    public static final int POWER_EQUAL                 = 216;   // **=
+
+    public static final int PLUS_PLUS                   = 250;   // ++
+    public static final int PREFIX_PLUS_PLUS            = 251;   // ++
+    public static final int POSTFIX_PLUS_PLUS           = 252;   // ++
+    public static final int PREFIX_PLUS                 = 253;   // +
+
+    public static final int MINUS_MINUS                 = 260;   // --
+    public static final int PREFIX_MINUS_MINUS          = 261;   // --
+    public static final int POSTFIX_MINUS_MINUS         = 262;   // --
+    public static final int PREFIX_MINUS                = 263;   // - (negation)
+*/
+    private static final int[] shiftOp = {
+        ISHL,           // LEFT_SHIFT               280
+        ISHR,           // RIGHT_SHIFT              281
+        IUSHR           // RIGHT_SHIFT_UNSIGNED     282
+    };
+
+/*
+    public static final int LEFT_SHIFT_EQUAL            = 285;   // <<=
+    public static final int RIGHT_SHIFT_EQUAL           = 286;   // >>=
+    public static final int RIGHT_SHIFT_UNSIGNED_EQUAL  = 287;   // >>>=
+
+    public static final int BITWISE_OR_EQUAL            = 350;   // |=
+    public static final int BITWISE_AND_EQUAL           = 351;   // &=
+    public static final int BITWISE_XOR_EQUAL           = 352;   // ^=
+    public static final int BITWISE_NEGATION            = REGEX_PATTERN;    // ~
+    */
+    
+    public BinaryIntExpressionHelper(WriterController wc) {
+        this(wc, intArraySet, intArrayGet);
+    }
+
+    /**
+     * @since 2.5.0
+     */
+    public BinaryIntExpressionHelper(WriterController wc, MethodCaller arraySet, MethodCaller arrayGet) {
+        super(wc, arraySet, arrayGet);
+    }
+
+    
+    /**
+     * writes a std compare. This involves the tokens IF_ICMPEQ, IF_ICMPNE, 
+     * IF_ICMPEQ, IF_ICMPNE, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE and IF_ICMPLT
+     * @param type the token type
+     * @return true if a successful std compare write
+     */
+    protected boolean writeStdCompare(int type, boolean simulate) {
+        type = type-COMPARE_NOT_EQUAL;
+        // look if really compare
+        if (type<0||type>7) return false;
+
+        if (!simulate) {
+            MethodVisitor mv = getController().getMethodVisitor();
+            OperandStack operandStack = getController().getOperandStack();
+            // operands are on the stack already
+            int bytecode = stdCompareCodes[type];
+            Label l1 = new Label();
+            mv.visitJumpInsn(bytecode,l1);
+            mv.visitInsn(ICONST_1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            mv.visitLabel(l1);
+            mv.visitInsn(ICONST_0);
+            mv.visitLabel(l2);
+            operandStack.replace(ClassHelper.boolean_TYPE, 2);
+        }
+        return true;
+    }
+    
+    /**
+     * writes the spaceship operator, type should be COMPARE_TO
+     * @param type the token type
+     * @return true if a successful spaceship operator write
+     */
+    protected boolean writeSpaceship(int type, boolean simulate) {
+        if (type != COMPARE_TO) return false;
+        /*  
+           we will actually do
+         
+          (x < y) ? -1 : ((x == y) ? 0 : 1)
+          which is the essence of what the call with Integers would do
+          this compiles to something along
+          
+              <x>
+              <y>
+              IF_ICMPGE L1
+              ICONST_M1
+              GOTO L2
+          L1
+              <x>
+              <y>
+              IF_ICMPNE L3
+              ICONST_0
+              GOTO L2
+          L3
+              ICONST_1
+          L2
+          
+          since the operators are already on the stack and we don't want
+          to load them again, we will instead duplicate them. This will
+          require some pop actions in the branches!
+          
+              DUP2          (operands: IIII) 
+              IF_ICMPGE L1  (operands: II)
+              ICONST_M1     (operands: III)
+              GOTO L2
+          L1
+              -----         (operands: II)
+              IF_ICMPNE L3  (operands: -)
+              ICONST_0      (operands: I)
+              GOTO L2
+          L3
+              - jump from L1 branch to here (operands: -)
+              ICONST_1      (operands: I)
+          L2  
+          - if jump from GOTO L2 we have III, but need only I
+          - if from L3 branch we get only I
+          
+          this means we have to pop of II before loading -1
+          
+        */
+        if (!simulate) {
+            MethodVisitor mv = getController().getMethodVisitor();
+            // duplicate int arguments
+            mv.visitInsn(DUP2);
+            
+            Label l1 = new Label();
+            mv.visitJumpInsn(IF_ICMPGE,l1);
+            // no jump, so -1, need to pop off surplus II
+            mv.visitInsn(POP2);
+            mv.visitInsn(ICONST_M1);
+            Label l2 = new Label();
+            mv.visitJumpInsn(GOTO, l2);
+            
+            mv.visitLabel(l1);
+            Label l3 = new Label();
+            mv.visitJumpInsn(IF_ICMPNE,l3);
+            mv.visitInsn(ICONST_0);
+            mv.visitJumpInsn(GOTO,l2);
+            
+            mv.visitLabel(l3);
+            mv.visitInsn(ICONST_1);
+
+            getController().getOperandStack().replace(ClassHelper.int_TYPE, 2);
+        }
+        return true;
+    }
+
+    protected void doubleTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(DUP2);
+    }
+
+    protected int getBitwiseOperationBytecode(int type) {
+        return bitOp[type];
+    }
+
+    protected int getCompareCode() {
+        return -1;
+    }
+
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.int_TYPE;
+    }
+
+    protected int getShiftOperationBytecode(int type) {
+        return shiftOp[type];
+    }
+
+    protected int getStandardOperationBytecode(int type) {
+        return stdOperations[type];
+    }
+
+    protected void removeTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(POP2);
+    }
+
+    protected void writeMinusMinus(MethodVisitor mv) {
+        mv.visitInsn(ICONST_1);
+        mv.visitInsn(ISUB);
+    }
+
+    protected void writePlusPlus(MethodVisitor mv) {
+        mv.visitInsn(ICONST_1);
+        mv.visitInsn(IADD);
+    }
+
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.int_TYPE;
+    }
+
+    @Override
+    protected boolean supportsDivision() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java
new file mode 100644
index 0000000..8bfaf98
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryLongExpressionHelper.java
@@ -0,0 +1,144 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.objectweb.asm.Opcodes.DUP2_X1;
+import static org.objectweb.asm.Opcodes.LADD;
+import static org.objectweb.asm.Opcodes.LAND;
+import static org.objectweb.asm.Opcodes.LCMP;
+import static org.objectweb.asm.Opcodes.LCONST_1;
+import static org.objectweb.asm.Opcodes.LDIV;
+import static org.objectweb.asm.Opcodes.LMUL;
+import static org.objectweb.asm.Opcodes.LOR;
+import static org.objectweb.asm.Opcodes.LREM;
+import static org.objectweb.asm.Opcodes.LSHL;
+import static org.objectweb.asm.Opcodes.LSHR;
+import static org.objectweb.asm.Opcodes.LSUB;
+import static org.objectweb.asm.Opcodes.LUSHR;
+import static org.objectweb.asm.Opcodes.LXOR;
+import static org.objectweb.asm.Opcodes.POP2;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryLongExpressionHelper extends BinaryExpressionWriter {
+
+    /**
+     * @since 2.5.0
+     */
+    public BinaryLongExpressionHelper(WriterController controller, MethodCaller arraySet, MethodCaller arrayGet) {
+        super(controller, arraySet, arrayGet);
+    }
+
+    public BinaryLongExpressionHelper(WriterController controller) {
+        this(controller, longArraySet, longArrayGet);
+    }
+
+    protected void doubleTwoOperands(MethodVisitor mv) {
+        /*
+            since there is no DUP4 we have to do this:
+            DUP2_X1
+            POP2
+            DUP2_X1
+            DUP2_X1
+            POP2
+            DUP2_X1          
+         */
+        mv.visitInsn(DUP2_X1);
+        mv.visitInsn(POP2);
+        mv.visitInsn(DUP2_X1);
+        mv.visitInsn(DUP2_X1);
+        mv.visitInsn(POP2);
+        mv.visitInsn(DUP2_X1);
+    }
+
+    protected void removeTwoOperands(MethodVisitor mv) {
+        mv.visitInsn(POP2);
+        mv.visitInsn(POP2);
+    }
+
+    private static final MethodCaller 
+        longArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "lArrayGet"),
+        longArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "lArraySet");
+
+    private static final int[] bitOp = {
+        LOR,            //  BITWISE_OR / PIPE   340
+        LAND,           //  BITWISE_AND         341
+        LXOR,           //  BIWISE_XOR          342
+    };
+
+    protected int getBitwiseOperationBytecode(int type) {
+        return bitOp[type];
+    }
+
+    protected int getCompareCode() {
+        return LCMP;
+    }
+
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.long_TYPE;
+    }
+
+    private static final int[] shiftOp = {
+        LSHL,           // LEFT_SHIFT               280
+        LSHR,           // RIGHT_SHIFT              281
+        LUSHR           // RIGHT_SHIFT_UNSIGNED     282
+    };
+    
+    protected int getShiftOperationBytecode(int type) {
+        return shiftOp[type];
+    }
+
+    private static final int[] stdOperations = {
+        LADD,           //  PLUS        200
+        LSUB,           //  MINUS       201
+        LMUL,           //  MULTIPLY    202
+        LDIV,           //  DIV         203
+        LDIV,           //  INTDIV      204
+        LREM,           //  MOD         203
+    };
+    
+    protected int getStandardOperationBytecode(int type) {
+        return stdOperations[type];
+    }
+
+    protected void writeMinusMinus(MethodVisitor mv) {
+        mv.visitInsn(LCONST_1);
+        mv.visitInsn(LSUB);
+    }
+
+    protected void writePlusPlus(MethodVisitor mv) {
+        mv.visitInsn(LCONST_1);
+        mv.visitInsn(LADD);
+    }
+
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.long_TYPE;
+    }
+
+    @Override
+    protected boolean supportsDivision() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java
new file mode 100644
index 0000000..31350d5
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryObjectExpressionHelper.java
@@ -0,0 +1,87 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryObjectExpressionHelper extends BinaryExpressionWriter {
+    private static final MethodCaller arrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "objectArrayGet");
+    private static final MethodCaller arraySet = MethodCaller.newStatic(BytecodeInterface8.class, "objectArraySet");
+
+    public BinaryObjectExpressionHelper(WriterController controller) {
+        super(controller, arraySet, arrayGet);
+    }
+    
+    // dummy methods
+    public boolean writePostOrPrefixMethod(int operation, boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+    
+    public boolean write(int operation, boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+    
+    protected boolean writeDivision(boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+
+    protected int getBitwiseOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected int getCompareCode() {
+        return -1;
+    }
+    
+    protected ClassNode getNormalOpResultType() {
+        return null;
+    }
+    
+    protected ClassNode getDevisionOpResultType() {
+        return null;
+    }
+    
+    protected int getShiftOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected int getStandardOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected void removeTwoOperands(MethodVisitor mv) {}
+    protected void writePlusPlus(MethodVisitor mv) {}
+    protected void writeMinusMinus(MethodVisitor mv) {}
+    protected void doubleTwoOperands(MethodVisitor mv) {}
+    
+    @Override
+    protected ClassNode getArrayGetResultType() {
+    	return ClassHelper.OBJECT_TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
new file mode 100644
index 0000000..935020f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
@@ -0,0 +1,52 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.control.BytecodeProcessor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.util.TraceClassVisitor;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * An utility class which can be used in test cases to dump generated bytecode.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public class BytecodeDumper implements BytecodeProcessor {
+    public static final BytecodeDumper STANDARD_ERR = new BytecodeDumper(new PrintWriter(System.err));
+
+    private final Writer out;
+
+    public BytecodeDumper(final Writer out) {
+        this.out = out;
+    }
+
+    @Override
+    public byte[] processBytecode(final String name, final byte[] original) {
+        PrintWriter pw = out instanceof PrintWriter ? (PrintWriter) out : new PrintWriter(out);
+        TraceClassVisitor visitor = new TraceClassVisitor(pw);
+        ClassReader reader = new ClassReader(original);
+        reader.accept(visitor, 0);
+        return original;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
new file mode 100644
index 0000000..d9eea08
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
@@ -0,0 +1,751 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Modifier;
+
+/**
+ * A helper class for bytecode generation with AsmClassGenerator.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class BytecodeHelper implements Opcodes {
+    
+    private static String DTT_CLASSNAME = BytecodeHelper.getClassInternalName(DefaultTypeTransformation.class.getName());
+
+    public static String getClassInternalName(ClassNode t) {
+        if (t.isPrimaryClassNode() || t instanceof DecompiledClassNode) {
+            if (t.isArray()) return "[L"+getClassInternalName(t.getComponentType())+";";
+            return getClassInternalName(t.getName());
+        }
+        return getClassInternalName(t.getTypeClass());
+    }
+
+    public static String getClassInternalName(Class t) {
+        return org.objectweb.asm.Type.getInternalName(t);
+    }
+
+    /**
+     * @return the ASM internal name of the type
+     */
+    public static String getClassInternalName(String name) {
+        return name.replace('.', '/');
+    }
+
+    public static String getMethodDescriptor(ClassNode returnType, Parameter[] parameters) {
+        StringBuilder buffer = new StringBuilder("(");
+        for (int i = 0; i < parameters.length; i++) {
+            buffer.append(getTypeDescription(parameters[i].getType()));
+        }
+        buffer.append(")");
+        buffer.append(getTypeDescription(returnType));
+        return buffer.toString();
+    }
+
+    /**
+     * Returns a method descriptor for the given {@link org.codehaus.groovy.ast.MethodNode}.
+     *
+     * @param methodNode the method node for which to create the descriptor
+     * @return a method descriptor as defined in section JVMS section 4.3.3
+     */
+    public static String getMethodDescriptor(MethodNode methodNode) {
+        return getMethodDescriptor(methodNode.getReturnType(), methodNode.getParameters());
+    }
+    
+    /**
+     * @return the ASM method type descriptor
+     */
+    public static String getMethodDescriptor(Class returnType, Class[] paramTypes) {
+        // lets avoid class loading
+        StringBuilder buffer = new StringBuilder("(");
+        for (int i = 0; i < paramTypes.length; i++) {
+            buffer.append(getTypeDescription(paramTypes[i]));
+        }
+        buffer.append(")");
+        buffer.append(getTypeDescription(returnType));
+        return buffer.toString();
+    }
+
+    public static String getTypeDescription(Class c) {
+        return org.objectweb.asm.Type.getDescriptor(c);
+    }
+
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava.lang.String;
+     * Object:   classname: java.lang.Object
+     * int[] :   classname: [I
+     * unlike getTypeDescription '.' is not replaced by '/'.
+     * it seems that makes problems for
+     * the class loading if '.' is replaced by '/'
+     *
+     * @return the ASM type description for class loading
+     */
+    public static String getClassLoadingTypeDescription(ClassNode c) {
+        StringBuilder buf = new StringBuilder();
+        boolean array = false;
+        while (true) {
+            if (c.isArray()) {
+                buf.append('[');
+                c = c.getComponentType();
+                array = true;
+            } else {
+                if (ClassHelper.isPrimitiveType(c)) {
+                    buf.append(getTypeDescription(c));
+                } else {
+                    if (array) buf.append('L');
+                    buf.append(c.getName());
+                    if (array) buf.append(';');
+                }
+                return buf.toString();
+            }
+        }
+    }
+
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava/lang/String;
+     * int[]: [I
+     *
+     * @return the ASM type description
+     */
+    public static String getTypeDescription(ClassNode c) {
+        return getTypeDescription(c, true);
+    }
+
+    /**
+     * array types are special:
+     * eg.: String[]: classname: [Ljava/lang/String;
+     * int[]: [I
+     *
+     * @return the ASM type description
+     */
+    private static String getTypeDescription(ClassNode c, boolean end) {
+        StringBuilder buf = new StringBuilder();
+        ClassNode d = c;
+        while (true) {
+            if (ClassHelper.isPrimitiveType(d.redirect())) {
+                d = d.redirect();
+                char car;
+                if (d == ClassHelper.int_TYPE) {
+                    car = 'I';
+                } else if (d == ClassHelper.VOID_TYPE) {
+                    car = 'V';
+                } else if (d == ClassHelper.boolean_TYPE) {
+                    car = 'Z';
+                } else if (d == ClassHelper.byte_TYPE) {
+                    car = 'B';
+                } else if (d == ClassHelper.char_TYPE) {
+                    car = 'C';
+                } else if (d == ClassHelper.short_TYPE) {
+                    car = 'S';
+                } else if (d == ClassHelper.double_TYPE) {
+                    car = 'D';
+                } else if (d == ClassHelper.float_TYPE) {
+                    car = 'F';
+                } else /* long */ {
+                    car = 'J';
+                }
+                buf.append(car);
+                return buf.toString();
+            } else if (d.isArray()) {
+                buf.append('[');
+                d = d.getComponentType();
+            } else {
+                buf.append('L');
+                String name = d.getName();
+                int len = name.length();
+                for (int i = 0; i < len; ++i) {
+                    char car = name.charAt(i);
+                    buf.append(car == '.' ? '/' : car);
+                }
+                if (end) buf.append(';');
+                return buf.toString();
+            }
+        }
+    }
+
+    /**
+     * @return an array of ASM internal names of the type
+     */
+    public static String[] getClassInternalNames(ClassNode[] names) {
+        int size = names.length;
+        String[] answer = new String[size];
+        for (int i = 0; i < size; i++) {
+            answer[i] = getClassInternalName(names[i]);
+        }
+        return answer;
+    }
+
+    public static void pushConstant(MethodVisitor mv, int value) {
+        switch (value) {
+            case 0:
+                mv.visitInsn(ICONST_0);
+                break;
+            case 1:
+                mv.visitInsn(ICONST_1);
+                break;
+            case 2:
+                mv.visitInsn(ICONST_2);
+                break;
+            case 3:
+                mv.visitInsn(ICONST_3);
+                break;
+            case 4:
+                mv.visitInsn(ICONST_4);
+                break;
+            case 5:
+                mv.visitInsn(ICONST_5);
+                break;
+            default:
+                if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
+                    mv.visitIntInsn(BIPUSH, value);
+                } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
+                    mv.visitIntInsn(SIPUSH, value);
+                } else {
+                    mv.visitLdcInsn(Integer.valueOf(value));
+                }
+        }
+    }
+    
+    /**
+     * negate a boolean on stack. true->false, false->true
+     */
+    public static void negateBoolean(MethodVisitor mv) {
+        // code to negate the primitive boolean
+        Label endLabel = new Label();
+        Label falseLabel = new Label();
+        mv.visitJumpInsn(IFNE, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, endLabel);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(endLabel);
+    }
+
+    /**
+     * load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
+     *
+     * @param msg
+     */
+    /*public void mark(String msg) {
+        mv.visitLdcInsn(msg);
+        mv.visitInsn(POP);
+    }*/
+
+    /**
+     * returns a name that Class.forName() can take. Notably for arrays:
+     * [I, [Ljava.lang.String; etc
+     * Regular object type:  java.lang.String
+     *
+     * @param name
+     */
+    public static String formatNameForClassLoading(String name) {
+        if (name == null) {
+            return "java.lang.Object;";
+        }
+
+        if (name.equals("int")
+                || name.equals("long")
+                || name.equals("short")
+                || name.equals("float")
+                || name.equals("double")
+                || name.equals("byte")
+                || name.equals("char")
+                || name.equals("boolean")
+                || name.equals("void")
+                ) {
+            return name;
+        }
+
+        if (name.startsWith("[")) {
+            return name.replace('/', '.');
+        }
+
+        if (name.startsWith("L")) {
+            name = name.substring(1);
+            if (name.endsWith(";")) {
+                name = name.substring(0, name.length() - 1);
+            }
+            return name.replace('/', '.');
+        }
+
+        String prefix = "";
+        if (name.endsWith("[]")) { // todo need process multi
+            prefix = "[";
+            name = name.substring(0, name.length() - 2);
+            if (name.equals("int")) {
+                return prefix + "I";
+            } else if (name.equals("long")) {
+                return prefix + "J";
+            } else if (name.equals("short")) {
+                return prefix + "S";
+            } else if (name.equals("float")) {
+                return prefix + "F";
+            } else if (name.equals("double")) {
+                return prefix + "D";
+            } else if (name.equals("byte")) {
+                return prefix + "B";
+            } else if (name.equals("char")) {
+                return prefix + "C";
+            } else if (name.equals("boolean")) {
+                return prefix + "Z";
+            } else {
+                return prefix + "L" + name.replace('/', '.') + ";";
+            }
+        }
+        return name.replace('/', '.');
+
+    }
+
+    /*public void dup() {
+        mv.visitInsn(DUP);
+    }*/
+
+    public static void doReturn(MethodVisitor mv, ClassNode returnType) {
+        if (returnType == ClassHelper.double_TYPE) {
+            mv.visitInsn(DRETURN);
+        } else if (returnType == ClassHelper.float_TYPE) {
+            mv.visitInsn(FRETURN);
+        } else if (returnType == ClassHelper.long_TYPE) {
+            mv.visitInsn(LRETURN);
+        } else if (
+                returnType == ClassHelper.boolean_TYPE
+                        || returnType == ClassHelper.char_TYPE
+                        || returnType == ClassHelper.byte_TYPE
+                        || returnType == ClassHelper.int_TYPE
+                        || returnType == ClassHelper.short_TYPE) {
+            //byte,short,boolean,int are all IRETURN
+            mv.visitInsn(IRETURN);
+        } else if (returnType == ClassHelper.VOID_TYPE) {
+            mv.visitInsn(RETURN);
+        } else {
+            mv.visitInsn(ARETURN);
+        }
+
+    }
+
+    private static boolean hasGenerics(Parameter[] param) {
+        if (param.length == 0) return false;
+        for (int i = 0; i < param.length; i++) {
+            ClassNode type = param[i].getType();
+            if (hasGenerics(type)) return true;
+        }
+        return false;
+    }
+
+    private static boolean hasGenerics(ClassNode type) {
+        return type.isArray() ? hasGenerics(type.getComponentType()) : type.getGenericsTypes() != null;
+    }
+
+    public static String getGenericsMethodSignature(MethodNode node) {
+        GenericsType[] generics = node.getGenericsTypes();
+        Parameter[] param = node.getParameters();
+        ClassNode returnType = node.getReturnType();
+
+        if (generics == null && !hasGenerics(param) && !hasGenerics(returnType)) return null;
+
+        StringBuilder ret = new StringBuilder(100);
+        getGenericsTypeSpec(ret, generics);
+
+        GenericsType[] paramTypes = new GenericsType[param.length];
+        for (int i = 0; i < param.length; i++) {
+            ClassNode pType = param[i].getType();
+            if (pType.getGenericsTypes() == null || !pType.isGenericsPlaceHolder()) {
+                paramTypes[i] = new GenericsType(pType);
+            } else {
+                paramTypes[i] = pType.getGenericsTypes()[0];
+            }
+        }
+        addSubTypes(ret, paramTypes, "(", ")");
+        addSubTypes(ret, new GenericsType[]{new GenericsType(returnType)}, "", "");
+        return ret.toString();
+    }
+
+    private static boolean usesGenericsInClassSignature(ClassNode node) {
+        if (!node.isUsingGenerics()) return false;
+        if (hasGenerics(node)) return true;
+        ClassNode sclass = node.getUnresolvedSuperClass(false);
+        if (sclass.isUsingGenerics()) return true;
+        ClassNode[] interfaces = node.getInterfaces();
+        if (interfaces != null) {
+            for (int i = 0; i < interfaces.length; i++) {
+                if (interfaces[i].isUsingGenerics()) return true;
+            }
+        }
+
+        return false;
+    }
+
+    public static String getGenericsSignature(ClassNode node) {
+        if (!usesGenericsInClassSignature(node)) return null;
+        GenericsType[] genericsTypes = node.getGenericsTypes();
+        StringBuilder ret = new StringBuilder(100);
+        getGenericsTypeSpec(ret, genericsTypes);
+        GenericsType extendsPart = new GenericsType(node.getUnresolvedSuperClass(false));
+        writeGenericsBounds(ret, extendsPart, true);
+        ClassNode[] interfaces = node.getInterfaces();
+        for (int i = 0; i < interfaces.length; i++) {
+            GenericsType interfacePart = new GenericsType(interfaces[i]);
+            writeGenericsBounds(ret, interfacePart, false);
+        }
+        return ret.toString();
+    }
+
+    private static void getGenericsTypeSpec(StringBuilder ret, GenericsType[] genericsTypes) {
+        if (genericsTypes == null) return;
+        ret.append('<');
+        for (int i = 0; i < genericsTypes.length; i++) {
+            String name = genericsTypes[i].getName();
+            ret.append(name);
+            ret.append(':');
+            writeGenericsBounds(ret, genericsTypes[i], true);
+        }
+        ret.append('>');
+    }
+
+    public static String getGenericsBounds(ClassNode type) {
+        GenericsType[] genericsTypes = type.getGenericsTypes();
+        if (genericsTypes == null) return null;
+        StringBuilder ret = new StringBuilder(100);
+        if (type.isGenericsPlaceHolder()) {
+            addSubTypes(ret, type.getGenericsTypes(), "", "");
+        } else {
+            GenericsType gt = new GenericsType(type);
+            writeGenericsBounds(ret, gt, false);
+        }
+
+        return ret.toString();
+    }
+
+    private static void writeGenericsBoundType(StringBuilder ret, ClassNode printType, boolean writeInterfaceMarker) {
+        if (writeInterfaceMarker && printType.isInterface()) ret.append(":");
+        if (printType.isGenericsPlaceHolder() && printType.getGenericsTypes()!=null) {
+            ret.append("T");
+            ret.append(printType.getGenericsTypes()[0].getName());
+            ret.append(";");
+        }
+        else {
+            ret.append(getTypeDescription(printType, false));
+            addSubTypes(ret, printType.getGenericsTypes(), "<", ">");
+            if (!ClassHelper.isPrimitiveType(printType)) ret.append(";");
+        }
+    }
+
+    private static void writeGenericsBounds(StringBuilder ret, GenericsType type, boolean writeInterfaceMarker) {
+        if (type.getUpperBounds() != null) {
+            ClassNode[] bounds = type.getUpperBounds();
+            for (int i = 0; i < bounds.length; i++) {
+                writeGenericsBoundType(ret, bounds[i], writeInterfaceMarker);
+            }
+        } else if (type.getLowerBound() != null) {
+            writeGenericsBoundType(ret, type.getLowerBound(), writeInterfaceMarker);
+        } else {
+            writeGenericsBoundType(ret, type.getType(), writeInterfaceMarker);
+        }
+    }
+
+    private static void addSubTypes(StringBuilder ret, GenericsType[] types, String start, String end) {
+        if (types == null) return;
+        ret.append(start);
+        for (int i = 0; i < types.length; i++) {
+            if (types[i].getType().isArray()) {
+                ret.append("[");
+                addSubTypes(ret, new GenericsType[]{new GenericsType(types[i].getType().getComponentType())}, "", "");
+            }
+            else {
+                if (types[i].isPlaceholder()) {
+                    ret.append('T');
+                    String name = types[i].getName();
+                    ret.append(name);
+                    ret.append(';');
+                } else if (types[i].isWildcard()) {
+                    if (types[i].getUpperBounds() != null) {
+                        ret.append('+');
+                        writeGenericsBounds(ret, types[i], false);
+                    } else if (types[i].getLowerBound() != null) {
+                        ret.append('-');
+                        writeGenericsBounds(ret, types[i], false);
+                    } else {
+                        ret.append('*');
+                    }
+                } else {
+                    writeGenericsBounds(ret, types[i], false);
+                }
+            }
+        }
+        ret.append(end);
+    }
+
+    public static void load(MethodVisitor mv, ClassNode type, int idx) {
+        if (type == ClassHelper.double_TYPE) {
+            mv.visitVarInsn(DLOAD, idx);
+        } else if (type == ClassHelper.float_TYPE) {
+            mv.visitVarInsn(FLOAD, idx);
+        } else if (type == ClassHelper.long_TYPE) {
+            mv.visitVarInsn(LLOAD, idx);
+        } else if (
+                type == ClassHelper.boolean_TYPE
+                        || type == ClassHelper.char_TYPE
+                        || type == ClassHelper.byte_TYPE
+                        || type == ClassHelper.int_TYPE
+                        || type == ClassHelper.short_TYPE) {
+            mv.visitVarInsn(ILOAD, idx);
+        } else {
+            mv.visitVarInsn(ALOAD, idx);
+        }
+    }
+    
+
+    public static void doCast(MethodVisitor mv, ClassNode type) {
+        if (type == ClassHelper.OBJECT_TYPE) return;
+        if (ClassHelper.isPrimitiveType(type) && type != ClassHelper.VOID_TYPE) {
+            unbox(mv, type);
+        } else {
+            mv.visitTypeInsn(
+                    CHECKCAST,
+                    type.isArray() ? 
+                            BytecodeHelper.getTypeDescription(type) : 
+                            BytecodeHelper.getClassInternalName(type.getName()));
+        }
+    }
+
+    /**
+     * Given a wrapped number type (Byte, Integer, Short, ...), generates bytecode
+     * to convert it to a primitive number (int, long, double) using calls to
+     * wrapped.[targetType]Value()
+     * @param mv method visitor
+     * @param sourceType the wrapped number type
+     * @param targetType the primitive target type
+     */
+    public static void doCastToPrimitive(MethodVisitor mv, ClassNode sourceType, ClassNode targetType) {
+        mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(sourceType), targetType.getName() + "Value", "()" + BytecodeHelper.getTypeDescription(targetType), false);
+    }
+
+    /**
+     * Given a primitive number type (byte, integer, short, ...), generates bytecode
+     * to convert it to a wrapped number (Integer, Long, Double) using calls to
+     * [WrappedType].valueOf
+     * @param mv method visitor
+     * @param sourceType the primitive number type
+     * @param targetType the wrapped target type
+     */
+    public static void doCastToWrappedType(MethodVisitor mv, ClassNode sourceType, ClassNode targetType) {
+        mv.visitMethodInsn(INVOKESTATIC, getClassInternalName(targetType), "valueOf", "(" + getTypeDescription(sourceType) + ")" + getTypeDescription(targetType), false);
+    }
+
+    public static void doCast(MethodVisitor mv, Class type) {
+        if (type == Object.class) return;
+        if (type.isPrimitive() && type != Void.TYPE) {
+            unbox(mv, type);
+        } else {
+            mv.visitTypeInsn(
+                    CHECKCAST,
+                    type.isArray() ? 
+                            BytecodeHelper.getTypeDescription(type) : 
+                                BytecodeHelper.getClassInternalName(type.getName()));
+        }
+    }
+
+    /**
+     * Generates the bytecode to unbox the current value on the stack
+     */
+    public static void unbox(MethodVisitor mv, Class type) {
+        if (type.isPrimitive() && type != Void.TYPE) {
+            String returnString = "(Ljava/lang/Object;)" + BytecodeHelper.getTypeDescription(type);
+            mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, type.getName() + "Unbox", returnString, false);
+        }
+    }
+
+    public static void unbox(MethodVisitor mv, ClassNode type) {
+        if (type.isPrimaryClassNode()) return;
+        unbox(mv, type.getTypeClass());
+    }
+
+    /**
+     * box top level operand
+     */
+    @Deprecated
+    public static boolean box(MethodVisitor mv, ClassNode type) {
+        if (type.isPrimaryClassNode()) return false;
+        return box(mv, type.getTypeClass());
+    }
+
+    
+    /**
+     * Generates the bytecode to autobox the current value on the stack
+     */
+    @Deprecated
+    public static boolean box(MethodVisitor mv, Class type) {
+        if (ReflectionCache.getCachedClass(type).isPrimitive && type != void.class) {
+            String returnString = "(" + BytecodeHelper.getTypeDescription(type) + ")Ljava/lang/Object;";
+            mv.visitMethodInsn(INVOKESTATIC, DTT_CLASSNAME, "box", returnString, false);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Visits a class literal. If the type of the classnode is a primitive type,
+     * the generated bytecode will be a GETSTATIC Integer.TYPE.
+     * If the classnode is not a primitive type, we will generate a LDC instruction.
+     */
+    public static void visitClassLiteral(MethodVisitor mv, ClassNode classNode) {
+        if (ClassHelper.isPrimitiveType(classNode)) {
+            mv.visitFieldInsn(
+                    GETSTATIC,
+                    getClassInternalName(ClassHelper.getWrapper(classNode)),
+                    "TYPE",
+                    "Ljava/lang/Class;");
+        } else {
+            mv.visitLdcInsn(org.objectweb.asm.Type.getType(getTypeDescription(classNode)));
+        }
+    }
+
+    /**
+     * Tells if a class node is candidate for class literal bytecode optimization. If so,
+     * bytecode may use LDC instructions instead of static constant Class fields to retrieve
+     * class literals.
+     * @param classNode the classnode for which we want to know if bytecode optimization is possible
+     * @return true if the bytecode can be optimized
+     */
+    public static boolean isClassLiteralPossible(ClassNode classNode) {
+        // the current implementation only checks for public modifier, because Groovy used to allow
+        // handles on classes even if they are package protected and not in the same package.
+        // There are situations where we could make more fine grained checks, but be careful of
+        // potential breakage of existing code.
+        return Modifier.isPublic(classNode.getModifiers());
+    }
+
+    /**
+     * Returns true if the two classes share the same compilation unit.
+     * @param a class a
+     * @param b class b
+     * @return true if both classes share the same compilation unit
+     */
+    public static boolean isSameCompilationUnit(ClassNode a, ClassNode b) {
+        CompileUnit cu1 = a.getCompileUnit();
+        CompileUnit cu2 = b.getCompileUnit();
+        return cu1 !=null && cu2 !=null && cu1==cu2;
+    }
+
+    /**
+     * Computes a hash code for a string. The purpose of this hashcode is to be constant independently of
+     * the JDK being used.
+     * @param str the string for which to compute the hashcode
+     * @return hashcode of the string
+     */
+    public static int hashCode(String str) {
+        final char[] chars = str.toCharArray();
+        int h = 0;
+        for (int i = 0; i < chars.length; i++) {
+            h = 31 * h + chars[i];
+        }
+        return h;
+    }
+
+    /**
+     * Converts a primitive type to boolean.
+     *
+     * @param mv method visitor
+     * @param type primitive type to convert
+     */
+    public static void convertPrimitiveToBoolean(MethodVisitor mv, ClassNode type) {
+        if (type == ClassHelper.boolean_TYPE) {
+            return;
+        }
+        // Special handling is done for floating point types in order to
+        // handle checking for 0 or NaN values.
+        if (type == ClassHelper.double_TYPE) {
+            convertDoubleToBoolean(mv, type);
+            return;
+        } else if (type == ClassHelper.float_TYPE) {
+            convertFloatToBoolean(mv, type);
+            return;
+        }
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        // Convert long to int for IFEQ comparison using LCMP
+        if (type==ClassHelper.long_TYPE) {
+            mv.visitInsn(LCONST_0);
+            mv.visitInsn(LCMP);
+        }
+        // This handles byte, short, char and int
+        mv.visitJumpInsn(IFEQ, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, trueLabel);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(trueLabel);
+    }
+
+    private static void convertDoubleToBoolean(MethodVisitor mv, ClassNode type) {
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        Label falseLabelWithPop = new Label();
+        mv.visitInsn(DUP2); // will need the extra for isNaN call if required
+        mv.visitInsn(DCONST_0);
+        mv.visitInsn(DCMPL);
+        mv.visitJumpInsn(IFEQ, falseLabelWithPop);
+        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "isNaN", "(D)Z", false);
+        mv.visitJumpInsn(IFNE, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, trueLabel);
+        mv.visitLabel(falseLabelWithPop);
+        mv.visitInsn(POP2);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(trueLabel);
+    }
+
+    private static void convertFloatToBoolean(MethodVisitor mv, ClassNode type) {
+        Label trueLabel = new Label();
+        Label falseLabel = new Label();
+        Label falseLabelWithPop = new Label();
+        mv.visitInsn(DUP); // will need the extra for isNaN call if required
+        mv.visitInsn(FCONST_0);
+        mv.visitInsn(FCMPL);
+        mv.visitJumpInsn(IFEQ, falseLabelWithPop);
+        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "isNaN", "(F)Z", false);
+        mv.visitJumpInsn(IFNE, falseLabel);
+        mv.visitInsn(ICONST_1);
+        mv.visitJumpInsn(GOTO, trueLabel);
+        mv.visitLabel(falseLabelWithPop);
+        mv.visitInsn(POP);
+        mv.visitLabel(falseLabel);
+        mv.visitInsn(ICONST_0);
+        mv.visitLabel(trueLabel);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java
new file mode 100644
index 0000000..1f34bc3
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BytecodeVariable.java
@@ -0,0 +1,124 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.objectweb.asm.Label;
+
+/**
+ * Represents compile time variable metadata while compiling a method.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class BytecodeVariable {
+    
+    public static final BytecodeVariable THIS_VARIABLE = new BytecodeVariable();
+    public static final BytecodeVariable SUPER_VARIABLE = new BytecodeVariable();
+
+    private final int index;
+    private ClassNode type;
+    private String name;
+    private final int prevCurrent;
+    private boolean holder;
+
+    // br for setting on the LocalVariableTable in the class file
+    // these fields should probably go to jvm Operand class
+    private Label startLabel = null;
+    private Label endLabel = null;
+    private boolean dynamicTyped;
+
+    private BytecodeVariable(){
+        dynamicTyped = true;
+        index=0;
+        holder=false;
+        prevCurrent=0;
+    }
+    
+    public BytecodeVariable(int index, ClassNode type, String name, int prevCurrent) {
+        this.index = index;
+        this.type = type;
+        this.name = name;
+        this.prevCurrent = prevCurrent;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+ 
+    /**
+     * @return the stack index for this variable
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * @return is this local variable shared in other scopes (and so must use a ValueHolder)
+     */
+    public boolean isHolder() {
+        return holder;
+    }
+
+    public void setHolder(boolean holder) {
+        this.holder = holder;
+    }
+    
+    public Label getStartLabel() {
+        return startLabel;
+    }
+
+    public void setStartLabel(Label startLabel) {
+        this.startLabel = startLabel;
+    }
+
+    public Label getEndLabel() {
+        return endLabel;
+    }
+
+    public void setEndLabel(Label endLabel) {
+        this.endLabel = endLabel;
+    }
+
+    public String toString() {
+        return name + "(index=" + index + ",type=" + type + ",holder="+holder+")";
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+        dynamicTyped |= type==ClassHelper.DYNAMIC_TYPE;
+    }
+
+    public void setDynamicTyped(boolean b) {
+        dynamicTyped = b;
+    }
+    
+    public boolean isDynamicTyped() {
+        return dynamicTyped;
+    }
+
+    public int getPrevIndex() {
+        return prevCurrent;
+    }
+}


[58/62] [abbrv] groovy git commit: Replace filter with regular expression rename

Posted by cc...@apache.org.
Replace filter with regular expression rename


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/386389d2
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/386389d2
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/386389d2

Branch: refs/heads/GROOVY_2_6_X
Commit: 386389d25c13bd4104a05dacc4ad981019200c35
Parents: e3dfcfd
Author: Cedric Champeau <cc...@apache.org>
Authored: Fri Dec 15 08:33:39 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:53:15 2017 +0100

----------------------------------------------------------------------
 .../codehaus/groovy/gradle/CacheableJar.groovy  | 29 ++++++++++++++++++++
 gradle/assemble.gradle                          |  8 +++---
 2 files changed, 33 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/386389d2/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy
new file mode 100644
index 0000000..fa4b5f2
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy
@@ -0,0 +1,29 @@
+/*
+ *  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.gradle
+
+import groovy.transform.CompileStatic
+import org.gradle.api.tasks.CacheableTask
+import org.gradle.api.tasks.bundling.Jar
+
+@CompileStatic
+@CacheableTask
+class CacheableJar extends Jar {
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/386389d2/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index d51a8d1..e56fd2b 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -167,7 +167,7 @@ allprojects {
             }
             from("$projectDir/notices/NOTICE-JARJAR")
             from(generateReleaseInfo)
-            rename { String filename -> filename == 'LICENSE-JARJAR' ? 'LICENSE' : filename == 'NOTICE-JARJAR' ? 'NOTICE' : filename }
+            rename '([A-Z]+)-(.*)', '$1'
         }
         arch.exclude '**/package-info.class'
 
@@ -314,7 +314,7 @@ subprojects { sp ->
             } else {
                 from "${rootProject.projectDir}/notices/NOTICE-BASE"
             }
-            rename { String filename -> filename == 'LICENSE-BASE' ? 'LICENSE' : filename == 'NOTICE-BASE' ? 'NOTICE' : filename }
+            rename '([A-Z]+)-(.*)', '$1'
         }
         exclude '**/package-info.class'
     }
@@ -356,7 +356,7 @@ ext.distSpec = copySpec {
     duplicatesStrategy = DuplicatesStrategy.EXCLUDE
     from("$projectDir/licenses/LICENSE-BINZIP")
     from("$projectDir/notices/NOTICE-BINZIP")
-    rename { String filename -> filename == 'LICENSE-BINZIP' ? 'LICENSE' : filename == 'NOTICE-BINZIP' ? 'NOTICE' : filename }
+    rename '([A-Z]+)-(.*)', '$1'
     exclude { it.file.name =~ /-raw/ }
     into('lib') {
         from jarjar
@@ -498,7 +498,7 @@ task dist(type: Zip, dependsOn: [checkCompatibility, distBin, distSrc, distDoc,
     into "groovy-$version"
     from("$projectDir/licenses/LICENSE-SDK")
     from("$projectDir/notices/NOTICE-SDK")
-    rename { String filename -> filename == 'LICENSE-SDK' ? 'LICENSE' : filename == 'NOTICE-SDK' ? 'NOTICE' : filename }
+    rename '([A-Z]+)-(.*)', '$1'
     with distSpec
     into('doc') {
         with docSpec


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/AssertionWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/AssertionWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/AssertionWriter.java
new file mode 100644
index 0000000..2200c30
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/AssertionWriter.java
@@ -0,0 +1,257 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.runtime.powerassert.SourceText;
+import org.codehaus.groovy.runtime.powerassert.SourceTextNotAvailableException;
+import org.codehaus.groovy.syntax.Token;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ATHROW;
+import static org.objectweb.asm.Opcodes.DUP;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static org.objectweb.asm.Opcodes.NEW;
+import static org.objectweb.asm.Opcodes.POP;
+
+public class AssertionWriter {
+    // assert
+    private static final MethodCaller assertFailedMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "assertFailed");
+    
+    private static class AssertionTracker {
+        int recorderIndex;
+        SourceText sourceText;
+    }
+
+    private final WriterController controller;
+    private AssertionTracker assertionTracker;
+    private AssertionTracker disabledTracker;
+    
+    public AssertionWriter(WriterController wc) {
+        this.controller = wc;
+    }
+    
+    public void writeAssertStatement(AssertStatement statement) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+        
+        boolean rewriteAssert = true;
+        // don't rewrite assertions with message
+        rewriteAssert = statement.getMessageExpression() == ConstantExpression.NULL;
+        AssertionTracker oldTracker = assertionTracker;
+        Janitor janitor = new Janitor();
+        final Label tryStart = new Label();
+        if (rewriteAssert){
+            assertionTracker = new AssertionTracker();
+            try {
+                // because source position seems to be more reliable for statements
+                // than for expressions, we get the source text for the whole statement
+                assertionTracker.sourceText = new SourceText(statement, controller.getSourceUnit(), janitor);
+                mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/powerassert/ValueRecorder");
+                mv.visitInsn(DUP);
+                mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/powerassert/ValueRecorder", "<init>", "()V", false);
+                //TODO: maybe use more specialized type here
+                controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
+                assertionTracker.recorderIndex = controller.getCompileStack().defineTemporaryVariable("recorder", true);
+                mv.visitLabel(tryStart);
+            } catch (SourceTextNotAvailableException e) {
+                // set assertionTracker to null to deactivate AssertionWriter#record calls
+                assertionTracker = null;
+                // don't rewrite assertions w/o source text
+                rewriteAssert = false;
+            }
+        }
+        
+        statement.getBooleanExpression().visit(controller.getAcg());
+
+        Label exceptionThrower = operandStack.jump(IFEQ);
+
+        // do nothing, but clear the value recorder
+        if (rewriteAssert) {
+            //clean up assertion recorder
+            mv.visitVarInsn(ALOAD, assertionTracker.recorderIndex);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "org/codehaus/groovy/runtime/powerassert/ValueRecorder", "clear", "()V", false);
+        }
+        Label afterAssert = new Label();
+        mv.visitJumpInsn(GOTO, afterAssert);
+        mv.visitLabel(exceptionThrower);
+        
+        if (rewriteAssert) {
+            mv.visitLdcInsn(assertionTracker.sourceText.getNormalizedText());
+            mv.visitVarInsn(ALOAD, assertionTracker.recorderIndex);
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/powerassert/AssertionRenderer", "render", "(Ljava/lang/String;Lorg/codehaus/groovy/runtime/powerassert/ValueRecorder;)Ljava/lang/String;", false);
+        } else {
+            writeSourcelessAssertText(statement);
+        }
+        operandStack.push(ClassHelper.STRING_TYPE);
+        AssertionTracker savedTracker = assertionTracker;
+        assertionTracker = null;
+        
+        // now the optional exception expression
+        statement.getMessageExpression().visit(controller.getAcg());
+        operandStack.box();
+        assertFailedMethod.call(mv);
+        operandStack.remove(2); // assertFailed called static with 2 arguments 
+        
+        if (rewriteAssert) {
+            final Label tryEnd = new Label();
+            mv.visitLabel(tryEnd);
+            mv.visitJumpInsn(GOTO, afterAssert);
+            // finally block to clean assertion recorder
+            final Label catchAny = new Label();
+            mv.visitLabel(catchAny);
+            mv.visitVarInsn(ALOAD, savedTracker.recorderIndex);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "org/codehaus/groovy/runtime/powerassert/ValueRecorder", "clear", "()V", false);
+            mv.visitInsn(ATHROW);
+            // add catch any block to exception table
+            controller.getCompileStack().addExceptionBlock(tryStart, tryEnd, catchAny, null);
+        }
+        
+        mv.visitLabel(afterAssert);
+        if (rewriteAssert) {
+            controller.getCompileStack().removeVar(savedTracker.recorderIndex);
+        }
+        assertionTracker = oldTracker;
+        // close possibly open file handles from getting a sample for 
+        // power asserts
+        janitor.cleanup();
+    }
+    
+    private void writeSourcelessAssertText(AssertStatement statement) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+        
+        BooleanExpression booleanExpression = statement.getBooleanExpression();
+        // push expression string onto stack
+        String expressionText = booleanExpression.getText();
+        List<String> list = new ArrayList<String>();
+        addVariableNames(booleanExpression, list);
+        if (list.isEmpty()) {
+            mv.visitLdcInsn(expressionText);
+        } else {
+            boolean first = true;
+
+            // let's create a new expression
+            mv.visitTypeInsn(NEW, "java/lang/StringBuffer");
+            mv.visitInsn(DUP);
+            mv.visitLdcInsn(expressionText + ". Values: ");
+            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuffer", "<init>", "(Ljava/lang/String;)V", false);
+            //TODO: maybe use more special type StringBuffer here
+            operandStack.push(ClassHelper.OBJECT_TYPE);
+            int tempIndex = controller.getCompileStack().defineTemporaryVariable("assert", true);
+
+            for (String name : list) {
+                String text = name + " = ";
+                if (first) {
+                    first = false;
+                } else {
+                    text = ", " + text;
+                }
+
+                mv.visitVarInsn(ALOAD, tempIndex);
+                mv.visitLdcInsn(text);
+                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/Object;)Ljava/lang/StringBuffer;", false);
+                mv.visitInsn(POP);
+
+                mv.visitVarInsn(ALOAD, tempIndex);
+                new VariableExpression(name).visit(controller.getAcg());
+                operandStack.box();
+                mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/InvokerHelper", "toString", "(Ljava/lang/Object;)Ljava/lang/String;", false);
+                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuffer", "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;", false);
+                mv.visitInsn(POP);
+                operandStack.remove(1);
+            }
+            mv.visitVarInsn(ALOAD, tempIndex);
+            controller.getCompileStack().removeVar(tempIndex);
+        }
+    }
+    
+    public void record(Expression expression) {
+        if (assertionTracker==null) return;
+        record(assertionTracker.sourceText.getNormalizedColumn(expression.getLineNumber(), expression.getColumnNumber()));
+    }
+
+    public void record(Token op) {
+        if (assertionTracker==null) return;
+        record(assertionTracker.sourceText.getNormalizedColumn(op.getStartLine(), op.getStartColumn()));
+    }
+    
+    private void record(int normalizedColumn) {
+        if (assertionTracker==null) return;
+        
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+        
+        operandStack.dup();
+        operandStack.box();
+        
+        mv.visitVarInsn(ALOAD, assertionTracker.recorderIndex);
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        //helper.swapWithObject(ClassHelper.OBJECT_TYPE);
+        operandStack.swap();
+        mv.visitLdcInsn(normalizedColumn);
+        mv.visitMethodInsn(INVOKEVIRTUAL, "org/codehaus/groovy/runtime/powerassert/ValueRecorder", "record", "(Ljava/lang/Object;I)Ljava/lang/Object;", false);
+        mv.visitInsn(POP);
+        operandStack.remove(2);
+    }
+    
+    private void addVariableNames(Expression expression, List<String> list) {
+        if (expression instanceof BooleanExpression) {
+            BooleanExpression boolExp = (BooleanExpression) expression;
+            addVariableNames(boolExp.getExpression(), list);
+        } else if (expression instanceof BinaryExpression) {
+            BinaryExpression binExp = (BinaryExpression) expression;
+            addVariableNames(binExp.getLeftExpression(), list);
+            addVariableNames(binExp.getRightExpression(), list);
+        } else if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            list.add(varExp.getName());
+        }
+    }
+
+    public void disableTracker() {
+        if (assertionTracker==null) return;
+        disabledTracker = assertionTracker;
+        assertionTracker = null;
+    }
+
+    public void reenableTracker() {
+        if (disabledTracker==null) return;
+        assertionTracker = disabledTracker;
+        disabledTracker = null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryBooleanExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryBooleanExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryBooleanExpressionHelper.java
new file mode 100644
index 0000000..18e3169
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryBooleanExpressionHelper.java
@@ -0,0 +1,94 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryBooleanExpressionHelper extends BinaryIntExpressionHelper {
+
+    public BinaryBooleanExpressionHelper(WriterController wc) {
+        super(wc, boolArraySet, boolArrayGet);
+    }
+    
+    private static final MethodCaller 
+        boolArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "zArrayGet"),
+        boolArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "zArraySet");
+
+    @Override
+    protected ClassNode getArrayGetResultType() {
+        return ClassHelper.boolean_TYPE;
+    }
+    
+    public boolean writePostOrPrefixMethod(int operation, boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+    
+    @Override
+    protected boolean writeStdOperators(int type, boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+    
+    protected boolean writeDivision(boolean simulate) {
+        if (simulate) return false;
+        throw new GroovyBugError("should not reach here");
+    }
+
+    protected int getBitwiseOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.boolean_TYPE;
+    }
+    
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.boolean_TYPE;
+    }
+    
+    protected int getShiftOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected int getStandardOperationBytecode(int type) {
+        return -1;
+    }
+    
+    protected void removeTwoOperands(MethodVisitor mv) {
+        throw new GroovyBugError("should not reach here");
+    }
+    protected void writePlusPlus(MethodVisitor mv) {
+        throw new GroovyBugError("should not reach here");
+    }
+    protected void writeMinusMinus(MethodVisitor mv) {
+        throw new GroovyBugError("should not reach here");
+    }
+    protected void doubleTwoOperands(MethodVisitor mv) {
+        throw new GroovyBugError("should not reach here");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryDoubleExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryDoubleExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryDoubleExpressionHelper.java
new file mode 100644
index 0000000..736e060
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryDoubleExpressionHelper.java
@@ -0,0 +1,106 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.objectweb.asm.Opcodes.DADD;
+import static org.objectweb.asm.Opcodes.DCMPG;
+import static org.objectweb.asm.Opcodes.DCONST_1;
+import static org.objectweb.asm.Opcodes.DDIV;
+import static org.objectweb.asm.Opcodes.DMUL;
+import static org.objectweb.asm.Opcodes.DREM;
+import static org.objectweb.asm.Opcodes.DSUB;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BinaryDoubleExpressionHelper extends BinaryLongExpressionHelper {
+
+
+    public BinaryDoubleExpressionHelper(WriterController controller) {
+        super(controller, doubleArraySet, doubleArrayGet);
+    }
+
+    private static final MethodCaller 
+        doubleArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "dArrayGet"),
+        doubleArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "dArraySet");
+
+    protected boolean writeBitwiseOp(int op, boolean simulate) {
+        if (!simulate) throw new GroovyBugError("should not reach here");
+        return false;   
+    }
+    
+    protected int getBitwiseOperationBytecode(int op) {
+        return -1;
+    }
+
+    protected int getCompareCode() {
+        return DCMPG;
+    }
+
+    protected ClassNode getNormalOpResultType() {
+        return ClassHelper.double_TYPE;
+    }
+
+    protected boolean writeShiftOp(int type, boolean simulate) {
+        if (!simulate) throw new GroovyBugError("should not reach here");
+        return false;   
+    }
+    
+    protected int getShiftOperationBytecode(int type) {
+        return -1;
+    }
+
+    private static final int[] stdOperations = {
+        DADD,           //  PLUS        200
+        DSUB,           //  MINUS       201
+        DMUL,           //  MULTIPLY    202
+        DDIV,           //  DIV         203
+        DDIV,           //  INTDIV      204
+        DREM,           //  MOD         203
+    };
+    
+    protected int getStandardOperationBytecode(int type) {
+        return stdOperations[type];
+    }
+    
+    protected void writeMinusMinus(MethodVisitor mv) {
+        mv.visitInsn(DCONST_1);
+        mv.visitInsn(DSUB);
+    }
+    
+    protected void writePlusPlus(MethodVisitor mv) {
+        mv.visitInsn(DCONST_1);
+        mv.visitInsn(DADD);
+    }
+    
+    protected ClassNode getDevisionOpResultType() {
+        return ClassHelper.double_TYPE;
+    }
+    
+    @Override
+    protected boolean supportsDivision() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
new file mode 100644
index 0000000..3279c14
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
@@ -0,0 +1,962 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+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.TernaryExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.tools.WideningCategories;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
+import static org.codehaus.groovy.syntax.Types.BITWISE_AND_EQUAL;
+import static org.codehaus.groovy.syntax.Types.BITWISE_OR;
+import static org.codehaus.groovy.syntax.Types.BITWISE_OR_EQUAL;
+import static org.codehaus.groovy.syntax.Types.BITWISE_XOR;
+import static org.codehaus.groovy.syntax.Types.BITWISE_XOR_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_GREATER_THAN;
+import static org.codehaus.groovy.syntax.Types.COMPARE_GREATER_THAN_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_IDENTICAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_LESS_THAN;
+import static org.codehaus.groovy.syntax.Types.COMPARE_LESS_THAN_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_IDENTICAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_IN;
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_INSTANCEOF;
+import static org.codehaus.groovy.syntax.Types.COMPARE_TO;
+import static org.codehaus.groovy.syntax.Types.DIVIDE;
+import static org.codehaus.groovy.syntax.Types.DIVIDE_EQUAL;
+import static org.codehaus.groovy.syntax.Types.ELVIS_EQUAL;
+import static org.codehaus.groovy.syntax.Types.EQUAL;
+import static org.codehaus.groovy.syntax.Types.FIND_REGEX;
+import static org.codehaus.groovy.syntax.Types.INTDIV;
+import static org.codehaus.groovy.syntax.Types.INTDIV_EQUAL;
+import static org.codehaus.groovy.syntax.Types.KEYWORD_IN;
+import static org.codehaus.groovy.syntax.Types.KEYWORD_INSTANCEOF;
+import static org.codehaus.groovy.syntax.Types.LEFT_SHIFT;
+import static org.codehaus.groovy.syntax.Types.LEFT_SHIFT_EQUAL;
+import static org.codehaus.groovy.syntax.Types.LEFT_SQUARE_BRACKET;
+import static org.codehaus.groovy.syntax.Types.LOGICAL_AND;
+import static org.codehaus.groovy.syntax.Types.LOGICAL_OR;
+import static org.codehaus.groovy.syntax.Types.MATCH_REGEX;
+import static org.codehaus.groovy.syntax.Types.MINUS;
+import static org.codehaus.groovy.syntax.Types.MINUS_EQUAL;
+import static org.codehaus.groovy.syntax.Types.MOD;
+import static org.codehaus.groovy.syntax.Types.MOD_EQUAL;
+import static org.codehaus.groovy.syntax.Types.MULTIPLY;
+import static org.codehaus.groovy.syntax.Types.MULTIPLY_EQUAL;
+import static org.codehaus.groovy.syntax.Types.PLUS;
+import static org.codehaus.groovy.syntax.Types.PLUS_EQUAL;
+import static org.codehaus.groovy.syntax.Types.POWER;
+import static org.codehaus.groovy.syntax.Types.POWER_EQUAL;
+import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT;
+import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_EQUAL;
+import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED;
+import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED_EQUAL;
+import static org.objectweb.asm.Opcodes.ACONST_NULL;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.IFNE;
+import static org.objectweb.asm.Opcodes.INSTANCEOF;
+
+public class BinaryExpressionHelper {
+    //compare
+    private static final MethodCaller compareIdenticalMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareIdentical");
+    private static final MethodCaller compareNotIdenticalMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareNotIdentical");
+    private static final MethodCaller compareEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareEqual");
+    private static final MethodCaller compareNotEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareNotEqual");
+    private static final MethodCaller compareToMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareTo");
+    private static final MethodCaller compareLessThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThan");
+    private static final MethodCaller compareLessThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareLessThanEqual");
+    private static final MethodCaller compareGreaterThanMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThan");
+    private static final MethodCaller compareGreaterThanEqualMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "compareGreaterThanEqual");
+    //regexpr
+    private static final MethodCaller findRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "findRegex");
+    private static final MethodCaller matchRegexMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "matchRegex");
+    // isCase
+    private static final MethodCaller isCaseMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "isCase");
+    // isNotCase
+    private static final MethodCaller isNotCaseMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "isNotCase");
+
+    private final WriterController controller;
+    private final UnaryExpressionHelper unaryExpressionHelper;
+    
+    public BinaryExpressionHelper(WriterController wc) {
+        this.controller = wc;
+        this.unaryExpressionHelper = new UnaryExpressionHelper(this.controller);
+    }
+    
+    public WriterController getController(){
+        return controller;
+    }
+    
+    public void eval(BinaryExpression expression) {
+        switch (expression.getOperation().getType()) {
+        case EQUAL: // = assignment
+            evaluateEqual(expression, false);
+            break;
+
+        case COMPARE_EQUAL: // ==
+            evaluateCompareExpression(compareEqualMethod, expression);
+            break;
+
+        case COMPARE_NOT_EQUAL:
+            evaluateCompareExpression(compareNotEqualMethod, expression);
+            break;
+
+        case COMPARE_TO:
+            evaluateCompareTo(expression);
+            break;
+
+        case COMPARE_GREATER_THAN:
+            evaluateCompareExpression(compareGreaterThanMethod, expression);
+            break;
+
+        case COMPARE_GREATER_THAN_EQUAL:
+            evaluateCompareExpression(compareGreaterThanEqualMethod, expression);
+            break;
+
+        case COMPARE_LESS_THAN:
+            evaluateCompareExpression(compareLessThanMethod, expression);
+            break;
+
+        case COMPARE_LESS_THAN_EQUAL:
+            evaluateCompareExpression(compareLessThanEqualMethod, expression);
+            break;
+
+        case LOGICAL_AND:
+            evaluateLogicalAndExpression(expression);
+            break;
+
+        case LOGICAL_OR:
+            evaluateLogicalOrExpression(expression);
+            break;
+
+        case BITWISE_AND:
+            evaluateBinaryExpression("and", expression);
+            break;
+
+        case BITWISE_AND_EQUAL:
+            evaluateBinaryExpressionWithAssignment("and", expression);
+            break;
+
+        case BITWISE_OR:
+            evaluateBinaryExpression("or", expression);
+            break;
+
+        case BITWISE_OR_EQUAL:
+            evaluateBinaryExpressionWithAssignment("or", expression);
+            break;
+
+        case BITWISE_XOR:
+            evaluateBinaryExpression("xor", expression);
+            break;
+
+        case BITWISE_XOR_EQUAL:
+            evaluateBinaryExpressionWithAssignment("xor", expression);
+            break;
+
+        case PLUS:
+            evaluateBinaryExpression("plus", expression);
+            break;
+
+        case PLUS_EQUAL:
+            evaluateBinaryExpressionWithAssignment("plus", expression);
+            break;
+
+        case MINUS:
+            evaluateBinaryExpression("minus", expression);
+            break;
+
+        case MINUS_EQUAL:
+            evaluateBinaryExpressionWithAssignment("minus", expression);
+            break;
+
+        case MULTIPLY:
+            evaluateBinaryExpression("multiply", expression);
+            break;
+
+        case MULTIPLY_EQUAL:
+            evaluateBinaryExpressionWithAssignment("multiply", expression);
+            break;
+
+        case DIVIDE:
+            evaluateBinaryExpression("div", expression);
+            break;
+
+        case DIVIDE_EQUAL:
+            //SPG don't use divide since BigInteger implements directly
+            //and we want to dispatch through DefaultGroovyMethods to get a BigDecimal result
+            evaluateBinaryExpressionWithAssignment("div", expression);
+            break;
+
+        case INTDIV:
+            evaluateBinaryExpression("intdiv", expression);
+            break;
+
+        case INTDIV_EQUAL:
+            evaluateBinaryExpressionWithAssignment("intdiv", expression);
+            break;
+
+        case MOD:
+            evaluateBinaryExpression("mod", expression);
+            break;
+
+        case MOD_EQUAL:
+            evaluateBinaryExpressionWithAssignment("mod", expression);
+            break;
+
+        case POWER:
+            evaluateBinaryExpression("power", expression);
+            break;
+
+        case POWER_EQUAL:
+            evaluateBinaryExpressionWithAssignment("power", expression);
+            break;
+
+        case ELVIS_EQUAL:
+            evaluateElvisEqual(expression);
+            break;
+
+        case LEFT_SHIFT:
+            evaluateBinaryExpression("leftShift", expression);
+            break;
+
+        case LEFT_SHIFT_EQUAL:
+            evaluateBinaryExpressionWithAssignment("leftShift", expression);
+            break;
+
+        case RIGHT_SHIFT:
+            evaluateBinaryExpression("rightShift", expression);
+            break;
+
+        case RIGHT_SHIFT_EQUAL:
+            evaluateBinaryExpressionWithAssignment("rightShift", expression);
+            break;
+
+        case RIGHT_SHIFT_UNSIGNED:
+            evaluateBinaryExpression("rightShiftUnsigned", expression);
+            break;
+
+        case RIGHT_SHIFT_UNSIGNED_EQUAL:
+            evaluateBinaryExpressionWithAssignment("rightShiftUnsigned", expression);
+            break;
+
+        case KEYWORD_INSTANCEOF:
+            evaluateInstanceof(expression);
+            break;
+
+        case COMPARE_NOT_INSTANCEOF:
+            evaluateNotInstanceof(expression);
+            break;
+
+        case FIND_REGEX:
+            evaluateCompareExpression(findRegexMethod, expression);
+            break;
+
+        case MATCH_REGEX:
+            evaluateCompareExpression(matchRegexMethod, expression);
+            break;
+
+        case LEFT_SQUARE_BRACKET:
+            if (controller.getCompileStack().isLHS()) {
+                evaluateEqual(expression, false);
+            } else {
+                evaluateBinaryExpression("getAt", expression);
+            }
+            break;
+
+        case KEYWORD_IN:
+            evaluateCompareExpression(isCaseMethod, expression);
+            break;
+
+        case COMPARE_NOT_IN:
+            evaluateCompareExpression(isNotCaseMethod, expression);
+            break;
+
+        case COMPARE_IDENTICAL:
+            evaluateCompareExpression(compareIdenticalMethod, expression);
+            break;
+
+        case COMPARE_NOT_IDENTICAL:
+            evaluateCompareExpression(compareNotIdenticalMethod, expression);
+            break;
+
+        default:
+            throw new GroovyBugError("Operation: " + expression.getOperation() + " not supported");
+        }
+    }
+    
+    protected void assignToArray(Expression parent, Expression receiver, Expression index, Expression rhsValueLoader, boolean safe) {
+        // let's replace this assignment to a subscript operator with a
+        // method call
+        // e.g. x[5] = 10
+        // -> (x, [], 5), =, 10
+        // -> methodCall(x, "putAt", [5, 10])
+        ArgumentListExpression ae = new ArgumentListExpression(index,rhsValueLoader);
+        controller.getInvocationWriter().makeCall(
+                parent, receiver, new ConstantExpression("putAt"),
+                ae, InvocationWriter.invokeMethod, safe, false, false);
+        controller.getOperandStack().pop();
+        // return value of assignment
+        rhsValueLoader.visit(controller.getAcg());
+    }
+
+    private static boolean isNull(Expression exp) {
+        if (exp instanceof ConstantExpression){
+            return ((ConstantExpression) exp).getValue()==null;
+        } else {
+            return false;
+        }
+    }
+
+    public void evaluateElvisEqual(BinaryExpression expression) {
+        Token operation = expression.getOperation();
+        BinaryExpression elvisAssignmentExpression =
+                new BinaryExpression(
+                        expression.getLeftExpression(),
+                        Token.newSymbol(Types.EQUAL, operation.getStartLine(), operation.getStartColumn()),
+                        new ElvisOperatorExpression(expression.getLeftExpression(), expression.getRightExpression())
+                );
+
+        this.evaluateEqual(elvisAssignmentExpression, false);
+    }
+
+    public void evaluateEqual(BinaryExpression expression, boolean defineVariable) {
+        AsmClassGenerator acg = controller.getAcg();
+        CompileStack compileStack = controller.getCompileStack();
+        OperandStack operandStack = controller.getOperandStack();
+        Expression rightExpression = expression.getRightExpression();
+        Expression leftExpression = expression.getLeftExpression();
+        ClassNode lhsType = controller.getTypeChooser().resolveType(leftExpression, controller.getClassNode());
+
+        if (    defineVariable &&
+                rightExpression instanceof EmptyExpression &&
+                !(leftExpression instanceof TupleExpression) )
+        {
+            VariableExpression ve = (VariableExpression) leftExpression;
+            BytecodeVariable var = compileStack.defineVariable(ve, controller.getTypeChooser().resolveType(ve, controller.getClassNode()), false);
+            operandStack.loadOrStoreVariable(var, false);
+            return;
+        }
+
+        // let's evaluate the RHS and store the result
+        ClassNode rhsType;
+        if (rightExpression instanceof ListExpression && lhsType.isArray()) {
+            ListExpression list = (ListExpression) rightExpression;
+            ArrayExpression array = new ArrayExpression(lhsType.getComponentType(), list.getExpressions());
+            array.setSourcePosition(list);
+            array.visit(acg);
+        } else if (rightExpression instanceof EmptyExpression) {
+            rhsType = leftExpression.getType();
+            loadInitValue(rhsType);
+        } else {
+            rightExpression.visit(acg);
+        }
+        rhsType = operandStack.getTopOperand();
+
+        boolean directAssignment = defineVariable && !(leftExpression instanceof TupleExpression);
+        int rhsValueId;
+        if (directAssignment) {
+            VariableExpression var = (VariableExpression) leftExpression;
+            if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(rhsType)) {
+                // GROOVY-5570: if a closure shared variable is a primitive type, it must be boxed
+                rhsType = ClassHelper.getWrapper(rhsType);
+                operandStack.box();
+            }
+
+            // ensure we try to unbox null to cause a runtime NPE in case we assign 
+            // null to a primitive typed variable, even if it is used only in boxed 
+            // form as it is closure shared
+            if (var.isClosureSharedVariable() && ClassHelper.isPrimitiveType(var.getOriginType()) && isNull(rightExpression)) {
+                operandStack.doGroovyCast(var.getOriginType());
+                // these two are never reached in bytecode and only there 
+                // to avoid verifyerrors and compiler infrastructure hazzle
+                operandStack.box(); 
+                operandStack.doGroovyCast(lhsType);
+            }
+            // normal type transformation 
+            if (!ClassHelper.isPrimitiveType(lhsType) && isNull(rightExpression)) {
+                operandStack.replace(lhsType);
+            } else {
+                operandStack.doGroovyCast(lhsType);
+            }
+            rhsType = lhsType;
+            rhsValueId = compileStack.defineVariable(var, lhsType, true).getIndex();
+        } else {
+            rhsValueId = compileStack.defineTemporaryVariable("$rhs", rhsType, true);
+        }
+        //TODO: if rhs is VariableSlotLoader already, then skip crating a new one
+        BytecodeExpression rhsValueLoader = new VariableSlotLoader(rhsType,rhsValueId,operandStack);
+        
+        // assignment for subscript
+        if (leftExpression instanceof BinaryExpression) {
+            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
+            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
+                assignToArray(expression, leftBinExpr.getLeftExpression(), leftBinExpr.getRightExpression(), rhsValueLoader, leftBinExpr.isSafe());
+            }
+            compileStack.removeVar(rhsValueId);
+            return;
+        }
+        
+        compileStack.pushLHS(true);
+
+        // multiple declaration
+        if (leftExpression instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) leftExpression;
+            int i = 0;
+            for (Expression e : tuple.getExpressions()) {
+                VariableExpression var = (VariableExpression) e;
+                MethodCallExpression call = new MethodCallExpression(
+                        rhsValueLoader, "getAt",
+                        new ArgumentListExpression(new ConstantExpression(i)));
+                call.visit(acg);
+                i++;
+                if (defineVariable) {
+                    operandStack.doGroovyCast(var);
+                    compileStack.defineVariable(var, true);
+                    operandStack.remove(1);
+                } else {
+                    acg.visitVariableExpression(var);
+                }
+            }
+        } 
+        // single declaration
+        else if (defineVariable) {
+            rhsValueLoader.visit(acg);
+            operandStack.remove(1);
+            compileStack.popLHS();
+            return;
+        } 
+        // normal assignment
+        else {
+            int mark = operandStack.getStackLength();
+            // to leave a copy of the rightExpression value on the stack after the assignment.
+            rhsValueLoader.visit(acg);
+            TypeChooser typeChooser = controller.getTypeChooser();
+            ClassNode targetType = typeChooser.resolveType(leftExpression, controller.getClassNode());
+            operandStack.doGroovyCast(targetType);
+            leftExpression.visit(acg);
+            operandStack.remove(operandStack.getStackLength()-mark);
+        }
+        compileStack.popLHS();
+        
+        // return value of assignment
+        rhsValueLoader.visit(acg);
+        compileStack.removeVar(rhsValueId);
+    }
+
+    private void loadInitValue(ClassNode type) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (ClassHelper.isPrimitiveType(type)) {
+            mv.visitLdcInsn(0);
+        } else {
+            mv.visitInsn(ACONST_NULL);
+        }
+        controller.getOperandStack().push(type);
+    }
+
+    protected void evaluateCompareExpression(MethodCaller compareMethod, BinaryExpression expression) {
+        Expression leftExp = expression.getLeftExpression();
+        TypeChooser typeChooser = controller.getTypeChooser();
+        ClassNode cn = controller.getClassNode();
+        ClassNode leftType = typeChooser.resolveType(leftExp,cn);
+        Expression rightExp = expression.getRightExpression();
+        ClassNode rightType = typeChooser.resolveType(rightExp,cn);
+
+        boolean done = false;
+        if (    ClassHelper.isPrimitiveType(leftType) &&
+                ClassHelper.isPrimitiveType(rightType))
+        {
+            BinaryExpressionMultiTypeDispatcher helper = new BinaryExpressionMultiTypeDispatcher(getController());
+            done = helper.doPrimitiveCompare(leftType, rightType, expression);
+        }
+        
+        if (!done) {
+            AsmClassGenerator acg = controller.getAcg();
+            OperandStack operandStack = controller.getOperandStack();
+            
+            leftExp.visit(acg);
+            operandStack.box();
+            rightExp.visit(acg);
+            operandStack.box();
+    
+            compareMethod.call(controller.getMethodVisitor());
+            ClassNode resType = ClassHelper.boolean_TYPE;
+            if (compareMethod==findRegexMethod) {
+                resType = ClassHelper.OBJECT_TYPE;
+            } 
+            operandStack.replace(resType,2);
+        }
+    }
+    
+    private void evaluateCompareTo(BinaryExpression expression) {
+        Expression leftExpression = expression.getLeftExpression();
+        AsmClassGenerator acg = controller.getAcg();
+        OperandStack operandStack = controller.getOperandStack();
+        
+        leftExpression.visit(acg);
+        operandStack.box();
+
+        // if the right hand side is a boolean expression, we need to autobox
+        Expression rightExpression = expression.getRightExpression();
+        rightExpression.visit(acg);
+        operandStack.box();
+
+        compareToMethod.call(controller.getMethodVisitor());
+        operandStack.replace(ClassHelper.Integer_TYPE,2);
+    }
+
+    private void evaluateLogicalAndExpression(BinaryExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        AsmClassGenerator acg = controller.getAcg();
+        OperandStack operandStack = controller.getOperandStack();
+
+        expression.getLeftExpression().visit(acg);
+        operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
+        Label falseCase = operandStack.jump(IFEQ);
+
+        expression.getRightExpression().visit(acg);
+        operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
+        operandStack.jump(IFEQ,falseCase);
+
+        ConstantExpression.PRIM_TRUE.visit(acg);
+        Label trueCase = new Label();
+        mv.visitJumpInsn(GOTO, trueCase);
+
+        mv.visitLabel(falseCase);
+        ConstantExpression.PRIM_FALSE.visit(acg);
+
+        mv.visitLabel(trueCase);
+        operandStack.remove(1); // have to remove 1 because of the GOTO
+    }
+    
+    private void evaluateLogicalOrExpression(BinaryExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        AsmClassGenerator acg = controller.getAcg();
+        OperandStack operandStack = controller.getOperandStack();
+
+        Label end = new Label();
+
+        expression.getLeftExpression().visit(acg);
+        operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
+        Label trueCase = operandStack.jump(IFNE);
+        
+        expression.getRightExpression().visit(acg);
+        operandStack.doGroovyCast(ClassHelper.boolean_TYPE);
+        Label falseCase = operandStack.jump(IFEQ);
+        
+        mv.visitLabel(trueCase);
+        ConstantExpression.PRIM_TRUE.visit(acg);
+        operandStack.jump(GOTO, end);
+
+        mv.visitLabel(falseCase);
+        ConstantExpression.PRIM_FALSE.visit(acg);
+        
+        mv.visitLabel(end);
+    }
+    
+    protected void evaluateBinaryExpression(String message, BinaryExpression binExp) {
+        CompileStack compileStack = controller.getCompileStack();
+
+        Expression receiver = binExp.getLeftExpression();
+        Expression arguments = binExp.getRightExpression();
+
+        // ensure VariableArguments are read, not stored
+        compileStack.pushLHS(false);
+        controller.getInvocationWriter().makeSingleArgumentCall(receiver, message, arguments, binExp.isSafe());
+        compileStack.popLHS();        
+    }
+
+    protected void evaluateArrayAssignmentWithOperator(String method, BinaryExpression expression, BinaryExpression leftBinExpr) {
+        CompileStack compileStack    = getController().getCompileStack();
+        AsmClassGenerator acg             = getController().getAcg();
+        OperandStack os              = getController().getOperandStack();
+
+        // e.g. x[a] += b
+        // to avoid loading x and a twice we transform the expression to use
+        // ExpressionAsVariableSlot
+        // -> subscript=a, receiver=x, receiver[subscript]+b, =, receiver[subscript]
+        // -> subscript=a, receiver=x, receiver#getAt(subscript)#plus(b), =, receiver#putAt(subscript)
+        // -> subscript=a, receiver=x, receiver#putAt(subscript, receiver#getAt(subscript)#plus(b))
+        // the result of x[a] += b is x[a]+b, thus:
+        // -> subscript=a, receiver=x, receiver#putAt(subscript, ret=receiver#getAt(subscript)#plus(b)), ret
+        ExpressionAsVariableSlot subscript = new ExpressionAsVariableSlot(controller, leftBinExpr.getRightExpression(), "subscript");
+        ExpressionAsVariableSlot receiver  = new ExpressionAsVariableSlot(controller, leftBinExpr.getLeftExpression(), "receiver");
+        MethodCallExpression getAt = new MethodCallExpression(receiver, "getAt", new ArgumentListExpression(subscript));
+        MethodCallExpression operation = new MethodCallExpression(getAt, method, expression.getRightExpression());
+        ExpressionAsVariableSlot ret = new ExpressionAsVariableSlot(controller, operation, "ret");
+        MethodCallExpression putAt = new MethodCallExpression(receiver, "putAt", new ArgumentListExpression(subscript, ret));
+
+        putAt.visit(acg);
+        os.pop();
+        os.load(ret.getType(), ret.getIndex());
+
+        compileStack.removeVar(ret.getIndex());
+        compileStack.removeVar(subscript.getIndex());
+        compileStack.removeVar(receiver.getIndex());
+    }
+
+    protected void evaluateBinaryExpressionWithAssignment(String method, BinaryExpression expression) {
+        Expression leftExpression = expression.getLeftExpression();
+        AsmClassGenerator acg = controller.getAcg();
+        OperandStack operandStack = controller.getOperandStack();
+        
+        if (leftExpression instanceof BinaryExpression) {
+            BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
+            if (leftBinExpr.getOperation().getType() == Types.LEFT_SQUARE_BRACKET) {
+                evaluateArrayAssignmentWithOperator(method, expression, leftBinExpr);
+                return;
+            }
+        } 
+
+        evaluateBinaryExpression(method, expression);
+
+        // br to leave a copy of rvalue on the stack. see also isPopRequired()
+        operandStack.dup();
+        
+        controller.getCompileStack().pushLHS(true);
+        leftExpression.visit(acg);
+        controller.getCompileStack().popLHS();
+    }
+    
+    private void evaluateInstanceof(BinaryExpression expression) {
+        OperandStack operandStack = controller.getOperandStack();
+        
+        expression.getLeftExpression().visit(controller.getAcg());
+        operandStack.box();
+        Expression rightExp = expression.getRightExpression();
+        ClassNode classType;
+        if (rightExp instanceof ClassExpression) {
+            ClassExpression classExp = (ClassExpression) rightExp;
+            classType = classExp.getType();
+        } else {
+            throw new RuntimeException(
+                    "Right hand side of the instanceof keyword must be a class name, not: " + rightExp);
+        }
+        String classInternalName = BytecodeHelper.getClassInternalName(classType);
+        controller.getMethodVisitor().visitTypeInsn(INSTANCEOF, classInternalName);
+        operandStack.replace(ClassHelper.boolean_TYPE);
+    }
+
+    private void evaluateNotInstanceof(BinaryExpression expression) {
+        unaryExpressionHelper.writeNotExpression(
+                new NotExpression(
+                        new BinaryExpression(
+                                expression.getLeftExpression(),
+                                Token.newSymbol(KEYWORD_INSTANCEOF, -1, -1),
+                                expression.getRightExpression()
+                        )
+                )
+        );
+    }
+
+    public MethodCaller getIsCaseMethod() {
+        return isCaseMethod;
+    }
+
+    private void evaluatePostfixMethod(int op, String method, Expression expression, Expression orig) {
+        CompileStack compileStack = controller.getCompileStack();
+        final OperandStack operandStack = controller.getOperandStack();
+        
+        // load Expressions
+        VariableSlotLoader usesSubscript = loadWithSubscript(expression);
+
+        // save copy for later
+        operandStack.dup();
+        ClassNode expressionType = operandStack.getTopOperand();
+        int tempIdx = compileStack.defineTemporaryVariable("postfix_" + method, expressionType, true);
+        
+        // execute Method
+        execMethodAndStoreForSubscriptOperator(op,method,expression,usesSubscript,orig);
+        
+        // remove the result of the method call
+        operandStack.pop();        
+        
+        //reload saved value
+        operandStack.load(expressionType, tempIdx);
+        compileStack.removeVar(tempIdx);
+        if (usesSubscript!=null) compileStack.removeVar(usesSubscript.getIndex());
+    }
+
+    public void evaluatePostfixMethod(PostfixExpression expression) {
+        int op = expression.getOperation().getType();
+        switch (op) {
+            case Types.PLUS_PLUS:
+                evaluatePostfixMethod(op, "next", expression.getExpression(), expression);
+                break;
+            case Types.MINUS_MINUS:
+                evaluatePostfixMethod(op, "previous", expression.getExpression(), expression);
+                break;
+        }
+    }
+
+    public void evaluatePrefixMethod(PrefixExpression expression) {
+        int type = expression.getOperation().getType();
+        switch (type) {
+            case Types.PLUS_PLUS:
+                evaluatePrefixMethod(type, "next", expression.getExpression(), expression);
+                break;
+            case Types.MINUS_MINUS:
+                evaluatePrefixMethod(type, "previous", expression.getExpression(), expression);
+                break;
+        }
+    }
+    
+    private void evaluatePrefixMethod(int op, String method, Expression expression, Expression orig) {
+        // load Expressions
+        VariableSlotLoader usesSubscript = loadWithSubscript(expression);
+        
+        // execute Method
+        execMethodAndStoreForSubscriptOperator(op,method,expression,usesSubscript,orig);
+
+        // new value is already on stack, so nothing to do here
+        if (usesSubscript!=null) controller.getCompileStack().removeVar(usesSubscript.getIndex());
+    }
+    
+    private VariableSlotLoader loadWithSubscript(Expression expression) {
+        final OperandStack operandStack = controller.getOperandStack();
+        // if we have a BinaryExpression, let us check if it is with
+        // subscription
+        if (expression instanceof BinaryExpression) {
+            BinaryExpression be = (BinaryExpression) expression;
+            if (be.getOperation().getType()== Types.LEFT_SQUARE_BRACKET) {
+                // right expression is the subscript expression
+                // we store the result of the subscription on the stack
+                Expression subscript = be.getRightExpression();
+                subscript.visit(controller.getAcg());
+                ClassNode subscriptType = operandStack.getTopOperand();
+                int id = controller.getCompileStack().defineTemporaryVariable("$subscript", subscriptType, true);
+                VariableSlotLoader subscriptExpression = new VariableSlotLoader(subscriptType, id, operandStack);
+                // do modified visit
+                BinaryExpression newBe = new BinaryExpression(be.getLeftExpression(), be.getOperation(), subscriptExpression);
+                newBe.copyNodeMetaData(be);
+                newBe.setSourcePosition(be);
+                newBe.visit(controller.getAcg());
+                return subscriptExpression;
+            } 
+        } 
+        
+        // normal loading of expression
+        expression.visit(controller.getAcg());
+        return null;
+    }
+    
+    private void execMethodAndStoreForSubscriptOperator(int op, String method, Expression expression, VariableSlotLoader usesSubscript, Expression orig) {
+        final OperandStack operandStack = controller.getOperandStack();
+        writePostOrPrefixMethod(op,method,expression,orig);
+
+        // we need special code for arrays to store the result (like for a[1]++)
+        if (usesSubscript!=null) {
+            CompileStack compileStack = controller.getCompileStack();
+            BinaryExpression be = (BinaryExpression) expression;
+            
+            ClassNode methodResultType = operandStack.getTopOperand();
+            final int resultIdx = compileStack.defineTemporaryVariable("postfix_" + method, methodResultType, true);
+            BytecodeExpression methodResultLoader = new VariableSlotLoader(methodResultType, resultIdx, operandStack);
+            
+            // execute the assignment, this will leave the right side 
+            // (here the method call result) on the stack
+            assignToArray(be, be.getLeftExpression(), usesSubscript, methodResultLoader, be.isSafe());
+
+            compileStack.removeVar(resultIdx);
+        } 
+        // here we handle a.b++ and a++
+        else if (expression instanceof VariableExpression ||
+            expression instanceof FieldExpression ||
+            expression instanceof PropertyExpression)
+        {
+            operandStack.dup();
+            controller.getCompileStack().pushLHS(true);
+            expression.visit(controller.getAcg());
+            controller.getCompileStack().popLHS();
+        }
+        // other cases don't need storing, so nothing to be done for them
+    }
+
+    protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
+        final OperandStack operandStack = controller.getOperandStack();
+        // at this point the receiver will be already on the stack.
+        // in a[1]++ the method will be "++" aka "next" and the receiver a[1]
+        
+        ClassNode BEType = controller.getTypeChooser().resolveType(expression, controller.getClassNode());
+        Expression callSiteReceiverSwap = new BytecodeExpression(BEType) {
+            @Override
+            public void visit(MethodVisitor mv) {
+                // CallSite is normally not showing up on the 
+                // operandStack, so we place a dummy here with same
+                // slot length.
+                operandStack.push(ClassHelper.OBJECT_TYPE);
+                // change (receiver,callsite) to (callsite,receiver)
+                operandStack.swap();
+                setType(operandStack.getTopOperand());
+                
+                // no need to keep any of those on the operand stack
+                // after this expression is processed, the operand stack
+                // will contain callSiteReceiverSwap.getType()
+                operandStack.remove(2);
+            }
+        };
+        // execute method
+        // this will load the callsite and the receiver normally in the wrong
+        // order since the receiver is already present, but before the callsite
+        // Therefore we use callSiteReceiverSwap to correct the order. 
+        // After this call the JVM operand stack will contain the the result of
+        // the method call... usually simply Object in operandStack
+        controller.getCallSiteWriter().makeCallSite(
+                callSiteReceiverSwap,
+                method,
+                MethodCallExpression.NO_ARGUMENTS,
+                false, false, false, false);
+        // now rhs is completely done and we need only to store. In a[1]++ this 
+        // would be a.getAt(1).next() for the rhs, "lhs" code is a.putAt(1, rhs)
+         
+    }
+    
+    private void evaluateElvisOperatorExpression(ElvisOperatorExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        CompileStack compileStack = controller.getCompileStack();
+        OperandStack operandStack = controller.getOperandStack();
+        TypeChooser typeChooser = controller.getTypeChooser();
+        
+        Expression boolPart = expression.getBooleanExpression().getExpression();
+        Expression falsePart = expression.getFalseExpression();
+        
+        ClassNode truePartType = typeChooser.resolveType(boolPart, controller.getClassNode());
+        ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode());
+        ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType);
+        
+        // x?:y is equal to x?x:y, which evals to 
+        //      var t=x; boolean(t)?t:y
+        // first we load x, dup it, convert the dupped to boolean, then 
+        // jump depending on the value. For true we are done, for false we
+        // have to load y, thus we first remove x and then load y. 
+        // But since x and y may have different stack lengths, this cannot work
+        // Thus we have to have to do the following:
+        // Be X the type of x, Y the type of y and S the common supertype of 
+        // X and Y, then we have to see x?:y as  
+        //      var t=x;boolean(t)?S(t):S(y)
+        // so we load x, dup it, store the value in a local variable (t), then 
+        // do boolean conversion. In the true part load t and cast it to S, 
+        // in the false part load y and cast y to S 
+
+        // load x, dup it, store one in $t and cast the remaining one to boolean
+        int mark = operandStack.getStackLength();
+        boolPart.visit(controller.getAcg());
+        operandStack.dup();
+        if (ClassHelper.isPrimitiveType(truePartType) && !ClassHelper.isPrimitiveType(operandStack.getTopOperand())) {
+            truePartType = ClassHelper.getWrapper(truePartType);
+        }
+        int retValueId = compileStack.defineTemporaryVariable("$t", truePartType, true);
+        operandStack.castToBool(mark,true);
+        
+        Label l0 = operandStack.jump(IFEQ);
+        // true part: load $t and cast to S
+        operandStack.load(truePartType, retValueId);
+        operandStack.doGroovyCast(common);
+        Label l1 = new Label();
+        mv.visitJumpInsn(GOTO, l1);
+        
+        // false part: load false expression and cast to S
+        mv.visitLabel(l0);
+        falsePart.visit(controller.getAcg());        
+        operandStack.doGroovyCast(common);
+        
+        // finish and cleanup
+        mv.visitLabel(l1);
+        compileStack.removeVar(retValueId);
+        controller.getOperandStack().replace(common, 2);        
+        
+    }
+
+    private void evaluateNormalTernary(TernaryExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+        TypeChooser typeChooser = controller.getTypeChooser();
+        
+        Expression boolPart = expression.getBooleanExpression();
+        Expression truePart = expression.getTrueExpression();
+        Expression falsePart = expression.getFalseExpression();
+        
+        ClassNode truePartType = typeChooser.resolveType(truePart, controller.getClassNode());
+        ClassNode falsePartType = typeChooser.resolveType(falsePart, controller.getClassNode());
+        ClassNode common = WideningCategories.lowestUpperBound(truePartType, falsePartType);
+
+        // we compile b?x:y as 
+        //      boolean(b)?S(x):S(y), S = common super type of x,y
+        // so we load b, do boolean conversion. 
+        // In the true part load x and cast it to S, 
+        // in the false part load y and cast y to S 
+
+        // load b and convert to boolean
+        int mark = operandStack.getStackLength();
+        boolPart.visit(controller.getAcg());
+        operandStack.castToBool(mark,true);
+        
+        Label l0 = operandStack.jump(IFEQ);
+        // true part: load x and cast to S
+        truePart.visit(controller.getAcg());
+        operandStack.doGroovyCast(common);
+        Label l1 = new Label();
+        mv.visitJumpInsn(GOTO, l1);
+        
+        // false part: load y and cast to S
+        mv.visitLabel(l0);
+        falsePart.visit(controller.getAcg());        
+        operandStack.doGroovyCast(common);
+        
+        // finish and cleanup
+        mv.visitLabel(l1);
+        controller.getOperandStack().replace(common, 2);        
+        
+    }
+
+    public void evaluateTernary(TernaryExpression expression) {
+        if (expression instanceof ElvisOperatorExpression) {
+            evaluateElvisOperatorExpression((ElvisOperatorExpression) expression);
+        } else {
+            evaluateNormalTernary(expression);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java
new file mode 100644
index 0000000..a85c7fd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/BinaryExpressionMultiTypeDispatcher.java
@@ -0,0 +1,422 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.char_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isBigDecCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isDoubleCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isIntCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isNumberCategory;
+import static org.codehaus.groovy.syntax.TokenUtil.removeAssignment;
+import static org.codehaus.groovy.syntax.Types.DIVIDE;
+import static org.codehaus.groovy.syntax.Types.LEFT_SHIFT;
+import static org.codehaus.groovy.syntax.Types.LEFT_SQUARE_BRACKET;
+import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT;
+import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED;
+
+/**
+ * This class is for internal use only!
+ * This class will dispatch to the right type adapters according to the 
+ * kind of binary expression that is provided.
+ */
+public class BinaryExpressionMultiTypeDispatcher extends BinaryExpressionHelper {
+    
+    private static class BinaryCharExpressionHelper extends BinaryIntExpressionHelper {
+        public BinaryCharExpressionHelper(WriterController wc) {
+            super(wc, charArraySet, charArrayGet);
+        }
+        private static final MethodCaller
+            charArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "cArrayGet"),
+            charArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "cArraySet");
+        @Override protected ClassNode getArrayGetResultType() { return ClassHelper.char_TYPE; }
+    }
+    
+    private static class BinaryByteExpressionHelper extends BinaryIntExpressionHelper {
+        public BinaryByteExpressionHelper(WriterController wc) {
+            super(wc, byteArraySet, byteArrayGet);
+        }
+        private static final MethodCaller
+            byteArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "bArrayGet"),
+            byteArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "bArraySet");
+        @Override protected ClassNode getArrayGetResultType() { return ClassHelper.byte_TYPE; }
+    }
+    
+    private static class BinaryShortExpressionHelper extends BinaryIntExpressionHelper {
+        public BinaryShortExpressionHelper(WriterController wc) {
+            super(wc, shortArraySet, shortArrayGet);
+        }
+        private static final MethodCaller
+            shortArrayGet = MethodCaller.newStatic(BytecodeInterface8.class, "sArrayGet"),
+            shortArraySet = MethodCaller.newStatic(BytecodeInterface8.class, "sArraySet");
+        @Override protected ClassNode getArrayGetResultType() { return ClassHelper.short_TYPE; }
+    }
+    
+    protected BinaryExpressionWriter[] binExpWriter = initializeDelegateHelpers();
+
+    protected BinaryExpressionWriter[] initializeDelegateHelpers() {
+        return new BinaryExpressionWriter[]{
+                /* 0: dummy  */ new BinaryObjectExpressionHelper(getController()),
+                /* 1: int    */ new BinaryIntExpressionHelper(getController()),
+                /* 2: long   */ new BinaryLongExpressionHelper(getController()),
+                /* 3: double */ new BinaryDoubleExpressionHelper(getController()),
+                /* 4: char   */ new BinaryCharExpressionHelper(getController()),
+                /* 5: byte   */ new BinaryByteExpressionHelper(getController()),
+                /* 6: short  */ new BinaryShortExpressionHelper(getController()),
+                /* 7: float  */ new BinaryFloatExpressionHelper(getController()),
+                /* 8: bool   */ new BinaryBooleanExpressionHelper(getController()),
+        };
+    }
+
+    public static Map<ClassNode,Integer> typeMap = new HashMap<ClassNode,Integer>(14);
+    static {
+        typeMap.put(int_TYPE,       1); typeMap.put(long_TYPE,          2);
+        typeMap.put(double_TYPE,    3); typeMap.put(char_TYPE,          4);
+        typeMap.put(byte_TYPE,      5); typeMap.put(short_TYPE,         6);
+        typeMap.put(float_TYPE,     7); typeMap.put(boolean_TYPE,       8);
+    }
+    public static final String[] typeMapKeyNames = {"dummy", "int", "long", "double", "char", "byte", "short", "float", "boolean"};
+
+    public BinaryExpressionMultiTypeDispatcher(WriterController wc) {
+        super(wc);
+    }
+
+    private static int getOperandConversionType(ClassNode leftType, ClassNode rightType) {
+        if (isIntCategory(leftType) && isIntCategory(rightType)) return 1;
+        if (isLongCategory(leftType) && isLongCategory(rightType)) return 2;
+        if (isBigDecCategory(leftType) && isBigDecCategory(rightType)) return 0;
+        if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) return 3;
+        return 0;
+    }
+    
+    protected int getOperandType(ClassNode type) {
+        Integer ret = typeMap.get(type);
+        if (ret==null) return 0;
+        return ret;
+    }
+
+    @Deprecated
+    protected boolean doPrimtiveCompare(ClassNode leftType, ClassNode rightType, BinaryExpression binExp) {
+        return doPrimitiveCompare(leftType, rightType, binExp);
+    }
+
+    protected boolean doPrimitiveCompare(ClassNode leftType, ClassNode rightType, BinaryExpression binExp) {
+        Expression leftExp = binExp.getLeftExpression();
+        Expression rightExp = binExp.getRightExpression();
+        int operation = binExp.getOperation().getType();
+        
+        int operationType = getOperandConversionType(leftType,rightType);
+        BinaryExpressionWriter bew = binExpWriter[operationType];
+
+        if (!bew.write(operation, true)) return false;
+            
+        AsmClassGenerator acg = getController().getAcg();
+        OperandStack os = getController().getOperandStack();
+        leftExp.visit(acg);
+        os.doGroovyCast(bew.getNormalOpResultType());
+        rightExp.visit(acg);
+        os.doGroovyCast(bew.getNormalOpResultType());
+        bew.write(operation, false);
+        
+        return true;
+    }
+    
+    @Override
+    protected void evaluateCompareExpression(final MethodCaller compareMethod, BinaryExpression binExp) {
+        ClassNode current =  getController().getClassNode();
+        TypeChooser typeChooser = getController().getTypeChooser();
+        
+        Expression leftExp = binExp.getLeftExpression();
+        ClassNode leftType = typeChooser.resolveType(leftExp, current);
+        Expression rightExp = binExp.getRightExpression();
+        ClassNode rightType = typeChooser.resolveType(rightExp, current);
+        
+        if (!doPrimitiveCompare(leftType, rightType, binExp)) {
+            super.evaluateCompareExpression(compareMethod, binExp);
+        }
+    }
+    
+    @Override
+    protected void evaluateBinaryExpression(final String message, BinaryExpression binExp) {
+        int operation = removeAssignment(binExp.getOperation().getType());
+        ClassNode current =  getController().getClassNode();
+
+        Expression leftExp = binExp.getLeftExpression();
+        ClassNode leftTypeOrig = getController().getTypeChooser().resolveType(leftExp, current);
+        ClassNode leftType = leftTypeOrig;
+        Expression rightExp = binExp.getRightExpression();
+        ClassNode rightType = getController().getTypeChooser().resolveType(rightExp, current);
+        
+        AsmClassGenerator acg = getController().getAcg();
+        OperandStack os = getController().getOperandStack();
+        
+        if (operation==LEFT_SQUARE_BRACKET) {
+            leftType = leftTypeOrig.getComponentType();
+            int operationType = getOperandType(leftType);
+            BinaryExpressionWriter bew = binExpWriter[operationType];
+            if (    leftTypeOrig.isArray() && isIntCastableType(rightExp) && 
+                    bew.arrayGet(operation, true) &&
+                    !binExp.isSafe())
+            {
+                leftExp.visit(acg);
+                os.doGroovyCast(leftTypeOrig);
+                rightExp.visit(acg);
+                os.doGroovyCast(int_TYPE);
+                bew.arrayGet(operation, false);
+                os.replace(bew.getArrayGetResultType(),2);
+            } else {
+                super.evaluateBinaryExpression(message, binExp);
+            }
+        } else if (operation == DIVIDE) { 
+            int operationType = getOperandType(getController().getTypeChooser().resolveType(binExp, current));
+            BinaryExpressionWriter bew = binExpWriter[operationType];
+            if (bew.writeDivision(true)) {
+                leftExp.visit(acg);
+                os.doGroovyCast(bew.getDevisionOpResultType());
+                rightExp.visit(acg);
+                os.doGroovyCast(bew.getDevisionOpResultType());
+                bew.writeDivision(false);
+            } else {
+                super.evaluateBinaryExpression(message, binExp);
+            }
+        } else {
+            int operationType = getOperandConversionType(leftType,rightType);
+            BinaryExpressionWriter bew = binExpWriter[operationType];
+            
+            if ( isShiftOperation(operation) && isIntCastableType(rightExp) &&
+                 bew.write(operation, true)) 
+            {
+                leftExp.visit(acg);
+                os.doGroovyCast(bew.getNormalOpResultType());
+                rightExp.visit(acg);
+                os.doGroovyCast(int_TYPE);
+                bew.write(operation, false);
+            } else if (bew.write(operation, true)) {
+                leftExp.visit(acg);
+                os.doGroovyCast(bew.getNormalOpResultType());
+                rightExp.visit(acg);
+                os.doGroovyCast(bew.getNormalOpResultType());
+                bew.write(operation, false);
+            } else {
+                super.evaluateBinaryExpression(message, binExp);
+            }
+        }
+    }
+    
+    private boolean isIntCastableType(Expression rightExp) {
+        ClassNode type = getController().getTypeChooser().resolveType(rightExp, getController().getClassNode());
+        return isNumberCategory(type);
+    }
+
+    private static boolean isShiftOperation(int operation) {
+        return  operation==LEFT_SHIFT   || 
+                operation==RIGHT_SHIFT  ||
+                operation==RIGHT_SHIFT_UNSIGNED;
+    }
+
+    private static boolean isAssignmentToArray(BinaryExpression binExp) {
+        Expression leftExpression = binExp.getLeftExpression();
+        if (!(leftExpression instanceof BinaryExpression)) return false;
+        BinaryExpression leftBinExpr = (BinaryExpression) leftExpression;
+        return leftBinExpr.getOperation().getType() == LEFT_SQUARE_BRACKET;
+    }
+
+    private boolean doAssignmentToArray(BinaryExpression binExp) {
+        if (!isAssignmentToArray(binExp)) return false;
+        // we need to handle only assignment to arrays combined with an operation
+        // special here. e.g x[a] += b
+        
+        int operation = removeAssignment(binExp.getOperation().getType());
+        ClassNode current =  getController().getClassNode();
+        
+        Expression leftExp = binExp.getLeftExpression();
+        ClassNode leftType = getController().getTypeChooser().resolveType(leftExp, current);
+        Expression rightExp = binExp.getRightExpression();
+        ClassNode rightType = getController().getTypeChooser().resolveType(rightExp, current);
+        
+        int operationType = getOperandType(leftType);
+        BinaryExpressionWriter bew = binExpWriter[operationType];
+        
+        boolean simulationSuccess = bew.arrayGet(LEFT_SQUARE_BRACKET, true);
+        simulationSuccess = simulationSuccess && bew.write(operation, true);
+        simulationSuccess = simulationSuccess && bew.arraySet(true);
+        if (!simulationSuccess) return false;
+        
+        AsmClassGenerator acg = getController().getAcg();
+        OperandStack operandStack = getController().getOperandStack();
+        CompileStack compileStack = getController().getCompileStack();
+               
+        // for x[a] += b we have the structure:
+        //   x = left(left(binExp))), b = right(binExp), a = right(left(binExp)))
+        // for array set we need these values on stack: array, index, right 
+        // for array get we need these values on stack: array, index
+        // to eval the expression we need x[a] = x[a]+b
+        // -> arraySet(x,a, x[a]+b) 
+        // -> arraySet(x,a, arrayGet(x,a,b))
+        // --> x,a, x,a, b as operands
+        // --> load x, load a, DUP2, call arrayGet, load b, call operation,call arraySet
+        // since we cannot DUP2 here easily we will save the subscript and DUP x
+        // --> sub=a, load x, DUP, load sub, call arrayGet, load b, call operation, load sub, call arraySet
+        
+        BinaryExpression arrayWithSubscript = (BinaryExpression) leftExp;
+        Expression subscript = arrayWithSubscript.getRightExpression();
+
+        // load array index: sub=a [load x, DUP, load sub, call arrayGet, load b, call operation, load sub, call arraySet]
+        subscript.visit(acg);
+        operandStack.doGroovyCast(int_TYPE);
+        int subscriptValueId = compileStack.defineTemporaryVariable("$sub", ClassHelper.int_TYPE, true);
+        
+        // load array: load x and DUP [load sub, call arrayGet, load b, call operation, load sub, call arraySet] 
+        arrayWithSubscript.getLeftExpression().visit(acg);
+        operandStack.doGroovyCast(leftType.makeArray());
+        operandStack.dup();
+        
+        // array get: load sub, call arrayGet [load b, call operation, load sub, call arraySet]
+        operandStack.load(ClassHelper.int_TYPE, subscriptValueId);
+        bew.arrayGet(LEFT_SQUARE_BRACKET, false);
+        operandStack.replace(leftType, 2);
+        
+        // complete rhs: load b, call operation [load sub, call arraySet]
+        binExp.getRightExpression().visit(acg);
+        if (! (bew instanceof BinaryObjectExpressionHelper)) {
+            // in primopts we convert to the left type for supported binary operations
+            operandStack.doGroovyCast(leftType);  
+        }
+        bew.write(operation, false);
+        
+        // let us save that value for the return
+        operandStack.dup();
+        int resultValueId = compileStack.defineTemporaryVariable("$result", rightType, true);
+
+        // array set: load sub, call arraySet []
+        operandStack.load(ClassHelper.int_TYPE, subscriptValueId);
+        operandStack.swap();
+        bew.arraySet(false);
+        operandStack.remove(3); // 3 operands, the array, the index and the value!
+
+        // load return value
+        operandStack.load(rightType, resultValueId);
+        
+        // cleanup
+        compileStack.removeVar(resultValueId);
+        compileStack.removeVar(subscriptValueId);
+        return true;
+    }
+    
+    @Override
+    protected void evaluateBinaryExpressionWithAssignment(String method, BinaryExpression binExp) {
+        if (doAssignmentToArray(binExp)) return;
+        if (doAssignmentToLocalVariable(method, binExp)) return;
+        super.evaluateBinaryExpressionWithAssignment(method, binExp);
+    }
+
+    private boolean doAssignmentToLocalVariable(String method, BinaryExpression binExp) {
+        Expression left = binExp.getLeftExpression();
+        if (left instanceof VariableExpression) {
+            VariableExpression ve = (VariableExpression) left;
+            Variable v = ve.getAccessedVariable();
+            if (v instanceof DynamicVariable) return false;
+            if (v instanceof PropertyExpression) return false;
+            /* field and declaration we don't return false */
+        } else {
+            return false;
+        }
+        
+        evaluateBinaryExpression(method, binExp);
+        getController().getOperandStack().dup();
+        getController().getCompileStack().pushLHS(true);
+        binExp.getLeftExpression().visit(getController().getAcg());
+        getController().getCompileStack().popLHS();
+        
+        return true;
+    }
+
+    @Override
+    protected void assignToArray(Expression orig, Expression receiver, Expression index, Expression rhsValueLoader, boolean safe) {
+        ClassNode current = getController().getClassNode();
+        ClassNode arrayType = getController().getTypeChooser().resolveType(receiver, current);
+        ClassNode arrayComponentType = arrayType.getComponentType();
+        int operationType = getOperandType(arrayComponentType);
+        BinaryExpressionWriter bew = binExpWriter[operationType];
+        AsmClassGenerator acg = getController().getAcg();
+        
+        if (bew.arraySet(true) && arrayType.isArray() && !safe) {
+            OperandStack operandStack   =   getController().getOperandStack();
+            
+            // load the array
+            receiver.visit(acg);
+            operandStack.doGroovyCast(arrayType);
+            
+            // load index
+            index.visit(acg);
+            operandStack.doGroovyCast(int_TYPE);
+            
+            // load rhs
+            rhsValueLoader.visit(acg);
+            operandStack.doGroovyCast(arrayComponentType);
+            
+            // store value in array
+            bew.arraySet(false);
+            
+            // load return value && correct operand stack stack
+            operandStack.remove(3);
+            rhsValueLoader.visit(acg);
+        } else {        
+            super.assignToArray(orig, receiver, index, rhsValueLoader, safe);
+        }
+    }
+    
+    @Override
+    protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
+        ClassNode type = getController().getTypeChooser().resolveType(orig, getController().getClassNode());
+        int operationType = getOperandType(type);
+        BinaryExpressionWriter bew = binExpWriter[operationType];
+        if (bew.writePostOrPrefixMethod(op,true)) {
+            OperandStack operandStack   =   getController().getOperandStack();
+            // at this point the receiver will be already on the stack
+            operandStack.doGroovyCast(type);
+            bew.writePostOrPrefixMethod(op,false);
+            operandStack.replace(bew.getNormalOpResultType());
+        } else {
+            super.writePostOrPrefixMethod(op, method, expression, orig);
+        }
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableClassVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableClassVisitor.java b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableClassVisitor.java
new file mode 100644
index 0000000..b794235
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableClassVisitor.java
@@ -0,0 +1,34 @@
+/*
+ *  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.classgen.asm.util;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.util.TraceClassVisitor;
+
+/**
+ * A ClassVisitor proxy, which can log bytecode generation
+ *
+ * @since 2.5.0
+ */
+public class LoggableClassVisitor extends ClassVisitor {
+    public LoggableClassVisitor(final ClassVisitor cv) {
+        super(Opcodes.ASM6, new TraceClassVisitor(cv, new LoggableTextifier(), null));
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
new file mode 100644
index 0000000..e5b0dea
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
@@ -0,0 +1,438 @@
+/*
+ *  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.classgen.asm.util;
+
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.TypePath;
+import org.objectweb.asm.util.Printer;
+import org.objectweb.asm.util.Textifier;
+
+import java.util.List;
+
+/**
+ * Logging bytecode generation, which can make debugging easy
+ *
+ * @since 2.5.0
+ */
+public class LoggableTextifier extends Textifier {
+//    private static final Logger LOGGER = Logger.getLogger(LoggableTextifier.class.getName());
+    private int loggedLineCnt = 0;
+
+    public LoggableTextifier() {
+        super(Opcodes.ASM6);
+    }
+
+    @Override
+    protected Textifier createTextifier() {
+        return new LoggableTextifier();
+    }
+
+    protected void log() {
+        int textSize = text.size();
+
+        for (int i = loggedLineCnt; i < textSize; i++) {
+            Object bc = text.get(i);
+
+            if (bc instanceof List && 0 == ((List) bc).size()) {
+                continue;
+            }
+
+            System.out.print(bc);
+        }
+
+        loggedLineCnt = textSize;
+    }
+
+
+    @Override
+    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+        super.visit(version, access, name, signature, superName, interfaces);
+        log();
+    }
+
+    @Override
+    public void visitSource(String file, String debug) {
+        super.visitSource(file, debug);
+        log();
+    }
+
+    @Override
+    public Printer visitModule(final String name, final int access, final String version) {
+        Printer p = super.visitModule(name, access, version);
+        log();
+        return p;
+    }
+
+    @Override
+    public void visitOuterClass(String owner, String name, String desc) {
+        super.visitOuterClass(owner, name, desc);
+        log();
+    }
+
+    @Override
+    public Textifier visitClassAnnotation(String desc, boolean visible) {
+        Textifier t = super.visitClassAnnotation(desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public Printer visitClassTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+        Printer t = super.visitClassTypeAnnotation(typeRef, typePath, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitClassAttribute(Attribute attr) {
+        super.visitClassAttribute(attr);
+        log();
+    }
+
+    @Override
+    public void visitInnerClass(String name, String outerName, String innerName, int access) {
+        super.visitInnerClass(name, outerName, innerName, access);
+        log();
+    }
+
+    @Override
+    public Textifier visitField(int access, String name, String desc, String signature, Object value) {
+        Textifier t = super.visitField(access, name, desc, signature, value);
+        log();
+        return t;
+    }
+
+    @Override
+    public Textifier visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+        Textifier t = super.visitMethod(access, name, desc, signature, exceptions);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitClassEnd() {
+        super.visitClassEnd();
+        log();
+    }
+
+    @Override
+    public void visitRequire(String require, int access, String version) {
+        super.visitRequire(require, access, version);
+        log();
+    }
+
+    @Override
+    public void visitExport(String export, int access, String... modules) {
+        super.visitExport(export, access, modules);
+        log();
+    }
+
+    @Override
+    public void visitUse(String use) {
+        super.visitUse(use);
+        log();
+    }
+
+    @Override
+    public void visitProvide(String provide, String... providers) {
+        super.visitProvide(provide, providers);
+        log();
+    }
+
+    @Override
+    public void visitModuleEnd() {
+        super.visitModuleEnd();
+        log();
+    }
+
+    @Override
+    public void visit(String name, Object value) {
+        super.visit(name, value);
+        log();
+    }
+
+    @Override
+    public void visitEnum(String name, String desc, String value) {
+        super.visitEnum(name, desc, value);
+        log();
+    }
+
+    @Override
+    public Textifier visitAnnotation(String name, String desc) {
+        Textifier t = super.visitAnnotation(name, desc);
+        log();
+        return t;
+    }
+
+    @Override
+    public Textifier visitArray(String name) {
+        Textifier t = super.visitArray(name);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitAnnotationEnd() {
+        super.visitAnnotationEnd();
+        log();
+    }
+
+    @Override
+    public Textifier visitFieldAnnotation(String desc, boolean visible) {
+        Textifier t = super.visitFieldAnnotation(desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public Printer visitFieldTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+        Printer t = super.visitFieldTypeAnnotation(typeRef, typePath, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitFieldAttribute(Attribute attr) {
+        super.visitFieldAttribute(attr);
+        log();
+    }
+
+    @Override
+    public void visitFieldEnd() {
+        super.visitFieldEnd();
+        log();
+    }
+
+    @Override
+    public void visitParameter(String name, int access) {
+        super.visitParameter(name, access);
+        log();
+    }
+
+    @Override
+    public Textifier visitAnnotationDefault() {
+        Textifier t = super.visitAnnotationDefault();
+        log();
+        return t;
+    }
+
+    @Override
+    public Textifier visitMethodAnnotation(String desc, boolean visible) {
+        Textifier t = super.visitMethodAnnotation(desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public Printer visitMethodTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+        Printer t = super.visitMethodTypeAnnotation(typeRef, typePath, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public Textifier visitParameterAnnotation(int parameter, String desc, boolean visible) {
+        Textifier t = super.visitParameterAnnotation(parameter, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitMethodAttribute(Attribute attr) {
+        super.visitMethodAttribute(attr);
+        log();
+    }
+
+    @Override
+    public void visitCode() {
+        super.visitCode();
+        log();
+    }
+
+    @Override
+    public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+        super.visitFrame(type, nLocal, local, nStack, stack);
+        log();
+    }
+
+    @Override
+    public void visitInsn(int opcode) {
+        super.visitInsn(opcode);
+        log();
+    }
+
+    @Override
+    public void visitIntInsn(int opcode, int operand) {
+        super.visitIntInsn(opcode, operand);
+        log();
+    }
+
+    @Override
+    public void visitVarInsn(int opcode, int var) {
+        super.visitVarInsn(opcode, var);
+        log();
+    }
+
+    @Override
+    public void visitTypeInsn(int opcode, String type) {
+        super.visitTypeInsn(opcode, type);
+        log();
+    }
+
+    @Override
+    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+        super.visitFieldInsn(opcode, owner, name, desc);
+        log();
+    }
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+        super.visitMethodInsn(opcode, owner, name, desc);
+        log();
+    }
+
+    @Override
+    public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+        super.visitMethodInsn(opcode, owner, name, desc, itf);
+        log();
+    }
+
+    @Override
+    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+        super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+        log();
+    }
+
+    @Override
+    public void visitJumpInsn(int opcode, Label label) {
+        super.visitJumpInsn(opcode, label);
+        log();
+    }
+
+    @Override
+    public void visitLabel(Label label) {
+        super.visitLabel(label);
+        log();
+    }
+
+    @Override
+    public void visitLdcInsn(Object cst) {
+        super.visitLdcInsn(cst);
+        log();
+    }
+
+    @Override
+    public void visitIincInsn(int var, int increment) {
+        super.visitIincInsn(var, increment);
+        log();
+    }
+
+    @Override
+    public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
+        super.visitTableSwitchInsn(min, max, dflt, labels);
+        log();
+    }
+
+    @Override
+    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+        super.visitLookupSwitchInsn(dflt, keys, labels);
+        log();
+    }
+
+    @Override
+    public void visitMultiANewArrayInsn(String desc, int dims) {
+        super.visitMultiANewArrayInsn(desc, dims);
+        log();
+    }
+
+    @Override
+    public Printer visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+        Printer t = super.visitInsnAnnotation(typeRef, typePath, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+        super.visitTryCatchBlock(start, end, handler, type);
+        log();
+    }
+
+    @Override
+    public Printer visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+        Printer t = super.visitTryCatchAnnotation(typeRef, typePath, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+        super.visitLocalVariable(name, desc, signature, start, end, index);
+        log();
+    }
+
+    @Override
+    public Printer visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
+        Printer t = super.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitLineNumber(int line, Label start) {
+        super.visitLineNumber(line, start);
+        log();
+    }
+
+    @Override
+    public void visitMaxs(int maxStack, int maxLocals) {
+        super.visitMaxs(maxStack, maxLocals);
+        log();
+    }
+
+    @Override
+    public void visitMethodEnd() {
+        super.visitMethodEnd();
+        log();
+    }
+
+    @Override
+    public Textifier visitAnnotation(String desc, boolean visible) {
+        Textifier t = super.visitAnnotation(desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public Textifier visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+        Textifier t = super.visitTypeAnnotation(typeRef, typePath, desc, visible);
+        log();
+        return t;
+    }
+
+    @Override
+    public void visitAttribute(Attribute attr) {
+        super.visitAttribute(attr);
+        log();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/package.html b/src/main/java/org/codehaus/groovy/classgen/package.html
new file mode 100644
index 0000000..a72224a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.classgen.*</title>
+  </head>
+  <body>
+    <p>Generates Java classes for Groovy classes using ASM.</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java b/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java
new file mode 100644
index 0000000..e583ac9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/cli/GroovyPosixParser.java
@@ -0,0 +1,281 @@
+/*
+ *  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.cli;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.Parser;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This is a hacked version of Commons CLI 1.2 PosixParser with some bug fixes added.
+ * We aren't aware of any use cases where it isn't now preferable to use the
+ * Commons CLI 1.3 DefaultParser but this class is retained for the time being for
+ * backwards compatibility if someone is relying on this class's exact functionality.
+ *
+ * @author John Keyes (john at integralsource.com)
+ * @author Paul King (Groovy hacks/fixes)
+ * @deprecated use the DefaultParser from Commons CLI
+ */
+@Deprecated
+public class GroovyPosixParser extends Parser
+{
+    /** holder for flattened tokens */
+    private List tokens = new ArrayList();
+
+    /** specifies if bursting should continue */
+    private boolean eatTheRest;
+
+    /** holder for the current option */
+    private Option currentOption;
+
+    /** the command line Options */
+    private Options options;
+
+    /**
+     * Resets the members to their original state i.e. remove
+     * all of <code>tokens</code> entries and set <code>eatTheRest</code>
+     * to false.
+     */
+    private void init()
+    {
+        eatTheRest = false;
+        tokens.clear();
+    }
+
+    /**
+     * An implementation of {@link Parser}'s abstract
+     * {@link Parser#flatten(Options,String[],boolean) flatten} method.
+     * <p>
+     * The following are the rules used by this flatten method.
+     * <ol>
+     *  <li>if <code>stopAtNonOption</code> is <b>true</b> then do not
+     *  burst anymore of <code>arguments</code> entries, just add each
+     *  successive entry without further processing.  Otherwise, ignore
+     *  <code>stopAtNonOption</code>.</li>
+     *  <li>if the current <code>arguments</code> entry is "<b>--</b>"
+     *  just add the entry to the list of processed tokens</li>
+     *  <li>if the current <code>arguments</code> entry is "<b>-</b>"
+     *  just add the entry to the list of processed tokens</li>
+     *  <li>if the current <code>arguments</code> entry is two characters
+     *  in length and the first character is "<b>-</b>" then check if this
+     *  is a valid {@link Option} id.  If it is a valid id, then add the
+     *  entry to the list of processed tokens and set the current {@link Option}
+     *  member.  If it is not a valid id and <code>stopAtNonOption</code>
+     *  is true, then the remaining entries are copied to the list of
+     *  processed tokens.  Otherwise, the current entry is ignored.</li>
+     *  <li>if the current <code>arguments</code> entry is more than two
+     *  characters in length and the first character is "<b>-</b>" then
+     *  we need to burst the entry to determine its constituents.  For more
+     *  information on the bursting algorithm see
+     *  {@link GroovyPosixParser#burstToken(String, boolean) burstToken}.</li>
+     *  <li>if the current <code>arguments</code> entry is not handled
+     *  by any of the previous rules, then the entry is added to the list
+     *  of processed tokens.</li>
+     * </ol>
+     *
+     * @param options The command line {@link Options}
+     * @param arguments The command line arguments to be parsed
+     * @param stopAtNonOption Specifies whether to stop flattening when an non option is found.
+     * @return The flattened <code>arguments</code> String array.
+     */
+    protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) {
+        init();
+        this.options = options;
+
+        // an iterator for the command line tokens
+        Iterator iter = Arrays.asList(arguments).iterator();
+
+        // process each command line token
+        while (iter.hasNext())
+        {
+            // get the next command line token
+            String token = (String) iter.next();
+
+            // handle long option --foo or --foo=bar
+            if (token.startsWith("--"))
+            {
+                int pos = token.indexOf('=');
+                String opt = pos == -1 ? token : token.substring(0, pos); // --foo
+
+                if (!options.hasOption(opt))
+                {
+                    processNonOptionToken(token, stopAtNonOption);
+                }
+                else
+                {
+                    tokens.add(opt);
+                    if (pos != -1)
+                    {
+                        tokens.add(token.substring(pos + 1));
+                    } else {
+                        currentOption = options.getOption(opt);
+                    }
+                }
+            }
+
+            // single hyphen
+            else if ("-".equals(token))
+            {
+                tokens.add(token);
+            }
+            else if (token.startsWith("-"))
+            {
+                if (token.length() == 2 || options.hasOption(token))
+                {
+                    processOptionToken(token, stopAtNonOption);
+                }
+                // requires bursting
+                else
+                {
+                    burstToken(token, stopAtNonOption);
+                }
+            }
+            else
+            {
+                processNonOptionToken(token, stopAtNonOption);
+            }
+
+            gobble(iter);
+        }
+
+        return (String[]) tokens.toArray(new String[tokens.size()]);
+    }
+
+    /**
+     * Adds the remaining tokens to the processed tokens list.
+     *
+     * @param iter An iterator over the remaining tokens
+     */
+    private void gobble(Iterator iter)
+    {
+        if (eatTheRest)
+        {
+            while (iter.hasNext())
+            {
+                tokens.add(iter.next());
+            }
+        }
+    }
+
+    /**
+     * Add the special token "<b>--</b>" and the current <code>value</code>
+     * to the processed tokens list. Then add all the remaining
+     * <code>argument</code> values to the processed tokens list.
+     *
+     * @param value The current token
+     */
+    private void processNonOptionToken(String value, boolean stopAtNonOption)
+    {
+        if (stopAtNonOption && (currentOption == null || !currentOption.hasArg()))
+        {
+            eatTheRest = true;
+            tokens.add("--");
+        }
+
+        tokens.add(value);
+        currentOption = null;
+    }
+
+    /**
+     * If an {@link Option} exists for <code>token</code> then
+     * add the token to the processed list.
+     * <p>
+     * If an {@link Option} does not exist and <code>stopAtNonOption</code>
+     * is set then add the remaining tokens to the processed tokens list
+     * directly.
+     *
+     * @param token The current option token
+     * @param stopAtNonOption Specifies whether flattening should halt at the first non option.
+     */
+    private void processOptionToken(String token, boolean stopAtNonOption) {
+        if (stopAtNonOption && !options.hasOption(token))
+        {
+            eatTheRest = true;
+        }
+
+        if (options.hasOption(token)) {
+            currentOption = options.getOption(token);
+        } else {
+            currentOption = null;
+        }
+
+        tokens.add(token);
+    }
+
+    /**
+     * Breaks <code>token</code> into its constituent parts
+     * using the following algorithm.
+     *
+     * <ul>
+     *  <li>ignore the first character ("<b>-</b>")</li>
+     *  <li>foreach remaining character check if an {@link Option}
+     *  exists with that id.</li>
+     *  <li>if an {@link Option} does exist then add that character
+     *  prepended with "<b>-</b>" to the list of processed tokens.</li>
+     *  <li>if the {@link Option} can have an argument value and there
+     *  are remaining characters in the token then add the remaining
+     *  characters as a token to the list of processed tokens.</li>
+     *  <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
+     *  <code>stopAtNonOption</code> <b>IS</b> set then add the special token
+     *  "<b>--</b>" followed by the remaining characters and also
+     *  the remaining tokens directly to the processed tokens list.</li>
+     *  <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>
+     *  <code>stopAtNonOption</code> <b>IS NOT</b> set then add that
+     *  character prepended with "<b>-</b>".</li>
+     * </ul>
+     *
+     * @param token The current token to be <b>burst</b>
+     * @param stopAtNonOption Specifies whether to stop processing
+     * at the first non-Option encountered.
+     */
+    protected void burstToken(String token, boolean stopAtNonOption)
+    {
+        for (int i = 1; i < token.length(); i++)
+        {
+            String ch = String.valueOf(token.charAt(i));
+
+            if (options.hasOption(ch))
+            {
+                tokens.add("-" + ch);
+                currentOption = options.getOption(ch);
+
+                if (currentOption.hasArg() && (token.length() != (i + 1)))
+                {
+                    tokens.add(token.substring(i + 1));
+                    break;
+                }
+            }
+            else if (stopAtNonOption)
+            {
+                processNonOptionToken(token.substring(i), true);
+                break;
+            }
+            else
+            {
+                tokens.add(token);
+                break;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java b/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java
new file mode 100644
index 0000000..ae95275
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ASTTransformationsContext.java
@@ -0,0 +1,53 @@
+/*
+ *  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.control;
+
+import groovy.lang.GroovyClassLoader;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Stores state information about global AST transformations applied to a compilation unit.
+ *
+ * @author Cedric Champeau
+*/
+public class ASTTransformationsContext {
+    protected final GroovyClassLoader transformLoader;  // Classloader for global and local transforms
+
+    protected final CompilationUnit compilationUnit; // The compilation unit global AST transformations are applied on
+    protected final Set<String> globalTransformNames = new HashSet<String>(); // collected AST transformation names
+
+    public ASTTransformationsContext(final CompilationUnit compilationUnit, final GroovyClassLoader transformLoader) {
+        this.compilationUnit = compilationUnit;
+        this.transformLoader = transformLoader;
+    }
+
+    public CompilationUnit getCompilationUnit() {
+        return compilationUnit;
+    }
+
+    public Set<String> getGlobalTransformNames() {
+        return globalTransformNames;
+    }
+
+    public GroovyClassLoader getTransformLoader() {
+        return transformLoader;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
new file mode 100644
index 0000000..b1610df
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/AnnotationConstantsVisitor.java
@@ -0,0 +1,133 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.classgen.Verifier;
+
+import java.math.BigDecimal;
+
+/**
+ * Visitor to resolve constants in annotation definitions.
+ *
+ * @author Paul King
+ */
+public class AnnotationConstantsVisitor extends ClassCodeVisitorSupport {
+    private SourceUnit source;
+    private boolean inAnnotationDef;
+
+    public void visitClass(ClassNode node, SourceUnit source) {
+        this.source = source;
+        this.inAnnotationDef = node.isAnnotationDefinition();
+        super.visitClass(node);
+        this.inAnnotationDef = false;
+    }
+
+    @Override
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        if (!inAnnotationDef) return;
+        visitStatement(node.getFirstStatement(), node.getReturnType());
+    }
+
+    private static void visitStatement(Statement statement, ClassNode returnType) {
+        if (statement instanceof ReturnStatement) {
+            // normal path
+            ReturnStatement rs = (ReturnStatement) statement;
+            rs.setExpression(transformConstantExpression(rs.getExpression(), returnType));
+        } else if (statement instanceof ExpressionStatement) {
+            // path for JavaStubGenerator
+            ExpressionStatement es = (ExpressionStatement) statement;
+            es.setExpression(transformConstantExpression(es.getExpression(), returnType));
+        }
+    }
+
+    private static Expression transformConstantExpression(Expression val, ClassNode returnType) {
+        ClassNode returnWrapperType = ClassHelper.getWrapper(returnType);
+        if (val instanceof ConstantExpression) {
+            Expression result = revertType(val, returnWrapperType);
+            if (result != null) {
+                return result;
+            }
+            return val;
+        }
+        if (val instanceof CastExpression) {
+            CastExpression castExp = (CastExpression) val;
+            Expression castee = castExp.getExpression();
+            if (castee instanceof ConstantExpression) {
+                if (ClassHelper.getWrapper(castee.getType()).isDerivedFrom(returnWrapperType)) {
+                    return castee;
+                }
+                Expression result = revertType(castee, returnWrapperType);
+                if (result != null) {
+                    return result;
+                }
+                return castee;
+            }
+        }
+        return val;
+    }
+
+    private static Expression revertType(Expression val, ClassNode returnWrapperType) {
+        ConstantExpression ce = (ConstantExpression) val;
+        if (ClassHelper.Character_TYPE.equals(returnWrapperType) && ClassHelper.STRING_TYPE.equals(val.getType())) {
+            return configure(val, Verifier.transformToPrimitiveConstantIfPossible((ConstantExpression) val));
+        }
+        ClassNode valWrapperType = ClassHelper.getWrapper(val.getType());
+        if (ClassHelper.Integer_TYPE.equals(valWrapperType)) {
+            Integer i = (Integer) ce.getValue();
+            if (ClassHelper.Character_TYPE.equals(returnWrapperType)) {
+                return configure(val, new ConstantExpression((char) i.intValue(), true));
+            }
+            if (ClassHelper.Short_TYPE.equals(returnWrapperType)) {
+                return configure(val, new ConstantExpression(i.shortValue(), true));
+            }
+            if (ClassHelper.Byte_TYPE.equals(returnWrapperType)) {
+                return configure(val, new ConstantExpression(i.byteValue(), true));
+            }
+        }
+        if (ClassHelper.BigDecimal_TYPE.equals(valWrapperType)) {
+            BigDecimal bd = (BigDecimal) ce.getValue();
+            if (ClassHelper.Float_TYPE.equals(returnWrapperType)) {
+                return configure(val, new ConstantExpression(bd.floatValue(), true));
+            }
+            if (ClassHelper.Double_TYPE.equals(returnWrapperType)) {
+                return configure(val, new ConstantExpression(bd.doubleValue(), true));
+            }
+        }
+        return null;
+    }
+
+    private static Expression configure(Expression orig, Expression result) {
+        result.setSourcePosition(orig);
+        return result;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java b/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java
new file mode 100644
index 0000000..6ef8c30
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/BytecodeProcessor.java
@@ -0,0 +1,23 @@
+/*
+ *  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.control;
+
+public interface BytecodeProcessor {
+    byte[] processBytecode(String name, byte[] original);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java b/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
new file mode 100644
index 0000000..3b64333
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ClassNodeResolver.java
@@ -0,0 +1,345 @@
+/*
+ *  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.control;
+
+import groovy.lang.GroovyClassLoader;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.decompiled.AsmDecompiler;
+import org.codehaus.groovy.ast.decompiled.AsmReferenceResolver;
+import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
+import org.codehaus.groovy.classgen.Verifier;
+import org.objectweb.asm.Opcodes;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class is used as a pluggable way to resolve class names.
+ * An instance of this class has to be added to {@link CompilationUnit} using 
+ * {@link CompilationUnit#setClassNodeResolver(ClassNodeResolver)}. The 
+ * CompilationUnit will then set the resolver on the {@link ResolveVisitor} each 
+ * time new. The ResolveVisitor will prepare name lookup and then finally ask
+ * the resolver if the class exists. This resolver then can return either a 
+ * SourceUnit or a ClassNode. In case of a SourceUnit the compiler is notified
+ * that a new source is to be added to the compilation queue. In case of a
+ * ClassNode no further action than the resolving is done. The lookup result
+ * is stored in the helper class {@link LookupResult}. This class provides a
+ * class cache to cache lookups. If you don't want this, you have to override
+ * the methods {@link ClassNodeResolver#cacheClass(String, ClassNode)} and 
+ * {@link ClassNodeResolver#getFromClassCache(String)}. Custom lookup logic is
+ * supposed to go into the method 
+ * {@link ClassNodeResolver#findClassNode(String, CompilationUnit)} while the 
+ * entry method is {@link ClassNodeResolver#resolveName(String, CompilationUnit)}
+ * 
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class ClassNodeResolver {
+
+    /**
+     * Helper class to return either a SourceUnit or ClassNode.
+     * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+     */
+    public static class LookupResult {
+        private final SourceUnit su;
+        private final ClassNode cn;
+        /**
+         * creates a new LookupResult. You are not supposed to supply
+         * a SourceUnit and a ClassNode at the same time
+         */
+        public LookupResult(SourceUnit su, ClassNode cn) {
+            this.su = su;
+            this.cn = cn;
+            if (su==null && cn==null) throw new IllegalArgumentException("Either the SourceUnit or the ClassNode must not be null.");
+            if (su!=null && cn!=null) throw new IllegalArgumentException("SourceUnit and ClassNode cannot be set at the same time.");
+        }
+        /**
+         * returns true if a ClassNode is stored
+         */
+        public boolean isClassNode() { return cn!=null; }
+        /**
+         * returns true if a SourecUnit is stored
+         */
+        public boolean isSourceUnit() { return su!=null; }
+        /**
+         * returns the SourceUnit
+         */
+        public SourceUnit getSourceUnit() { return su; }
+        /**
+         * returns the ClassNode
+         */
+        public ClassNode getClassNode() { return cn; }
+    }
+
+    // Map to store cached classes
+    private final Map<String,ClassNode> cachedClasses = new HashMap();
+    /**
+     * Internal helper used to indicate a cache hit for a class that does not exist. 
+     * This way further lookups through a slow {@link #findClassNode(String, CompilationUnit)} 
+     * path can be avoided.
+     * WARNING: This class is not to be used outside of ClassNodeResolver.
+     */
+    protected static final ClassNode NO_CLASS = new ClassNode("NO_CLASS", Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE){
+        public void setRedirect(ClassNode cn) {
+            throw new GroovyBugError("This is a dummy class node only! Never use it for real classes.");
+        }
+    };
+    
+    /**
+     * Resolves the name of a class to a SourceUnit or ClassNode. If no
+     * class or source is found this method returns null. A lookup is done
+     * by first asking the cache if there is an entry for the class already available
+     * to then call {@link #findClassNode(String, CompilationUnit)}. The result 
+     * of that method call will be cached if a ClassNode is found. If a SourceUnit
+     * is found, this method will not be asked later on again for that class, because
+     * ResolveVisitor will first ask the CompilationUnit for classes in the
+     * compilation queue and it will find the class for that SourceUnit there then.
+     * method return a ClassNode instead of a SourceUnit, the res 
+     * @param name - the name of the class
+     * @param compilationUnit - the current CompilationUnit
+     * @return the LookupResult
+     */
+    public LookupResult resolveName(String name, CompilationUnit compilationUnit) {
+        ClassNode res = getFromClassCache(name);
+        if (res==NO_CLASS) return null;
+        if (res!=null) return new LookupResult(null,res);
+        LookupResult lr = findClassNode(name, compilationUnit);
+        if (lr != null) {
+            if (lr.isClassNode()) cacheClass(name, lr.getClassNode());
+            return lr;
+        } else {
+            cacheClass(name, NO_CLASS);
+            return null;
+        }
+    }
+    
+    /**
+     * caches a ClassNode
+     * @param name - the name of the class
+     * @param res - the ClassNode for that name
+     */
+    public void cacheClass(String name, ClassNode res) {
+        cachedClasses.put(name, res);
+    }
+    
+    /**
+     * returns whatever is stored in the class cache for the given name
+     * @param name - the name of the class
+     * @return the result of the lookup, which may be null
+     */
+    public ClassNode getFromClassCache(String name) {
+        // We use here the class cache cachedClasses to prevent
+        // calls to ClassLoader#loadClass. Disabling this cache will
+        // cause a major performance hit.
+        ClassNode cached = cachedClasses.get(name);
+        return cached;
+    }
+    
+    /**
+     * Extension point for custom lookup logic of finding ClassNodes. Per default
+     * this will use the CompilationUnit class loader to do a lookup on the class
+     * path and load the needed class using that loader. Or if a script is found 
+     * and that script is seen as "newer", the script will be used instead of the 
+     * class.
+     * 
+     * @param name - the name of the class
+     * @param compilationUnit - the current compilation unit
+     * @return the lookup result
+     */
+    public LookupResult findClassNode(String name, CompilationUnit compilationUnit) {
+        return tryAsLoaderClassOrScript(name, compilationUnit);
+    }
+
+    /**
+     * This method is used to realize the lookup of a class using the compilation
+     * unit class loader. Should no class be found we fall back to a script lookup.
+     * If a class is found we check if there is also a script and maybe use that
+     * one in case it is newer.<p/>
+     *
+     * Two class search strategies are possible: by ASM decompilation or by usual Java classloading.
+     * The latter is slower but is unavoidable for scripts executed in dynamic environments where
+     * the referenced classes might only be available in the classloader, not on disk.
+     */
+    private LookupResult tryAsLoaderClassOrScript(String name, CompilationUnit compilationUnit) {
+        GroovyClassLoader loader = compilationUnit.getClassLoader();
+
+        Map<String, Boolean> options = compilationUnit.configuration.getOptimizationOptions();
+        boolean useAsm = !Boolean.FALSE.equals(options.get("asmResolving"));
+        boolean useClassLoader = !Boolean.FALSE.equals(options.get("classLoaderResolving"));
+
+        LookupResult result = useAsm ? findDecompiled(name, compilationUnit, loader) : null;
+        if (result != null) {
+            return result;
+        }
+
+        if (!useClassLoader) {
+            return tryAsScript(name, compilationUnit, null);
+        }
+
+        return findByClassLoading(name, compilationUnit, loader);
+    }
+
+    /**
+     * Search for classes using class loading
+     */
+    private static LookupResult findByClassLoading(String name, CompilationUnit compilationUnit, GroovyClassLoader loader) {
+        Class cls;
+        try {
+            // NOTE: it's important to do no lookup against script files
+            // here since the GroovyClassLoader would create a new CompilationUnit
+            cls = loader.loadClass(name, false, true);
+        } catch (ClassNotFoundException cnfe) {
+            LookupResult lr = tryAsScript(name, compilationUnit, null);
+            return lr;
+        } catch (CompilationFailedException cfe) {
+            throw new GroovyBugError("The lookup for "+name+" caused a failed compilaton. There should not have been any compilation from this call.", cfe);
+        }
+        //TODO: the case of a NoClassDefFoundError needs a bit more research
+        // a simple recompilation is not possible it seems. The current class
+        // we are searching for is there, so we should mark that somehow.
+        // Basically the missing class needs to be completely compiled before
+        // we can again search for the current name.
+        /*catch (NoClassDefFoundError ncdfe) {
+            cachedClasses.put(name,SCRIPT);
+            return false;
+        }*/
+        if (cls == null) return null;
+        //NOTE: we might return false here even if we found a class,
+        //      because  we want to give a possible script a chance to
+        //      recompile. This can only be done if the loader was not
+        //      the instance defining the class.
+        ClassNode cn = ClassHelper.make(cls);
+        if (cls.getClassLoader() != loader) {
+            return tryAsScript(name, compilationUnit, cn);
+        }
+        return new LookupResult(null,cn);
+    }
+
+    /**
+     * Search for classes using ASM decompiler
+     */
+    private LookupResult findDecompiled(String name, CompilationUnit compilationUnit, GroovyClassLoader loader) {
+        ClassNode node = ClassHelper.make(name);
+        if (node.isResolved()) {
+            return new LookupResult(null, node);
+        }
+
+        DecompiledClassNode asmClass = null;
+        String fileName = name.replace('.', '/') + ".class";
+        URL resource = loader.getResource(fileName);
+        if (resource != null) {
+            try {
+                asmClass = new DecompiledClassNode(AsmDecompiler.parseClass(resource), new AsmReferenceResolver(this, compilationUnit));
+                if (!asmClass.getName().equals(name)) {
+                    // this may happen under Windows because getResource is case insensitive under that OS!
+                    asmClass = null;
+                }
+            } catch (IOException e) {
+                // fall through and attempt other search strategies
+            }
+        }
+
+        if (asmClass != null) {
+            if (isFromAnotherClassLoader(loader, fileName)) {
+                return tryAsScript(name, compilationUnit, asmClass);
+            }
+
+            return new LookupResult(null, asmClass);
+        }
+        return null;
+    }
+
+    private static boolean isFromAnotherClassLoader(GroovyClassLoader loader, String fileName) {
+        ClassLoader parent = loader.getParent();
+        return parent != null && parent.getResource(fileName) != null;
+    }
+
+    /**
+     * try to find a script using the compilation unit class loader.
+     */
+    private static LookupResult tryAsScript(String name, CompilationUnit compilationUnit, ClassNode oldClass) {
+        LookupResult lr = null;
+        if (oldClass!=null) {
+            lr = new LookupResult(null, oldClass);
+        }
+        
+        if (name.startsWith("java.")) return lr;
+        //TODO: don't ignore inner static classes completely
+        if (name.indexOf('$') != -1) return lr;
+        
+        // try to find a script from classpath*/
+        GroovyClassLoader gcl = compilationUnit.getClassLoader();
+        URL url = null;
+        try {
+            url = gcl.getResourceLoader().loadGroovySource(name);
+        } catch (MalformedURLException e) {
+            // fall through and let the URL be null
+        }
+        if (url != null && ( oldClass==null || isSourceNewer(url, oldClass))) {
+            SourceUnit su = compilationUnit.addSource(url);
+            return new LookupResult(su,null);
+        }
+        return lr;
+    }
+
+    /**
+     * get the time stamp of a class
+     * NOTE: copied from GroovyClassLoader
+     */
+    private static long getTimeStamp(ClassNode cls) {
+        if (!(cls instanceof DecompiledClassNode)) {
+            return Verifier.getTimestamp(cls.getTypeClass());
+        }
+
+        return ((DecompiledClassNode) cls).getCompilationTimeStamp();
+    }
+
+    /**
+     * returns true if the source in URL is newer than the class
+     * NOTE: copied from GroovyClassLoader
+     */
+    private static boolean isSourceNewer(URL source, ClassNode cls) {
+        try {
+            long lastMod;
+
+            // Special handling for file:// protocol, as getLastModified() often reports
+            // incorrect results (-1)
+            if (source.getProtocol().equals("file")) {
+                // Coerce the file URL to a File
+                String path = source.getPath().replace('/', File.separatorChar).replace('|', ':');
+                File file = new File(path);
+                lastMod = file.lastModified();
+            } else {
+                URLConnection conn = source.openConnection();
+                lastMod = conn.getLastModified();
+                conn.getInputStream().close();
+            }
+            return lastMod > getTimeStamp(cls);
+        } catch (IOException e) {
+            // if the stream can't be opened, let's keep the old reference
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java b/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java
new file mode 100644
index 0000000..741b647
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/CompilationFailedException.java
@@ -0,0 +1,77 @@
+/*
+ *  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.control;
+
+import groovy.lang.GroovyRuntimeException;
+
+
+/**
+ * Thrown when compilation fails from source errors.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class CompilationFailedException extends GroovyRuntimeException {
+
+    protected int phase;   // The phase in which the failures occurred
+    protected ProcessingUnit unit;    // The *Unit object this exception wraps
+
+    public CompilationFailedException(int phase, ProcessingUnit unit, Throwable cause) {
+        super(Phases.getDescription(phase) + " failed", cause);
+        this.phase = phase;
+        this.unit = unit;
+    }
+
+
+    public CompilationFailedException(int phase, ProcessingUnit unit) {
+        super(Phases.getDescription(phase) + " failed");
+        this.phase = phase;
+        this.unit = unit;
+    }
+
+
+    /**
+     * Formats the error data as a String.
+     */
+
+    /*public String toString() {
+        StringWriter data = new StringWriter();
+        PrintWriter writer = new PrintWriter(data);
+        Janitor janitor = new Janitor();
+
+        try {
+            unit.getErrorReporter().write(writer, janitor);
+        }
+        finally {
+            janitor.cleanup();
+        }
+
+        return data.toString();
+    }*/
+
+
+    /**
+     * Returns the ProcessingUnit in which the error occurred.
+     */
+
+    public ProcessingUnit getUnit() {
+        return this.unit;
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java
new file mode 100644
index 0000000..2222590
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassSignatureParser.java
@@ -0,0 +1,84 @@
+/*
+ *  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.ClassNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Peter Gromov
+ */
+class ClassSignatureParser {
+    static void configureClass(ClassNode classNode, ClassStub stub, AsmReferenceResolver resolver) {
+        if (stub.signature != null) {
+            parseClassSignature(classNode, stub.signature, resolver);
+            return;
+        }
+
+        if (stub.superName != null) {
+            classNode.setSuperClass(resolver.resolveClass(AsmDecompiler.fromInternalName(stub.superName)));
+        }
+
+        ClassNode[] interfaces = new ClassNode[stub.interfaceNames.length];
+        for (int i = 0; i < stub.interfaceNames.length; i++) {
+            interfaces[i] = resolver.resolveClass(AsmDecompiler.fromInternalName(stub.interfaceNames[i]));
+        }
+        classNode.setInterfaces(interfaces);
+    }
+
+    private static void parseClassSignature(final ClassNode classNode, String signature, final AsmReferenceResolver resolver) {
+        final List<ClassNode> interfaces = new ArrayList<ClassNode>();
+        FormalParameterParser v = new FormalParameterParser(resolver) {
+
+            @Override
+            public SignatureVisitor visitSuperclass() {
+                flushTypeParameter();
+                return new TypeSignatureParser(resolver) {
+                    @Override
+                    void finished(ClassNode result) {
+                        classNode.setSuperClass(result);
+                    }
+                };
+            }
+
+            @Override
+            public SignatureVisitor visitInterface() {
+                flushTypeParameter();
+                return new TypeSignatureParser(resolver) {
+                    @Override
+                    void finished(ClassNode result) {
+                        interfaces.add(result);
+                    }
+                };
+            }
+
+        };
+        new SignatureReader(signature).accept(v);
+        GenericsType[] typeParameters = v.getTypeParameters();
+        if (typeParameters.length > 0) {
+            classNode.setGenericsTypes(typeParameters);
+        }
+        classNode.setInterfaces(interfaces.toArray(new ClassNode[interfaces.size()]));
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java
new file mode 100644
index 0000000..364b69d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/ClassStub.java
@@ -0,0 +1,117 @@
+/*
+ *  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 java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Peter Gromov
+ */
+public class ClassStub extends MemberStub {
+    final String className;
+    final int accessModifiers;
+    final String signature;
+    final String superName;
+    final String[] interfaceNames;
+    List<MethodStub> methods;
+    List<FieldStub> fields;
+    final Map<String, Integer> innerClassModifiers = new HashMap<String, Integer>();
+
+    public ClassStub(String className, int accessModifiers, String signature, String superName, String[] interfaceNames) {
+        this.className = className;
+        this.accessModifiers = accessModifiers;
+        this.signature = signature;
+        this.superName = superName;
+        this.interfaceNames = interfaceNames;
+    }
+}
+
+class MemberStub {
+    List<AnnotationStub> annotations = null;
+
+    AnnotationStub addAnnotation(String desc) {
+        AnnotationStub stub = new AnnotationStub(desc);
+        if (annotations == null) annotations = new ArrayList<AnnotationStub>(1);
+        annotations.add(stub);
+        return stub;
+    }
+}
+
+class MethodStub extends MemberStub {
+    final String methodName;
+    final int accessModifiers;
+    final String desc;
+    final String signature;
+    final String[] exceptions;
+    Map<Integer, List<AnnotationStub>> parameterAnnotations;
+    Object annotationDefault;
+
+    public MethodStub(String methodName, int accessModifiers, String desc, String signature, String[] exceptions) {
+        this.methodName = methodName;
+        this.accessModifiers = accessModifiers;
+        this.desc = desc;
+        this.signature = signature;
+        this.exceptions = exceptions;
+    }
+}
+
+class FieldStub extends MemberStub {
+    final String fieldName;
+    final int accessModifiers;
+    final String desc;
+    final String signature;
+
+    public FieldStub(String fieldName, int accessModifiers, String desc, String signature) {
+        this.fieldName = fieldName;
+        this.accessModifiers = accessModifiers;
+        this.desc = desc;
+        this.signature = signature;
+    }
+}
+
+class AnnotationStub {
+    final String className;
+    final Map<String, Object> members = new LinkedHashMap<String, Object>();
+
+    public AnnotationStub(String className) {
+        this.className = className;
+    }
+}
+
+class TypeWrapper {
+    final String desc;
+
+    public TypeWrapper(String desc) {
+        this.desc = desc;
+    }
+}
+
+class EnumConstantWrapper {
+    final String enumDesc;
+    final String constant;
+
+    public EnumConstantWrapper(String enumDesc, String constant) {
+        this.enumDesc = enumDesc;
+        this.constant = constant;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java b/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
new file mode 100644
index 0000000..18cc79f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/DecompiledClassNode.java
@@ -0,0 +1,242 @@
+/*
+ *  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.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.MixinNode;
+import org.codehaus.groovy.classgen.Verifier;
+
+import java.lang.reflect.Modifier;
+import java.util.List;
+
+/**
+ * A {@link ClassNode} kind representing the classes coming from *.class files decompiled using ASM.
+ *
+ * @see AsmDecompiler
+ * @author Peter Gromov
+ */
+public class DecompiledClassNode extends ClassNode {
+    private final ClassStub classData;
+    private final AsmReferenceResolver resolver;
+    private boolean supersInitialized = false;
+    private boolean membersInitialized = false;
+
+    public DecompiledClassNode(ClassStub data, AsmReferenceResolver resolver) {
+        super(data.className, getFullModifiers(data, resolver), null, null, MixinNode.EMPTY_ARRAY);
+        classData = data;
+        this.resolver = resolver;
+        isPrimaryNode = false;
+    }
+
+    /**
+     * Static inner classes don't have "static" part in their own modifiers. Their containing classes have to be inspected
+     * whether they have an inner class with the same name that's static. '$' separator convention is used to search
+     * for parent classes.
+     */
+    private static int getFullModifiers(ClassStub data, AsmReferenceResolver resolver) {
+        String className = data.className;
+        int bound = className.length();
+        while (bound > 0) {
+            int idx = className.lastIndexOf('$', bound);
+            if (idx > 0) {
+                ClassNode outerClass = resolver.resolveClassNullable(className.substring(0, idx));
+                if (outerClass instanceof DecompiledClassNode) {
+                    Integer outerModifiers = ((DecompiledClassNode) outerClass).classData.innerClassModifiers.get(className.substring(idx + 1));
+                    if (outerModifiers != null) {
+                        return data.accessModifiers | outerModifiers;
+                    }
+                }
+            }
+            bound = idx - 1;
+        }
+        return data.accessModifiers;
+    }
+
+    public long getCompilationTimeStamp() {
+        if (classData.fields != null) {
+            for (FieldStub field : classData.fields) {
+                if (Modifier.isStatic(field.accessModifiers)) {
+                    Long timestamp = Verifier.getTimestampFromFieldName(field.fieldName);
+                    if (timestamp != null) {
+                        return timestamp;
+                    }
+                }
+            }
+        }
+        return Long.MAX_VALUE;
+    }
+
+    @Override
+    public GenericsType[] getGenericsTypes() {
+        lazyInitSupers();
+        return super.getGenericsTypes();
+    }
+
+    @Override
+    public boolean isUsingGenerics() {
+        lazyInitSupers();
+        return super.isUsingGenerics();
+    }
+
+    @Override
+    public List<FieldNode> getFields() {
+        lazyInitMembers();
+        return super.getFields();
+    }
+
+    @Override
+    public ClassNode[] getInterfaces() {
+        lazyInitSupers();
+        return super.getInterfaces();
+    }
+
+    @Override
+    public List<MethodNode> getMethods() {
+        lazyInitMembers();
+        return super.getMethods();
+    }
+
+    @Override
+    public List<ConstructorNode> getDeclaredConstructors() {
+        lazyInitMembers();
+        return super.getDeclaredConstructors();
+    }
+
+    @Override
+    public FieldNode getDeclaredField(String name) {
+        lazyInitMembers();
+        return super.getDeclaredField(name);
+    }
+
+    @Override
+    public List<MethodNode> getDeclaredMethods(String name) {
+        lazyInitMembers();
+        return super.getDeclaredMethods(name);
+    }
+
+    @Override
+    public ClassNode getUnresolvedSuperClass(boolean useRedirect) {
+        lazyInitSupers();
+        return super.getUnresolvedSuperClass(useRedirect);
+    }
+
+    @Override
+    public ClassNode[] getUnresolvedInterfaces(boolean useRedirect) {
+        lazyInitSupers();
+        return super.getUnresolvedInterfaces(useRedirect);
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations() {
+        lazyInitSupers();
+        return super.getAnnotations();
+    }
+
+    @Override
+    public List<AnnotationNode> getAnnotations(ClassNode type) {
+        lazyInitSupers();
+        return super.getAnnotations(type);
+    }
+
+    @Override
+    public void setRedirect(ClassNode cn) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setGenericsPlaceHolder(boolean b) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setUsingGenerics(boolean b) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String setName(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isResolved() {
+        return true;
+    }
+
+    @Override
+    public Class getTypeClass() {
+        return resolver.resolveJvmClass(getName());
+    }
+
+    private void lazyInitSupers() {
+        synchronized (lazyInitLock) {
+            if (!supersInitialized) {
+                ClassSignatureParser.configureClass(this, this.classData, this.resolver);
+                addAnnotations(classData, this);
+                supersInitialized = true;
+            }
+        }
+
+    }
+
+    private void lazyInitMembers() {
+        synchronized (lazyInitLock) {
+            if (!membersInitialized) {
+                if (classData.methods != null) {
+                    for (MethodStub method : classData.methods) {
+                        MethodNode node = addAnnotations(method, MemberSignatureParser.createMethodNode(resolver, method));
+                        if (node instanceof ConstructorNode) {
+                            addConstructor((ConstructorNode) node);
+                        } else {
+                            addMethod(node);
+                        }
+                    }
+                }
+
+                if (classData.fields != null) {
+                    for (FieldStub field : classData.fields) {
+                        addField(addAnnotations(field, MemberSignatureParser.createFieldNode(field, resolver, this)));
+                    }
+                }
+
+                membersInitialized = true;
+            }
+        }
+    }
+
+    private <T extends AnnotatedNode> T addAnnotations(MemberStub stub, T node) {
+        List<AnnotationStub> annotations = stub.annotations;
+        if (annotations != null) {
+            for (AnnotationStub annotation : annotations) {
+                AnnotationNode annotationNode = Annotations.createAnnotationNode(annotation, resolver);
+                if (annotationNode != null) {
+                    node.addAnnotation(annotationNode);
+                }
+            }
+        }
+        return node;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/FormalParameterParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/FormalParameterParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/FormalParameterParser.java
new file mode 100644
index 0000000..98277d8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/FormalParameterParser.java
@@ -0,0 +1,80 @@
+/*
+ *  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.ClassNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.vmplugin.v5.Java5;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.signature.SignatureVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* @author Peter Gromov
+*/
+abstract class FormalParameterParser extends SignatureVisitor {
+    private final AsmReferenceResolver resolver;
+    private String currentTypeParameter;
+    private final List<ClassNode> parameterBounds = new ArrayList<ClassNode>();
+    private final List<GenericsType> typeParameters = new ArrayList<GenericsType>();
+
+    public FormalParameterParser(AsmReferenceResolver resolver) {
+        super(Opcodes.ASM5);
+        this.resolver = resolver;
+    }
+
+    @Override
+    public void visitFormalTypeParameter(String name) {
+        flushTypeParameter();
+        currentTypeParameter = name;
+    }
+
+    protected void flushTypeParameter() {
+        if (currentTypeParameter != null) {
+            ClassNode ref = Java5.configureTypeVariableReference(currentTypeParameter);
+            ClassNode[] boundNodes = parameterBounds.toArray(new ClassNode[parameterBounds.size()]);
+            typeParameters.add(Java5.configureTypeVariableDefinition(ref, boundNodes));
+
+            currentTypeParameter = null;
+            parameterBounds.clear();
+        }
+    }
+
+    @Override
+    public SignatureVisitor visitClassBound() {
+        return new TypeSignatureParser(resolver) {
+            @Override
+            void finished(ClassNode result) {
+                parameterBounds.add(result);
+            }
+        };
+    }
+
+    @Override
+    public SignatureVisitor visitInterfaceBound() {
+        return visitClassBound();
+    }
+
+    public GenericsType[] getTypeParameters() {
+        flushTypeParameter();
+        return typeParameters.toArray(new GenericsType[typeParameters.size()]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java
new file mode 100644
index 0000000..6627c85
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/MemberSignatureParser.java
@@ -0,0 +1,155 @@
+/*
+ *  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.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Peter Gromov
+ */
+class MemberSignatureParser {
+    static MethodNode createMethodNode(final AsmReferenceResolver resolver, MethodStub method) {
+        GenericsType[] typeParameters = null;
+
+        Type[] argumentTypes = Type.getArgumentTypes(method.desc);
+        final ClassNode[] parameterTypes = new ClassNode[argumentTypes.length];
+        for (int i = 0; i < argumentTypes.length; i++) {
+            parameterTypes[i] = resolver.resolveType(argumentTypes[i]);
+        }
+
+        final ClassNode[] exceptions = new ClassNode[method.exceptions.length];
+        for (int i = 0; i < method.exceptions.length; i++) {
+            exceptions[i] = resolver.resolveClass(AsmDecompiler.fromInternalName(method.exceptions[i]));
+        }
+
+        final ClassNode[] returnType = {resolver.resolveType(Type.getReturnType(method.desc))};
+
+        if (method.signature != null) {
+            FormalParameterParser v = new FormalParameterParser(resolver) {
+                int paramIndex = 0;
+
+                @Override
+                public SignatureVisitor visitParameterType() {
+                    return new TypeSignatureParser(resolver) {
+                        @Override
+                        void finished(ClassNode result) {
+                            parameterTypes[paramIndex] = applyErasure(result, parameterTypes[paramIndex]);
+                            paramIndex++;
+                        }
+                    };
+                }
+
+                @Override
+                public SignatureVisitor visitReturnType() {
+                    return new TypeSignatureParser(resolver) {
+                        @Override
+                        void finished(ClassNode result) {
+                            returnType[0] = applyErasure(result, returnType[0]);
+                        }
+                    };
+                }
+
+                int exceptionIndex = 0;
+
+                @Override
+                public SignatureVisitor visitExceptionType() {
+                    return new TypeSignatureParser(resolver) {
+                        @Override
+                        void finished(ClassNode result) {
+                            exceptions[exceptionIndex] = applyErasure(result, exceptions[exceptionIndex]);
+                            exceptionIndex++;
+                        }
+                    };
+                }
+            };
+            new SignatureReader(method.signature).accept(v);
+            typeParameters = v.getTypeParameters();
+        }
+
+        Parameter[] parameters = new Parameter[parameterTypes.length];
+        for (int i = 0; i < parameterTypes.length; i++) {
+            parameters[i] = new Parameter(parameterTypes[i], "param" + i);
+        }
+
+        if (method.parameterAnnotations != null) {
+            for (Map.Entry<Integer, List<AnnotationStub>> entry : method.parameterAnnotations.entrySet()) {
+                for (AnnotationStub stub : entry.getValue()) {
+                    AnnotationNode annotationNode = Annotations.createAnnotationNode(stub, resolver);
+                    if (annotationNode != null) {
+                        parameters[entry.getKey()].addAnnotation(annotationNode);
+                    }
+                }
+            }
+        }
+
+        MethodNode result;
+        if ("<init>".equals(method.methodName)) {
+            result = new ConstructorNode(method.accessModifiers, parameters, exceptions, null);
+        } else {
+            result = new MethodNode(method.methodName, method.accessModifiers, returnType[0], parameters, exceptions, null);
+            if (method.annotationDefault != null) {
+                result.setCode(new ReturnStatement(new ConstantExpression(method.annotationDefault)));
+                result.setAnnotationDefault(true);
+            } else {
+                // Seems wrong but otherwise some tests fail (e.g. TestingASTTransformsTest)
+                result.setCode(new ReturnStatement(ConstantExpression.NULL));
+            }
+
+        }
+        if (typeParameters != null && typeParameters.length > 0) {
+            result.setGenericsTypes(typeParameters);
+        }
+        return result;
+    }
+
+    private static ClassNode applyErasure(ClassNode genericType, ClassNode erasure) {
+        if (genericType.isGenericsPlaceHolder()) {
+            genericType.setRedirect(erasure);
+        }
+        return genericType;
+    }
+
+    static FieldNode createFieldNode(FieldStub field, AsmReferenceResolver resolver, DecompiledClassNode owner) {
+        final ClassNode[] type = {resolver.resolveType(Type.getType(field.desc))};
+        if (field.signature != null) {
+            new SignatureReader(field.signature).accept(new TypeSignatureParser(resolver) {
+                @Override
+                void finished(ClassNode result) {
+                    type[0] = applyErasure(result, type[0]);
+                }
+            });
+        }
+        return new FieldNode(field.fieldName, field.accessModifiers, type[0], owner, null);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
new file mode 100644
index 0000000..7d971ed
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
@@ -0,0 +1,123 @@
+/*
+ *  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.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.vmplugin.v5.Java5;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.signature.SignatureVisitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* @author Peter Gromov
+*/
+abstract class TypeSignatureParser extends SignatureVisitor {
+    private final AsmReferenceResolver resolver;
+
+    public TypeSignatureParser(AsmReferenceResolver resolver) {
+        super(Opcodes.ASM5);
+        this.resolver = resolver;
+    }
+
+    abstract void finished(ClassNode result);
+
+    private String baseName;
+    private final List<GenericsType> arguments = new ArrayList<GenericsType>();
+
+    @Override
+    public void visitTypeVariable(String name) {
+        finished(Java5.configureTypeVariableReference(name));
+    }
+
+    @Override
+    public void visitBaseType(char descriptor) {
+        finished(resolver.resolveType(Type.getType(String.valueOf(descriptor))));
+    }
+
+    @Override
+    public SignatureVisitor visitArrayType() {
+        final TypeSignatureParser outer = this;
+        return new TypeSignatureParser(resolver) {
+            @Override
+            void finished(ClassNode result) {
+                outer.finished(result.makeArray());
+            }
+        };
+    }
+
+    @Override
+    public void visitClassType(String name) {
+        baseName = AsmDecompiler.fromInternalName(name);
+    }
+
+    @Override
+    public void visitTypeArgument() {
+        arguments.add(createWildcard(new ClassNode[]{ClassHelper.OBJECT_TYPE}, null));
+    }
+
+    @Override
+    public SignatureVisitor visitTypeArgument(final char wildcard) {
+        return new TypeSignatureParser(resolver) {
+            @Override
+            void finished(ClassNode result) {
+                if (wildcard == INSTANCEOF) {
+                    arguments.add(new GenericsType(result));
+                    return;
+                }
+
+                ClassNode[] upper = wildcard == EXTENDS ? new ClassNode[]{result} : null;
+                ClassNode lower = wildcard == SUPER ? result : null;
+                arguments.add(createWildcard(upper, lower));
+            }
+        };
+    }
+
+    private static GenericsType createWildcard(ClassNode[] upper, ClassNode lower) {
+        ClassNode base = ClassHelper.makeWithoutCaching("?");
+        base.setRedirect(ClassHelper.OBJECT_TYPE);
+        GenericsType t = new GenericsType(base, upper, lower);
+        t.setWildcard(true);
+        return t;
+    }
+
+    @Override
+    public void visitInnerClassType(String name) {
+        baseName += "$" + name;
+        arguments.clear();
+    }
+
+    @Override
+    public void visitEnd() {
+        ClassNode base = resolver.resolveClass(baseName);
+        if (arguments.isEmpty()) {
+            finished(base);
+            return;
+        }
+
+        ClassNode bound = base.getPlainNodeReference();
+        bound.setGenericsTypes(arguments.toArray(new GenericsType[arguments.size()]));
+        finished(bound);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/AnnotationConstantExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/AnnotationConstantExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/AnnotationConstantExpression.java
new file mode 100644
index 0000000..bb4d78f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/AnnotationConstantExpression.java
@@ -0,0 +1,50 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+import java.util.Map;
+
+/**
+ * Represents an annotation "constant" that may appear in annotation attributes
+ * (mainly used as a marker).
+ *
+ * @author <a href='mailto:the[dot]mindstorm[at]gmail[dot]com'>Alex Popescu</a>
+ */
+public class AnnotationConstantExpression extends ConstantExpression {
+    public AnnotationConstantExpression(AnnotationNode node) {
+        super(node);
+        setType(node.getClassNode());
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        AnnotationNode node = (AnnotationNode) getValue();
+        Map<String, Expression> attrs = node.getMembers();
+        for (Expression expr : attrs.values()) {
+            expr.visit(visitor);
+        }
+        super.visit(visitor);
+    }
+
+    public String toString() {
+        return "AnnotationConstantExpression[" + getValue() + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ArgumentListExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ArgumentListExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ArgumentListExpression.java
new file mode 100644
index 0000000..de835b7
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ArgumentListExpression.java
@@ -0,0 +1,78 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+
+import java.util.List;
+
+/**
+ * Represents one or more arguments being passed into a method
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ArgumentListExpression extends TupleExpression {
+
+    public static final Object[] EMPTY_ARRAY = {
+    };
+    
+    public static final ArgumentListExpression EMPTY_ARGUMENTS = new ArgumentListExpression();
+
+    public ArgumentListExpression() {
+    }
+
+    public ArgumentListExpression(List<Expression> expressions) {
+        super(expressions);
+    }
+
+    public ArgumentListExpression(Expression[] expressions) {
+        super(expressions);
+    }
+
+    public ArgumentListExpression(Parameter[] parameters) {
+        for (int i = 0; i < parameters.length; i++) {
+            Parameter parameter = parameters[i];
+            addExpression(new VariableExpression(parameter));
+        }
+    }
+    
+    public ArgumentListExpression(Expression expr) {
+        super(expr);
+    }
+
+    public ArgumentListExpression(Expression expr1, Expression expr2) {
+        super(expr1, expr2);
+    }
+
+    public ArgumentListExpression(Expression expr1, Expression expr2, Expression expr3) {
+        super(expr1, expr2, expr3);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new ArgumentListExpression(transformExpressions(getExpressions(), transformer));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitArgumentlistExpression(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ArrayExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ArrayExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ArrayExpression.java
new file mode 100644
index 0000000..a70102d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ArrayExpression.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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents an array object construction either using a fixed size
+ * or an initializer expression
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ArrayExpression extends Expression {
+    private final List<Expression> expressions;
+    private final List<Expression> sizeExpression;
+
+    private final ClassNode elementType;
+
+    private static ClassNode makeArray(ClassNode base, List<Expression> sizeExpression) {
+        ClassNode ret = base.makeArray();
+        if (sizeExpression == null) return ret;
+        int size = sizeExpression.size();
+        for (int i = 1; i < size; i++) {
+            ret = ret.makeArray();
+        }
+        return ret;
+    }
+
+    public ArrayExpression(ClassNode elementType, List<Expression> expressions, List<Expression> sizeExpression) {
+        //expect to get the elementType
+        super.setType(makeArray(elementType, sizeExpression));
+        if (expressions == null) expressions = Collections.emptyList();
+        this.elementType = elementType;
+        this.expressions = expressions;
+        this.sizeExpression = sizeExpression;
+
+        for (Object item : expressions) {
+            if (item != null && !(item instanceof Expression)) {
+                throw new ClassCastException("Item: " + item + " is not an Expression");
+            }
+        }
+        if (sizeExpression != null) {
+            for (Object item : sizeExpression) {
+                if (!(item instanceof Expression)) {
+                    throw new ClassCastException("Item: " + item + " is not an Expression");
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Creates an array using an initializer expression
+     */
+    public ArrayExpression(ClassNode elementType, List<Expression> expressions) {
+        this(elementType, expressions, null);
+    }
+
+    public void addExpression(Expression expression) {
+        expressions.add(expression);
+    }
+
+    public List<Expression> getExpressions() {
+        return expressions;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitArrayExpression(this);
+    }
+
+    public boolean isDynamic() {
+        return false;
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        List<Expression> exprList = transformExpressions(expressions, transformer);
+        List<Expression> sizes = null;
+        if (sizeExpression != null) sizes = transformExpressions(sizeExpression, transformer);
+        Expression ret = new ArrayExpression(elementType, exprList, sizes);
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public Expression getExpression(int i) {
+        return expressions.get(i);
+    }
+
+    public ClassNode getElementType() {
+        return elementType;
+    }
+
+    public String getText() {
+        StringBuilder buffer = new StringBuilder("[");
+        boolean first = true;
+        for (Expression expression : expressions) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(", ");
+            }
+
+            buffer.append(expression.getText());
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    public List<Expression> getSizeExpression() {
+        return sizeExpression;
+    }
+
+    public String toString() {
+        return super.toString() + expressions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/AttributeExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/AttributeExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/AttributeExpression.java
new file mode 100644
index 0000000..a52929c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/AttributeExpression.java
@@ -0,0 +1,50 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents an attribute access (accessing the field of a class) such as the expression "foo.@bar".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class AttributeExpression extends PropertyExpression {
+
+    public AttributeExpression(Expression objectExpression, Expression property) {
+        super(objectExpression, property, false);
+    }
+
+    public AttributeExpression(Expression objectExpression, Expression property, boolean safe) {
+        super(objectExpression, property, safe);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitAttributeExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        AttributeExpression ret = new AttributeExpression(transformer.transform(getObjectExpression()),transformer.transform(getProperty()),isSafe());
+        ret.setSourcePosition(this);
+        ret.setSpreadSafe(isSpreadSafe());
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/BinaryExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/BinaryExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/BinaryExpression.java
new file mode 100644
index 0000000..e970947
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/BinaryExpression.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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+
+/**
+ * Represents two expressions and an operation
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class BinaryExpression extends Expression {
+
+    private Expression leftExpression;
+    private Expression rightExpression;
+    private final Token operation;
+    private boolean safe = false;
+
+    public BinaryExpression(Expression leftExpression,
+                            Token operation,
+                            Expression rightExpression) {
+        this.leftExpression = leftExpression;
+        this.operation = operation;
+        this.rightExpression = rightExpression;
+    }
+
+    public BinaryExpression(Expression leftExpression,
+                            Token operation,
+                            Expression rightExpression,
+                            boolean safe) {
+        this(leftExpression, operation, rightExpression);
+        this.safe = safe;
+    }
+
+    public String toString() {
+        return super.toString() + "[" + leftExpression + operation + rightExpression + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBinaryExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new BinaryExpression(transformer.transform(leftExpression), operation, transformer.transform(rightExpression), safe);
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public Expression getLeftExpression() {
+        return leftExpression;
+    }
+
+    public void setLeftExpression(Expression leftExpression) {
+        this.leftExpression = leftExpression;
+    }
+
+    public void setRightExpression(Expression rightExpression) {
+        this.rightExpression = rightExpression;
+    }
+
+    public Token getOperation() {
+        return operation;
+    }
+
+    public Expression getRightExpression() {
+        return rightExpression;
+    }
+
+    public String getText() {
+        if (operation.getType() == Types.LEFT_SQUARE_BRACKET) {
+            return leftExpression.getText() + (safe ? "?" : "") + "[" + rightExpression.getText() + "]";
+        }
+        return "(" + leftExpression.getText() + " " + operation.getText() + " " + rightExpression.getText() + ")";
+    }
+
+    public boolean isSafe() {
+        return safe;
+    }
+
+    public void setSafe(boolean safe) {
+        this.safe = safe;
+    }
+
+    /**
+     * Creates an assignment expression in which the specified expression
+     * is written into the specified variable name.
+     */
+
+    public static BinaryExpression newAssignmentExpression(Variable variable, Expression rhs) {
+        VariableExpression lhs = new VariableExpression(variable);
+        Token operator = Token.newPlaceholder(Types.ASSIGN);
+
+        return new BinaryExpression(lhs, operator, rhs);
+    }
+
+
+    /**
+     * Creates variable initialization expression in which the specified expression
+     * is written into the specified variable name.
+     */
+
+    public static BinaryExpression newInitializationExpression(String variable, ClassNode type, Expression rhs) {
+        VariableExpression lhs = new VariableExpression(variable);
+
+        if (type != null) {
+            lhs.setType(type);
+        }
+
+        Token operator = Token.newPlaceholder(Types.ASSIGN);
+
+        return new BinaryExpression(lhs, operator, rhs);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/BitwiseNegationExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/BitwiseNegationExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/BitwiseNegationExpression.java
new file mode 100644
index 0000000..dece59d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/BitwiseNegationExpression.java
@@ -0,0 +1,58 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * @author phk
+ */
+public class BitwiseNegationExpression extends Expression {
+
+    private final Expression expression;
+
+    public BitwiseNegationExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBitwiseNegationExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new BitwiseNegationExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public String getText() {
+        return expression.getText();
+    }
+
+    public ClassNode getType() {
+        return expression.getType();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/BooleanExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/BooleanExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/BooleanExpression.java
new file mode 100644
index 0000000..5cab929
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/BooleanExpression.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a boolean expression
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class BooleanExpression extends Expression {
+    private final Expression expression;
+
+    public BooleanExpression(Expression expression) {
+        this.expression = expression;
+        setType(ClassHelper.boolean_TYPE); // for consistency with AsmClassGenerator. see AsmClassGenerator.visitBooleanExpression.
+    }
+    
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBooleanExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new BooleanExpression(transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+    
+    public String getText() {
+        return expression.getText();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/CastExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/CastExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/CastExpression.java
new file mode 100644
index 0000000..f6145bb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/CastExpression.java
@@ -0,0 +1,111 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a type cast expression
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class CastExpression extends Expression {
+    
+    private final Expression expression;
+    private boolean ignoreAutoboxing=false;
+    private boolean coerce = false;
+    private boolean strict = false;
+
+    public static CastExpression asExpression(ClassNode type, Expression expression) {
+        CastExpression answer = new CastExpression(type, expression);
+        answer.setCoerce(true);
+        return answer;
+    }
+
+    public CastExpression(ClassNode type, Expression expression) {
+        this(type,expression,false);
+    }
+
+    public CastExpression(ClassNode type, Expression expression, boolean ignoreAutoboxing) {
+        super.setType(type);
+        this.expression = expression;
+        this.ignoreAutoboxing = ignoreAutoboxing;
+    }
+    
+    public boolean isIgnoringAutoboxing(){
+        return ignoreAutoboxing;
+    }
+
+    public boolean isCoerce() {
+        return coerce;
+    }
+
+    public void setCoerce(boolean coerce) {
+        this.coerce = coerce;
+    }
+
+    /**
+     * If strict mode is true, then when the compiler generates a cast, it will disable
+     * Groovy casts and rely on a strict cast (CHECKCAST)
+     * @return true if strict mode is enable
+     */
+    public boolean isStrict() {
+        return strict;
+    }
+
+    /**
+     * If strict mode is true, then when the compiler generates a cast, it will disable
+     * Groovy casts and rely on a strict cast (CHECKCAST)
+     * @param strict strict mode
+     */
+    public void setStrict(final boolean strict) {
+        this.strict = strict;
+    }
+
+    public String toString() {
+        return super.toString() +"[(" + getType().getName() + ") " + expression + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCastExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        CastExpression ret =  new CastExpression(getType(), transformer.transform(expression));
+        ret.setSourcePosition(this);
+        ret.setCoerce(this.isCoerce());
+        ret.setStrict(this.isStrict());
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+    
+    public String getText() {
+        return "(" + getType() + ") " + expression.getText();
+    }
+ 
+    public Expression getExpression() {
+        return expression;
+    }
+    
+    public void setType(ClassNode t) {
+        super.setType(t);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ClassExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ClassExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ClassExpression.java
new file mode 100644
index 0000000..9b29e5c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ClassExpression.java
@@ -0,0 +1,51 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents access to a Java/Groovy class in an expression, such
+ * as when invoking a static method or accessing a static type
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ClassExpression extends Expression {
+
+    public ClassExpression(ClassNode type) {
+        super.setType(type);
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitClassExpression(this);
+    }
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+    
+    public String getText() {
+        return getType().getName();
+    }
+
+    public String toString() {
+       return super.toString() + "[type: " + getType().getName() + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java
new file mode 100644
index 0000000..802a6ee
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ClosureExpression.java
@@ -0,0 +1,105 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.AstToTextHelper;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+/**
+ * Represents a closure expression such as { statement }
+ * or { i -> statement } or { i, x, String y ->  statement }
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Hamlet D'Arcy
+ */
+public class ClosureExpression extends Expression {
+    
+    private final Parameter[] parameters;
+    private Statement code;
+    private VariableScope variableScope;
+    
+    public ClosureExpression(Parameter[] parameters, Statement code) {
+        this.parameters = parameters;
+        this.code = code;
+        super.setType(ClassHelper.CLOSURE_TYPE.getPlainNodeReference());
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitClosureExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+    
+    public String toString() {
+        return super.toString() + InvokerHelper.toString(parameters) + "{ " + code + " }";
+    }
+
+    /**
+     * This gets the code statement of the closure. You can read this method to find out what actions
+     * the closure is going to perform.
+     *
+     * @return the code statement of the closure
+     */
+    public Statement getCode() {
+        return code;
+    }
+
+    /**
+     * This sets the code statement of the closure. You can use this method in order to add more actions
+     * during the closure execution.
+     *
+     * @param code the new Statement
+     */
+    public void setCode(Statement code) {
+        this.code = code;
+    }
+
+    public Parameter[] getParameters() {
+        return parameters;
+    }
+
+    public boolean isParameterSpecified() {
+        return parameters != null && parameters.length > 0;
+    }
+    
+    public VariableScope getVariableScope() {
+        return variableScope;
+    }
+
+    public void setVariableScope(VariableScope variableScope) {
+        this.variableScope = variableScope;
+    }
+
+    @Override
+    public String getText() {
+        String paramText = AstToTextHelper.getParametersText(parameters);
+        if (paramText.length() > 0) {
+            return "{ " + paramText + " -> ... }";
+        } else {
+            return "{ -> ... }";
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ClosureListExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ClosureListExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ClosureListExpression.java
new file mode 100644
index 0000000..ecbd333
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ClosureListExpression.java
@@ -0,0 +1,88 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.VariableScope;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a list of expressions used to
+ * create closures. Example:
+ * <code>
+ * def foo = (1;2;;)
+ * </code>
+ * The right side is a ClosureListExpression consisting of
+ * two ConstantExpressions for the values 1 and 2, and two
+ * EmptyStatement entries. The ClosureListExpression defines a new 
+ * variable scope. All created Closures share this scope.
+ * 
+ * 
+ * @author Jochen Theodorou
+ */
+public class ClosureListExpression extends ListExpression {
+
+    private VariableScope scope;
+    
+    public ClosureListExpression(List<Expression> expressions) {
+        super(expressions);
+        scope = new VariableScope();
+    }
+    
+    public ClosureListExpression() {
+        this(new ArrayList<Expression>(3));
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitClosureListExpression(this);
+    }
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new ClosureListExpression(transformExpressions(getExpressions(), transformer));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret;       
+    }
+    
+    public void setVariableScope(VariableScope scope) {
+        this.scope = scope;
+    }
+    
+    public VariableScope getVariableScope() {
+        return scope;
+    }
+    
+    public String getText() {
+        StringBuilder buffer = new StringBuilder("(");
+        boolean first = true;
+        for (Expression expression : getExpressions()) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append("; ");
+            }
+            
+            buffer.append(expression.getText());
+        }
+        buffer.append(")");
+        return buffer.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ConstantExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ConstantExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ConstantExpression.java
new file mode 100644
index 0000000..dfa2c52
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ConstantExpression.java
@@ -0,0 +1,124 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a constant expression such as null, true, false
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ConstantExpression extends Expression {
+    // The following fields are only used internally; every occurrence of a user-defined expression of the same kind
+    // has its own instance so as to preserve line information. Consequently, to test for such an expression, don't
+    // compare against the field but call isXXXExpression() instead.
+    public static final ConstantExpression NULL = new ConstantExpression(null);
+    public static final ConstantExpression TRUE = new ConstantExpression(Boolean.TRUE);
+    public static final ConstantExpression FALSE = new ConstantExpression(Boolean.FALSE);
+    public static final ConstantExpression EMPTY_STRING = new ConstantExpression("");
+    public static final ConstantExpression PRIM_TRUE = new ConstantExpression(Boolean.TRUE, true);
+    public static final ConstantExpression PRIM_FALSE = new ConstantExpression(Boolean.FALSE, true);
+    //public static final Expression EMPTY_ARRAY = new PropertyExpression(new ClassExpression(ArgumentListExpression.class.getName()), "EMPTY_ARRAY");
+
+    // the following fields are only used internally; there are no user-defined expressions of the same kind
+    public static final ConstantExpression VOID = new ConstantExpression(Void.class);
+    public static final ConstantExpression EMPTY_EXPRESSION = new ConstantExpression(null);
+    
+    private final Object value;
+    private String constantName;
+
+    public ConstantExpression(Object value) {
+        this(value,false);
+    }
+
+    public ConstantExpression(Object value, boolean keepPrimitive) {
+        this.value = value;
+        if (value != null) {
+            if (keepPrimitive) {
+                if (value instanceof Integer) {
+                    setType(ClassHelper.int_TYPE);
+                } else if (value instanceof Long) {
+                    setType(ClassHelper.long_TYPE);
+                } else if (value instanceof Boolean) {
+                    setType(ClassHelper.boolean_TYPE);
+                } else if (value instanceof Double) {
+                    setType(ClassHelper.double_TYPE);
+                } else if (value instanceof Float) {
+                    setType(ClassHelper.float_TYPE);
+                } else if (value instanceof Character) {
+                    setType(ClassHelper.char_TYPE);
+                } else {
+                    setType(ClassHelper.make(value.getClass()));
+                }
+                //TODO: more cases here
+            } else {
+                setType(ClassHelper.make(value.getClass()));
+            }
+        }
+    }
+
+    public String toString() {
+        return "ConstantExpression[" + value + "]";
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitConstantExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+
+    /**
+     * @return the value of this constant expression
+     */    
+    public Object getValue() {
+        return value;
+    }
+
+    public String getText() {
+        return (value == null) ? "null" : value.toString();
+    }
+
+    public String getConstantName() {
+        return constantName;
+    }
+
+    public void setConstantName(String constantName) {
+        this.constantName = constantName;
+    }
+
+    public boolean isNullExpression() {
+        return value == null;
+    }
+
+    public boolean isTrueExpression() {
+        return Boolean.TRUE.equals(value);
+    }
+
+    public boolean isFalseExpression() {
+        return Boolean.FALSE.equals(value);
+    }
+
+    public boolean isEmptyStringExpression() {
+        return "".equals(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ConstructorCallExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ConstructorCallExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ConstructorCallExpression.java
new file mode 100644
index 0000000..0c040fa
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ConstructorCallExpression.java
@@ -0,0 +1,105 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * A constructor call
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Jochen Theodorou
+ */
+public class ConstructorCallExpression extends Expression implements MethodCall {
+
+    private final Expression arguments;
+    private boolean usesAnonymousInnerClass;
+
+    public ConstructorCallExpression(ClassNode type, Expression arguments) {
+        super.setType(type);
+        if (!(arguments instanceof TupleExpression)) {
+            this.arguments = new TupleExpression(arguments);
+        } else {
+            this.arguments = arguments;
+        }
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitConstructorCallExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression args = transformer.transform(arguments);
+        ConstructorCallExpression ret = new ConstructorCallExpression(getType(), args);
+        ret.setSourcePosition(this);
+        ret.setUsingAnonymousInnerClass(isUsingAnonymousInnerClass());
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+
+    public ASTNode getReceiver() {
+        return null;
+    }
+
+    public String getMethodAsString() {
+        return "<init>";
+    }
+
+    public Expression getArguments() {
+        return arguments;
+    }
+
+    public String getText() {
+        String text = null;
+        if (isSuperCall()) {
+            text = "super ";
+        } else if (isThisCall()) {
+            text = "this ";
+        } else {
+            text = "new " + getType().getName();
+        }
+        return text + arguments.getText();
+    }
+
+    public String toString() {
+        return super.toString() + "[type: " + getType() + " arguments: " + arguments + "]";
+    }
+
+    public boolean isSuperCall() {
+        return getType() == ClassNode.SUPER;
+    }
+
+    public boolean isSpecialCall() {
+        return isThisCall() || isSuperCall();
+    }
+
+    public boolean isThisCall() {
+        return getType() == ClassNode.THIS;
+    }
+
+    public void setUsingAnonymousInnerClass(boolean usage) {
+        this.usesAnonymousInnerClass = usage;
+    }
+
+    public boolean isUsingAnonymousInnerClass() {
+        return usesAnonymousInnerClass;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/DeclarationExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/DeclarationExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/DeclarationExpression.java
new file mode 100644
index 0000000..6c082a7
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/DeclarationExpression.java
@@ -0,0 +1,168 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.syntax.Token;
+
+/**
+ * Represents one or more local variables. Typically it is a single local variable
+ * declared by name with an expression like "def foo" or with type "String foo". However, 
+ * the multiple assignment feature allows you to create two or more variables using
+ * an expression like: <code>def (x, y) = [1, 2]</code>.
+ * <p>
+ * You can access the left hand side of a declaration using the
+ * "<code>Expression getLeftExpression()</code>" method. In which case you might then
+ * use <code>instanceof</code> and casting to perform operations specific to a
+ * single local variable (<code>VariableExpression</code>) or for the multiple
+ * assignment case (<code>TupleExpression</code>).
+ * <p>
+ * Alternatively, if <code>isMultipleAssignmentDeclaration()</code> is <code>false</code>
+ * you can use the method "<code>VariableExpression getVariableExpression()</code>" method.
+ * Similarly, if <code>isMultipleAssignmentDeclaration()</code> is <code>true</code>
+ * you can use the method "<code>TupleExpression getTupleExpression()</code>" method.
+ * Calling either of these expression getters when the "isMultipleAssignment" condition
+ * is not appropriate is unsafe and will result in a <code>ClassCastException</code>.
+ *
+ * @author Jochen Theodorou
+ * @author Hamlet D'Arcy
+ */
+public class DeclarationExpression extends BinaryExpression {
+    
+    /**
+     * Creates a DeclarationExpression for VariableExpressions like "def x" or "String y = 'foo'". 
+     * @param left
+     *      the left hand side of a variable declaration
+     * @param operation
+     *      the operation, typically an assignment operator
+     * @param right
+     *      the right hand side of a declaration
+     */ 
+    public DeclarationExpression(VariableExpression left, Token operation, Expression right) {
+        super(left,operation,right);
+    }
+    
+    /**
+     * Creates a DeclarationExpression for Expressions like "def (x, y) = [1, 2]"
+     * @param left
+     *      the left hand side of a declaration. Must be either a VariableExpression or 
+     *      a TupleExpression with at least one element.  
+     * @param operation
+     *       the operation, typically an assignment operator
+     * @param right
+     *       the right hand side of a declaration
+     */ 
+    public DeclarationExpression(Expression left, Token operation, Expression right) {
+        super(left,operation,right);
+        check(left);
+    }
+    
+    private static void check(Expression left) {
+        if (left instanceof VariableExpression) {
+            //nothing
+        } else if (left instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) left;
+            if (tuple.getExpressions().isEmpty()) throw new GroovyBugError("one element required for left side");
+        } else {
+            throw new GroovyBugError("illegal left expression for declaration: "+left);
+        }
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitDeclarationExpression(this);
+    }
+
+    /**
+     * This method returns the left hand side of the declaration cast to the VariableExpression type.
+     * This is an unsafe method to call. In a multiple assignment statement, the left hand side will
+     * be a TupleExpression and a ClassCastException will occur. If you invoke this method then
+     * be sure to invoke isMultipleAssignmentDeclaration() first to check that it is safe to do so. 
+     * If that method returns true then this method is safe to call.
+     *
+     * @return left hand side of normal variable declarations
+     * @throws ClassCastException if the left hand side is not a VariableExpression (and is probably a multiple assignment statement).
+     */
+    public VariableExpression getVariableExpression() {
+        Expression leftExpression = this.getLeftExpression();
+
+        return leftExpression instanceof VariableExpression
+                    ? (VariableExpression) leftExpression
+                    : null;
+    }
+    
+    /**
+     * This method returns the left hand side of the declaration cast to the TupleExpression type.
+     * This is an unsafe method to call. In a single assignment statement, the left hand side will
+     * be a VariableExpression and a ClassCastException will occur. If you invoke this method then
+     * be sure to invoke isMultipleAssignmentDeclaration() first to check that it is safe to do so. 
+     * If that method returns true then this method is safe to call. 
+     * @return
+     *      left hand side of multiple assignment declarations
+     * @throws ClassCastException 
+     *      if the left hand side is not a TupleExpression (and is probably a VariableExpression).
+     *
+     */
+    public TupleExpression getTupleExpression() {
+        Expression leftExpression = this.getLeftExpression();
+
+        return leftExpression instanceof TupleExpression
+                    ? (TupleExpression) leftExpression
+                    : null;
+    }
+    
+    /**
+     * This method sets the leftExpression for this BinaryExpression. The parameter must be
+     * either a VariableExpression or a TupleExpression with one or more elements. 
+     * @param leftExpression
+     *      either a VariableExpression or a TupleExpression with one or more elements. 
+     */ 
+    public void setLeftExpression(Expression leftExpression) {
+        check(leftExpression);
+        super.setLeftExpression(leftExpression);
+    }
+    
+    public void setRightExpression(Expression rightExpression) {
+        super.setRightExpression(rightExpression);
+    }
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new DeclarationExpression(transformer.transform(getLeftExpression()),
+                getOperation(), transformer.transform(getRightExpression()));
+        ret.setSourcePosition(this);
+        ret.addAnnotations(getAnnotations());
+        ret.setDeclaringClass(getDeclaringClass());
+        ret.copyNodeMetaData(this);
+        return ret;
+    }
+    
+    /**
+     * This method tells you if this declaration is a multiple assignment declaration, which 
+     * has the form "def (x, y) = ..." in Groovy. If this method returns true, then the left
+     * hand side is an ArgumentListExpression. Do not call "getVariableExpression()" on this 
+     * object if this method returns true, instead use "getLeftExpression()". 
+     * @return
+     *      true if this declaration is a multiple assignment declaration, which means the
+     *      left hand side is an ArgumentListExpression. 
+     */ 
+    public boolean isMultipleAssignmentDeclaration() {
+        return getLeftExpression() instanceof TupleExpression;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/ElvisOperatorExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/ElvisOperatorExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/ElvisOperatorExpression.java
new file mode 100644
index 0000000..64df749
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/ElvisOperatorExpression.java
@@ -0,0 +1,71 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+/**
+ * Represents a short ternary expression x ?: y, which is equal 
+ * to 
+ * <pre>
+ * def truePart = x
+ * def booleanPart = truePart as boolean
+ * booleanPart? truePart : y
+ * </pre>
+ * Even if x is no atomic expression, x will be evaluated only 
+ * once. Example:
+ * <pre class="groovyTestCase">
+ * class Foo { 
+ *   def index=0 
+ *   def getX(){ index++; return index }
+ * }
+ * def foo = new Foo()
+ * def result = foo.x ?: "false case" 
+ * assert foo.index == 1
+ * assert result == 1 
+ * </pre>
+ * 
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @since 1.5
+ */
+public class ElvisOperatorExpression extends TernaryExpression {
+
+    public ElvisOperatorExpression(Expression base, Expression falseExpression) {
+        super(getBool(base), base, falseExpression);
+    }
+    
+    private static BooleanExpression getBool(Expression base) {
+       BooleanExpression be = new BooleanExpression(base);
+       be.setSourcePosition(base);
+       return be;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitShortTernaryExpression(this);
+    }
+    
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        Expression ret = new ElvisOperatorExpression(
+                transformer.transform(getTrueExpression()),
+                transformer.transform(getFalseExpression()));
+        ret.setSourcePosition(this);
+        ret.copyNodeMetaData(this);
+        return ret; 
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/VariableAccessReplacer.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/VariableAccessReplacer.groovy b/src/main/groovy/VariableAccessReplacer.groovy
new file mode 100644
index 0000000..d62dc46
--- /dev/null
+++ b/src/main/groovy/VariableAccessReplacer.groovy
@@ -0,0 +1,73 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.expr.VariableExpression
+
+/**
+ * Replace all access to variables and args by new variables.
+ * The variable names to replace as well as their replacement name and type have to be configured
+ * in nameAndTypeMapping before calling replaceIn().
+ *
+ * The VariableReplacedListener can be set if clients want to react to variable replacement.
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class VariableAccessReplacer {
+
+    /**
+     * Nested map of variable accesses to replace
+     * e.g.: [
+     *          'varToReplace': [name: 'newVar', type: TypeOfVar],
+     *          'varToReplace2': [name: 'newVar2', type: TypeOfVar2],
+     *       ]
+     */
+    Map<String, Map> nameAndTypeMapping = [:]
+
+    VariableReplacedListener listener = VariableReplacedListener.NULL
+
+    void replaceIn(ASTNode root) {
+        Closure<Boolean> whenParam = { VariableExpression expr ->
+            return nameAndTypeMapping.containsKey(expr.name)
+        }
+        Closure<VariableExpression> replaceWithLocalVariable = { VariableExpression expr ->
+            Map nameAndType = nameAndTypeMapping[expr.name]
+            VariableExpression newVar = AstHelper.createVariableReference(nameAndType)
+            listener.variableReplaced(expr, newVar)
+            return newVar
+        }
+        new VariableExpressionReplacer(when: whenParam, replaceWith: replaceWithLocalVariable).replaceIn(root)
+    }
+
+}
+
+@CompileStatic
+interface VariableReplacedListener {
+    void variableReplaced(VariableExpression oldVar, VariableExpression newVar)
+
+    static VariableReplacedListener NULL = new VariableReplacedListener() {
+        @Override
+        void variableReplaced(VariableExpression oldVar, VariableExpression newVar) {
+            //do nothing
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/VariableExpressionReplacer.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/VariableExpressionReplacer.groovy b/src/main/groovy/VariableExpressionReplacer.groovy
new file mode 100644
index 0000000..1f14490
--- /dev/null
+++ b/src/main/groovy/VariableExpressionReplacer.groovy
@@ -0,0 +1,171 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.CodeVisitorSupport
+import org.codehaus.groovy.ast.expr.BinaryExpression
+import org.codehaus.groovy.ast.expr.BooleanExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.ExpressionTransformer
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.AssertStatement
+import org.codehaus.groovy.ast.stmt.CaseStatement
+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.WhileStatement
+
+import java.lang.reflect.Method
+
+/**
+ * Tool for replacing VariableExpression instances in an AST by other VariableExpression instances.
+ * Regardless of a real change taking place in nested expressions, all considered expression (trees) will be replaced.
+ * This could be optimized to accelerate compilation.
+ *
+ * Within @TailRecursive it is used
+ * - to swap the access of method args with the access to iteration variables
+ * - to swap the access of iteration variables with the access of temp vars
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class VariableExpressionReplacer extends CodeVisitorSupport {
+
+    Closure<Boolean> when = { VariableExpression node -> false }
+    Closure<VariableExpression> replaceWith = { VariableExpression variableExpression -> variableExpression }
+
+    private ExpressionTransformer transformer
+
+    synchronized void replaceIn(ASTNode root) {
+        transformer = new VariableExpressionTransformer(when: when, replaceWith: replaceWith)
+        root.visit(this)
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement)
+        super.visitReturnStatement(statement);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        replaceExpressionPropertyWhenNecessary(ifElse, 'booleanExpression', BooleanExpression)
+        super.visitIfElse(ifElse);
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        replaceExpressionPropertyWhenNecessary(forLoop, 'collectionExpression')
+        super.visitForLoop(forLoop);
+    }
+
+    /**
+     * It's the only Expression type in which replacing is considered.
+     * That's an abuse of the class, but I couldn't think of a better way.
+     */
+    public void visitBinaryExpression(BinaryExpression expression) {
+        //A hack: Only replace right expression b/c ReturnStatementToIterationConverter needs it that way :-/
+        replaceExpressionPropertyWhenNecessary(expression, 'rightExpression')
+        expression.getRightExpression().visit(this);
+        super.visitBinaryExpression(expression)
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        replaceExpressionPropertyWhenNecessary(loop, 'booleanExpression', BooleanExpression)
+        super.visitWhileLoop(loop);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        replaceExpressionPropertyWhenNecessary(loop, 'booleanExpression', BooleanExpression)
+        super.visitDoWhileLoop(loop);
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement)
+        super.visitSwitch(statement)
+    }
+
+    public void visitCaseStatement(CaseStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement)
+        super.visitCaseStatement(statement)
+    }
+
+    public void visitExpressionStatement(ExpressionStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement)
+        super.visitExpressionStatement(statement);
+    }
+
+    public void visitThrowStatement(ThrowStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement)
+        super.visitThrowStatement(statement)
+    }
+
+    public void visitAssertStatement(AssertStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement, 'booleanExpression', BooleanExpression)
+        replaceExpressionPropertyWhenNecessary(statement, 'messageExpression')
+        super.visitAssertStatement(statement)
+    }
+
+    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+        replaceExpressionPropertyWhenNecessary(statement)
+        super.visitSynchronizedStatement(statement)
+    }
+
+    private void replaceExpressionPropertyWhenNecessary(ASTNode node, String propName = "expression", Class propClass = Expression) {
+        Expression expr = getExpression(node, propName)
+
+        if (expr instanceof VariableExpression) {
+            if (when(expr)) {
+                VariableExpression newExpr = replaceWith(expr)
+                replaceExpression(node, propName, propClass, expr, newExpr)
+            }
+        } else {
+            Expression newExpr = expr.transformExpression(transformer)
+            replaceExpression(node, propName, propClass, expr, newExpr)
+        }
+    }
+
+    private void replaceExpression(ASTNode node, String propName, Class propClass, Expression oldExpr, Expression newExpr) {
+        //Use reflection to enable CompileStatic
+        String setterName = 'set' + capitalizeFirst(propName)
+        Method setExpressionMethod = node.class.getMethod(setterName, [propClass].toArray(new Class[1]))
+        newExpr.setSourcePosition(oldExpr);
+        newExpr.copyNodeMetaData(oldExpr);
+        setExpressionMethod.invoke(node, [newExpr].toArray())
+    }
+
+    private Expression getExpression(ASTNode node, String propName) {
+        //Use reflection to enable CompileStatic
+        String getterName = 'get' + capitalizeFirst(propName)
+        Method getExpressionMethod = node.class.getMethod(getterName, new Class[0])
+        getExpressionMethod.invoke(node, new Object[0]) as Expression
+    }
+
+    private String capitalizeFirst(String propName) {
+        propName[0].toUpperCase() + propName[1..-1]
+    }
+
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/VariableExpressionTransformer.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/VariableExpressionTransformer.groovy b/src/main/groovy/VariableExpressionTransformer.groovy
new file mode 100644
index 0000000..106a2f1
--- /dev/null
+++ b/src/main/groovy/VariableExpressionTransformer.groovy
@@ -0,0 +1,47 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.ExpressionTransformer
+import org.codehaus.groovy.ast.expr.VariableExpression
+
+/**
+ * An expression transformer used in the process of replacing the access to variables
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class VariableExpressionTransformer implements ExpressionTransformer {
+
+    Closure<Boolean> when
+    Closure<VariableExpression> replaceWith
+
+    @Override
+    Expression transform(Expression expr) {
+        if ((expr instanceof VariableExpression) && when(expr)) {
+            VariableExpression newExpr = replaceWith(expr)
+            newExpr.setSourcePosition(expr);
+            newExpr.copyNodeMetaData(expr);
+            return newExpr
+        }
+        return expr.transformExpression(this)
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/genArrayAccess.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/genArrayAccess.groovy b/src/main/groovy/genArrayAccess.groovy
new file mode 100644
index 0000000..08cb68a
--- /dev/null
+++ b/src/main/groovy/genArrayAccess.groovy
@@ -0,0 +1,146 @@
+/*
+ *  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.classgen
+
+println """
+package org.codehaus.groovy.runtime.dgmimpl;
+
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ReflectionCache;
+
+public class ArrayOperations {
+  ${genInners()}
+}
+"""
+
+def genInners () {
+    def res = ""
+
+    final Map primitives = [
+            "boolean": "Boolean",
+            "byte": "Byte",
+            "char": "Character",
+            "short": "Short",
+            "int": "Integer",
+            "long": "Long",
+            "float": "Float",
+            "double": "Double"
+    ]
+
+    primitives.each {primName, clsName ->
+        res += """
+         public static class ${clsName}ArrayGetAtMetaMethod extends ArrayGetAtMetaMethod {
+            private static final CachedClass ARR_CLASS = ReflectionCache.getCachedClass(${primName}[].class);
+
+            public Class getReturnType() {
+                return ${clsName}.class;
+            }
+
+            public final CachedClass getDeclaringClass() {
+                return ARR_CLASS;
+            }
+
+            public Object invoke(Object object, Object[] args) {
+                final ${primName}[] objects = (${primName}[]) object;
+                return objects[normaliseIndex(((Integer) args[0]).intValue(), objects.length)];
+            }
+
+            public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+                if (!(args [0] instanceof Integer))
+                  return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
+                else
+                    return new PojoMetaMethodSite(site, metaClass, metaMethod, params) {
+                        public Object invoke(Object receiver, Object[] args) {
+                            final ${primName}[] objects = (${primName}[]) receiver;
+                            return objects[normaliseIndex(((Integer) args[0]).intValue(), objects.length)];
+                        }
+
+                        public Object callBinop(Object receiver, Object arg) {
+                            if ((receiver instanceof ${primName}[] && arg instanceof Integer)
+                                    && checkMetaClass()) {
+                                final ${primName}[] objects = (${primName}[]) receiver;
+                                return objects[normaliseIndex(((Integer) arg).intValue(), objects.length)];
+                            }
+                            else
+                              return super.callBinop(receiver,arg);
+                        }
+
+                        public Object invokeBinop(Object receiver, Object arg) {
+                            final ${primName}[] objects = (${primName}[]) receiver;
+                            return objects[normaliseIndex(((Integer) arg).intValue(), objects.length)];
+                        }
+                    };
+            }
+         }
+
+
+        public static class ${clsName}ArrayPutAtMetaMethod extends ArrayPutAtMetaMethod {
+            private static final CachedClass OBJECT_CLASS = ReflectionCache.OBJECT_CLASS;
+            private static final CachedClass ARR_CLASS = ReflectionCache.getCachedClass(${primName}[].class);
+            private static final CachedClass [] PARAM_CLASS_ARR = new CachedClass[] {INTEGER_CLASS, OBJECT_CLASS};
+
+            public ${clsName}ArrayPutAtMetaMethod() {
+                parameterTypes = PARAM_CLASS_ARR;
+            }
+
+            public final CachedClass getDeclaringClass() {
+                return ARR_CLASS;
+            }
+
+            public Object invoke(Object object, Object[] args) {
+                final ${primName}[] objects = (${primName}[]) object;
+                final int index = normaliseIndex(((Integer) args[0]).intValue(), objects.length);
+                Object newValue = args[1];
+                if (!(newValue instanceof ${clsName})) {
+                    Number n = (Number) newValue;
+                    objects[index] = ((Number)newValue).${primName}Value();
+                }
+                else
+                  objects[index] = ((${clsName})args[1]).${primName}Value();
+                return null;
+            }
+
+            public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+                if (!(args [0] instanceof Integer) || !(args [1] instanceof ${clsName}))
+                  return PojoMetaMethodSite.createNonAwareCallSite(site, metaClass, metaMethod, params, args);
+                else
+                    return new PojoMetaMethodSite(site, metaClass, metaMethod, params) {
+                        public Object call(Object receiver, Object[] args) {
+                            if ((receiver instanceof ${primName}[] && args[0] instanceof Integer && args[1] instanceof ${clsName} )
+                                    && checkMetaClass()) {
+                                final ${primName}[] objects = (${primName}[]) receiver;
+                                objects[normaliseIndex(((Integer) args[0]).intValue(), objects.length)] = ((${clsName})args[1]).${primName}Value();
+                                return null;
+                            }
+                            else
+                              return super.call(receiver,args);
+                        }
+                    };
+            }
+        }
+
+       """
+    }
+
+    res
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/genArrays.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/genArrays.groovy b/src/main/groovy/genArrays.groovy
new file mode 100644
index 0000000..9bbe3cf
--- /dev/null
+++ b/src/main/groovy/genArrays.groovy
@@ -0,0 +1,53 @@
+/*
+ *  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.classgen
+
+print """
+
+public class ArrayUtil {
+   ${genMethods()}
+}
+
+"""
+
+def genMethods () {
+    def res = ""
+    for (i in 1..250)
+      res += "\n\n" + genMethod (i)
+    res
+}
+
+def genMethod (int paramNum) {
+    def res = "public static Object [] createArray ("
+    for (k in 0..<paramNum) {
+        res += "Object arg" + k
+        if (k != paramNum-1)
+          res += ", "
+    }
+    res += ") {\n"
+    res += "return new Object [] {\n"
+        for (k in 0..<paramNum) {
+            res += "arg" + k
+            if (k != paramNum-1)
+              res += ", "
+        }
+        res += "};\n"
+    res += "}"
+    res
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/genDgmMath.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/genDgmMath.groovy b/src/main/groovy/genDgmMath.groovy
new file mode 100644
index 0000000..71bdd5f
--- /dev/null
+++ b/src/main/groovy/genDgmMath.groovy
@@ -0,0 +1,87 @@
+/*
+ *  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.classgen
+
+def types = ["Integer", "Long", "Float", "Double"]
+
+def getMath (a,b) {
+    if (a == "Double" || b == "Double" || a == "Float" || b == "Float")
+      return "FloatingPointMath"
+
+    if (a == "Long" || b == "Long")
+      return "LongMath"
+
+    "IntegerMath"
+}
+
+println """
+public CallSite createPojoCallSite(CallSite site, MetaClassImpl metaClass, MetaMethod metaMethod, Class[] params, Object receiver, Object[] args) {
+    NumberMath m = NumberMath.getMath((Number)receiver, (Number)args[0]);
+"""
+
+types.each {
+    a ->
+    print """
+    if (receiver instanceof $a) {"""
+    types.each {
+        b ->
+        print """
+        if (args[0] instanceof $b)
+            return new NumberNumberCallSite (site, metaClass, metaMethod, params, (Number)receiver, (Number)args[0]){
+                public final Object invoke(Object receiver, Object[] args) {
+                    return ${getMath(a,b)}.INSTANCE.addImpl(($a)receiver,($b)args[0]);
+                }
+
+                public final Object invokeBinop(Object receiver, Object arg) {
+                    return ${getMath(a,b)}.INSTANCE.addImpl(($a)receiver,($b)arg);
+                }
+            };
+        """
+    }
+    println "}"
+}
+
+println """
+    return new NumberNumberCallSite (site, metaClass, metaMethod, params, (Number)receiver, (Number)args[0]){
+        public final Object invoke(Object receiver, Object[] args) {
+            return math.addImpl((Number)receiver,(Number)args[0]);
+        }
+
+        public final Object invokeBinop(Object receiver, Object arg) {
+            return math.addImpl((Number)receiver,(Number)arg);
+        }
+}
+"""
+
+for (i in 2..256) {
+    print "public Object invoke$i (Object receiver, "
+    for (j in 1..(i-1)) {
+        print "Object a$j, "
+    }
+    println "Object a$i) {"
+
+    print "  return invoke (receiver, new Object[] {"
+
+    for (j in 1..(i-1)) {
+        print "a$j, "
+    }
+    println "a$i} );"
+
+    println "}"
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/genMathModification.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/genMathModification.groovy b/src/main/groovy/genMathModification.groovy
new file mode 100644
index 0000000..10cc7eb
--- /dev/null
+++ b/src/main/groovy/genMathModification.groovy
@@ -0,0 +1,133 @@
+/*
+ *  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.classgen
+
+def ops = [
+        "plus",
+        "minus",
+        "multiply",
+        "div",
+        "or",
+        "and",
+        "xor",
+        "intdiv",
+        "mod",
+        "leftShift",
+        "rightShift",
+        "rightShiftUnsigned"
+]
+
+def numbers = ["Byte":"byte", "Short":"short", "Integer":"int", "Long":"long", "Float":"float", "Double":"double"]
+
+ops.each { op ->
+    numbers.each { wrappedType, type ->
+        println "public boolean ${type}_${op};";    
+    }
+}
+
+ops.each { op ->
+    println "if (\"${op}\".equals(name)) {"
+    numbers.each { wrappedType, type ->
+        println """if (klazz==${wrappedType}.class) {
+                ${type}_${op} = true;
+            }"""
+    }
+    println "if (klazz==Object.class) {"
+    numbers.each { wrappedType, type ->
+        println "${type}_${op} = true;"
+            }
+    println "}"
+    println "}"
+}
+
+ops.each { op ->
+    numbers.each { wrappedType1, type1 ->
+        numbers.each { wrappedType2, type2 ->
+            def math = getMath(wrappedType1, wrappedType2)
+            if (math [op]) {
+                println """public static ${math.resType} ${op}(${type1} op1, ${type2} op2) {
+                   if (instance.${type1}_${op}) {
+                      return ${op}Slow(op1, op2);
+                   }
+                   else {
+                      return ${math.resType != type1 ? "((" + math.resType+ ")op1)" : "op1"} ${math[op]} ${math.resType != type2 ? "((" + math.resType+ ")op2)" : "op2"};
+                   }
+                }"""
+                println """private static ${math.resType} ${op}Slow(${type1} op1,${type2} op2) {
+                      return ((Number)InvokerHelper.invokeMethod(op1, "${op}", op2)).${math.resType}Value();
+                }"""
+            }
+        }
+    }
+}
+
+def isFloatingPoint(number) {
+    return number == "Double" || number == "Float";
+}
+
+def isLong(number) {
+    return number == "Long";
+}
+
+def getMath (left, right) {
+    if (isFloatingPoint(left) || isFloatingPoint(right)) {
+        return [
+                resType : "double",
+
+                plus : "+",
+                minus : "-",
+                multiply : "*",
+                div : "/",
+        ];
+    }
+    if (isLong(left) || isLong(right)){
+        return [
+                resType : "long",
+
+                plus : "+",
+                minus : "-",
+                multiply : "*",
+                div : "/",
+                or : "|",
+                and : "&",
+                xor : "^",
+                intdiv : "/",
+                mod : "%",
+                leftShift : "<<",
+                rightShift : ">>",
+                rightShiftUnsigned : ">>>"
+        ]
+    }
+    return [
+            resType : "int",
+
+            plus : "+",
+            minus : "-",
+            multiply : "*",
+            div : "/",
+            or : "|",
+            and : "&",
+            xor : "^",
+            intdiv : "/",
+            mod : "%",
+            leftShift : "<<",
+            rightShift : ">>",
+            rightShiftUnsigned : ">>>"
+    ]
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
new file mode 100644
index 0000000..98e0fe2
--- /dev/null
+++ b/src/main/java/org/apache/groovy/ast/tools/ClassNodeUtils.java
@@ -0,0 +1,273 @@
+/*
+ *  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.apache.groovy.ast.tools;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MapExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
+
+/**
+ * Utility class for working with ClassNodes
+ */
+public class ClassNodeUtils {
+    /**
+     * Formats a type name into a human readable version. For arrays, appends "[]" to the formatted
+     * type name of the component. For unit class nodes, uses the class node name.
+     *
+     * @param cNode the type to format
+     * @return a human readable version of the type name (java.lang.String[] for example)
+     */
+    public static String formatTypeName(ClassNode cNode) {
+        if (cNode.isArray()) {
+            ClassNode it = cNode;
+            int dim = 0;
+            while (it.isArray()) {
+                dim++;
+                it = it.getComponentType();
+            }
+            StringBuilder sb = new StringBuilder(it.getName().length() + 2 * dim);
+            sb.append(it.getName());
+            for (int i = 0; i < dim; i++) {
+                sb.append("[]");
+            }
+            return sb.toString();
+        }
+        return cNode.getName();
+    }
+
+    /**
+     * Add methods from the super class.
+     *
+     * @param cNode The ClassNode
+     * @return A map of methods
+     */
+    public static Map<String, MethodNode> getDeclaredMethodsFromSuper(ClassNode cNode) {
+        ClassNode parent = cNode.getSuperClass();
+        if (parent == null) {
+            return new HashMap<String, MethodNode>();
+        }
+        return parent.getDeclaredMethodsMap();
+    }
+
+    /**
+     * Add in methods from all interfaces. Existing entries in the methods map take precedence.
+     * Methods from interfaces visited early take precedence over later ones.
+     *
+     * @param cNode The ClassNode
+     * @param methodsMap A map of existing methods to alter
+     */
+    public static void addDeclaredMethodsFromInterfaces(ClassNode cNode, Map<String, MethodNode> methodsMap) {
+        // add in unimplemented abstract methods from the interfaces
+        for (ClassNode iface : cNode.getInterfaces()) {
+            Map<String, MethodNode> ifaceMethodsMap = iface.getDeclaredMethodsMap();
+            for (Map.Entry<String, MethodNode> entry : ifaceMethodsMap.entrySet()) {
+                String methSig = entry.getKey();
+                if (!methodsMap.containsKey(methSig)) {
+                    methodsMap.put(methSig, entry.getValue());
+                }
+            }
+        }
+    }
+
+    /**
+     * Get methods from all interfaces.
+     * Methods from interfaces visited early will be overwritten by later ones.
+     *
+     * @param cNode The ClassNode
+     * @return A map of methods
+     */
+    public static Map<String, MethodNode> getDeclaredMethodsFromInterfaces(ClassNode cNode) {
+        Map<String, MethodNode> result = new HashMap<String, MethodNode>();
+        ClassNode[] interfaces = cNode.getInterfaces();
+        for (ClassNode iface : interfaces) {
+            result.putAll(iface.getDeclaredMethodsMap());
+        }
+        return result;
+    }
+
+    /**
+     * Adds methods from interfaces and parent interfaces. Existing entries in the methods map take precedence.
+     * Methods from interfaces visited early take precedence over later ones.
+     *
+     * @param cNode The ClassNode
+     * @param methodsMap A map of existing methods to alter
+     */
+    public static void addDeclaredMethodsFromAllInterfaces(ClassNode cNode, Map<String, MethodNode> methodsMap) {
+        List cnInterfaces = Arrays.asList(cNode.getInterfaces());
+        ClassNode parent = cNode.getSuperClass();
+        while (parent != null && !parent.equals(ClassHelper.OBJECT_TYPE)) {
+            ClassNode[] interfaces = parent.getInterfaces();
+            for (ClassNode iface : interfaces) {
+                if (!cnInterfaces.contains(iface)) {
+                    methodsMap.putAll(iface.getDeclaredMethodsMap());
+                }
+            }
+            parent = parent.getSuperClass();
+        }
+    }
+
+    /**
+     * Returns true if the given method has a possibly matching static method with the given name and arguments.
+     * Handles default arguments and optionally spread expressions.
+     *
+     * @param cNode     the ClassNode of interest
+     * @param name      the name of the method of interest
+     * @param arguments the arguments to match against
+     * @param trySpread whether to try to account for SpreadExpressions within the arguments
+     * @return true if a matching method was found
+     */
+    public static boolean hasPossibleStaticMethod(ClassNode cNode, String name, Expression arguments, boolean trySpread) {
+        int count = 0;
+        boolean foundSpread = false;
+
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) arguments;
+            for (Expression arg : tuple.getExpressions()) {
+                if (arg instanceof SpreadExpression) {
+                    foundSpread = true;
+                } else {
+                    count++;
+                }
+            }
+        } else if (arguments instanceof MapExpression) {
+            count = 1;
+        }
+
+        for (MethodNode method : cNode.getMethods(name)) {
+            if (method.isStatic()) {
+                Parameter[] parameters = method.getParameters();
+                // do fuzzy match for spread case: count will be number of non-spread args
+                if (trySpread && foundSpread && parameters.length >= count) return true;
+
+                if (parameters.length == count) return true;
+
+                // handle varargs case
+                if (parameters.length > 0 && parameters[parameters.length - 1].getType().isArray()) {
+                    if (count >= parameters.length - 1) return true;
+                    // fuzzy match any spread to a varargs
+                    if (trySpread && foundSpread) return true;
+                }
+
+                // handle parameters with default values
+                int nonDefaultParameters = 0;
+                for (Parameter parameter : parameters) {
+                    if (!parameter.hasInitialExpression()) {
+                        nonDefaultParameters++;
+                    }
+                }
+
+                if (count < parameters.length && nonDefaultParameters <= count) {
+                    return true;
+                }
+                // TODO handle spread with nonDefaultParams?
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return true if we have a static accessor
+     */
+    public static boolean hasPossibleStaticProperty(ClassNode cNode, String methodName) {
+        // assume explicit static method call checked first so we can assume a simple check here
+        if (!methodName.startsWith("get") && !methodName.startsWith("is")) {
+            return false;
+        }
+        String propName = getPropNameForAccessor(methodName);
+        PropertyNode pNode = getStaticProperty(cNode, propName);
+        return pNode != null && (methodName.startsWith("get") || boolean_TYPE.equals(pNode.getType()));
+    }
+
+    /**
+     * Returns the property name, e.g. age, given an accessor name, e.g. getAge.
+     * Returns the original if a valid prefix cannot be removed.
+     *
+     * @param accessorName the accessor name of interest, e.g. getAge
+     * @return the property name, e.g. age, or original if not a valid property accessor name
+     */
+    public static String getPropNameForAccessor(String accessorName) {
+        if (!isValidAccessorName(accessorName)) return accessorName;
+        int prefixLength = accessorName.startsWith("is") ? 2 : 3;
+        return String.valueOf(accessorName.charAt(prefixLength)).toLowerCase() + accessorName.substring(prefixLength + 1);
+    }
+
+    /**
+     * Detect whether the given accessor name starts with "get", "set" or "is" followed by at least one character.
+     *
+     * @param accessorName the accessor name of interest, e.g. getAge
+     * @return true if a valid prefix is found
+     */
+    public static boolean isValidAccessorName(String accessorName) {
+        if (accessorName.startsWith("get") || accessorName.startsWith("is") || accessorName.startsWith("set")) {
+            int prefixLength = accessorName.startsWith("is") ? 2 : 3;
+            return accessorName.length() > prefixLength;
+        };
+        return false;
+    }
+
+    public static boolean hasStaticProperty(ClassNode cNode, String propName) {
+        return getStaticProperty(cNode, propName) != null;
+    }
+
+    /**
+     * Detect whether a static property with the given name is within the class
+     * or a super class.
+     *
+     * @param cNode the ClassNode of interest
+     * @param propName the property name
+     * @return the static property if found or else null
+     */
+    public static PropertyNode getStaticProperty(ClassNode cNode, String propName) {
+        ClassNode classNode = cNode;
+        while (classNode != null) {
+            for (PropertyNode pn : classNode.getProperties()) {
+                if (pn.getName().equals(propName) && pn.isStatic()) return pn;
+            }
+            classNode = classNode.getSuperClass();
+        }
+        return null;
+    }
+
+    /**
+     * Detect whether a given ClassNode is a inner class (non-static).
+     *
+     * @param cNode the ClassNode of interest
+     * @return true if the given node is a (non-static) inner class, else false
+     */
+    public static boolean isInnerClass(ClassNode cNode) {
+        return cNode.redirect().getOuterClass() != null
+                && !Modifier.isStatic(cNode.getModifiers());
+    }
+
+    private ClassNodeUtils() { }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java b/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.java
new file mode 100644
index 0000000..94427f0
--- /dev/null
+++ b/src/main/java/org/apache/groovy/ast/tools/MethodNodeUtils.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.apache.groovy.ast.tools;
+
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+
+/**
+ * Utility class for working with MethodNodes
+ */
+public class MethodNodeUtils {
+    /**
+     * Return the method node's descriptor including its
+     * name and parameter types without generics.
+     *
+     * @param mNode the method node
+     * @return the method node's abbreviated descriptor excluding the return type
+     */
+    public static String methodDescriptorWithoutReturnType(MethodNode mNode) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(mNode.getName()).append(':');
+        for (Parameter p : mNode.getParameters()) {
+            sb.append(ClassNodeUtils.formatTypeName(p.getType())).append(',');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Return the method node's descriptor which includes its return type,
+     * name and parameter types without generics.
+     *
+     * @param mNode the method node
+     * @return the method node's descriptor
+     */
+    public static String methodDescriptor(MethodNode mNode) {
+        StringBuilder sb = new StringBuilder(mNode.getName().length() + mNode.getParameters().length * 10);
+        sb.append(mNode.getReturnType().getName());
+        sb.append(' ');
+        sb.append(mNode.getName());
+        sb.append('(');
+        for (int i = 0; i < mNode.getParameters().length; i++) {
+            if (i > 0) {
+                sb.append(", ");
+            }
+            Parameter p = mNode.getParameters()[i];
+            sb.append(ClassNodeUtils.formatTypeName(p.getType()));
+        }
+        sb.append(')');
+        return sb.toString();
+    }
+
+    private MethodNodeUtils() { }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/internal/metaclass/MetaClassConstant.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/internal/metaclass/MetaClassConstant.java b/src/main/java/org/apache/groovy/internal/metaclass/MetaClassConstant.java
new file mode 100644
index 0000000..df5a7ec
--- /dev/null
+++ b/src/main/java/org/apache/groovy/internal/metaclass/MetaClassConstant.java
@@ -0,0 +1,50 @@
+/*
+ *  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.apache.groovy.internal.metaclass;
+
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.lang.invoke.SwitchPoint;
+
+/**
+ * The one and only implementation of a meta class.
+ * INTERNAL USE ONLY.
+ */
+@Incubating
+public final class MetaClassConstant<T> {
+    private final SwitchPoint switchPoint = new SwitchPoint();
+    //TODO Joche: replace with real implementation
+    private final MetaClassImpl impl;
+
+    public MetaClassConstant(Class<T> clazz) {
+        impl = new MetaClassImpl(clazz);
+    }
+
+    public SwitchPoint getSwitchPoint() {
+        return switchPoint;
+    }
+
+    // TODO Jochen: replace with new MetaMethod
+    public MetaMethod getMethod(String name, Class[] parameters) {
+        return impl.pickMethod(name, parameters);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/internal/util/Function.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/internal/util/Function.java b/src/main/java/org/apache/groovy/internal/util/Function.java
new file mode 100644
index 0000000..3a4fea5
--- /dev/null
+++ b/src/main/java/org/apache/groovy/internal/util/Function.java
@@ -0,0 +1,31 @@
+/*
+ *  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.apache.groovy.internal.util;
+
+import org.apache.groovy.lang.annotation.Incubating;
+
+/**
+ * Backport of Java8 Function.
+ * INTERNAL USE ONLY.
+ */
+@Incubating
+public interface Function<T, R> {
+    R apply(T t);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/internal/util/ReevaluatingReference.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/internal/util/ReevaluatingReference.java b/src/main/java/org/apache/groovy/internal/util/ReevaluatingReference.java
new file mode 100644
index 0000000..feeeea8
--- /dev/null
+++ b/src/main/java/org/apache/groovy/internal/util/ReevaluatingReference.java
@@ -0,0 +1,88 @@
+/*
+ *  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.apache.groovy.internal.util;
+
+import org.apache.groovy.lang.annotation.Incubating;
+import org.codehaus.groovy.GroovyBugError;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
+import java.lang.ref.WeakReference;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * This class represents a reference to the most actual incarnation of a Metaclass.
+ * INTERNAL USE ONLY.
+ */
+@Incubating
+public class ReevaluatingReference<T> {
+    private static final MethodHandle FALLBACK_HANDLE;
+    static {
+        try {
+            //TODO Jochen: move the findSpecial to a central place together with others to easy security configuration
+            FALLBACK_HANDLE = AccessController.doPrivileged(new PrivilegedExceptionAction<MethodHandle>() {
+                @Override
+                public MethodHandle run() throws Exception {
+                    return  MethodHandles.lookup().findSpecial(
+                            ReevaluatingReference.class, "replacePayLoad",
+                            MethodType.methodType(Object.class),
+                            ReevaluatingReference.class);
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw new GroovyBugError(e);
+        }
+    }
+
+    private final Supplier<T> valueSupplier;
+    private final Function<T, SwitchPoint> validationSupplier;
+    private final WeakReference<Class<T>> clazzRef;
+    private MethodHandle returnRef;
+
+
+    public ReevaluatingReference(Class clazz, Supplier<T> valueSupplier, Function<T, SwitchPoint> validationSupplier) {
+        this.valueSupplier = valueSupplier;
+        this.validationSupplier = validationSupplier;
+        clazzRef = new WeakReference<Class<T>>(clazz);
+        replacePayLoad();
+    }
+
+    private T replacePayLoad() {
+        T payload = valueSupplier.get();
+        MethodHandle ref = MethodHandles.constant(clazzRef.get(), payload);
+        SwitchPoint sp = validationSupplier.apply(payload);
+        returnRef = sp.guardWithTest(ref, FALLBACK_HANDLE);
+        return payload;
+    }
+
+    public T getPayload() {
+        T ref = null;
+        try {
+            ref = (T) returnRef.invokeExact();
+        } catch (Throwable throwable) {
+            UncheckedThrow.rethrow(throwable);
+        }
+        return ref;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/internal/util/Supplier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/internal/util/Supplier.java b/src/main/java/org/apache/groovy/internal/util/Supplier.java
new file mode 100644
index 0000000..3a01785
--- /dev/null
+++ b/src/main/java/org/apache/groovy/internal/util/Supplier.java
@@ -0,0 +1,31 @@
+/*
+ *  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.apache.groovy.internal.util;
+
+import org.apache.groovy.lang.annotation.Incubating;
+
+/**
+ * Backport of Java8 Supplier.
+ * INTERNAL USE ONLY.
+ */
+@Incubating
+public interface Supplier<T> {
+    T get();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/internal/util/UncheckedThrow.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/internal/util/UncheckedThrow.java b/src/main/java/org/apache/groovy/internal/util/UncheckedThrow.java
new file mode 100644
index 0000000..7f6cc8a
--- /dev/null
+++ b/src/main/java/org/apache/groovy/internal/util/UncheckedThrow.java
@@ -0,0 +1,38 @@
+/*
+ *  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.apache.groovy.internal.util;
+
+import org.apache.groovy.lang.annotation.Incubating;
+
+/**
+ * Allows to throw a checked exception unchecked.
+ * INTERNAL USE ONLY.
+ */
+@Incubating
+public class UncheckedThrow {
+    public static void rethrow( final Throwable checkedException ) {
+        UncheckedThrow.<RuntimeException>thrownInsteadOf( checkedException );
+    }
+    @SuppressWarnings("unchecked")
+    private static <T extends Throwable> void thrownInsteadOf(Throwable t) throws T {
+        throw (T) t;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/lang/annotation/Incubating.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/lang/annotation/Incubating.java b/src/main/java/org/apache/groovy/lang/annotation/Incubating.java
new file mode 100644
index 0000000..d6964f8
--- /dev/null
+++ b/src/main/java/org/apache/groovy/lang/annotation/Incubating.java
@@ -0,0 +1,43 @@
+/*
+ *  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.apache.groovy.lang.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PACKAGE;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Annotation to indicate experimental and still to be refined API, which may change at any time
+ */
+@Incubating
+@Documented
+@Retention(value=RUNTIME)
+@Target(value={TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
+public @interface Incubating {
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/metaclass/MetaClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/metaclass/MetaClass.java b/src/main/java/org/apache/groovy/metaclass/MetaClass.java
new file mode 100644
index 0000000..6ebe4fc
--- /dev/null
+++ b/src/main/java/org/apache/groovy/metaclass/MetaClass.java
@@ -0,0 +1,41 @@
+/*
+ *  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.apache.groovy.metaclass;
+
+import groovy.lang.MetaMethod;
+import org.apache.groovy.internal.metaclass.MetaClassConstant;
+import org.apache.groovy.internal.util.ReevaluatingReference;
+import org.apache.groovy.lang.annotation.Incubating;
+
+/**
+ * A MetaClass within Groovy defines the behaviour of any given Groovy or Java class
+ */
+@Incubating
+public final class MetaClass<T> {
+    private final ReevaluatingReference<MetaClassConstant<T>> implRef;
+
+    MetaClass(ReevaluatingReference<MetaClassConstant<T>> implRef) {
+        this.implRef = implRef;
+    }
+
+    public MetaMethod getMethod(String name, Class[] parameters) {
+        return implRef.getPayload().getMethod(name, parameters);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/metaclass/Realm.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/metaclass/Realm.java b/src/main/java/org/apache/groovy/metaclass/Realm.java
new file mode 100644
index 0000000..a652dab
--- /dev/null
+++ b/src/main/java/org/apache/groovy/metaclass/Realm.java
@@ -0,0 +1,91 @@
+/*
+ *  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.apache.groovy.metaclass;
+
+import org.apache.groovy.internal.metaclass.MetaClassConstant;
+import org.apache.groovy.internal.util.Function;
+import org.apache.groovy.internal.util.ReevaluatingReference;
+import org.apache.groovy.internal.util.Supplier;
+import org.apache.groovy.lang.annotation.Incubating;
+
+import java.lang.invoke.SwitchPoint;
+import java.util.Objects;
+
+/**
+ * A Realm is the representation of a metaclass layer in a tree of realm objects.
+ */
+@Incubating
+public final class Realm {
+    private static final Realm ROOT = new Realm("ROOT", null);
+
+    private final String name;
+    private final Realm parent;
+    private final ClassValue<MetaClassConstant<?>> cv = new ClassValue<MetaClassConstant<?>>() {
+        @Override
+        @SuppressWarnings("unchecked")
+        protected MetaClassConstant<?> computeValue(Class<?> type) {
+            return new MetaClassConstant(type);
+        }
+    };
+
+    private Realm(String name, Realm parent) {
+        this.name = name;
+        this.parent = parent;
+    }
+
+    public static Realm newRealm(String name, Realm parent) {
+        Objects.requireNonNull(name, "missing realm name");
+        if (parent == null) {
+            return new Realm(name, ROOT);
+        } else {
+            return new Realm(name, parent);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Realm{" +
+                "name='" + name + '\'' +
+                ", parent=" + parent +
+                '}';
+    }
+
+    public <T> MetaClass<T> getMetaClass(final Class<T> theClass) {
+        Supplier<MetaClassConstant<T>> valueSupplier = new Supplier<MetaClassConstant<T>>() {
+            @Override
+            @SuppressWarnings("unchecked")
+            public MetaClassConstant<T> get() {
+                return (MetaClassConstant<T>) cv.get(theClass);
+            }
+        };
+        Function<MetaClassConstant<T>, SwitchPoint> validationSupplier = new Function<MetaClassConstant<T>, SwitchPoint>() {
+            @Override
+            public SwitchPoint apply(MetaClassConstant<T> metaClassImpl) {
+                return metaClassImpl.getSwitchPoint();
+            }
+        };
+        ReevaluatingReference<MetaClassConstant<T>> ref = new ReevaluatingReference<>(
+                MetaClassConstant.class,
+                valueSupplier,
+                validationSupplier
+        );
+        return new MetaClass<>(ref);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/plugin/DefaultRunners.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/plugin/DefaultRunners.java b/src/main/java/org/apache/groovy/plugin/DefaultRunners.java
new file mode 100644
index 0000000..5f570eb
--- /dev/null
+++ b/src/main/java/org/apache/groovy/plugin/DefaultRunners.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.apache.groovy.plugin;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.runtime.InvokerHelper;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * Provides access to built-in {@link GroovyRunner} instances
+ * for the registry.  These instances should be accessed via
+ * the registry and not used directly.
+ */
+final class DefaultRunners {
+
+    /*
+     * These runners were originally included directly in GroovyShell.
+     * Since they are part of core they are added directly to the
+     * GroovyRunnerRegistry rather than via a provider configuration
+     * file in META-INF/services. If any of these runners are moved
+     * out to a submodule then they should be registered using the
+     * provider configuration file (see groovy-testng).
+     *
+     * These are internal classes and not meant to be referenced
+     * outside of the GroovyRunnerRegistry.
+     */
+
+    private static final GroovyRunner JUNIT3_TEST = new Junit3TestRunner();
+    private static final GroovyRunner JUNIT3_SUITE = new Junit3SuiteRunner();
+    private static final GroovyRunner JUNIT4_TEST = new Junit4TestRunner();
+
+    private DefaultRunners() {
+    }
+
+    static GroovyRunner junit3TestRunner() {
+        return JUNIT3_TEST;
+    }
+
+    static GroovyRunner junit3SuiteRunner() {
+        return JUNIT3_SUITE;
+    }
+
+    static GroovyRunner junit4TestRunner() {
+        return JUNIT4_TEST;
+    }
+
+    private static class Junit3TestRunner implements GroovyRunner {
+        /**
+         * Utility method to check through reflection if the class appears to be a
+         * JUnit 3.8.x test, i.e. checks if it extends JUnit 3.8.x's TestCase.
+         *
+         * @param scriptClass the class we want to check
+         * @param loader the class loader
+         * @return true if the class appears to be a test
+         */
+        @Override
+        public boolean canRun(Class<?> scriptClass, GroovyClassLoader loader) {
+            try {
+                Class<?> testCaseClass = loader.loadClass("junit.framework.TestCase");
+                return testCaseClass.isAssignableFrom(scriptClass);
+            } catch (Throwable e) {
+                return false;
+            }
+        }
+
+        /**
+         * Run the specified class extending TestCase as a unit test.
+         * This is done through reflection, to avoid adding a dependency to the JUnit framework.
+         * Otherwise, developers embedding Groovy and using GroovyShell to load/parse/compile
+         * groovy scripts and classes would have to add another dependency on their classpath.
+         *
+         * @param scriptClass the class to be run as a unit test
+         * @param loader the class loader
+         */
+        @Override
+        public Object run(Class<?> scriptClass, GroovyClassLoader loader) {
+            try {
+                Object testSuite = InvokerHelper.invokeConstructorOf("junit.framework.TestSuite", new Object[]{scriptClass});
+                return InvokerHelper.invokeStaticMethod("junit.textui.TestRunner", "run", new Object[]{testSuite});
+            } catch (ClassNotFoundException e) {
+                throw new GroovyRuntimeException("Failed to run the unit test. JUnit is not on the Classpath.", e);
+            }
+        }
+    }
+
+    private static class Junit3SuiteRunner implements GroovyRunner {
+        /**
+         * Utility method to check through reflection if the class appears to be a
+         * JUnit 3.8.x test suite, i.e. checks if it extends JUnit 3.8.x's TestSuite.
+         *
+         * @param scriptClass the class we want to check
+         * @param loader the class loader
+         * @return true if the class appears to be a test
+         */
+        @Override
+        public boolean canRun(Class<?> scriptClass, GroovyClassLoader loader) {
+            try {
+                Class<?> testSuiteClass = loader.loadClass("junit.framework.TestSuite");
+                return testSuiteClass.isAssignableFrom(scriptClass);
+            } catch (Throwable e) {
+                return false;
+            }
+        }
+
+        /**
+         * Run the specified class extending TestSuite as a unit test.
+         * This is done through reflection, to avoid adding a dependency to the JUnit framework.
+         * Otherwise, developers embedding Groovy and using GroovyShell to load/parse/compile
+         * groovy scripts and classes would have to add another dependency on their classpath.
+         *
+         * @param scriptClass the class to be run as a unit test
+         * @param loader the class loader
+         */
+        @Override
+        public Object run(Class<?> scriptClass, GroovyClassLoader loader) {
+            try {
+                Object testSuite = InvokerHelper.invokeStaticMethod(scriptClass, "suite", new Object[]{});
+                return InvokerHelper.invokeStaticMethod("junit.textui.TestRunner", "run", new Object[]{testSuite});
+            } catch (ClassNotFoundException e) {
+                throw new GroovyRuntimeException("Failed to run the unit test. JUnit is not on the Classpath.", e);
+            }
+        }
+    }
+
+    private static class Junit4TestRunner implements GroovyRunner {
+        /**
+         * Utility method to check via reflection if the parsed class appears to be a JUnit4
+         * test, i.e. checks whether it appears to be using the relevant JUnit 4 annotations.
+         *
+         * @param scriptClass the class we want to check
+         * @param loader the class loader
+         * @return true if the class appears to be a test
+         */
+        @Override
+        public boolean canRun(Class<?> scriptClass, GroovyClassLoader loader) {
+            return hasRunWithAnnotation(scriptClass, loader)
+                    || hasTestAnnotatedMethod(scriptClass, loader);
+        }
+
+        /**
+         * Run the specified class extending TestCase as a unit test.
+         * This is done through reflection, to avoid adding a dependency to the JUnit framework.
+         * Otherwise, developers embedding Groovy and using GroovyShell to load/parse/compile
+         * groovy scripts and classes would have to add another dependency on their classpath.
+         *
+         * @param scriptClass the class to be run as a unit test
+         * @param loader the class loader
+         */
+        @Override
+        public Object run(Class<?> scriptClass, GroovyClassLoader loader) {
+            try {
+                Class<?> junitCoreClass = loader.loadClass("org.junit.runner.JUnitCore");
+                Object result = InvokerHelper.invokeStaticMethod(junitCoreClass,
+                        "runClasses", new Object[]{scriptClass});
+                System.out.print("JUnit 4 Runner, Tests: " + InvokerHelper.getProperty(result, "runCount"));
+                System.out.print(", Failures: " + InvokerHelper.getProperty(result, "failureCount"));
+                System.out.println(", Time: " + InvokerHelper.getProperty(result, "runTime"));
+                List<?> failures = (List<?>) InvokerHelper.getProperty(result, "failures");
+                for (Object f : failures) {
+                    System.out.println("Test Failure: " + InvokerHelper.getProperty(f, "description"));
+                    System.out.println(InvokerHelper.getProperty(f, "trace"));
+                }
+                return result;
+            } catch (ClassNotFoundException e) {
+                throw new GroovyRuntimeException("Error running JUnit 4 test.", e);
+            }
+        }
+
+        private static boolean hasRunWithAnnotation(Class<?> scriptClass, ClassLoader loader) {
+            try {
+                @SuppressWarnings("unchecked")
+                Class<? extends Annotation> runWithAnnotationClass =
+                        (Class<? extends Annotation>)loader.loadClass("org.junit.runner.RunWith");
+                return scriptClass.isAnnotationPresent(runWithAnnotationClass);
+            } catch (Throwable e) {
+                return false;
+            }
+        }
+
+        private static boolean hasTestAnnotatedMethod(Class<?> scriptClass, ClassLoader loader) {
+            try {
+                @SuppressWarnings("unchecked")
+                Class<? extends Annotation> testAnnotationClass =
+                        (Class<? extends Annotation>) loader.loadClass("org.junit.Test");
+                Method[] methods = scriptClass.getMethods();
+                for (Method method : methods) {
+                    if (method.isAnnotationPresent(testAnnotationClass)) {
+                        return true;
+                    }
+                }
+            } catch (Throwable e) {
+                // fall through
+            }
+            return false;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/plugin/GroovyRunner.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/plugin/GroovyRunner.java b/src/main/java/org/apache/groovy/plugin/GroovyRunner.java
new file mode 100644
index 0000000..283d092
--- /dev/null
+++ b/src/main/java/org/apache/groovy/plugin/GroovyRunner.java
@@ -0,0 +1,49 @@
+/*
+ *  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.apache.groovy.plugin;
+
+import groovy.lang.GroovyClassLoader;
+
+/**
+ * Classes which can run scripts should implement this interface.
+ *
+ * @since 2.5.0
+ */
+public interface GroovyRunner {
+
+    /**
+     * Returns {@code true} if this runner is able to
+     * run the given class.
+     *
+     * @param scriptClass class to run
+     * @param loader used to locate classes and resources
+     * @return true if given class can be run, else false
+     */
+    boolean canRun(Class<?> scriptClass, GroovyClassLoader loader);
+
+    /**
+     * Runs the given class.
+     *
+     * @param scriptClass class to run
+     * @param loader used to locate classes and resources
+     * @return result of running the class
+     */
+    Object run(Class<?> scriptClass, GroovyClassLoader loader);
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java b/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
new file mode 100644
index 0000000..213a82b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
@@ -0,0 +1,700 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.tools.WideningCategories;
+import org.codehaus.groovy.classgen.ClassGeneratorException;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.objectweb.asm.Opcodes.ACONST_NULL;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ASTORE;
+import static org.objectweb.asm.Opcodes.BIPUSH;
+import static org.objectweb.asm.Opcodes.CHECKCAST;
+import static org.objectweb.asm.Opcodes.D2F;
+import static org.objectweb.asm.Opcodes.D2I;
+import static org.objectweb.asm.Opcodes.D2L;
+import static org.objectweb.asm.Opcodes.DCONST_0;
+import static org.objectweb.asm.Opcodes.DCONST_1;
+import static org.objectweb.asm.Opcodes.DSTORE;
+import static org.objectweb.asm.Opcodes.DUP;
+import static org.objectweb.asm.Opcodes.DUP2;
+import static org.objectweb.asm.Opcodes.DUP2_X1;
+import static org.objectweb.asm.Opcodes.DUP2_X2;
+import static org.objectweb.asm.Opcodes.DUP_X2;
+import static org.objectweb.asm.Opcodes.F2D;
+import static org.objectweb.asm.Opcodes.F2I;
+import static org.objectweb.asm.Opcodes.F2L;
+import static org.objectweb.asm.Opcodes.FCONST_0;
+import static org.objectweb.asm.Opcodes.FCONST_1;
+import static org.objectweb.asm.Opcodes.FCONST_2;
+import static org.objectweb.asm.Opcodes.FSTORE;
+import static org.objectweb.asm.Opcodes.GETSTATIC;
+import static org.objectweb.asm.Opcodes.I2B;
+import static org.objectweb.asm.Opcodes.I2C;
+import static org.objectweb.asm.Opcodes.I2D;
+import static org.objectweb.asm.Opcodes.I2F;
+import static org.objectweb.asm.Opcodes.I2L;
+import static org.objectweb.asm.Opcodes.I2S;
+import static org.objectweb.asm.Opcodes.ICONST_0;
+import static org.objectweb.asm.Opcodes.ICONST_1;
+import static org.objectweb.asm.Opcodes.ICONST_2;
+import static org.objectweb.asm.Opcodes.ICONST_3;
+import static org.objectweb.asm.Opcodes.ICONST_4;
+import static org.objectweb.asm.Opcodes.ICONST_5;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static org.objectweb.asm.Opcodes.ISTORE;
+import static org.objectweb.asm.Opcodes.L2D;
+import static org.objectweb.asm.Opcodes.L2F;
+import static org.objectweb.asm.Opcodes.L2I;
+import static org.objectweb.asm.Opcodes.LCONST_0;
+import static org.objectweb.asm.Opcodes.LCONST_1;
+import static org.objectweb.asm.Opcodes.LSTORE;
+import static org.objectweb.asm.Opcodes.NEW;
+import static org.objectweb.asm.Opcodes.POP;
+import static org.objectweb.asm.Opcodes.POP2;
+import static org.objectweb.asm.Opcodes.SIPUSH;
+import static org.objectweb.asm.Opcodes.SWAP;
+
+public class OperandStack {
+
+    private final WriterController controller;
+    private final List<ClassNode> stack = new ArrayList<ClassNode>();
+
+    public OperandStack(WriterController wc) {
+        this.controller = wc;        
+    }
+    
+    public int getStackLength() {
+        return stack.size();
+    }
+    
+    public void popDownTo(int elements) {
+        int last = stack.size();
+        MethodVisitor mv = controller.getMethodVisitor();
+        while (last>elements) {
+            last--;
+            ClassNode element = popWithMessage(last);
+            if (isTwoSlotType(element)) {
+                mv.visitInsn(POP2);
+            } else {
+                mv.visitInsn(POP);
+            }
+        }   
+    }
+    
+    private ClassNode popWithMessage(int last) {
+        try {
+            return stack.remove(last);
+        } catch (ArrayIndexOutOfBoundsException ai) {
+            String method = controller.getMethodNode() == null ?
+                    controller.getConstructorNode().getTypeDescriptor() :
+                    controller.getMethodNode().getTypeDescriptor();
+            throw new GroovyBugError("Error while popping argument from operand stack tracker in class " +
+                    controller.getClassName() + " method " + method + ".");
+        }
+    }
+
+    /**
+     * returns true for long and double
+     */
+    private static boolean isTwoSlotType(ClassNode type) {
+        return type==ClassHelper.long_TYPE || type==ClassHelper.double_TYPE;
+    }
+
+    /**
+     * ensure last marked parameter on the stack is a primitive boolean
+     * if mark==stack size, we assume an empty expression or statement.
+     * was used and we will use the value given in emptyDefault as boolean 
+     * if mark==stack.size()-1 the top element will be cast to boolean using
+     * Groovy truth.
+     * In other cases we throw a GroovyBugError
+     */
+    public void castToBool(int mark, boolean emptyDefault) {
+        int size = stack.size();
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (mark==size) {
+            // no element, so use emptyDefault
+            if (emptyDefault) {
+                mv.visitIntInsn(BIPUSH, 1);
+            } else {
+                mv.visitIntInsn(BIPUSH, 0);
+            }
+            stack.add(null);
+        } else if (mark==stack.size()-1) {
+            ClassNode last =  stack.get(size-1);
+            // nothing to do in that case
+            if (last == ClassHelper.boolean_TYPE) return;
+            // not a primitive type, so call booleanUnbox
+            if (!ClassHelper.isPrimitiveType(last)) {
+                controller.getInvocationWriter().castNonPrimitiveToBool(last);
+            } else {
+                BytecodeHelper.convertPrimitiveToBoolean(mv, last);
+            }            
+        } else { 
+            throw new GroovyBugError(
+                    "operand stack contains "+stack.size()+
+                    " elements, but we expected only "+mark
+                );
+        }
+        stack.set(mark,ClassHelper.boolean_TYPE);
+    }
+
+    /**
+     * remove operand stack top element using bytecode pop
+     */
+    public void pop() {
+        popDownTo(stack.size()-1);
+    }
+
+    public Label jump(int ifIns) {
+        Label label = new Label();
+        jump(ifIns,label);
+        return label;
+    }
+    
+    public void jump(int ifIns, Label label) {
+        controller.getMethodVisitor().visitJumpInsn(ifIns, label);
+        // remove the boolean from the operand stack tracker
+        remove(1);
+    }
+
+    /**
+     * duplicate top element
+     */
+    public void dup() {
+        ClassNode type = getTopOperand();
+        stack.add(type);
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (type == ClassHelper.double_TYPE || type == ClassHelper.long_TYPE) {
+            mv.visitInsn(DUP2);
+        } else {
+            mv.visitInsn(DUP);
+        }
+    }
+
+    public ClassNode box() {
+        MethodVisitor mv = controller.getMethodVisitor();
+        int size = stack.size();
+        ClassNode type = stack.get(size-1);
+        if (ClassHelper.isPrimitiveType(type) && ClassHelper.VOID_TYPE!=type) {
+            ClassNode wrapper = ClassHelper.getWrapper(type);
+            BytecodeHelper.doCastToWrappedType(mv, type, wrapper);
+            type = wrapper;
+        } // else nothing to box
+        stack.set(size-1, type);
+        return type;
+    }
+
+    /**
+     * Remove amount elements from the operand stack, without using pop. 
+     * For example after a method invocation
+     */
+    public void remove(int amount) {
+        int size = stack.size();
+        for (int i=size-1; i>size-1-amount; i--) {
+            popWithMessage(i);
+        }
+    }
+
+    /**
+     * push operand on stack
+     */
+    public void push(ClassNode type) {
+        stack.add(type);
+    }
+
+    /**
+     * swap two top level operands
+     */
+    public void swap() {
+        MethodVisitor mv = controller.getMethodVisitor();
+        int size = stack.size();
+        ClassNode b = stack.get(size-1);
+        ClassNode a = stack.get(size-2);
+        //        dup_x1:     --- 
+        //        dup_x2:     aab  -> baab
+        //        dup2_x1:    abb  -> bbabb
+        //        dup2_x2:    aabb -> bbaabb
+        //        b = top element, a = element under b
+        //        top element at right
+        if (isTwoSlotType(a)) { // aa
+            if (isTwoSlotType(b)) { // aabb
+                // aabb -> bbaa
+                mv.visitInsn(DUP2_X2);   // bbaabb
+                mv.visitInsn(POP2);      // bbaa
+            } else {
+                // aab -> baa
+                mv.visitInsn(DUP_X2);   // baab
+                mv.visitInsn(POP);      // baa
+            }
+        } else { // a
+            if (isTwoSlotType(b)) { //abb
+                // abb -> bba
+                mv.visitInsn(DUP2_X1);   // bbabb
+                mv.visitInsn(POP2);      // bba
+            } else {
+                // ab -> ba
+                mv.visitInsn(SWAP);
+            }
+        }
+        stack.set(size-1,a);
+        stack.set(size-2,b);
+    }
+
+    /**
+     * replace top level element with new element of given type
+     */
+    public void replace(ClassNode type) {
+        int size = stack.size();
+        try {
+            if (size==0) throw new ArrayIndexOutOfBoundsException("size==0");
+        } catch (ArrayIndexOutOfBoundsException ai) {
+            System.err.println("index problem in "+controller.getSourceUnit().getName());
+            throw ai;
+        }
+        stack.set(size-1, type);
+    }
+    
+    /**
+     * replace n top level elements with new element of given type
+     */
+    public void replace(ClassNode type, int n) {
+        remove(n);
+        push(type);
+    }
+    
+    /**
+     * do Groovy cast for top level element
+     */
+    public void doGroovyCast(ClassNode targetType) {
+        doConvertAndCast(targetType,false);
+    }
+    
+    public void doGroovyCast(Variable v) {
+        ClassNode targetType = v.getOriginType();
+        doConvertAndCast(targetType,false);
+    }
+    
+    public void doAsType(ClassNode targetType) {
+        doConvertAndCast(targetType,true);
+    }
+
+    private void throwExceptionForNoStackElement(int size, ClassNode targetType, boolean coerce) {
+        if (size>0) return;
+        StringBuilder sb = new StringBuilder();
+        sb.append("Internal compiler error while compiling ").append(controller.getSourceUnit().getName()).append("\n");
+        MethodNode methodNode = controller.getMethodNode();
+        if (methodNode!=null) {
+            sb.append("Method: ");
+            sb.append(methodNode);
+            sb.append("\n");
+        }
+        ConstructorNode constructorNode = controller.getConstructorNode();
+        if (constructorNode!=null) {
+            sb.append("Constructor: ");
+            sb.append(methodNode);
+            sb.append("\n");
+        }
+        sb.append("Line ").append(controller.getLineNumber()).append(",");
+        sb.append(" expecting ").append(coerce ? "coercion" : "casting").append(" to ").append(targetType.toString(false));
+        sb.append(" but operand stack is empty");
+        throw new ArrayIndexOutOfBoundsException(sb.toString());
+    }
+
+    private void doConvertAndCast(ClassNode targetType, boolean coerce) {
+        int size = stack.size();
+        throwExceptionForNoStackElement(size, targetType, coerce);
+
+        ClassNode top = stack.get(size-1);
+        targetType = targetType.redirect();
+        if (targetType == top) return;
+
+        if (coerce) {
+            controller.getInvocationWriter().coerce(top,targetType);
+            return;
+        }
+
+        boolean primTarget = ClassHelper.isPrimitiveType(targetType);
+        boolean primTop = ClassHelper.isPrimitiveType(top);
+
+        if (primTop && primTarget) {
+            // here we box and unbox to get the goal type
+            if (convertPrimitive(top, targetType)) {
+                replace(targetType);
+                return;
+            }
+            box();
+        } else if (primTarget) {
+            // top is not primitive so unbox
+            // leave that BH#doCast later
+        } else {
+            // top might be primitive, target is not
+            // so let invocation writer box if needed and do groovy cast otherwise
+            controller.getInvocationWriter().castToNonPrimitiveIfNecessary(top, targetType);
+        }
+
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (primTarget && !ClassHelper.boolean_TYPE.equals(targetType) && !primTop && ClassHelper.getWrapper(targetType).equals(top)) {
+            BytecodeHelper.doCastToPrimitive(mv, top, targetType);
+        } else {
+            top = stack.get(size-1);
+            if (!WideningCategories.implementsInterfaceOrSubclassOf(top, targetType)) {
+                BytecodeHelper.doCast(mv,targetType);
+            }
+        }
+        replace(targetType);
+    }
+
+    private boolean convertFromInt(ClassNode target) {
+        int convertCode;
+        if (target==ClassHelper.char_TYPE){
+            convertCode = I2C;
+        } else if (target==ClassHelper.byte_TYPE){
+            convertCode = I2B;
+        } else if (target==ClassHelper.short_TYPE){
+            convertCode = I2S;
+        } else if (target==ClassHelper.long_TYPE){
+            convertCode = I2L;
+        } else if (target==ClassHelper.float_TYPE){
+            convertCode = I2F;
+        } else if (target==ClassHelper.double_TYPE){
+            convertCode = I2D;
+        } else {
+            return false;
+        }
+        controller.getMethodVisitor().visitInsn(convertCode);
+        return true;
+    }
+    
+    private boolean convertFromLong(ClassNode target) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (target==ClassHelper.int_TYPE){
+            mv.visitInsn(L2I);
+            return true;
+        } else if ( target==ClassHelper.char_TYPE ||
+                    target==ClassHelper.byte_TYPE ||
+                    target==ClassHelper.short_TYPE)
+        {
+            mv.visitInsn(L2I);
+            return convertFromInt(target);
+        } else if (target==ClassHelper.double_TYPE){
+            mv.visitInsn(L2D);
+            return true;
+        } else if (target==ClassHelper.float_TYPE){
+            mv.visitInsn(L2F);
+            return true;
+        } 
+        return false;
+    }
+
+    private boolean convertFromDouble(ClassNode target) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (target==ClassHelper.int_TYPE){
+            mv.visitInsn(D2I);
+            return true;
+        } else if ( target==ClassHelper.char_TYPE ||
+                    target==ClassHelper.byte_TYPE ||
+                    target==ClassHelper.short_TYPE)
+        {
+            mv.visitInsn(D2I);
+            return convertFromInt(target);
+        } else if (target==ClassHelper.long_TYPE){
+            mv.visitInsn(D2L);
+            return true;
+        } else if (target==ClassHelper.float_TYPE){
+            mv.visitInsn(D2F);
+            return true;
+        } 
+        return false;
+    }    
+    
+    private boolean convertFromFloat(ClassNode target) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (target==ClassHelper.int_TYPE){
+            mv.visitInsn(F2I);
+            return true;
+        } else if ( target==ClassHelper.char_TYPE ||
+                    target==ClassHelper.byte_TYPE ||
+                    target==ClassHelper.short_TYPE)
+        {
+            mv.visitInsn(F2I);
+            return convertFromInt(target);
+        } else if (target==ClassHelper.long_TYPE){
+            mv.visitInsn(F2L);
+            return true;
+        } else if (target==ClassHelper.double_TYPE){
+            mv.visitInsn(F2D);
+            return true;
+        } 
+        return false;
+    }
+    
+    private boolean convertPrimitive(ClassNode top, ClassNode target) {
+        if (top==target) return true;
+        if (top==ClassHelper.int_TYPE) {
+            return convertFromInt(target);
+        } else if ( top==ClassHelper.char_TYPE || 
+                    top==ClassHelper.byte_TYPE ||
+                    top==ClassHelper.short_TYPE)
+        {
+            return target == ClassHelper.int_TYPE || convertFromInt(target);
+        } else if ( top==ClassHelper.float_TYPE) {
+            return convertFromFloat(target);
+        } else if ( top==ClassHelper.double_TYPE) {
+            return convertFromDouble(target);
+        } else if ( top==ClassHelper.long_TYPE) {
+            return convertFromLong(target);
+        }
+        return false;
+    }
+
+    /**
+     * load the constant on the operand stack. 
+     */
+    public void pushConstant(ConstantExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        Object value = expression.getValue();
+        ClassNode origType = expression.getType().redirect();
+        ClassNode type = ClassHelper.getUnwrapper(origType);
+        boolean boxing = origType!=type;
+        boolean asPrimitive = boxing || ClassHelper.isPrimitiveType(type);
+
+        if (value == null) {
+            mv.visitInsn(ACONST_NULL);
+        } else if (boxing && value instanceof Boolean) {
+            // special path for boxed boolean
+            Boolean bool = (Boolean) value;
+            String text = bool ? "TRUE" : "FALSE";
+            mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
+            boxing = false;
+            type = origType;
+        } else if (asPrimitive) {
+            pushPrimitiveConstant(mv, value, type);
+        } else if (value instanceof BigDecimal) {
+            String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
+            mv.visitTypeInsn(NEW, className);
+            mv.visitInsn(DUP);
+            mv.visitLdcInsn(value.toString());
+            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(Ljava/lang/String;)V", false);
+        } else if (value instanceof BigInteger) {
+            String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
+            mv.visitTypeInsn(NEW, className);
+            mv.visitInsn(DUP);
+            mv.visitLdcInsn(value.toString());
+            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(Ljava/lang/String;)V", false);
+        } else if (value instanceof String) {
+            mv.visitLdcInsn(value);
+        } else {
+            throw new ClassGeneratorException(
+                    "Cannot generate bytecode for constant: " + value + " of type: " + type.getName());
+        }
+        
+        push(type);
+        if (boxing) box(); 
+    }
+
+    private static void pushPrimitiveConstant(final MethodVisitor mv, final Object value, final ClassNode type) {
+        boolean isInt = ClassHelper.int_TYPE.equals(type);
+        boolean isShort = ClassHelper.short_TYPE.equals(type);
+        boolean isByte = ClassHelper.byte_TYPE.equals(type);
+        boolean isChar = ClassHelper.char_TYPE.equals(type);
+        if (isInt || isShort || isByte || isChar) {
+            int val = isInt?(Integer)value:isShort?(Short)value:isChar?(Character)value:(Byte)value;
+            switch (val) {
+                case 0:
+                    mv.visitInsn(ICONST_0);
+                    break;
+                case 1:
+                    mv.visitInsn(ICONST_1);
+                    break;
+                case 2:
+                    mv.visitInsn(ICONST_2);
+                    break;
+                case 3:
+                    mv.visitInsn(ICONST_3);
+                    break;
+                case 4:
+                    mv.visitInsn(ICONST_4);
+                    break;
+                case 5:
+                    mv.visitInsn(ICONST_5);
+                    break;
+                default:
+                    if (val>=Byte.MIN_VALUE && val<=Byte.MAX_VALUE) {
+                        mv.visitIntInsn(BIPUSH, val);
+                    } else if (val>=Short.MIN_VALUE && val<=Short.MAX_VALUE) {
+                        mv.visitIntInsn(SIPUSH, val);
+                    } else {
+                        mv.visitLdcInsn(value);
+                    }
+            }
+        } else if (ClassHelper.long_TYPE.equals(type)) {
+            if ((Long)value==0L) {
+                mv.visitInsn(LCONST_0);
+            } else if ((Long)value==1L) {
+                mv.visitInsn(LCONST_1);
+            } else {
+                mv.visitLdcInsn(value);
+            }
+        } else if (ClassHelper.float_TYPE.equals(type)) {
+            if ((Float)value==0f) {
+                mv.visitInsn(FCONST_0);
+            } else if ((Float)value==1f) {
+                mv.visitInsn(FCONST_1);
+            } else if ((Float)value==2f) {
+                mv.visitInsn(FCONST_2);
+            } else {
+                mv.visitLdcInsn(value);
+            }
+        } else if (ClassHelper.double_TYPE.equals(type)) {
+            if ((Double)value==0d) {
+                mv.visitInsn(DCONST_0);
+            } else if ((Double)value==1d) {
+                mv.visitInsn(DCONST_1);
+            } else {
+                mv.visitLdcInsn(value);
+            }
+        } else if (ClassHelper.boolean_TYPE.equals(type)) {
+            boolean b = (Boolean) value;
+            if (b) {
+                mv.visitInsn(ICONST_1);
+            } else {
+                mv.visitInsn(ICONST_0);
+            }
+        } else {
+            mv.visitLdcInsn(value);
+        }
+    }
+
+    public void pushDynamicName(Expression name) {
+        if (name instanceof ConstantExpression) {
+            ConstantExpression ce = (ConstantExpression) name;
+            Object value = ce.getValue();
+            if (value instanceof String) {
+                pushConstant(ce);
+                return;
+            }
+        }
+        new CastExpression(ClassHelper.STRING_TYPE, name).visit(controller.getAcg());
+    }
+
+    public void loadOrStoreVariable(BytecodeVariable variable, boolean useReferenceDirectly) {
+        CompileStack compileStack = controller.getCompileStack();
+        
+        if (compileStack.isLHS()) {
+            storeVar(variable);
+        } else {
+            MethodVisitor mv = controller.getMethodVisitor();
+            int idx = variable.getIndex();
+            ClassNode type = variable.getType();
+            
+            if (variable.isHolder()) {
+                mv.visitVarInsn(ALOAD, idx);
+                if (!useReferenceDirectly) {
+                    mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;", false);
+                    BytecodeHelper.doCast(mv, type);
+                    push(type);
+                } else {
+                    push(ClassHelper.REFERENCE_TYPE);
+                }
+            } else {
+                load(type,idx);
+            }
+        }
+    }
+
+    public void storeVar(BytecodeVariable variable) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        int idx = variable.getIndex();
+        ClassNode type = variable.getType();
+        // value is on stack
+        if (variable.isHolder()) {
+            doGroovyCast(type);
+            box();
+            mv.visitVarInsn(ALOAD, idx);
+            mv.visitTypeInsn(CHECKCAST, "groovy/lang/Reference");
+            mv.visitInsn(SWAP);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V", false);
+        } else {
+            doGroovyCast(type);
+            if (type == ClassHelper.double_TYPE) {
+                mv.visitVarInsn(DSTORE, idx);
+            } else if (type == ClassHelper.float_TYPE) {
+                mv.visitVarInsn(FSTORE, idx);
+            } else if (type == ClassHelper.long_TYPE) {
+                mv.visitVarInsn(LSTORE, idx);
+            } else if (
+                    type == ClassHelper.boolean_TYPE
+                            || type == ClassHelper.char_TYPE
+                            || type == ClassHelper.byte_TYPE
+                            || type == ClassHelper.int_TYPE
+                            || type == ClassHelper.short_TYPE) {
+                mv.visitVarInsn(ISTORE, idx);
+            } else {
+                mv.visitVarInsn(ASTORE, idx);
+            }
+        }
+        // remove RHS value from operand stack
+        remove(1);
+    }
+
+    public void load(ClassNode type, int idx) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        BytecodeHelper.load(mv, type, idx);
+        push(type);
+    }
+
+    public void pushBool(boolean inclusive) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitLdcInsn(inclusive);
+        push(ClassHelper.boolean_TYPE);
+    }
+    
+    public String toString() {
+        return "OperandStack(size="+stack.size()+":"+stack.toString()+")";
+    }
+
+    public ClassNode getTopOperand() {
+        int size = stack.size();
+        try {
+            if (size==0) throw new ArrayIndexOutOfBoundsException("size==0");
+        } catch (ArrayIndexOutOfBoundsException ai) {
+            System.err.println("index problem in "+controller.getSourceUnit().getName());
+            throw ai;
+        }
+        return stack.get(size-1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
new file mode 100644
index 0000000..e553477
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
@@ -0,0 +1,948 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BitwiseNegationExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PostfixExpression;
+import org.codehaus.groovy.ast.expr.PrefixExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+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.BlockStatement;
+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.Statement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.ast.tools.ParameterUtils;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.BytecodeInterface8;
+import org.codehaus.groovy.syntax.Types;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.codehaus.groovy.ast.ClassHelper.BigDecimal_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.GROOVY_INTERCEPTABLE_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
+import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isBigDecCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isDoubleCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isFloatingCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isIntCategory;
+import static org.codehaus.groovy.ast.tools.WideningCategories.isLongCategory;
+import static org.codehaus.groovy.classgen.asm.BinaryExpressionMultiTypeDispatcher.typeMap;
+import static org.codehaus.groovy.classgen.asm.BinaryExpressionMultiTypeDispatcher.typeMapKeyNames;
+import static org.objectweb.asm.Opcodes.ACC_FINAL;
+import static org.objectweb.asm.Opcodes.GETSTATIC;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.IFNE;
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
+
+/**
+ * A class to write out the optimized statements
+ */
+public class OptimizingStatementWriter extends StatementWriter {
+
+    private static class FastPathData {
+        private Label pathStart = new Label();
+        private Label afterPath = new Label();
+    }
+
+    public static class ClassNodeSkip{}
+
+    public static class StatementMeta {
+        private boolean optimize=false;
+        protected MethodNode target;
+        protected ClassNode type;
+        protected VariableExpression declaredVariableExpression;
+        protected boolean[] involvedTypes = new boolean[typeMapKeyNames.length];
+        public void chainInvolvedTypes(OptimizeFlagsCollector opt) {
+            for (int i=0; i<typeMapKeyNames.length; i++) {
+                if (opt.current.involvedTypes[i]) {
+                    this.involvedTypes[i] = true;
+                }
+            }
+        }
+        public String toString() {
+            StringBuilder ret = new StringBuilder("optimize=" + optimize + " target=" + target + " type=" + type + " involvedTypes=");
+            for (int i=0; i<typeMapKeyNames.length; i++) {
+                if (involvedTypes[i]) ret.append(" ").append(typeMapKeyNames[i]);
+            }
+            return ret.toString();
+        }
+    }
+
+    private static final MethodCaller[] guards = {
+        null,
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigInt"),
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigL"),
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigD"),
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigC"),
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigB"),
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigS"),
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigF"),
+        MethodCaller.newStatic(BytecodeInterface8.class, "isOrigZ"),
+    };
+
+    private static final MethodCaller disabledStandardMetaClass = MethodCaller.newStatic(BytecodeInterface8.class, "disabledStandardMetaClass");
+    private boolean fastPathBlocked = false;
+    private final WriterController controller;
+
+    public OptimizingStatementWriter(WriterController controller) {
+        super(controller);
+        this.controller = controller;
+    }
+
+    private boolean notEnableFastPath(StatementMeta meta) {
+        // return false if cannot do fast path and if are already on the path
+        return fastPathBlocked || meta==null || !meta.optimize || controller.isFastPath();
+    }
+
+    private FastPathData writeGuards(StatementMeta meta, Statement statement) {
+        if (notEnableFastPath(meta)) return null;
+        controller.getAcg().onLineNumber(statement, null);
+        MethodVisitor mv = controller.getMethodVisitor();
+        FastPathData fastPathData = new FastPathData();
+        Label slowPath = new Label();
+
+        for (int i=0; i<guards.length; i++) {
+            if (meta.involvedTypes[i]) {
+                guards[i].call(mv);
+                mv.visitJumpInsn(IFEQ, slowPath);
+            }
+        }
+
+        // meta class check with boolean holder
+        String owner = BytecodeHelper.getClassInternalName(controller.getClassNode());
+        MethodNode mn = controller.getMethodNode();
+        if (mn!=null) {
+            mv.visitFieldInsn(GETSTATIC, owner, Verifier.STATIC_METACLASS_BOOL, "Z");
+            mv.visitJumpInsn(IFNE, slowPath);
+        }
+
+        //standard metaclass check
+        disabledStandardMetaClass.call(mv);
+        mv.visitJumpInsn(IFNE, slowPath);
+
+        // other guards here
+
+        mv.visitJumpInsn(GOTO, fastPathData.pathStart);
+        mv.visitLabel(slowPath);
+
+        return fastPathData;
+    }
+
+    private void writeFastPathPrelude(FastPathData meta) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitJumpInsn(GOTO, meta.afterPath);
+        mv.visitLabel(meta.pathStart);
+        controller.switchToFastPath();
+    }
+
+    private void writeFastPathEpilogue(FastPathData meta) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitLabel(meta.afterPath);
+        controller.switchToSlowPath();
+    }
+
+    @Override
+    public void writeBlockStatement(BlockStatement statement) {
+        StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+        FastPathData fastPathData = writeGuards(meta, statement);
+
+        if (fastPathData==null) {
+            // normal mode with different paths
+            // important is to not to have a fastpathblock here,
+            // otherwise the per expression statement improvement 
+            // is impossible
+            super.writeBlockStatement(statement);
+        } else {
+            // fast/slow path generation
+            boolean oldFastPathBlock = fastPathBlocked;
+            fastPathBlocked = true;
+            super.writeBlockStatement(statement);
+            fastPathBlocked = oldFastPathBlock;
+
+            writeFastPathPrelude(fastPathData);
+            super.writeBlockStatement(statement);
+            writeFastPathEpilogue(fastPathData);
+        }
+    }
+
+    @Override
+    public void writeDoWhileLoop(DoWhileStatement statement) {
+        if (controller.isFastPath()) {
+            super.writeDoWhileLoop(statement);
+        } else {
+            StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+            FastPathData fastPathData = writeGuards(meta, statement);
+
+            boolean oldFastPathBlock = fastPathBlocked;
+            fastPathBlocked = true;
+            super.writeDoWhileLoop(statement);
+            fastPathBlocked = oldFastPathBlock;
+
+            if (fastPathData==null) return;
+            writeFastPathPrelude(fastPathData);
+            super.writeDoWhileLoop(statement);
+            writeFastPathEpilogue(fastPathData);
+        }
+    }
+
+    @Override
+    protected void writeIteratorHasNext(MethodVisitor mv) {
+        if (controller.isFastPath()) {
+            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true);
+        } else {
+            super.writeIteratorHasNext(mv);
+        }
+    }
+
+    @Override
+    protected void writeIteratorNext(MethodVisitor mv) {
+        if (controller.isFastPath()) {
+            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true);
+        } else {
+            super.writeIteratorNext(mv);
+        }
+    }
+
+    @Override
+    protected void writeForInLoop(ForStatement statement) {
+        if (controller.isFastPath()) {
+            super.writeForInLoop(statement);
+        } else {
+            StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+            FastPathData fastPathData = writeGuards(meta, statement);
+
+            boolean oldFastPathBlock = fastPathBlocked;
+            fastPathBlocked = true;
+            super.writeForInLoop(statement);
+            fastPathBlocked = oldFastPathBlock;
+
+            if (fastPathData==null) return;
+            writeFastPathPrelude(fastPathData);
+            super.writeForInLoop(statement);
+            writeFastPathEpilogue(fastPathData);
+        }
+    }
+
+    @Override
+    protected void writeForLoopWithClosureList(ForStatement statement) {
+        if (controller.isFastPath()) {
+            super.writeForLoopWithClosureList(statement);
+        } else {
+            StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+            FastPathData fastPathData = writeGuards(meta, statement);
+
+            boolean oldFastPathBlock = fastPathBlocked;
+            fastPathBlocked = true;
+            super.writeForLoopWithClosureList(statement);
+            fastPathBlocked = oldFastPathBlock;
+
+            if (fastPathData==null) return;
+            writeFastPathPrelude(fastPathData);
+            super.writeForLoopWithClosureList(statement);
+            writeFastPathEpilogue(fastPathData);
+        }
+    }
+
+    @Override
+    public void writeWhileLoop(WhileStatement statement) {
+        if (controller.isFastPath()) {
+            super.writeWhileLoop(statement);
+        } else {
+            StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+            FastPathData fastPathData = writeGuards(meta, statement);
+
+            boolean oldFastPathBlock = fastPathBlocked;
+            fastPathBlocked = true;
+            super.writeWhileLoop(statement);
+            fastPathBlocked = oldFastPathBlock;
+
+            if (fastPathData==null) return;
+            writeFastPathPrelude(fastPathData);
+            super.writeWhileLoop(statement);
+            writeFastPathEpilogue(fastPathData);
+        }
+    }
+
+    @Override
+    public void writeIfElse(IfStatement statement) {
+        StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+        FastPathData fastPathData = writeGuards(meta, statement);
+
+        if (fastPathData==null) {
+            super.writeIfElse(statement);
+        } else {
+            boolean oldFastPathBlock = fastPathBlocked;
+            fastPathBlocked = true;
+            super.writeIfElse(statement);
+            fastPathBlocked = oldFastPathBlock;
+
+            if (fastPathData == null) return;
+            writeFastPathPrelude(fastPathData);
+            super.writeIfElse(statement);
+            writeFastPathEpilogue(fastPathData);
+        }
+    }
+
+    private boolean isNewPathFork(StatementMeta meta) {
+        // meta.optimize -> can do fast path
+        if (meta==null || meta.optimize==false) return false;
+        // fastPathBlocked -> slow path
+        if (fastPathBlocked) return false;
+        // controller.isFastPath() -> fastPath
+        return !controller.isFastPath();
+    }
+
+    @Override
+    public void writeReturn(ReturnStatement statement) {
+        if (controller.isFastPath()) {
+            super.writeReturn(statement);
+        } else {
+            StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+            if (isNewPathFork(meta) && writeDeclarationExtraction(statement)) {
+                if (meta.declaredVariableExpression != null) {
+                    // declaration was replaced by assignment so we need to define the variable
+                    controller.getCompileStack().defineVariable(meta.declaredVariableExpression, false);
+                }
+                FastPathData fastPathData = writeGuards(meta, statement);
+
+                boolean oldFastPathBlock = fastPathBlocked;
+                fastPathBlocked = true;
+                super.writeReturn(statement);
+                fastPathBlocked = oldFastPathBlock;
+
+                if (fastPathData==null) return;
+                writeFastPathPrelude(fastPathData);
+                super.writeReturn(statement);
+                writeFastPathEpilogue(fastPathData);
+            } else {
+                super.writeReturn(statement);
+            }
+        }
+    }
+
+    @Override
+    public void writeExpressionStatement(ExpressionStatement statement) {
+        if (controller.isFastPath()) {
+            super.writeExpressionStatement(statement);
+        } else {
+            StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+            // we have to have handle DelcarationExpressions special, since their 
+            // entry should be outside the optimization path, we have to do that of
+            // course only if we are actually going to do two different paths, 
+            // otherwise it is not needed
+            //
+            // there are several cases to be considered now.
+            // (1) no fast path possible, so just do super
+            // (2) fast path possible, and at path split point (meaning not in 
+            //     fast path and not in slow path). Here we have to extract the 
+            //     Declaration and replace by an assignment
+            // (3) fast path possible and in slow or fastPath. Nothing to do here.
+            //
+            // the only case we need to handle is then (2).
+
+            if (isNewPathFork(meta) && writeDeclarationExtraction(statement)) {
+                if (meta.declaredVariableExpression != null) {
+                    // declaration was replaced by assignment so we need to define the variable
+                    controller.getCompileStack().defineVariable(meta.declaredVariableExpression, false);
+                }
+                FastPathData fastPathData = writeGuards(meta, statement);
+
+                boolean oldFastPathBlock = fastPathBlocked;
+                fastPathBlocked = true;
+                super.writeExpressionStatement(statement);
+                fastPathBlocked = oldFastPathBlock;
+
+                if (fastPathData==null) return;
+                writeFastPathPrelude(fastPathData);
+                super.writeExpressionStatement(statement);
+                writeFastPathEpilogue(fastPathData);
+            } else {
+                super.writeExpressionStatement(statement);
+            }
+        }
+    }
+
+    private boolean writeDeclarationExtraction(Statement statement) {
+        Expression ex = null;
+        if (statement instanceof ReturnStatement) {
+            ReturnStatement rs = (ReturnStatement) statement;
+            ex = rs.getExpression();
+        } else if (statement instanceof ExpressionStatement) {
+            ExpressionStatement es = (ExpressionStatement) statement;
+            ex = es.getExpression();
+        } else {
+            throw new GroovyBugError("unknown statement type :"+statement.getClass());
+        }
+        if (!(ex instanceof DeclarationExpression)) return true;
+        DeclarationExpression declaration = (DeclarationExpression) ex;
+        ex = declaration.getLeftExpression();
+        if (ex instanceof TupleExpression) return false;
+
+        // stash declared variable in case we do subsequent visits after we
+        // change to assignment only
+        StatementMeta meta = statement.getNodeMetaData(StatementMeta.class);
+        if (meta != null) {
+            meta.declaredVariableExpression = declaration.getVariableExpression();
+        }
+
+        // change statement to do assignment only
+        BinaryExpression assignment = new BinaryExpression(
+                declaration.getLeftExpression(),
+                declaration.getOperation(),
+                declaration.getRightExpression());
+        assignment.setSourcePosition(declaration);
+        assignment.copyNodeMetaData(declaration);
+        // replace statement code
+        if (statement instanceof ReturnStatement) {
+            ReturnStatement rs = (ReturnStatement) statement;
+            rs.setExpression(assignment);
+        } else if (statement instanceof ExpressionStatement) {
+            ExpressionStatement es = (ExpressionStatement) statement;
+            es.setExpression(assignment);
+        } else {
+            throw new GroovyBugError("unknown statement type :"+statement.getClass());
+        }
+        return true;
+    }
+
+    public static void setNodeMeta(TypeChooser chooser, ClassNode classNode) {
+        if (classNode.getNodeMetaData(ClassNodeSkip.class)!=null) return;
+        new OptVisitor(chooser).visitClass(classNode);
+    }
+
+    private static StatementMeta addMeta(ASTNode node) {
+        StatementMeta metaOld = node.getNodeMetaData(StatementMeta.class);
+        StatementMeta meta = metaOld;
+        if (meta==null) meta = new StatementMeta();
+        meta.optimize = true;
+        if (metaOld==null) node.setNodeMetaData(StatementMeta.class, meta);
+        return meta;
+    }
+
+    private static StatementMeta addMeta(ASTNode node, OptimizeFlagsCollector opt) {
+        StatementMeta meta = addMeta(node);
+        meta.chainInvolvedTypes(opt);
+        return meta;
+    }
+
+    private static class OptimizeFlagsCollector {
+        private static class OptimizeFlagsEntry {
+            private boolean canOptimize = false;
+            private boolean shouldOptimize = false;
+            private boolean[] involvedTypes = new boolean[typeMapKeyNames.length];
+        }
+        private OptimizeFlagsEntry current = new OptimizeFlagsEntry();
+        private final LinkedList<OptimizeFlagsEntry> olderEntries = new LinkedList<OptimizeFlagsEntry>();
+        public void push() {
+            olderEntries.addLast(current);
+            current = new OptimizeFlagsEntry();
+        }
+        public void pop(boolean propagateFlags){
+            OptimizeFlagsEntry old = current;
+            current = olderEntries.removeLast();
+            if (propagateFlags) {
+                chainCanOptimize(old.canOptimize);
+                chainShouldOptimize(old.shouldOptimize);
+                for (int i=0; i<typeMapKeyNames.length; i++) current.involvedTypes[i] |= old.involvedTypes[i];
+            }
+        }
+        public String toString() {
+            StringBuilder ret;
+            if (current.shouldOptimize) {
+                ret = new StringBuilder("should optimize, can = " + current.canOptimize);
+            } else if (current.canOptimize) {
+                ret = new StringBuilder("can optimize");
+            } else {
+                ret = new StringBuilder("don't optimize");
+            }
+            ret.append(" involvedTypes =");
+            for (int i=0; i<typeMapKeyNames.length; i++) {
+                if (current.involvedTypes[i]) ret.append(" ").append(typeMapKeyNames[i]);
+            }
+            return ret.toString();
+        }
+        /**
+         * @return true iff we should Optimize - this is almost seen as must
+         */
+        private boolean shouldOptimize() {
+            return current.shouldOptimize;
+        }
+        /**
+         * @return true iff we can optimize, but not have to
+         */
+        private boolean canOptimize() {
+            return current.canOptimize || current.shouldOptimize;
+        }
+        /**
+         * set "should" to true, if not already
+         */
+        public void chainShouldOptimize(boolean opt) {
+            current.shouldOptimize = shouldOptimize() || opt;
+        }
+        /**
+         * set "can" to true, if not already
+         */
+        public void chainCanOptimize(boolean opt) {
+            current.canOptimize = current.canOptimize || opt;
+        }
+        public void chainInvolvedType(ClassNode type) {
+            Integer res = typeMap.get(type);
+            if (res==null) return;
+            current.involvedTypes[res] = true;
+        }
+        public void reset() {
+            current.canOptimize = false;
+            current.shouldOptimize = false;
+            current.involvedTypes = new boolean[typeMapKeyNames.length];
+        }
+    }
+
+    private static class OptVisitor extends ClassCodeVisitorSupport {
+        private final TypeChooser typeChooser;
+
+        public OptVisitor(final TypeChooser chooser) {
+            this.typeChooser = chooser;
+        }
+
+        @Override protected SourceUnit getSourceUnit() {return null;}
+
+        private ClassNode node;
+        private OptimizeFlagsCollector opt = new OptimizeFlagsCollector();
+        private boolean optimizeMethodCall = true;
+        private VariableScope scope;
+        private static final VariableScope nonStaticScope = new VariableScope();
+
+        @Override
+        public void visitClass(ClassNode node) {
+            this.optimizeMethodCall = !node.implementsInterface(GROOVY_INTERCEPTABLE_TYPE);
+            this.node = node;
+            this.scope = nonStaticScope;
+            super.visitClass(node);
+            this.scope=null;
+            this.node=null;
+        }
+
+        @Override
+        public void visitMethod(MethodNode node) {
+            scope = node.getVariableScope();
+            super.visitMethod(node);
+            opt.reset();
+        }
+
+        @Override
+        public void visitConstructor(ConstructorNode node) {
+            scope = node.getVariableScope();
+            super.visitConstructor(node);
+        }
+
+        @Override
+        public void visitReturnStatement(ReturnStatement statement) {
+            opt.push();
+            super.visitReturnStatement(statement);
+            if (opt.shouldOptimize()) addMeta(statement,opt);
+            opt.pop(opt.shouldOptimize());
+        }
+
+        @Override
+        public void visitUnaryMinusExpression(UnaryMinusExpression expression) {
+            //TODO: implement int operations for this
+            super.visitUnaryMinusExpression(expression);
+            StatementMeta meta = addMeta(expression);
+            meta.type = OBJECT_TYPE;
+        }
+
+        @Override
+        public void visitUnaryPlusExpression(UnaryPlusExpression expression) {
+            //TODO: implement int operations for this
+            super.visitUnaryPlusExpression(expression);
+            StatementMeta meta = addMeta(expression);
+            meta.type = OBJECT_TYPE;
+        }
+
+        @Override
+        public void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
+            //TODO: implement int operations for this
+            super.visitBitwiseNegationExpression(expression);
+            StatementMeta meta = addMeta(expression);
+            meta.type = OBJECT_TYPE;
+        }
+
+        private void addTypeInformation(Expression expression, Expression orig) {
+            ClassNode type = typeChooser.resolveType(expression, node);
+            if (isPrimitiveType(type)) {
+                StatementMeta meta = addMeta(orig);
+                meta.type = type;
+                opt.chainShouldOptimize(true);
+                opt.chainInvolvedType(type);
+            }
+        }
+
+        @Override
+        public void visitPrefixExpression(PrefixExpression expression) {
+            super.visitPrefixExpression(expression);
+            addTypeInformation(expression.getExpression(),expression);
+        }
+
+        @Override
+        public void visitPostfixExpression(PostfixExpression expression) {
+            super.visitPostfixExpression(expression);
+            addTypeInformation(expression.getExpression(),expression);
+        }
+
+        @Override
+        public void visitDeclarationExpression(DeclarationExpression expression) {
+            Expression right = expression.getRightExpression();
+            right.visit(this);
+
+            ClassNode leftType = typeChooser.resolveType(expression.getLeftExpression(), node);
+            Expression rightExpression = expression.getRightExpression();
+            ClassNode rightType = optimizeDivWithIntOrLongTarget(rightExpression, leftType);
+            if (rightType==null) rightType = typeChooser.resolveType(expression.getRightExpression(), node);
+            if (isPrimitiveType(leftType) && isPrimitiveType(rightType)) {
+                // if right is a constant, then we optimize only if it makes
+                // a block complete, so we set a maybe
+                if (right instanceof ConstantExpression) {
+                    opt.chainCanOptimize(true);
+                } else {
+                    opt.chainShouldOptimize(true);
+                }
+                StatementMeta meta = addMeta(expression);
+                ClassNode declarationType = typeChooser.resolveType(expression, node);
+                meta.type = declarationType!=null?declarationType:leftType;
+                opt.chainInvolvedType(leftType);
+                opt.chainInvolvedType(rightType);
+            }
+        }
+
+        @Override
+        public void visitBinaryExpression(BinaryExpression expression) {
+            if (expression.getNodeMetaData(StatementMeta.class)!=null) return;
+            super.visitBinaryExpression(expression);
+
+            ClassNode leftType = typeChooser.resolveType(expression.getLeftExpression(), node);
+            ClassNode rightType = typeChooser.resolveType(expression.getRightExpression(), node);
+            ClassNode resultType = null;
+            int operation = expression.getOperation().getType();
+
+            if (operation==Types.LEFT_SQUARE_BRACKET && leftType.isArray()) {
+                opt.chainShouldOptimize(true);
+                resultType = leftType.getComponentType();
+            } else {
+                switch (operation) {
+                    case Types.COMPARE_EQUAL:
+                    case Types.COMPARE_LESS_THAN:
+                    case Types.COMPARE_LESS_THAN_EQUAL:
+                    case Types.COMPARE_GREATER_THAN:
+                    case Types.COMPARE_GREATER_THAN_EQUAL:
+                    case Types.COMPARE_NOT_EQUAL:
+                        if (isIntCategory(leftType) && isIntCategory(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else if (isLongCategory(leftType) && isLongCategory(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else {
+                            opt.chainCanOptimize(true);
+                        }
+                        resultType = boolean_TYPE;
+                        break;
+                    case Types.LOGICAL_AND: case Types.LOGICAL_AND_EQUAL:
+                    case Types.LOGICAL_OR: case Types.LOGICAL_OR_EQUAL:
+                        if (boolean_TYPE.equals(leftType) && boolean_TYPE.equals(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else {
+                            opt.chainCanOptimize(true);
+                        }
+                        expression.setType(boolean_TYPE);
+                        resultType = boolean_TYPE;
+                        break;
+                    case Types.DIVIDE: case Types.DIVIDE_EQUAL:
+                        if (isLongCategory(leftType) && isLongCategory(rightType)) {
+                            resultType = BigDecimal_TYPE;
+                            opt.chainShouldOptimize(true);
+                        } else if (isBigDecCategory(leftType) && isBigDecCategory(rightType)) {
+                            // no optimization for BigDecimal yet
+                            //resultType = BigDecimal_TYPE;
+                        } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
+                            resultType = double_TYPE;
+                            opt.chainShouldOptimize(true);
+                        }
+                        break;
+                    case Types.POWER: case Types.POWER_EQUAL:
+                        //TODO: implement
+                        break;
+                    case Types.ASSIGN:
+                        resultType = optimizeDivWithIntOrLongTarget(expression.getRightExpression(), leftType);
+                        opt.chainCanOptimize(true);
+                        break;
+                    default:
+                        if (isIntCategory(leftType) && isIntCategory(rightType)) {
+                            resultType = int_TYPE;
+                            opt.chainShouldOptimize(true);
+                        } else if (isLongCategory(leftType) && isLongCategory(rightType)) {
+                            resultType = long_TYPE;
+                            opt.chainShouldOptimize(true);
+                        } else if (isBigDecCategory(leftType) && isBigDecCategory(rightType)) {
+                            // no optimization for BigDecimal yet
+                            //resultType = BigDecimal_TYPE;
+                        } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
+                            resultType = double_TYPE;
+                            opt.chainShouldOptimize(true);
+                        }
+                }
+            }
+
+            if (resultType!=null) {
+                StatementMeta meta = addMeta(expression);
+                meta.type = resultType;
+                opt.chainInvolvedType(resultType);
+                opt.chainInvolvedType(leftType);
+                opt.chainInvolvedType(rightType);
+            }
+        }
+
+        /**
+         * method to optimize Z = X/Y with Z being int or long style
+         * @returns null if the optimization cannot be applied, otherwise it
+         * will return the new target type
+         */
+        private ClassNode optimizeDivWithIntOrLongTarget(Expression rhs, ClassNode assignmentTartgetType) {
+            if (!(rhs instanceof BinaryExpression)) return null;
+            BinaryExpression binExp = (BinaryExpression) rhs;
+            int op = binExp.getOperation().getType();
+            if (op!=Types.DIVIDE && op!=Types.DIVIDE_EQUAL) return null;
+
+            ClassNode originalResultType = typeChooser.resolveType(binExp, node);
+            if (    !originalResultType.equals(BigDecimal_TYPE) ||
+                    !(isLongCategory(assignmentTartgetType) || isFloatingCategory(assignmentTartgetType))
+            ) {
+                return null;
+            }
+
+            ClassNode leftType = typeChooser.resolveType(binExp.getLeftExpression(), node);
+            if (!isLongCategory(leftType)) return null;
+            ClassNode rightType = typeChooser.resolveType(binExp.getRightExpression(), node);
+            if (!isLongCategory(rightType)) return null;
+
+            ClassNode target;
+            if (isIntCategory(leftType) && isIntCategory(rightType)) {
+                target = int_TYPE;
+            } else if (isLongCategory(leftType) && isLongCategory(rightType)) {
+                target = long_TYPE;
+            } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
+                target = double_TYPE;
+            } else {
+                return null;
+            }
+            StatementMeta meta = addMeta(rhs);
+            meta.type = target;
+            opt.chainInvolvedType(target);
+            return target;
+        }
+
+        @Override
+        public void visitExpressionStatement(ExpressionStatement statement) {
+            if (statement.getNodeMetaData(StatementMeta.class)!=null) return;
+            opt.push();
+            super.visitExpressionStatement(statement);
+            if (opt.shouldOptimize()) addMeta(statement,opt);
+            opt.pop(opt.shouldOptimize());
+        }
+
+        @Override
+        public void visitBlockStatement(BlockStatement block) {
+            opt.push();
+            boolean optAll = true;
+            for (Statement statement : block.getStatements()) {
+                opt.push();
+                statement.visit(this);
+                optAll = optAll && opt.canOptimize();
+                opt.pop(true);
+            }
+            if (block.isEmpty()) {
+                opt.chainCanOptimize(true);
+                opt.pop(true);
+            } else {
+                opt.chainShouldOptimize(optAll);
+                if (optAll) addMeta(block,opt);
+                opt.pop(optAll);
+            }
+        }
+
+        @Override
+        public void visitIfElse(IfStatement statement) {
+            opt.push();
+            super.visitIfElse(statement);
+            if (opt.shouldOptimize()) addMeta(statement,opt);
+            opt.pop(opt.shouldOptimize());
+        }
+
+        /*@Override
+        public void visitConstantExpression(ConstantExpression expression) {
+            super.visitConstantExpression(expression);
+            opt.chainShouldOptimize(true);
+        }*/
+
+        @Override
+        public void visitStaticMethodCallExpression(StaticMethodCallExpression expression) {
+            if (expression.getNodeMetaData(StatementMeta.class)!=null) return;
+            super.visitStaticMethodCallExpression(expression);
+
+            setMethodTarget(expression,expression.getMethod(), expression.getArguments(), true);
+        }
+
+        @Override
+        public void visitMethodCallExpression(MethodCallExpression expression) {
+            if (expression.getNodeMetaData(StatementMeta.class)!=null) return;
+            super.visitMethodCallExpression(expression);
+
+            Expression object = expression.getObjectExpression();
+            boolean setTarget = AsmClassGenerator.isThisExpression(object);
+            if (!setTarget) {
+                if (!(object instanceof ClassExpression)) return;
+                setTarget = object.equals(node);
+            }
+
+            if (!setTarget) return;
+            setMethodTarget(expression, expression.getMethodAsString(), expression.getArguments(), true);
+        }
+
+        @Override
+        public void visitConstructorCallExpression(ConstructorCallExpression call) {
+            if (call.getNodeMetaData(StatementMeta.class)!=null) return;
+            super.visitConstructorCallExpression(call);
+
+            // we cannot a target for the constructor call, since we cannot easily
+            // check the meta class of the other class
+            // setMethodTarget(call, "<init>", call.getArguments(), false);
+        }
+
+        private void setMethodTarget(Expression expression, String name, Expression callArgs, boolean isMethod) {
+            if (name==null) return;
+            if (!optimizeMethodCall) return;
+            if (AsmClassGenerator.containsSpreadExpression(callArgs)) return;
+            // find method call target
+            Parameter[] paraTypes = null;
+            if (callArgs instanceof ArgumentListExpression) {
+                ArgumentListExpression args = (ArgumentListExpression) callArgs;
+                int size = args.getExpressions().size();
+                paraTypes = new Parameter[size];
+                int i=0;
+                for (Expression exp: args.getExpressions()) {
+                    ClassNode type = typeChooser.resolveType(exp, node);
+                    if (!validTypeForCall(type)) return;
+                    paraTypes[i] = new Parameter(type,"");
+                    i++;
+                }
+            } else {
+                ClassNode type = typeChooser.resolveType(callArgs, node);
+                if (!validTypeForCall(type)) return;
+                paraTypes = new Parameter[]{new Parameter(type,"")};
+            }
+
+            MethodNode target;
+            ClassNode type;
+            if (isMethod) {
+                target = node.getMethod(name, paraTypes);
+                if (target==null) return;
+                if (!target.getDeclaringClass().equals(node)) return;
+                if (scope.isInStaticContext() && !target.isStatic()) return;
+                type = target.getReturnType().redirect();
+            } else {
+                type = expression.getType();
+                target = selectConstructor(type, paraTypes);
+                if (target==null) return;
+            }
+
+            StatementMeta meta = addMeta(expression);
+            meta.target = target;
+            meta.type = type;
+            opt.chainShouldOptimize(true);
+        }
+
+        private static MethodNode selectConstructor(ClassNode node, Parameter[] paraTypes) {
+            List<ConstructorNode> cl = node.getDeclaredConstructors();
+            MethodNode res = null;
+            for (ConstructorNode cn : cl) {
+                if (ParameterUtils.parametersEqual(cn.getParameters(), paraTypes)) {
+                    res = cn;
+                    break;
+                }
+            }
+            if (res !=null && res.isPublic()) return res;
+            return null;
+        }
+
+        private static boolean validTypeForCall(ClassNode type) {
+            // do call only for final classes and primitive types
+            if (isPrimitiveType(type)) return true;
+            return (type.getModifiers() & ACC_FINAL) > 0;
+        }
+
+        @Override
+        public void visitClosureExpression(ClosureExpression expression) {
+            return;
+        }
+
+        @Override
+        public void visitForLoop(ForStatement statement) {
+            opt.push();
+            super.visitForLoop(statement);
+            if (opt.shouldOptimize()) addMeta(statement,opt);
+            opt.pop(opt.shouldOptimize());
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/StatementMetaTypeChooser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/StatementMetaTypeChooser.java b/src/main/java/org/codehaus/groovy/classgen/asm/StatementMetaTypeChooser.java
new file mode 100644
index 0000000..2ada09d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/StatementMetaTypeChooser.java
@@ -0,0 +1,58 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+
+/**
+ * A {@link TypeChooser} which is aware of statement metadata.
+ *
+ * @author Jochen Theodorou
+ * @author Cedric Champeau
+ */
+public class StatementMetaTypeChooser implements TypeChooser {
+    public ClassNode resolveType(final Expression exp, final ClassNode current) {
+        if (exp instanceof ClassExpression) return ClassHelper.CLASS_Type;
+        OptimizingStatementWriter.StatementMeta meta = exp.getNodeMetaData(OptimizingStatementWriter.StatementMeta.class);
+        ClassNode type = null;
+        if (meta != null) type = meta.type;
+        if (type != null) return type;
+        if (exp instanceof VariableExpression) {
+            VariableExpression ve = (VariableExpression) exp;
+            if (ve.isClosureSharedVariable()) return ve.getType();
+            type = ve.getOriginType();
+            if (ve.getAccessedVariable() instanceof FieldNode) {
+                FieldNode fn = (FieldNode) ve.getAccessedVariable();
+                if (!fn.getDeclaringClass().equals(current)) return fn.getOriginType();
+            }
+        } else if (exp instanceof Variable) {
+            Variable v = (Variable) exp;
+            type = v.getOriginType();
+        } else {
+            type = exp.getType();
+        }
+        return type.redirect();
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/Verifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/Verifier.java b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
new file mode 100644
index 0000000..59a8d60
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/Verifier.java
@@ -0,0 +1,1565 @@
+/*
+ *  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.classgen;
+
+import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyObject;
+import groovy.lang.MetaClass;
+import groovy.transform.Generated;
+import org.apache.groovy.ast.tools.ClassNodeUtils;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.GroovyClassVisitor;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+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.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.tools.GenericsUtils;
+import org.codehaus.groovy.ast.tools.PropertyNodeUtils;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.classgen.asm.MopWriter;
+import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.ClassNodeSkip;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.trait.Traits;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static java.lang.reflect.Modifier.isAbstract;
+import static java.lang.reflect.Modifier.isFinal;
+import static java.lang.reflect.Modifier.isPrivate;
+import static java.lang.reflect.Modifier.isPublic;
+import static java.lang.reflect.Modifier.isStatic;
+import static org.apache.groovy.ast.tools.MethodNodeUtils.methodDescriptorWithoutReturnType;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+
+/**
+ * Verifies the AST node and adds any default AST code before bytecode generation occurs.
+ *
+ * Checks include:
+ * <ul>
+ *     <li>Methods with duplicate signatures</li>
+ *     <li>Duplicate interfaces</li>
+ *     <li>Reassigned final variables/parameters</li>
+ *     <li>Uninitialized variables</li>
+ *     <li>Bad code in object initializers or constructors</li>
+ *     <li>Mismatches in modifiers or return types between implementations and interfaces/abstract classes</li>
+ * </ul>
+ *
+ * Added code includes:
+ * <ul>
+ *     <li>Methods needed to implement GroovyObject</li>
+ *     <li>Property accessor methods</li>
+ *     <li>Covariant methods</li>
+ *     <li>Additional methods/constructors as needed for default parameters</li>
+ * </ul>
+ */
+public class Verifier implements GroovyClassVisitor, Opcodes {
+
+    public static final String STATIC_METACLASS_BOOL = "__$stMC";
+    public static final String SWAP_INIT = "__$swapInit";
+    public static final String INITIAL_EXPRESSION = "INITIAL_EXPRESSION";
+    public static final String DEFAULT_PARAMETER_GENERATED = "DEFAULT_PARAMETER_GENERATED";
+
+    // NOTE: timeStamp constants shouldn't belong to Verifier but kept here
+    // for binary compatibility
+    public static final String __TIMESTAMP = "__timeStamp";
+    public static final String __TIMESTAMP__ = "__timeStamp__239_neverHappen";
+    private static final Parameter[] INVOKE_METHOD_PARAMS = new Parameter[]{
+            new Parameter(ClassHelper.STRING_TYPE, "method"),
+            new Parameter(ClassHelper.OBJECT_TYPE, "arguments")
+    };
+    private static final Parameter[] SET_PROPERTY_PARAMS = new Parameter[]{
+            new Parameter(ClassHelper.STRING_TYPE, "property"),
+            new Parameter(ClassHelper.OBJECT_TYPE, "value")
+    };
+    private static final Parameter[] GET_PROPERTY_PARAMS = new Parameter[]{
+            new Parameter(ClassHelper.STRING_TYPE, "property")
+    };
+    private static final Parameter[] SET_METACLASS_PARAMS = new Parameter[]{
+            new Parameter(ClassHelper.METACLASS_TYPE, "mc")
+    };
+
+    private static final Class GENERATED_ANNOTATION = Generated.class;
+
+    private ClassNode classNode;
+    private MethodNode methodNode;
+
+    public ClassNode getClassNode() {
+        return classNode;
+    }
+
+    protected void setClassNode(ClassNode classNode) {
+        this.classNode = classNode;
+    }
+
+    public MethodNode getMethodNode() {
+        return methodNode;
+    }
+
+    private static FieldNode setMetaClassFieldIfNotExists(ClassNode node, FieldNode metaClassField) {
+        if (metaClassField != null) return metaClassField;
+        final String classInternalName = BytecodeHelper.getClassInternalName(node);
+        metaClassField =
+                node.addField("metaClass", ACC_PRIVATE | ACC_TRANSIENT | ACC_SYNTHETIC, ClassHelper.METACLASS_TYPE,
+                        new BytecodeExpression(ClassHelper.METACLASS_TYPE) {
+                            public void visit(MethodVisitor mv) {
+                                mv.visitVarInsn(ALOAD, 0);
+                                mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                            }
+                        });
+        metaClassField.setSynthetic(true);
+        return metaClassField;
+    }
+
+    private static FieldNode getMetaClassField(ClassNode node) {
+        FieldNode ret = node.getDeclaredField("metaClass");
+        if (ret != null) {
+            ClassNode mcFieldType = ret.getType();
+            if (!mcFieldType.equals(ClassHelper.METACLASS_TYPE)) {
+                throw new RuntimeParserException("The class " + node.getName() +
+                        " cannot declare field 'metaClass' of type " + mcFieldType.getName() + " as it needs to be of " +
+                        "the type " + ClassHelper.METACLASS_TYPE.getName() + " for internal groovy purposes", ret);
+            }
+            return ret;
+        }
+        ClassNode current = node;
+        while (current != ClassHelper.OBJECT_TYPE) {
+            current = current.getSuperClass();
+            if (current == null) break;
+            ret = current.getDeclaredField("metaClass");
+            if (ret == null) continue;
+            if (isPrivate(ret.getModifiers())) continue;
+            return ret;
+        }
+        return null;
+    }
+
+    /**
+     * walk the class
+     *
+     * @param node the node to visit
+     */
+    public void visitClass(final ClassNode node) {
+        this.classNode = node;
+
+        if (Traits.isTrait(node) // maybe possible to have this true in joint compilation mode
+                || classNode.isInterface()) {
+            //interfaces have no constructors, but this code expects one,
+            //so create a dummy and don't add it to the class node
+            ConstructorNode dummy = new ConstructorNode(0, null);
+            addInitialization(node, dummy);
+            node.visitContents(this);
+            if (classNode.getNodeMetaData(ClassNodeSkip.class) == null) {
+                classNode.setNodeMetaData(ClassNodeSkip.class, true);
+            }
+            return;
+        }
+
+        ClassNode[] classNodes = classNode.getInterfaces();
+        List<String> interfaces = new ArrayList<String>();
+        for (ClassNode classNode : classNodes) {
+            interfaces.add(classNode.getName());
+        }
+        Set<String> interfaceSet = new HashSet<String>(interfaces);
+        if (interfaceSet.size() != interfaces.size()) {
+            throw new RuntimeParserException("Duplicate interfaces in implements list: " + interfaces, classNode);
+        }
+
+        addDefaultParameterMethods(node);
+        addDefaultParameterConstructors(node);
+
+        final String classInternalName = BytecodeHelper.getClassInternalName(node);
+
+        addStaticMetaClassField(node, classInternalName);
+
+        boolean knownSpecialCase =
+                node.isDerivedFrom(ClassHelper.GSTRING_TYPE)
+                        || node.isDerivedFrom(ClassHelper.GROOVY_OBJECT_SUPPORT_TYPE);
+
+        addFastPathHelperFieldsAndHelperMethod(node, classInternalName, knownSpecialCase);
+        if (!knownSpecialCase) addGroovyObjectInterfaceAndMethods(node, classInternalName);
+
+        addDefaultConstructor(node);
+
+        addInitialization(node);
+        checkReturnInObjectInitializer(node.getObjectInitializerStatements());
+        node.getObjectInitializerStatements().clear();
+        node.visitContents(this);
+        checkForDuplicateMethods(node);
+        addCovariantMethods(node);
+
+        checkFinalVariables(node);
+    }
+
+    private void checkFinalVariables(ClassNode node) {
+        FinalVariableAnalyzer analyzer = new FinalVariableAnalyzer(null, getFinalVariablesCallback());
+        analyzer.visitClass(node);
+
+    }
+
+    protected FinalVariableAnalyzer.VariableNotFinalCallback getFinalVariablesCallback() {
+        return new FinalVariableAnalyzer.VariableNotFinalCallback() {
+            @Override
+            public void variableNotFinal(Variable var, Expression bexp) {
+                if (var instanceof VariableExpression) {
+                    var = ((VariableExpression) var).getAccessedVariable();
+                }
+                if (var instanceof VariableExpression && isFinal(var.getModifiers())) {
+                    throw new RuntimeParserException("The variable [" + var.getName() + "] is declared final but is reassigned", bexp);
+                }
+                if (var instanceof Parameter && isFinal(var.getModifiers())) {
+                    throw new RuntimeParserException("The parameter [" + var.getName() + "] is declared final but is reassigned", bexp);
+                }
+            }
+
+            @Override
+            public void variableNotAlwaysInitialized(final VariableExpression var) {
+                throw new RuntimeParserException("The variable [" + var.getName() + "] may be uninitialized", var);
+            }
+        };
+    }
+
+    private static void checkForDuplicateMethods(ClassNode cn) {
+        Set<String> descriptors = new HashSet<String>();
+        for (MethodNode mn : cn.getMethods()) {
+            if (mn.isSynthetic()) continue;
+            String mySig = methodDescriptorWithoutReturnType(mn);
+            if (descriptors.contains(mySig)) {
+                if (mn.isScriptBody() || mySig.equals(scriptBodySignatureWithoutReturnType(cn))) {
+                    throw new RuntimeParserException("The method " + mn.getText() +
+                            " is a duplicate of the one declared for this script's body code", mn);
+                } else {
+                    throw new RuntimeParserException("The method " + mn.getText() +
+                            " duplicates another method of the same signature", mn);
+                }
+            }
+            descriptors.add(mySig);
+        }
+    }
+
+    private static String scriptBodySignatureWithoutReturnType(ClassNode cn) {
+        for (MethodNode mn : cn.getMethods()) {
+            if (mn.isScriptBody()) return methodDescriptorWithoutReturnType(mn);
+        }
+        return null;
+    }
+
+    private static FieldNode checkFieldDoesNotExist(ClassNode node, String fieldName) {
+        FieldNode ret = node.getDeclaredField(fieldName);
+        if (ret != null) {
+            if (isPublic(ret.getModifiers()) &&
+                    ret.getType().redirect() == ClassHelper.boolean_TYPE) {
+                return ret;
+            }
+            throw new RuntimeParserException("The class " + node.getName() +
+                    " cannot declare field '" + fieldName + "' as this" +
+                    " field is needed for internal groovy purposes", ret);
+        }
+        return null;
+    }
+
+    private static void addFastPathHelperFieldsAndHelperMethod(ClassNode node, final String classInternalName, boolean knownSpecialCase) {
+        if (node.getNodeMetaData(ClassNodeSkip.class) != null) return;
+        FieldNode stMCB = checkFieldDoesNotExist(node, STATIC_METACLASS_BOOL);
+        if (stMCB == null) {
+            stMCB = node.addField(
+                    STATIC_METACLASS_BOOL,
+                    ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC | ACC_TRANSIENT,
+                    ClassHelper.boolean_TYPE, null);
+            stMCB.setSynthetic(true);
+        }
+    }
+
+    protected void addDefaultConstructor(ClassNode node) {
+        if (!node.getDeclaredConstructors().isEmpty()) return;
+
+        BlockStatement empty = new BlockStatement();
+        empty.setSourcePosition(node);
+        ConstructorNode constructor = new ConstructorNode(ACC_PUBLIC, empty);
+        constructor.setSourcePosition(node);
+        constructor.setHasNoRealSourcePosition(true);
+        node.addConstructor(constructor);
+    }
+
+    private void addStaticMetaClassField(final ClassNode node, final String classInternalName) {
+        String _staticClassInfoFieldName = "$staticClassInfo";
+        while (node.getDeclaredField(_staticClassInfoFieldName) != null)
+            _staticClassInfoFieldName = _staticClassInfoFieldName + "$";
+        final String staticMetaClassFieldName = _staticClassInfoFieldName;
+
+        FieldNode staticMetaClassField = node.addField(staticMetaClassFieldName, ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.make(ClassInfo.class, false), null);
+        staticMetaClassField.setSynthetic(true);
+
+        node.addSyntheticMethod(
+                "$getStaticMetaClass",
+                ACC_PROTECTED,
+                ClassHelper.make(MetaClass.class),
+                Parameter.EMPTY_ARRAY,
+                ClassNode.EMPTY_ARRAY,
+                new BytecodeSequence(new BytecodeInstruction() {
+                    public void visit(MethodVisitor mv) {
+                        mv.visitVarInsn(ALOAD, 0);
+                        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
+                        if (BytecodeHelper.isClassLiteralPossible(node) || BytecodeHelper.isSameCompilationUnit(classNode, node)) {
+                            BytecodeHelper.visitClassLiteral(mv, node);
+                        } else {
+                            mv.visitMethodInsn(INVOKESTATIC, classInternalName, "$get$$class$" + classInternalName.replaceAll("\\/", "\\$"), "()Ljava/lang/Class;", false);
+                        }
+                        Label l1 = new Label();
+                        mv.visitJumpInsn(IF_ACMPEQ, l1);
+
+                        mv.visitVarInsn(ALOAD, 0);
+                        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/ScriptBytecodeAdapter", "initMetaClass", "(Ljava/lang/Object;)Lgroovy/lang/MetaClass;", false);
+                        mv.visitInsn(ARETURN);
+
+                        mv.visitLabel(l1);
+
+                        mv.visitFieldInsn(GETSTATIC, classInternalName, staticMetaClassFieldName, "Lorg/codehaus/groovy/reflection/ClassInfo;");
+                        mv.visitVarInsn(ASTORE, 1);
+                        mv.visitVarInsn(ALOAD, 1);
+                        Label l0 = new Label();
+                        mv.visitJumpInsn(IFNONNULL, l0);
+
+                        mv.visitVarInsn(ALOAD, 0);
+                        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
+                        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/reflection/ClassInfo", "getClassInfo", "(Ljava/lang/Class;)Lorg/codehaus/groovy/reflection/ClassInfo;", false);
+                        mv.visitInsn(DUP);
+                        mv.visitVarInsn(ASTORE, 1);
+                        mv.visitFieldInsn(PUTSTATIC, classInternalName, staticMetaClassFieldName, "Lorg/codehaus/groovy/reflection/ClassInfo;");
+
+                        mv.visitLabel(l0);
+
+                        mv.visitVarInsn(ALOAD, 1);
+                        mv.visitMethodInsn(INVOKEVIRTUAL, "org/codehaus/groovy/reflection/ClassInfo", "getMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                        mv.visitInsn(ARETURN);
+
+                    }
+                })
+        );
+    }
+
+    protected void addGroovyObjectInterfaceAndMethods(ClassNode node, final String classInternalName) {
+        if (!node.isDerivedFromGroovyObject()) node.addInterface(ClassHelper.make(GroovyObject.class));
+        FieldNode metaClassField = getMetaClassField(node);
+
+        boolean shouldAnnotate = classNode.getModule().getContext() != null;
+        AnnotationNode generatedAnnotation = shouldAnnotate ? new AnnotationNode(ClassHelper.make(GENERATED_ANNOTATION)) : null;
+
+        if (!node.hasMethod("getMetaClass", Parameter.EMPTY_ARRAY)) {
+            metaClassField = setMetaClassFieldIfNotExists(node, metaClassField);
+            MethodNode methodNode = addMethod(node, !isAbstract(node.getModifiers()),
+                    "getMetaClass",
+                    ACC_PUBLIC,
+                    ClassHelper.METACLASS_TYPE,
+                    Parameter.EMPTY_ARRAY,
+                    ClassNode.EMPTY_ARRAY,
+                    new BytecodeSequence(new BytecodeInstruction() {
+                        public void visit(MethodVisitor mv) {
+                            Label nullLabel = new Label();
+                            /**
+                             *  the code is:
+                             *  if (this.metaClass==null) {
+                             *      this.metaClass = this.$getStaticMetaClass
+                             *      return this.metaClass
+                             *  } else {
+                             *      return this.metaClass
+                             *  }
+                             *  with the optimization that the result of the
+                             *  first this.metaClass is duped on the operand
+                             *  stack and reused for the return in the else part
+                             */
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitFieldInsn(GETFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
+                            mv.visitInsn(DUP);
+                            mv.visitJumpInsn(IFNULL, nullLabel);
+                            mv.visitInsn(ARETURN);
+
+                            mv.visitLabel(nullLabel);
+                            mv.visitInsn(POP);
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitInsn(DUP);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "$getStaticMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                            mv.visitFieldInsn(PUTFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitFieldInsn(GETFIELD, classInternalName, "metaClass", "Lgroovy/lang/MetaClass;");
+                            mv.visitInsn(ARETURN);
+                        }
+                    })
+            );
+            if (shouldAnnotate) methodNode.addAnnotation(generatedAnnotation);
+        }
+
+        Parameter[] parameters = new Parameter[]{new Parameter(ClassHelper.METACLASS_TYPE, "mc")};
+        if (!node.hasMethod("setMetaClass", parameters)) {
+            metaClassField = setMetaClassFieldIfNotExists(node, metaClassField);
+            Statement setMetaClassCode;
+            if (isFinal(metaClassField.getModifiers())) {
+                ConstantExpression text = new ConstantExpression("cannot set read-only meta class");
+                ConstructorCallExpression cce = new ConstructorCallExpression(ClassHelper.make(IllegalArgumentException.class), text);
+                setMetaClassCode = new ExpressionStatement(cce);
+            } else {
+                List list = new ArrayList();
+                list.add(new BytecodeInstruction() {
+                    public void visit(MethodVisitor mv) {
+                        /**
+                         * the code is (meta class is stored in 1):
+                         * this.metaClass = <1>
+                         */
+                        mv.visitVarInsn(ALOAD, 0);
+                        mv.visitVarInsn(ALOAD, 1);
+                        mv.visitFieldInsn(PUTFIELD, classInternalName,
+                                "metaClass", "Lgroovy/lang/MetaClass;");
+                        mv.visitInsn(RETURN);
+                    }
+                });
+                setMetaClassCode = new BytecodeSequence(list);
+            }
+
+            MethodNode methodNode = addMethod(node, !isAbstract(node.getModifiers()),
+                    "setMetaClass",
+                    ACC_PUBLIC, ClassHelper.VOID_TYPE,
+                    SET_METACLASS_PARAMS, ClassNode.EMPTY_ARRAY,
+                    setMetaClassCode
+            );
+            if (shouldAnnotate) methodNode.addAnnotation(generatedAnnotation);
+        }
+
+        if (!node.hasMethod("invokeMethod", INVOKE_METHOD_PARAMS)) {
+            VariableExpression vMethods = new VariableExpression("method");
+            VariableExpression vArguments = new VariableExpression("arguments");
+            VariableScope blockScope = new VariableScope();
+            blockScope.putReferencedLocalVariable(vMethods);
+            blockScope.putReferencedLocalVariable(vArguments);
+
+            MethodNode methodNode = addMethod(node, !isAbstract(node.getModifiers()),
+                    "invokeMethod",
+                    ACC_PUBLIC,
+                    ClassHelper.OBJECT_TYPE, INVOKE_METHOD_PARAMS,
+                    ClassNode.EMPTY_ARRAY,
+                    new BytecodeSequence(new BytecodeInstruction() {
+                        public void visit(MethodVisitor mv) {
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "getMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitVarInsn(ALOAD, 1);
+                            mv.visitVarInsn(ALOAD, 2);
+                            mv.visitMethodInsn(INVOKEINTERFACE, "groovy/lang/MetaClass", "invokeMethod", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;", true);
+                            mv.visitInsn(ARETURN);
+                        }
+                    })
+            );
+            if (shouldAnnotate) methodNode.addAnnotation(generatedAnnotation);
+        }
+
+        if (!node.hasMethod("getProperty", GET_PROPERTY_PARAMS)) {
+            MethodNode methodNode = addMethod(node, !isAbstract(node.getModifiers()),
+                    "getProperty",
+                    ACC_PUBLIC,
+                    ClassHelper.OBJECT_TYPE,
+                    GET_PROPERTY_PARAMS,
+                    ClassNode.EMPTY_ARRAY,
+                    new BytecodeSequence(new BytecodeInstruction() {
+                        public void visit(MethodVisitor mv) {
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "getMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitVarInsn(ALOAD, 1);
+                            mv.visitMethodInsn(INVOKEINTERFACE, "groovy/lang/MetaClass", "getProperty", "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", true);
+                            mv.visitInsn(ARETURN);
+                        }
+                    })
+            );
+            if (shouldAnnotate) methodNode.addAnnotation(generatedAnnotation);
+        }
+
+        if (!node.hasMethod("setProperty", SET_PROPERTY_PARAMS)) {
+            MethodNode methodNode = addMethod(node, !isAbstract(node.getModifiers()),
+                    "setProperty",
+                    ACC_PUBLIC,
+                    ClassHelper.VOID_TYPE,
+                    SET_PROPERTY_PARAMS,
+                    ClassNode.EMPTY_ARRAY,
+                    new BytecodeSequence(new BytecodeInstruction() {
+                        public void visit(MethodVisitor mv) {
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitMethodInsn(INVOKEVIRTUAL, classInternalName, "getMetaClass", "()Lgroovy/lang/MetaClass;", false);
+                            mv.visitVarInsn(ALOAD, 0);
+                            mv.visitVarInsn(ALOAD, 1);
+                            mv.visitVarInsn(ALOAD, 2);
+                            mv.visitMethodInsn(INVOKEINTERFACE, "groovy/lang/MetaClass", "setProperty", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", true);
+                            mv.visitInsn(RETURN);
+                        }
+                    })
+            );
+            if (shouldAnnotate) methodNode.addAnnotation(generatedAnnotation);
+        }
+    }
+
+    /**
+     * Helper method to add a new method to a ClassNode.  Depending on the shouldBeSynthetic flag the
+     * call will either be made to ClassNode.addSyntheticMethod() or ClassNode.addMethod(). If a non-synthetic method
+     * is to be added the ACC_SYNTHETIC modifier is removed if it has been accidentally supplied.
+     */
+    protected MethodNode addMethod(ClassNode node, boolean shouldBeSynthetic, String name, int modifiers, ClassNode returnType, Parameter[] parameters,
+                                   ClassNode[] exceptions, Statement code) {
+        if (shouldBeSynthetic) {
+            return node.addSyntheticMethod(name, modifiers, returnType, parameters, exceptions, code);
+        } else {
+            return node.addMethod(name, modifiers & ~ACC_SYNTHETIC, returnType, parameters, exceptions, code);
+        }
+    }
+
+    @Deprecated
+    protected void addTimeStamp(ClassNode node) {
+    }
+
+    private static void checkReturnInObjectInitializer(List<Statement> init) {
+        CodeVisitorSupport cvs = new CodeVisitorSupport() {
+            @Override
+            public void visitClosureExpression(ClosureExpression expression) {
+                // return is OK in closures in object initializers
+            }
+
+            public void visitReturnStatement(ReturnStatement statement) {
+                throw new RuntimeParserException("'return' is not allowed in object initializer", statement);
+            }
+        };
+        for (Statement stm : init) {
+            stm.visit(cvs);
+        }
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+        CodeVisitorSupport checkSuper = new CodeVisitorSupport() {
+            boolean firstMethodCall = true;
+            String type = null;
+
+            public void visitMethodCallExpression(MethodCallExpression call) {
+                if (!firstMethodCall) return;
+                firstMethodCall = false;
+                String name = call.getMethodAsString();
+                // the name might be null if the method name is a GString for example
+                if (name == null) return;
+                if (!name.equals("super") && !name.equals("this")) return;
+                type = name;
+                call.getArguments().visit(this);
+                type = null;
+            }
+
+            public void visitConstructorCallExpression(ConstructorCallExpression call) {
+                if (!call.isSpecialCall()) return;
+                type = call.getText();
+                call.getArguments().visit(this);
+                type = null;
+            }
+
+            public void visitVariableExpression(VariableExpression expression) {
+                if (type == null) return;
+                String name = expression.getName();
+                if (!name.equals("this") && !name.equals("super")) return;
+                throw new RuntimeParserException("cannot reference " + name + " inside of " + type + "(....) before supertype constructor has been called", expression);
+            }
+        };
+        Statement s = node.getCode();
+        if (s == null) {
+            return;
+        } else {
+            s.visit(new VerifierCodeVisitor(this));
+        }
+        s.visit(checkSuper);
+    }
+
+    public void visitMethod(MethodNode node) {
+        //GROOVY-3712 - if it's an MOP method, it's an error as they aren't supposed to exist before ACG is invoked
+        if (MopWriter.isMopMethod(node.getName())) {
+            throw new RuntimeParserException("Found unexpected MOP methods in the class node for " + classNode.getName() +
+                    "(" + node.getName() + ")", classNode);
+        }
+        this.methodNode = node;
+        adjustTypesIfStaticMainMethod(node);
+        addReturnIfNeeded(node);
+        Statement statement;
+        statement = node.getCode();
+        if (statement != null) statement.visit(new VerifierCodeVisitor(this));
+    }
+
+    private static void adjustTypesIfStaticMainMethod(MethodNode node) {
+        if (node.getName().equals("main") && node.isStatic()) {
+            Parameter[] params = node.getParameters();
+            if (params.length == 1) {
+                Parameter param = params[0];
+                if (param.getType() == null || param.getType() == ClassHelper.OBJECT_TYPE) {
+                    param.setType(ClassHelper.STRING_TYPE.makeArray());
+                    ClassNode returnType = node.getReturnType();
+                    if (returnType == ClassHelper.OBJECT_TYPE) {
+                        node.setReturnType(ClassHelper.VOID_TYPE);
+                    }
+                }
+            }
+        }
+    }
+
+    protected void addReturnIfNeeded(MethodNode node) {
+        ReturnAdder adder = new ReturnAdder();
+        adder.visitMethod(node);
+    }
+
+    public void visitField(FieldNode node) {
+    }
+
+    private boolean methodNeedsReplacement(MethodNode m) {
+        // no method found, we need to replace
+        if (m == null) return true;
+        // method is in current class, nothing to be done
+        if (m.getDeclaringClass() == this.getClassNode()) return false;
+        // do not overwrite final
+        if (isFinal(m.getModifiers())) return false;
+        return true;
+    }
+
+    public void visitProperty(PropertyNode node) {
+        String name = node.getName();
+        FieldNode field = node.getField();
+
+        String getterName = "get" + capitalize(name);
+        String setterName = "set" + capitalize(name);
+
+        int accessorModifiers = PropertyNodeUtils.adjustPropertyModifiersForMethod(node);
+
+        Statement getterBlock = node.getGetterBlock();
+        if (getterBlock == null) {
+            MethodNode getter = classNode.getGetterMethod(getterName, !node.isStatic());
+            if (getter == null && ClassHelper.boolean_TYPE == node.getType()) {
+                String secondGetterName = "is" + capitalize(name);
+                getter = classNode.getGetterMethod(secondGetterName);
+            }
+            if (!node.isPrivate() && methodNeedsReplacement(getter)) {
+                getterBlock = createGetterBlock(node, field);
+            }
+        }
+        Statement setterBlock = node.getSetterBlock();
+        if (setterBlock == null) {
+            // 2nd arg false below: though not usual, allow setter with non-void return type
+            MethodNode setter = classNode.getSetterMethod(setterName, false);
+            if (!node.isPrivate() && !isFinal(accessorModifiers) && methodNeedsReplacement(setter)) {
+                setterBlock = createSetterBlock(node, field);
+            }
+        }
+
+        int getterModifiers = accessorModifiers;
+        // don't make static accessors final
+        if (node.isStatic()) {
+            getterModifiers = ~Modifier.FINAL & getterModifiers;
+        }
+        if (getterBlock != null) {
+            MethodNode getter =
+                    new MethodNode(getterName, getterModifiers, node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
+            getter.setSynthetic(true);
+            addPropertyMethod(getter);
+            visitMethod(getter);
+
+            if (ClassHelper.boolean_TYPE == node.getType() || ClassHelper.Boolean_TYPE == node.getType()) {
+                String secondGetterName = "is" + capitalize(name);
+                MethodNode secondGetter =
+                        new MethodNode(secondGetterName, getterModifiers, node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
+                secondGetter.setSynthetic(true);
+                addPropertyMethod(secondGetter);
+                visitMethod(secondGetter);
+            }
+        }
+        if (setterBlock != null) {
+            Parameter[] setterParameterTypes = {new Parameter(node.getType(), "value")};
+            MethodNode setter =
+                    new MethodNode(setterName, accessorModifiers, ClassHelper.VOID_TYPE, setterParameterTypes, ClassNode.EMPTY_ARRAY, setterBlock);
+            setter.setSynthetic(true);
+            addPropertyMethod(setter);
+            visitMethod(setter);
+        }
+    }
+
+    protected void addPropertyMethod(MethodNode method) {
+        classNode.addMethod(method);
+        // GROOVY-4415 / GROOVY-4645: check that there's no abstract method which corresponds to this one
+        List<MethodNode> abstractMethods = classNode.getAbstractMethods();
+        if (abstractMethods == null) return;
+        String methodName = method.getName();
+        Parameter[] parameters = method.getParameters();
+        ClassNode methodReturnType = method.getReturnType();
+        for (MethodNode node : abstractMethods) {
+            if (!node.getDeclaringClass().equals(classNode)) continue;
+            if (node.getName().equals(methodName) && node.getParameters().length == parameters.length) {
+                if (parameters.length == 1) {
+                    // setter
+                    ClassNode abstractMethodParameterType = node.getParameters()[0].getType();
+                    ClassNode methodParameterType = parameters[0].getType();
+                    if (!methodParameterType.isDerivedFrom(abstractMethodParameterType) && !methodParameterType.implementsInterface(abstractMethodParameterType)) {
+                        continue;
+                    }
+                }
+                ClassNode nodeReturnType = node.getReturnType();
+                if (!methodReturnType.isDerivedFrom(nodeReturnType) && !methodReturnType.implementsInterface(nodeReturnType)) {
+                    continue;
+                }
+                // matching method, remove abstract status and use the same body
+                node.setModifiers(node.getModifiers() ^ ACC_ABSTRACT);
+                node.setCode(method.getCode());
+            }
+        }
+    }
+
+    public interface DefaultArgsAction {
+        void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method);
+    }
+
+    /**
+     * Creates a new helper method for each combination of default parameter expressions
+     */
+    protected void addDefaultParameterMethods(final ClassNode node) {
+        List methods = new ArrayList(node.getMethods());
+        addDefaultParameters(methods, new DefaultArgsAction() {
+            public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method) {
+                final BlockStatement code = new BlockStatement();
+
+                MethodNode newMethod = new MethodNode(method.getName(), method.getModifiers(), method.getReturnType(), newParams, method.getExceptions(), code);
+
+                // GROOVY-5681 and GROOVY-5632
+                for (Expression argument : arguments.getExpressions()) {
+                    if (argument instanceof CastExpression) {
+                        argument = ((CastExpression) argument).getExpression();
+                    }
+                    if (argument instanceof ConstructorCallExpression) {
+                        ClassNode type = argument.getType();
+                        if (type instanceof InnerClassNode && ((InnerClassNode) type).isAnonymous()) {
+                            type.setEnclosingMethod(newMethod);
+                        }
+                    }
+
+                    // check whether closure shared variables refer to params with default values (GROOVY-5632)
+                    if (argument instanceof ClosureExpression) {
+                        final List<Parameter> newMethodNodeParameters = Arrays.asList(newParams);
+
+                        CodeVisitorSupport visitor = new CodeVisitorSupport() {
+                            @Override
+                            public void visitVariableExpression(VariableExpression expression) {
+                                Variable v = expression.getAccessedVariable();
+                                if (!(v instanceof Parameter)) return;
+
+                                Parameter param = (Parameter) v;
+                                if (param.hasInitialExpression() && code.getVariableScope().getDeclaredVariable(param.getName()) == null && !newMethodNodeParameters.contains(param)) {
+
+                                    VariableExpression localVariable = new VariableExpression(param.getName(), ClassHelper.makeReference());
+                                    DeclarationExpression declarationExpression = new DeclarationExpression(localVariable, Token.newSymbol(Types.EQUAL, -1, -1), new ConstructorCallExpression(ClassHelper.makeReference(), param.getInitialExpression()));
+
+                                    code.addStatement(new ExpressionStatement(declarationExpression));
+                                    code.getVariableScope().putDeclaredVariable(localVariable);
+                                }
+                            }
+                        };
+
+                        visitor.visitClosureExpression((ClosureExpression) argument);
+                    }
+                }
+
+                MethodCallExpression expression = new MethodCallExpression(VariableExpression.THIS_EXPRESSION, method.getName(), arguments);
+                expression.setMethodTarget(method);
+                expression.setImplicitThis(true);
+
+                if (method.isVoidMethod()) {
+                    code.addStatement(new ExpressionStatement(expression));
+                } else {
+                    code.addStatement(new ReturnStatement(expression));
+                }
+
+                List<AnnotationNode> annotations = method.getAnnotations();
+                if (annotations != null) {
+                    newMethod.addAnnotations(annotations);
+                }
+                MethodNode oldMethod = node.getDeclaredMethod(method.getName(), newParams);
+                if (oldMethod != null) {
+                    throw new RuntimeParserException(
+                            "The method with default parameters \"" + method.getTypeDescriptor() +
+                                    "\" defines a method \"" + newMethod.getTypeDescriptor() +
+                                    "\" that is already defined.",
+                            method);
+                }
+                addPropertyMethod(newMethod);
+                newMethod.setGenericsTypes(method.getGenericsTypes());
+                newMethod.putNodeMetaData(DEFAULT_PARAMETER_GENERATED, true);
+            }
+        });
+    }
+
+    protected void addDefaultParameterConstructors(final ClassNode node) {
+        List methods = new ArrayList(node.getDeclaredConstructors());
+        addDefaultParameters(methods, new DefaultArgsAction() {
+            public void call(ArgumentListExpression arguments, Parameter[] newParams, MethodNode method) {
+                ConstructorNode ctor = (ConstructorNode) method;
+                ConstructorCallExpression expression = new ConstructorCallExpression(ClassNode.THIS, arguments);
+                Statement code = new ExpressionStatement(expression);
+                addConstructor(newParams, ctor, code, node);
+            }
+        });
+    }
+
+    protected void addConstructor(Parameter[] newParams, ConstructorNode ctor, Statement code, ClassNode node) {
+        node.addConstructor(ctor.getModifiers(), newParams, ctor.getExceptions(), code);
+    }
+
+    /**
+     * Creates a new helper method for each combination of default parameter expressions
+     */
+    protected void addDefaultParameters(List methods, DefaultArgsAction action) {
+        for (Object next : methods) {
+            MethodNode method = (MethodNode) next;
+            if (method.hasDefaultValue()) {
+                addDefaultParameters(action, method);
+            }
+        }
+    }
+
+    protected void addDefaultParameters(DefaultArgsAction action, MethodNode method) {
+        Parameter[] parameters = method.getParameters();
+        int counter = 0;
+        List paramValues = new ArrayList();
+        int size = parameters.length;
+        for (int i = size - 1; i >= 0; i--) {
+            Parameter parameter = parameters[i];
+            if (parameter != null && parameter.hasInitialExpression()) {
+                paramValues.add(i);
+                paramValues.add(
+                        new CastExpression(
+                                parameter.getType(),
+                                parameter.getInitialExpression()
+                        )
+                );
+                counter++;
+            }
+        }
+
+        for (int j = 1; j <= counter; j++) {
+            Parameter[] newParams = new Parameter[parameters.length - j];
+            ArgumentListExpression arguments = new ArgumentListExpression();
+            int index = 0;
+            int k = 1;
+            for (Parameter parameter : parameters) {
+                if (parameter == null) {
+                    throw new GroovyBugError("Parameter should not be null for method " + methodNode.getName());
+                } else {
+                    if (k > counter - j && parameter.hasInitialExpression()) {
+                        arguments.addExpression(
+                                new CastExpression(
+                                        parameter.getType(),
+                                        parameter.getInitialExpression()
+                                )
+                        );
+                        k++;
+                    } else if (parameter.hasInitialExpression()) {
+                        newParams[index++] = parameter;
+                        arguments.addExpression(
+                                new CastExpression(
+                                        parameter.getType(),
+                                        new VariableExpression(parameter.getName())
+                                )
+                        );
+                        k++;
+                    } else {
+                        newParams[index++] = parameter;
+                        arguments.addExpression(
+                                new CastExpression(
+                                        parameter.getType(),
+                                        new VariableExpression(parameter.getName())
+                                )
+                        );
+                    }
+                }
+            }
+            action.call(arguments, newParams, method);
+        }
+
+        for (Parameter parameter : parameters) {
+            // remove default expression and store it as node metadata
+            parameter.putNodeMetaData(Verifier.INITIAL_EXPRESSION, parameter.getInitialExpression());
+            parameter.setInitialExpression(null);
+        }
+    }
+
+    protected void addClosureCode(InnerClassNode node) {
+        // add a new invoke
+    }
+
+    protected void addInitialization(final ClassNode node) {
+        boolean addSwapInit = moveOptimizedConstantsInitialization(node);
+
+        for (ConstructorNode cn : node.getDeclaredConstructors()) {
+            addInitialization(node, cn);
+        }
+
+        if (addSwapInit) {
+            BytecodeSequence seq = new BytecodeSequence(
+                    new BytecodeInstruction() {
+                        @Override
+                        public void visit(MethodVisitor mv) {
+                            mv.visitMethodInsn(INVOKESTATIC, BytecodeHelper.getClassInternalName(node), SWAP_INIT, "()V", false);
+                        }
+                    });
+
+            List<Statement> swapCall = new ArrayList<Statement>(1);
+            swapCall.add(seq);
+            node.addStaticInitializerStatements(swapCall, true);
+        }
+    }
+
+    protected void addInitialization(ClassNode node, ConstructorNode constructorNode) {
+        Statement firstStatement = constructorNode.getFirstStatement();
+        // if some transformation decided to generate constructor then it probably knows who it does
+        if (firstStatement instanceof BytecodeSequence)
+            return;
+
+        ConstructorCallExpression first = getFirstIfSpecialConstructorCall(firstStatement);
+
+        // in case of this(...) let the other constructor do the init
+        if (first != null && (first.isThisCall())) return;
+
+        List<Statement> statements = new ArrayList<Statement>();
+        List<Statement> staticStatements = new ArrayList<Statement>();
+        final boolean isEnum = node.isEnum();
+        List<Statement> initStmtsAfterEnumValuesInit = new ArrayList<Statement>();
+        Set<String> explicitStaticPropsInEnum = new HashSet<String>();
+        if (isEnum) {
+            for (PropertyNode propNode : node.getProperties()) {
+                if (!propNode.isSynthetic() && propNode.getField().isStatic()) {
+                    explicitStaticPropsInEnum.add(propNode.getField().getName());
+                }
+            }
+            for (FieldNode fieldNode : node.getFields()) {
+                if (!fieldNode.isSynthetic() && fieldNode.isStatic() && fieldNode.getType() != node) {
+                    explicitStaticPropsInEnum.add(fieldNode.getName());
+                }
+            }
+        }
+
+        if (!Traits.isTrait(node)) {
+            for (FieldNode fn : node.getFields()) {
+                addFieldInitialization(statements, staticStatements, fn, isEnum,
+                        initStmtsAfterEnumValuesInit, explicitStaticPropsInEnum);
+            }
+        }
+
+        statements.addAll(node.getObjectInitializerStatements());
+
+        Statement code = constructorNode.getCode();
+        BlockStatement block = new BlockStatement();
+        List<Statement> otherStatements = block.getStatements();
+        if (code instanceof BlockStatement) {
+            block = (BlockStatement) code;
+            otherStatements = block.getStatements();
+        } else if (code != null) {
+            otherStatements.add(code);
+        }
+        if (!otherStatements.isEmpty()) {
+            if (first != null) {
+                // it is super(..) since this(..) is already covered
+                otherStatements.remove(0);
+                statements.add(0, firstStatement);
+            }
+            Statement stmtThis$0 = getImplicitThis$0StmtIfInnerClass(otherStatements);
+            if (stmtThis$0 != null) {
+                // since there can be field init statements that depend on method/property dispatching
+                // that uses this$0, it needs to bubble up before the super call itself (GROOVY-4471)
+                statements.add(0, stmtThis$0);
+            }
+            statements.addAll(otherStatements);
+        }
+        BlockStatement newBlock = new BlockStatement(statements, block.getVariableScope());
+        newBlock.setSourcePosition(block);
+        constructorNode.setCode(newBlock);
+
+
+        if (!staticStatements.isEmpty()) {
+            if (isEnum) {
+                /*
+                 * GROOVY-3161: initialize statements for explicitly declared static fields
+                 * inside an enum should come after enum values are initialized
+                 */
+                staticStatements.removeAll(initStmtsAfterEnumValuesInit);
+                node.addStaticInitializerStatements(staticStatements, true);
+                if (!initStmtsAfterEnumValuesInit.isEmpty()) {
+                    node.positionStmtsAfterEnumInitStmts(initStmtsAfterEnumValuesInit);
+                }
+            } else {
+                node.addStaticInitializerStatements(staticStatements, true);
+            }
+        }
+    }
+
+    /*
+    *  when InnerClassVisitor adds this.this$0 = $p$n, it adds it as a BlockStatement having that
+    *  ExpressionStatement
+    */
+    private Statement getImplicitThis$0StmtIfInnerClass(List<Statement> otherStatements) {
+        if (!(classNode instanceof InnerClassNode)) return null;
+        for (Statement stmt : otherStatements) {
+            if (stmt instanceof BlockStatement) {
+                List<Statement> stmts = ((BlockStatement) stmt).getStatements();
+                for (Statement bstmt : stmts) {
+                    if (bstmt instanceof ExpressionStatement) {
+                        if (extractImplicitThis$0StmtIfInnerClassFromExpression(stmts, bstmt)) return bstmt;
+                    }
+                }
+            } else if (stmt instanceof ExpressionStatement) {
+                if (extractImplicitThis$0StmtIfInnerClassFromExpression(otherStatements, stmt)) return stmt;
+            }
+        }
+        return null;
+    }
+
+    private static boolean extractImplicitThis$0StmtIfInnerClassFromExpression(final List<Statement> stmts, final Statement bstmt) {
+        Expression expr = ((ExpressionStatement) bstmt).getExpression();
+        if (expr instanceof BinaryExpression) {
+            Expression lExpr = ((BinaryExpression) expr).getLeftExpression();
+            if (lExpr instanceof FieldExpression) {
+                if ("this$0".equals(((FieldExpression) lExpr).getFieldName())) {
+                    stmts.remove(bstmt); // remove from here and let the caller reposition it
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static ConstructorCallExpression getFirstIfSpecialConstructorCall(Statement code) {
+        if (code == null || !(code instanceof ExpressionStatement)) return null;
+
+        Expression expression = ((ExpressionStatement) code).getExpression();
+        if (!(expression instanceof ConstructorCallExpression)) return null;
+        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
+        if (cce.isSpecialCall()) return cce;
+        return null;
+    }
+
+    protected void addFieldInitialization(List list, List staticList, FieldNode fieldNode,
+                                          boolean isEnumClassNode, List initStmtsAfterEnumValuesInit, Set explicitStaticPropsInEnum) {
+        Expression expression = fieldNode.getInitialExpression();
+        if (expression != null) {
+            final FieldExpression fe = new FieldExpression(fieldNode);
+            if (fieldNode.getType().equals(ClassHelper.REFERENCE_TYPE) && ((fieldNode.getModifiers() & Opcodes.ACC_SYNTHETIC) != 0)) {
+                fe.setUseReferenceDirectly(true);
+            }
+            ExpressionStatement statement =
+                    new ExpressionStatement(
+                            new BinaryExpression(
+                                    fe,
+                                    Token.newSymbol(Types.EQUAL, fieldNode.getLineNumber(), fieldNode.getColumnNumber()),
+                                    expression));
+            if (fieldNode.isStatic()) {
+                // GROOVY-3311: pre-defined constants added by groovy compiler for numbers/characters should be
+                // initialized first so that code dependent on it does not see their values as empty
+                Expression initialValueExpression = fieldNode.getInitialValueExpression();
+                if (initialValueExpression instanceof ConstantExpression) {
+                    ConstantExpression cexp = (ConstantExpression) initialValueExpression;
+                    cexp = transformToPrimitiveConstantIfPossible(cexp);
+                    if (fieldNode.isFinal() && ClassHelper.isStaticConstantInitializerType(cexp.getType()) && cexp.getType().equals(fieldNode.getType())) {
+                        return; // GROOVY-5150: primitive type constants will be initialized directly
+                    }
+                    staticList.add(0, statement);
+                } else {
+                    staticList.add(statement);
+                }
+                fieldNode.setInitialValueExpression(null); // to avoid double initialization in case of several constructors
+                /*
+                 * If it is a statement for an explicitly declared static field inside an enum, store its
+                 * reference. For enums, they need to be handled differently as such init statements should
+                 * come after the enum values have been initialized inside <clinit> block. GROOVY-3161.
+                 */
+                if (isEnumClassNode && explicitStaticPropsInEnum.contains(fieldNode.getName())) {
+                    initStmtsAfterEnumValuesInit.add(statement);
+                }
+            } else {
+                list.add(statement);
+            }
+        }
+    }
+
+    /**
+     * Capitalizes the start of the given bean property name
+     */
+    public static String capitalize(String name) {
+        return MetaClassHelper.capitalize(name);
+    }
+
+    protected Statement createGetterBlock(PropertyNode propertyNode, final FieldNode field) {
+        return new BytecodeSequence(new BytecodeInstruction() {
+            public void visit(MethodVisitor mv) {
+                if (field.isStatic()) {
+                    mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
+                } else {
+                    mv.visitVarInsn(ALOAD, 0);
+                    mv.visitFieldInsn(GETFIELD, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
+                }
+                BytecodeHelper.doReturn(mv, field.getType());
+            }
+        });
+    }
+
+    protected Statement createSetterBlock(PropertyNode propertyNode, final FieldNode field) {
+        return new BytecodeSequence(new BytecodeInstruction() {
+            public void visit(MethodVisitor mv) {
+                if (field.isStatic()) {
+                    BytecodeHelper.load(mv, field.getType(), 0);
+                    mv.visitFieldInsn(PUTSTATIC, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
+                } else {
+                    mv.visitVarInsn(ALOAD, 0);
+                    BytecodeHelper.load(mv, field.getType(), 1);
+                    mv.visitFieldInsn(PUTFIELD, BytecodeHelper.getClassInternalName(classNode), field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
+                }
+                mv.visitInsn(RETURN);
+            }
+        });
+    }
+
+    public void visitGenericType(GenericsType genericsType) {
+
+    }
+
+    public static Long getTimestampFromFieldName(String fieldName) {
+        if (fieldName.startsWith(__TIMESTAMP__)) {
+            try {
+                return Long.decode(fieldName.substring(__TIMESTAMP__.length()));
+            } catch (NumberFormatException e) {
+                return Long.MAX_VALUE;
+            }
+        }
+        return null;
+    }
+
+    public static long getTimestamp(Class clazz) {
+        if (clazz.getClassLoader() instanceof GroovyClassLoader.InnerLoader) {
+            GroovyClassLoader.InnerLoader innerLoader = (GroovyClassLoader.InnerLoader) clazz.getClassLoader();
+            return innerLoader.getTimeStamp();
+        }
+
+        final Field[] fields = clazz.getFields();
+        for (int i = 0; i != fields.length; ++i) {
+            if (isStatic(fields[i].getModifiers())) {
+                Long timestamp = getTimestampFromFieldName(fields[i].getName());
+                if (timestamp != null) {
+                    return timestamp;
+                }
+            }
+        }
+        return Long.MAX_VALUE;
+    }
+
+    protected void addCovariantMethods(ClassNode classNode) {
+        Map methodsToAdd = new HashMap();
+        Map genericsSpec = new HashMap();
+
+        // unimplemented abstract methods from interfaces
+        Map<String, MethodNode> abstractMethods = ClassNodeUtils.getDeclaredMethodsFromInterfaces(classNode);
+        Map<String, MethodNode> allInterfaceMethods = new HashMap<String, MethodNode>(abstractMethods);
+        ClassNodeUtils.addDeclaredMethodsFromAllInterfaces(classNode, allInterfaceMethods);
+
+        List<MethodNode> declaredMethods = new ArrayList<MethodNode>(classNode.getMethods());
+        // remove all static, private and package private methods
+        for (Iterator methodsIterator = declaredMethods.iterator(); methodsIterator.hasNext(); ) {
+            MethodNode m = (MethodNode) methodsIterator.next();
+            abstractMethods.remove(m.getTypeDescriptor());
+            if (m.isStatic() || !(m.isPublic() || m.isProtected())) {
+                methodsIterator.remove();
+            }
+            MethodNode intfMethod = allInterfaceMethods.get(m.getTypeDescriptor());
+            if (intfMethod != null && ((m.getModifiers() & ACC_SYNTHETIC) == 0)
+                    && !m.isPublic() && !m.isStaticConstructor()) {
+                throw new RuntimeParserException("The method " + m.getName() +
+                        " should be public as it implements the corresponding method from interface " +
+                        intfMethod.getDeclaringClass(), m);
+
+            }
+        }
+
+        addCovariantMethods(classNode, declaredMethods, abstractMethods, methodsToAdd, genericsSpec);
+
+        Map<String, MethodNode> declaredMethodsMap = new HashMap<String, MethodNode>();
+        if (!methodsToAdd.isEmpty()) {
+            for (MethodNode mn : declaredMethods) {
+                declaredMethodsMap.put(mn.getTypeDescriptor(), mn);
+            }
+        }
+
+        for (Object o : methodsToAdd.entrySet()) {
+            Map.Entry entry = (Map.Entry) o;
+            MethodNode method = (MethodNode) entry.getValue();
+            // we skip bridge methods implemented in current class already
+            MethodNode mn = declaredMethodsMap.get(entry.getKey());
+            if (mn != null && mn.getDeclaringClass().equals(classNode)) continue;
+            addPropertyMethod(method);
+        }
+    }
+
+    private void addCovariantMethods(ClassNode classNode, List declaredMethods, Map abstractMethods, Map methodsToAdd, Map oldGenericsSpec) {
+        ClassNode sn = classNode.getUnresolvedSuperClass(false);
+
+        if (sn != null) {
+            Map genericsSpec = createGenericsSpec(sn, oldGenericsSpec);
+            List<MethodNode> classMethods = sn.getMethods();
+            // original class causing bridge methods for methods in super class
+            for (Object declaredMethod : declaredMethods) {
+                MethodNode method = (MethodNode) declaredMethod;
+                if (method.isStatic()) continue;
+                storeMissingCovariantMethods(classMethods, method, methodsToAdd, genericsSpec, false);
+            }
+            // super class causing bridge methods for abstract methods in original class
+            if (!abstractMethods.isEmpty()) {
+                for (Object classMethod : classMethods) {
+                    MethodNode method = (MethodNode) classMethod;
+                    if (method.isStatic()) continue;
+                    storeMissingCovariantMethods(abstractMethods.values(), method, methodsToAdd, Collections.EMPTY_MAP, true);
+                }
+            }
+
+            addCovariantMethods(sn.redirect(), declaredMethods, abstractMethods, methodsToAdd, genericsSpec);
+        }
+
+        ClassNode[] interfaces = classNode.getInterfaces();
+        for (ClassNode anInterface : interfaces) {
+            List interfacesMethods = anInterface.getMethods();
+            Map genericsSpec = createGenericsSpec(anInterface, oldGenericsSpec);
+            for (Object declaredMethod : declaredMethods) {
+                MethodNode method = (MethodNode) declaredMethod;
+                if (method.isStatic()) continue;
+                storeMissingCovariantMethods(interfacesMethods, method, methodsToAdd, genericsSpec, false);
+            }
+            addCovariantMethods(anInterface, declaredMethods, abstractMethods, methodsToAdd, genericsSpec);
+        }
+
+    }
+
+    private MethodNode getCovariantImplementation(final MethodNode oldMethod, final MethodNode overridingMethod, Map genericsSpec, boolean ignoreError) {
+        // method name
+        if (!oldMethod.getName().equals(overridingMethod.getName())) return null;
+        if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null;
+        if (oldMethod.isPrivate()) return null;
+
+        // parameters
+        boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod);
+        boolean genericEqualParameters = equalParametersWithGenerics(overridingMethod, oldMethod, genericsSpec);
+        if (!normalEqualParameters && !genericEqualParameters) return null;
+
+        //correct to method level generics for the overriding method
+        genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec);
+
+        // return type
+        ClassNode mr = overridingMethod.getReturnType();
+        ClassNode omr = oldMethod.getReturnType();
+        boolean equalReturnType = mr.equals(omr);
+
+        ClassNode testmr = correctToGenericsSpec(genericsSpec, omr);
+        if (!isAssignable(mr, testmr)) {
+            if (ignoreError) return null;
+            throw new RuntimeParserException(
+                    "The return type of " +
+                            overridingMethod.getTypeDescriptor() +
+                            " in " + overridingMethod.getDeclaringClass().getName() +
+                            " is incompatible with " + testmr.getName() +
+                            " in " + oldMethod.getDeclaringClass().getName(),
+                    overridingMethod);
+        }
+
+        if (equalReturnType && normalEqualParameters) return null;
+
+        if ((oldMethod.getModifiers() & ACC_FINAL) != 0) {
+            throw new RuntimeParserException(
+                    "Cannot override final method " +
+                            oldMethod.getTypeDescriptor() +
+                            " in " + oldMethod.getDeclaringClass().getName(),
+                    overridingMethod);
+        }
+        if (oldMethod.isStatic() != overridingMethod.isStatic()) {
+            throw new RuntimeParserException(
+                    "Cannot override method " +
+                            oldMethod.getTypeDescriptor() +
+                            " in " + oldMethod.getDeclaringClass().getName() +
+                            " with disparate static modifier",
+                    overridingMethod);
+        }
+        if (!equalReturnType) {
+            boolean oldM = ClassHelper.isPrimitiveType(oldMethod.getReturnType());
+            boolean newM = ClassHelper.isPrimitiveType(overridingMethod.getReturnType());
+            if (oldM || newM) {
+                String message = "";
+                if (oldM && newM) {
+                    message = " with old and new method having different primitive return types";
+                } else if (newM) {
+                    message = " with new method having a primitive return type and old method not";
+                } else /* oldM */ {
+                    message = " with old method having a primitive return type and new method not";
+                }
+                throw new RuntimeParserException(
+                        "Cannot override method " +
+                                oldMethod.getTypeDescriptor() +
+                                " in " + oldMethod.getDeclaringClass().getName() +
+                                message,
+                        overridingMethod);
+            }
+        }
+
+        // if we reach this point we have at least one parameter or return type, that
+        // is different in its specified form. That means we have to create a bridge method!
+        MethodNode newMethod = new MethodNode(
+                oldMethod.getName(),
+                overridingMethod.getModifiers() | ACC_SYNTHETIC | ACC_BRIDGE,
+                cleanType(oldMethod.getReturnType()),
+                cleanParameters(oldMethod.getParameters()),
+                oldMethod.getExceptions(),
+                null
+        );
+        List instructions = new ArrayList(1);
+        instructions.add(
+                new BytecodeInstruction() {
+                    public void visit(MethodVisitor mv) {
+                        mv.visitVarInsn(ALOAD, 0);
+                        Parameter[] para = oldMethod.getParameters();
+                        Parameter[] goal = overridingMethod.getParameters();
+                        int doubleSlotOffset = 0;
+                        for (int i = 0; i < para.length; i++) {
+                            ClassNode type = para[i].getType();
+                            BytecodeHelper.load(mv, type, i + 1 + doubleSlotOffset);
+                            if (type.redirect() == ClassHelper.double_TYPE ||
+                                    type.redirect() == ClassHelper.long_TYPE) {
+                                doubleSlotOffset++;
+                            }
+                            if (!type.equals(goal[i].getType())) {
+                                BytecodeHelper.doCast(mv, goal[i].getType());
+                            }
+                        }
+                        mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(classNode), overridingMethod.getName(), BytecodeHelper.getMethodDescriptor(overridingMethod.getReturnType(), overridingMethod.getParameters()), false);
+
+                        BytecodeHelper.doReturn(mv, oldMethod.getReturnType());
+                    }
+                }
+
+        );
+        newMethod.setCode(new BytecodeSequence(instructions));
+        return newMethod;
+    }
+
+    private boolean isAssignable(ClassNode node, ClassNode testNode) {
+        if (node.isArray() && testNode.isArray()) {
+            return isArrayAssignable(node.getComponentType(), testNode.getComponentType());
+        }
+        if (testNode.isInterface()) {
+            if (node.equals(testNode) || node.implementsInterface(testNode)) return true;
+        }
+        return node.isDerivedFrom(testNode);
+    }
+
+    private boolean isArrayAssignable(ClassNode node, ClassNode testNode) {
+        if (node.isArray() && testNode.isArray()) {
+            return isArrayAssignable(node.getComponentType(), testNode.getComponentType());
+        }
+        return isAssignable(node, testNode);
+    }
+
+    private static Parameter[] cleanParameters(Parameter[] parameters) {
+        Parameter[] params = new Parameter[parameters.length];
+        for (int i = 0; i < params.length; i++) {
+            params[i] = new Parameter(cleanType(parameters[i].getType()), parameters[i].getName());
+        }
+        return params;
+    }
+
+    private static ClassNode cleanType(ClassNode type) {
+        // todo: should this be directly handled by getPlainNodeReference?
+        if (type.isArray()) return cleanType(type.getComponentType()).makeArray();
+        return type.getPlainNodeReference();
+    }
+
+    private void storeMissingCovariantMethods(Collection methods, MethodNode method, Map methodsToAdd, Map genericsSpec, boolean ignoreError) {
+        for (Object next : methods) {
+            MethodNode toOverride = (MethodNode) next;
+            MethodNode bridgeMethod = getCovariantImplementation(toOverride, method, genericsSpec, ignoreError);
+            if (bridgeMethod == null) continue;
+            methodsToAdd.put(bridgeMethod.getTypeDescriptor(), bridgeMethod);
+            return;
+        }
+    }
+
+    private static boolean equalParametersNormal(MethodNode m1, MethodNode m2) {
+        Parameter[] p1 = m1.getParameters();
+        Parameter[] p2 = m2.getParameters();
+        if (p1.length != p2.length) return false;
+        for (int i = 0; i < p2.length; i++) {
+            ClassNode type = p2[i].getType();
+            ClassNode parameterType = p1[i].getType();
+            if (!parameterType.equals(type)) return false;
+        }
+        return true;
+    }
+
+    private static boolean equalParametersWithGenerics(MethodNode m1, MethodNode m2, Map genericsSpec) {
+        Parameter[] p1 = m1.getParameters();
+        Parameter[] p2 = m2.getParameters();
+        if (p1.length != p2.length) return false;
+        for (int i = 0; i < p2.length; i++) {
+            ClassNode type = p2[i].getType();
+            ClassNode genericsType = correctToGenericsSpec(genericsSpec, type);
+            ClassNode parameterType = p1[i].getType();
+            if (!parameterType.equals(genericsType)) return false;
+        }
+        return true;
+    }
+
+    private static boolean moveOptimizedConstantsInitialization(final ClassNode node) {
+        if (node.isInterface() && !Traits.isTrait(node)) return false;
+
+        final int mods = Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_PUBLIC;
+        String name = SWAP_INIT;
+        BlockStatement methodCode = new BlockStatement();
+
+        methodCode.addStatement(new SwapInitStatement());
+        boolean swapInitRequired = false;
+        for (FieldNode fn : node.getFields()) {
+            if (!fn.isStatic() || !fn.isSynthetic() || !fn.getName().startsWith("$const$")) continue;
+            if (fn.getInitialExpression() == null) continue;
+            final FieldExpression fe = new FieldExpression(fn);
+            if (fn.getType().equals(ClassHelper.REFERENCE_TYPE)) fe.setUseReferenceDirectly(true);
+            ConstantExpression init = (ConstantExpression) fn.getInitialExpression();
+            init = new ConstantExpression(init.getValue(), true);
+            ExpressionStatement statement =
+                    new ExpressionStatement(
+                            new BinaryExpression(
+                                    fe,
+                                    Token.newSymbol(Types.EQUAL, fn.getLineNumber(), fn.getColumnNumber()),
+                                    init));
+            fn.setInitialValueExpression(null);
+            methodCode.addStatement(statement);
+            swapInitRequired = true;
+        }
+
+        if (swapInitRequired) {
+            node.addSyntheticMethod(
+                    name, mods, ClassHelper.VOID_TYPE,
+                    Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, methodCode);
+        }
+
+        return swapInitRequired;
+    }
+
+    /**
+     * When constant expressions are created, the value is always wrapped to a non primitive type.
+     * Some constant expressions are optimized to return primitive types, but not all primitives are
+     * handled. This method guarantees to return a similar constant expression but with a primitive type
+     * instead of a boxed type.
+     * <p/>
+     * Additionally, single char strings are converted to 'char' types.
+     *
+     * @param constantExpression a constant expression
+     * @return the same instance of constant expression if the type is already primitive, or a primitive
+     * constant if possible.
+     */
+    public static ConstantExpression transformToPrimitiveConstantIfPossible(ConstantExpression constantExpression) {
+        Object value = constantExpression.getValue();
+        if (value == null) return constantExpression;
+        ConstantExpression result;
+        ClassNode type = constantExpression.getType();
+        if (ClassHelper.isPrimitiveType(type)) return constantExpression;
+        if (value instanceof String && ((String) value).length() == 1) {
+            result = new ConstantExpression(((String) value).charAt(0));
+            result.setType(ClassHelper.char_TYPE);
+        } else {
+            type = ClassHelper.getUnwrapper(type);
+            result = new ConstantExpression(value, true);
+            result.setType(type);
+        }
+        return result;
+    }
+
+    private static class SwapInitStatement extends BytecodeSequence {
+
+        private WriterController controller;
+
+        public SwapInitStatement() {
+            super(new SwapInitInstruction());
+            ((SwapInitInstruction) getInstructions().get(0)).statement = this;
+        }
+
+        @Override
+        public void visit(final GroovyCodeVisitor visitor) {
+            if (visitor instanceof AsmClassGenerator) {
+                AsmClassGenerator generator = (AsmClassGenerator) visitor;
+                controller = generator.getController();
+            }
+            super.visit(visitor);
+        }
+
+        private static class SwapInitInstruction extends BytecodeInstruction {
+            SwapInitStatement statement;
+
+            @Override
+            public void visit(final MethodVisitor mv) {
+                statement.controller.getCallSiteWriter().makeCallSiteArrayInitializer();
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
new file mode 100644
index 0000000..424aa7e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/VerifierCodeVisitor.java
@@ -0,0 +1,102 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+import org.objectweb.asm.Opcodes;
+
+/**
+ * Performs various checks on code inside methods and constructors
+ * including checking for valid field, variables names etc. that
+ * would otherwise lead to invalid code.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class VerifierCodeVisitor extends CodeVisitorSupport implements Opcodes {
+
+    private final Verifier verifier;
+
+    VerifierCodeVisitor(Verifier verifier) {
+        this.verifier = verifier;
+    }
+
+    public void visitForLoop(ForStatement expression) {
+        assertValidIdentifier(expression.getVariable().getName(), "for loop variable name", expression);
+        super.visitForLoop(expression);
+    }
+
+    public void visitFieldExpression(FieldExpression expression) {
+        if (!expression.getField().isSynthetic()) {
+            assertValidIdentifier(expression.getFieldName(), "field name", expression);
+        }
+        super.visitFieldExpression(expression);
+    }
+
+    public void visitVariableExpression(VariableExpression expression) {
+        assertValidIdentifier(expression.getName(), "variable name", expression);
+        super.visitVariableExpression(expression);
+    }
+
+    public void visitListExpression(ListExpression expression) {
+        for (Expression element : expression.getExpressions()) {
+            if (element instanceof MapEntryExpression) {
+                throw new RuntimeParserException("No map entry allowed at this place", element);
+            }
+        }
+        super.visitListExpression(expression);
+    }
+
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        ClassNode callType = call.getType();
+        if (callType.isEnum() && !callType.equals(verifier.getClassNode())) {
+            throw new RuntimeParserException("Enum constructor calls are only allowed inside the enum class", call);
+        }
+    }
+
+    public static void assertValidIdentifier(String name, String message, ASTNode node) {
+        int size = name.length();
+        if (size <= 0) {
+            throw new RuntimeParserException("Invalid " + message + ". Identifier must not be empty", node);
+        }
+        char firstCh = name.charAt(0);
+        if (size == 1 && firstCh == '$') {
+            throw new RuntimeParserException("Invalid " + message + ". Must include a letter but only found: " + name, node);
+        }
+        if (!Character.isJavaIdentifierStart(firstCh)) {
+            throw new RuntimeParserException("Invalid " + message + ". Must start with a letter but was: " + name, node);
+        }
+
+        for (int i = 1; i < size; i++) {
+            char ch = name.charAt(i);
+            if (!Character.isJavaIdentifierPart(ch)) {
+                throw new RuntimeParserException("Invalid " + message + ". Invalid character at position: " + (i + 1) + " of value:  " + ch + " in name: " + name, node);
+            }
+        }
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/FieldNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/FieldNode.java b/src/main/java/org/codehaus/groovy/ast/FieldNode.java
new file mode 100644
index 0000000..d38f4f4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/FieldNode.java
@@ -0,0 +1,205 @@
+/*
+ *  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.groovydoc.Groovydoc;
+import groovy.lang.groovydoc.GroovydocHolder;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Field;
+
+/**
+ * Represents a field (member variable)
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class FieldNode extends AnnotatedNode implements Opcodes, Variable, GroovydocHolder<FieldNode> {
+
+    private String name;
+    private int modifiers;
+    private ClassNode type;
+    private ClassNode owner;
+    private Expression initialValueExpression;
+    private boolean dynamicTyped;
+    private boolean holder;
+    private ClassNode originType = ClassHelper.DYNAMIC_TYPE;
+
+    public static FieldNode newStatic(Class theClass, String name) throws SecurityException, NoSuchFieldException {
+        Field field = theClass.getField(name);
+        ClassNode fldType = ClassHelper.make(field.getType());
+        return new FieldNode(name, ACC_PUBLIC | ACC_STATIC, fldType, ClassHelper.make(theClass), null);
+    }
+
+    public FieldNode(String name, int modifiers, ClassNode type, ClassNode owner, Expression initialValueExpression) {
+        this.name = name;
+        this.modifiers = modifiers;
+        this.type = type;
+        if (this.type == ClassHelper.DYNAMIC_TYPE && initialValueExpression != null)
+            this.setType(initialValueExpression.getType());
+        this.setType(type);
+        this.originType = type;
+        this.owner = owner;
+        this.initialValueExpression = initialValueExpression;
+    }
+
+    public Expression getInitialExpression() {
+        return initialValueExpression;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+        this.originType = type;
+        dynamicTyped |= type == ClassHelper.DYNAMIC_TYPE;
+    }
+
+    public ClassNode getOwner() {
+        return owner;
+    }
+
+    public boolean isHolder() {
+        return holder;
+    }
+
+    public void setHolder(boolean holder) {
+        this.holder = holder;
+    }
+
+    public boolean isDynamicTyped() {
+        return dynamicTyped;
+    }
+
+    public void setModifiers(int modifiers) {
+        this.modifiers = modifiers;
+    }
+
+    /**
+     * @return true if the field is static
+     */
+    public boolean isStatic() {
+        return (modifiers & ACC_STATIC) != 0;
+    }
+
+    /**
+     * @return true if the field is an enum
+     */
+    public boolean isEnum() {
+        return (modifiers & ACC_ENUM) != 0;
+    }
+
+    /**
+     * @return true if the field is final
+     */
+    public boolean isFinal() {
+        return (modifiers & ACC_FINAL) != 0;
+    }
+
+    /**
+     * @return true if the field is volatile
+     */
+    public boolean isVolatile() {
+        return (modifiers & ACC_VOLATILE) != 0;
+    }
+
+    /**
+     * @return true if the field is public
+     */
+    public boolean isPublic() {
+        return (modifiers & ACC_PUBLIC) != 0;
+    }
+
+   /**
+     * @return true if the field is protected
+     */
+    public boolean isProtected() {
+        return (modifiers & ACC_PROTECTED) != 0;
+    }
+
+    /**
+     * @param owner The owner to set.
+     */
+    public void setOwner(ClassNode owner) {
+        this.owner = owner;
+    }
+
+    public boolean hasInitialExpression() {
+        return initialValueExpression != null;
+    }
+
+    public boolean isInStaticContext() {
+        return isStatic();
+    }
+
+    public Expression getInitialValueExpression() {
+        return initialValueExpression;
+    }
+
+    public void setInitialValueExpression(Expression initialValueExpression) {
+        this.initialValueExpression = initialValueExpression;
+    }
+
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public boolean isClosureSharedVariable() {
+        return false;
+    }
+    /**
+     * @deprecated
+     */
+    @Deprecated
+    public void setClosureSharedVariable(boolean inClosure) {
+    }
+
+    public ClassNode getOriginType() {
+        return originType;
+    }
+    
+    public void setOriginType(ClassNode cn) {
+        originType = cn;
+    }
+
+    public void rename(String name) {
+        declaringClass.renameField(this.name, name);
+        this.name = name;
+    }
+
+    @Override
+    public Groovydoc getGroovydoc() {
+        return this.<Groovydoc>getNodeMetaData(DOC_COMMENT);
+    }
+
+    @Override
+    public FieldNode getInstance() {
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/GenericsType.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/GenericsType.java b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
new file mode 100644
index 0000000..57d4919
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/GenericsType.java
@@ -0,0 +1,500 @@
+/*
+ *  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.tools.GenericsUtils;
+import org.codehaus.groovy.ast.tools.WideningCategories;
+
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.codehaus.groovy.ast.ClassHelper.GROOVY_OBJECT_TYPE;
+
+/**
+ * This class is used to describe generic type signatures for ClassNodes.
+ *
+ * @author Jochen Theodorou
+ * @see ClassNode
+ */
+public class GenericsType extends ASTNode {
+    public static final GenericsType[] EMPTY_ARRAY = new GenericsType[0];
+    
+    private final ClassNode[] upperBounds;
+    private final ClassNode lowerBound;
+    private ClassNode type;
+    private String name;
+    private boolean placeholder;
+    private boolean resolved;
+    private boolean wildcard;
+
+    public GenericsType(ClassNode type, ClassNode[] upperBounds, ClassNode lowerBound) {
+        this.type = type;
+        this.name = type.isGenericsPlaceHolder() ? type.getUnresolvedName() : type.getName();
+        this.upperBounds = upperBounds;
+        this.lowerBound = lowerBound;
+        placeholder = type.isGenericsPlaceHolder();
+        resolved = false;
+    }
+
+    public GenericsType(ClassNode basicType) {
+        this(basicType, null, null);
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+
+    public void setType(ClassNode type) {
+        this.type = type;
+    }
+
+    public String toString() {
+        Set<String> visited = new HashSet<String>();
+        return toString(visited);
+    }
+
+    private String toString(Set<String> visited) {
+        if (placeholder) visited.add(name);
+        StringBuilder ret = new StringBuilder(wildcard ? "?" : ((type == null || placeholder) ? name : genericsBounds(type, visited)));
+        if (upperBounds != null) {
+            if (placeholder && upperBounds.length==1 && !upperBounds[0].isGenericsPlaceHolder() && upperBounds[0].getName().equals("java.lang.Object")) {
+                // T extends Object should just be printed as T
+            } else {
+                ret.append(" extends ");
+                for (int i = 0; i < upperBounds.length; i++) {
+                    ret.append(genericsBounds(upperBounds[i], visited));
+                    if (i + 1 < upperBounds.length) ret.append(" & ");
+                }
+            }
+        } else if (lowerBound != null) {
+            ret.append(" super ").append(genericsBounds(lowerBound, visited));
+        }
+        return ret.toString();
+    }
+
+    private String nameOf(ClassNode theType) {
+        StringBuilder ret = new StringBuilder();
+        if (theType.isArray()) {
+            ret.append(nameOf(theType.getComponentType()));
+            ret.append("[]");
+        } else {
+            ret.append(theType.getName());
+        }
+        return ret.toString();
+    }
+
+    private String genericsBounds(ClassNode theType, Set<String> visited) {
+
+        StringBuilder ret = new StringBuilder();
+
+        if (theType.isArray()) {
+            ret.append(nameOf(theType));
+        } else if (theType.redirect() instanceof InnerClassNode) {
+            InnerClassNode innerClassNode = (InnerClassNode) theType.redirect();
+            String parentClassNodeName = innerClassNode.getOuterClass().getName();
+            if (Modifier.isStatic(innerClassNode.getModifiers()) || innerClassNode.isInterface()) {
+                ret.append(innerClassNode.getOuterClass().getName());
+            } else {
+                ret.append(genericsBounds(innerClassNode.getOuterClass(), new HashSet<String>()));
+            }
+            ret.append(".");
+            String typeName = theType.getName();
+            ret.append(typeName.substring(parentClassNodeName.length() + 1));
+        } else {
+            ret.append(theType.getName());
+        }
+
+        GenericsType[] genericsTypes = theType.getGenericsTypes();
+        if (genericsTypes == null || genericsTypes.length == 0)
+            return ret.toString();
+
+        // TODO instead of catching Object<T> here stop it from being placed into type in first place
+        if (genericsTypes.length == 1 && genericsTypes[0].isPlaceholder() && theType.getName().equals("java.lang.Object")) {
+            return genericsTypes[0].getName();
+        }
+
+        ret.append("<");
+        for (int i = 0; i < genericsTypes.length; i++) {
+            if (i != 0) ret.append(", ");
+
+            GenericsType type = genericsTypes[i];
+            if (type.isPlaceholder() && visited.contains(type.getName())) {
+                ret.append(type.getName());
+            }
+            else {
+                ret.append(type.toString(visited));
+            }
+        }
+        ret.append(">");
+
+        return ret.toString();
+    }
+
+    public ClassNode[] getUpperBounds() {
+        return upperBounds;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public boolean isPlaceholder() {
+        return placeholder;
+    }
+
+    public void setPlaceholder(boolean placeholder) {
+        this.placeholder = placeholder;
+        type.setGenericsPlaceHolder(placeholder);
+    }
+
+    public boolean isResolved() {
+        return resolved || placeholder;
+    }
+
+    public void setResolved(boolean res) {
+        resolved = res;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isWildcard() {
+        return wildcard;
+    }
+
+    public void setWildcard(boolean wildcard) {
+        this.wildcard = wildcard;
+    }
+
+    public ClassNode getLowerBound() {
+        return lowerBound;
+    }
+
+    /**
+     * Tells if the provided class node is compatible with this generic type definition
+     * @param classNode the class node to be checked
+     * @return true if the class node is compatible with this generics type definition
+     */
+    public boolean isCompatibleWith(ClassNode classNode) {
+        return new GenericsTypeMatcher().matches(classNode);
+    }
+
+    /**
+     * Implements generics type comparison.
+     */
+    private class GenericsTypeMatcher {
+
+        public boolean implementsInterfaceOrIsSubclassOf(ClassNode type, ClassNode superOrInterface) {
+            boolean result = type.equals(superOrInterface)
+                    || type.isDerivedFrom(superOrInterface)
+                    || type.implementsInterface(superOrInterface);
+            if (result) {
+                return true;
+            }
+            if (GROOVY_OBJECT_TYPE.equals(superOrInterface) && type.getCompileUnit()!=null) {
+                // type is being compiled so it will implement GroovyObject later
+                return true;
+            }
+            if (superOrInterface instanceof WideningCategories.LowestUpperBoundClassNode) {
+                WideningCategories.LowestUpperBoundClassNode cn = (WideningCategories.LowestUpperBoundClassNode) superOrInterface;
+                result = implementsInterfaceOrIsSubclassOf(type, cn.getSuperClass());
+                if (result) {
+                    for (ClassNode interfaceNode : cn.getInterfaces()) {
+                        result = implementsInterfaceOrIsSubclassOf(type,interfaceNode);
+                        if (!result) break;
+                    }
+                }
+                if (result) return true;
+            }
+            if (type.isArray() && superOrInterface.isArray()) {
+                return implementsInterfaceOrIsSubclassOf(type.getComponentType(), superOrInterface.getComponentType());
+            }
+            return false;
+        }
+
+        /**
+         * Compares this generics type with the one represented by the provided class node. If the provided
+         * classnode is compatible with the generics specification, returns true. Otherwise, returns false.
+         * The check is complete, meaning that we also check "nested" generics.
+         * @param classNode the classnode to be checked
+         * @return true iff the classnode is compatible with this generics specification
+         */
+        public boolean matches(ClassNode classNode) {
+            GenericsType[] genericsTypes = classNode.getGenericsTypes();
+            // diamond always matches
+            if (genericsTypes!=null && genericsTypes.length==0) return true;
+            if (classNode.isGenericsPlaceHolder()) {
+                // if the classnode we compare to is a generics placeholder (like <E>) then we
+                // only need to check that the names are equal
+                if (genericsTypes==null) return true;
+                if (isWildcard()) {
+                    if (lowerBound!=null) return genericsTypes[0].getName().equals(lowerBound.getUnresolvedName());
+                    if (upperBounds!=null) {
+                        for (ClassNode upperBound : upperBounds) {
+                            String name = upperBound.getGenericsTypes()[0].getName();
+                            if (genericsTypes[0].getName().equals(name)) return true;
+                        }
+                        return false;
+                    }
+                }
+                return genericsTypes[0].getName().equals(name);
+            }
+            if (wildcard || placeholder) {
+                // if the current generics spec is a wildcard spec or a placeholder spec
+                // then we must check upper and lower bounds
+                if (upperBounds != null) {
+                    // check that the provided classnode is a subclass of all provided upper bounds
+                    boolean upIsOk = true;
+                    for (int i = 0, upperBoundsLength = upperBounds.length; i < upperBoundsLength && upIsOk; i++) {
+                        final ClassNode upperBound = upperBounds[i];
+                        upIsOk = implementsInterfaceOrIsSubclassOf(classNode, upperBound);
+                    }
+                    // if the provided classnode is a subclass of the upper bound
+                    // then check that the generic types supplied by the class node are compatible with
+                    // this generics specification
+                    // for example, we could have the spec saying List<String> but provided classnode
+                    // saying List<Integer>
+                    upIsOk = upIsOk && checkGenerics(classNode);
+                    return upIsOk;
+                }
+                if (lowerBound != null) {
+                    // if a lower bound is declared, then we must perform the same checks that for an upper bound
+                    // but with reversed arguments
+                    return implementsInterfaceOrIsSubclassOf(lowerBound, classNode) && checkGenerics(classNode);
+                }
+                // If there are no bounds, the generic type is basically Object, and everything is compatible.
+                return true;
+            }
+            // if this is not a generics placeholder, first compare that types represent the same type
+            if ((type!=null && !type.equals(classNode))) {
+                return false;
+            }
+            // last, we could have the spec saying List<String> and a classnode saying List<Integer> so
+            // we must check that generics are compatible.
+            // The null check is normally not required but done to prevent from NPEs
+            return type == null || compareGenericsWithBound(classNode, type);
+        }
+
+        /**
+         * Iterates over each generics bound of this generics specification, and checks
+         * that the generics defined by the bound are compatible with the generics specified
+         * by the type.
+         * @param classNode the classnode the bounds should be compared with
+         * @return true if generics from bounds are compatible
+         */
+        private boolean checkGenerics(final ClassNode classNode) {
+            if (upperBounds!=null) {
+                for (ClassNode upperBound : upperBounds) {
+                    if (!compareGenericsWithBound(classNode, upperBound)) return false;
+                }
+            }
+            if (lowerBound!=null) {
+                if (!lowerBound.redirect().isUsingGenerics()) {
+                    if (!compareGenericsWithBound(classNode, lowerBound)) return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Given a parameterized type (List&lt;String&gt; for example), checks that its
+         * generic types are compatible with those from a bound.
+         * @param classNode the classnode from which we will compare generics types
+         * @param bound the bound to which the types will be compared
+         * @return true if generics are compatible
+         */
+        private boolean compareGenericsWithBound(final ClassNode classNode, final ClassNode bound) {
+            if (classNode==null) return false;
+            if (!bound.isUsingGenerics() || (classNode.getGenericsTypes()==null && classNode.redirect().getGenericsTypes()!=null)) {
+                // if the bound is not using generics, there's nothing to compare with
+                return true;
+            }
+            if (!classNode.equals(bound)) {
+                 // the class nodes are on different types
+                // in this situation, we must choose the correct execution path : either the bound
+                // is an interface and we must find the implementing interface from the classnode
+                // to compare their parameterized generics, or the bound is a regular class and we
+                // must compare the bound with a superclass
+                if (bound.isInterface()) {
+                    Set<ClassNode> interfaces = classNode.getAllInterfaces();
+                    // iterate over all interfaces to check if any corresponds to the bound we are
+                    // comparing to
+                    for (ClassNode anInterface : interfaces) {
+                        if (anInterface.equals(bound)) {
+                            // when we obtain an interface, the types represented by the interface
+                            // class node are not parameterized. This means that we must create a
+                            // new class node with the parameterized types that the current class node
+                            // has defined.
+                            ClassNode node = GenericsUtils.parameterizeType(classNode, anInterface);
+                            return compareGenericsWithBound(node, bound);
+                        }
+                    }
+                }
+                if (bound instanceof WideningCategories.LowestUpperBoundClassNode) {
+                    // another special case here, where the bound is a "virtual" type
+                    // we must then check the superclass and the interfaces
+                    boolean success = compareGenericsWithBound(classNode, bound.getSuperClass());
+                    if (success) {
+                        ClassNode[] interfaces = bound.getInterfaces();
+                        for (ClassNode anInterface : interfaces) {
+                            success &= compareGenericsWithBound(classNode, anInterface);
+                            if (!success) break;
+                        }
+                        if (success) return true;
+                    }
+                }
+                return compareGenericsWithBound(getParameterizedSuperClass(classNode), bound);
+            }
+            GenericsType[] cnTypes = classNode.getGenericsTypes();
+            if (cnTypes==null && classNode.isRedirectNode()) cnTypes=classNode.redirect().getGenericsTypes();
+            if (cnTypes==null) {
+                // may happen if generic type is Foo<T extends Foo> and classnode is Foo -> Foo
+                return true;
+            }
+            GenericsType[] redirectBoundGenericTypes = bound.redirect().getGenericsTypes();
+            Map<String, GenericsType> classNodePlaceholders = GenericsUtils.extractPlaceholders(classNode);
+            Map<String, GenericsType> boundPlaceHolders = GenericsUtils.extractPlaceholders(bound);
+            boolean match = true;
+            for (int i = 0; redirectBoundGenericTypes!=null && i < redirectBoundGenericTypes.length && match; i++) {
+                GenericsType redirectBoundType = redirectBoundGenericTypes[i];
+                GenericsType classNodeType = cnTypes[i];
+                if (classNodeType.isPlaceholder()) {
+                    String name = classNodeType.getName();
+                    if (redirectBoundType.isPlaceholder()) {
+                        match = name.equals(redirectBoundType.getName());
+                        if (!match) {
+                            GenericsType genericsType = boundPlaceHolders.get(redirectBoundType.getName());
+                            match = false;
+                            if (genericsType!=null) {
+                                if (genericsType.isPlaceholder()) {
+                                    match = true;
+                                } else if (genericsType.isWildcard()) {
+                                    if (genericsType.getUpperBounds()!=null) {
+                                        for (ClassNode up : genericsType.getUpperBounds()) {
+                                            match |= redirectBoundType.isCompatibleWith(up);
+                                        }
+                                        if (genericsType.getLowerBound()!=null) {
+                                            match |= redirectBoundType.isCompatibleWith(genericsType.getLowerBound());
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    } else {
+                        if (classNodePlaceholders.containsKey(name)) classNodeType=classNodePlaceholders.get(name);
+                        match = classNodeType.isCompatibleWith(redirectBoundType.getType());
+                    }
+                } else {
+                    if (redirectBoundType.isPlaceholder()) {
+                        if (classNodeType.isPlaceholder()) {
+                            match = classNodeType.getName().equals(redirectBoundType.getName());
+                        } else {
+                            String name = redirectBoundType.getName();
+                            if (boundPlaceHolders.containsKey(name)) {
+                                redirectBoundType = boundPlaceHolders.get(name);
+                                boolean wildcard = redirectBoundType.isWildcard();
+                                boolean placeholder = redirectBoundType.isPlaceholder();
+                                if (placeholder || wildcard) {
+                                    // placeholder aliases, like Map<U,V> -> Map<K,V>
+//                                    redirectBoundType = classNodePlaceholders.get(name);
+                                    if (wildcard) {
+                                        // ex: Comparable<Integer> <=> Comparable<? super T>
+                                        if (redirectBoundType.lowerBound!=null) {
+                                            GenericsType gt = new GenericsType(redirectBoundType.lowerBound);
+                                            if (gt.isPlaceholder()) {
+                                                // check for recursive generic typedef, like in
+                                                // <T extends Comparable<? super T>>
+                                                if (classNodePlaceholders.containsKey(gt.getName())) {
+                                                    gt = classNodePlaceholders.get(gt.getName());
+                                                }
+                                            }
+                                            match = implementsInterfaceOrIsSubclassOf(gt.getType(), classNodeType.getType());
+                                        }
+                                        if (match && redirectBoundType.upperBounds!=null) {
+                                            for (ClassNode upperBound : redirectBoundType.upperBounds) {
+                                                GenericsType gt = new GenericsType(upperBound);
+                                                if (gt.isPlaceholder()) {
+                                                    // check for recursive generic typedef, like in
+                                                    // <T extends Comparable<? super T>>
+                                                    if (classNodePlaceholders.containsKey(gt.getName())) {
+                                                        gt = classNodePlaceholders.get(gt.getName());
+                                                    }
+                                                }
+                                                match = implementsInterfaceOrIsSubclassOf(classNodeType.getType(), gt.getType())
+                                                         || classNodeType.isCompatibleWith(gt.getType()); // workaround for GROOVY-6095
+                                                if (!match) break;
+                                            }
+                                        }
+                                        return match;
+                                    } else if (classNodePlaceholders.containsKey(name)) {
+                                        redirectBoundType = classNodePlaceholders.get(name);
+                                    }
+                                }
+                            }
+                            match = redirectBoundType.isCompatibleWith(classNodeType.getType());
+                        }
+                    } else {
+                        // todo: the check for isWildcard should be replaced with a more complete check
+                        match = redirectBoundType.isWildcard() || classNodeType.isCompatibleWith(redirectBoundType.getType());
+                    }
+                }
+            }
+            return match;
+        }
+    }
+
+    /**
+     * If you have a class which extends a class using generics, returns the superclass with parameterized types. For
+     * example, if you have:
+     * <code>class MyList&lt;T&gt; extends LinkedList&lt;T&gt;
+     * def list = new MyList&lt;String&gt;
+     * </code>
+     * then the parameterized superclass for MyList&lt;String&gt; is LinkedList&lt;String&gt;
+     * @param classNode the class for which we want to return the parameterized superclass
+     * @return the parameterized superclass
+     */
+    private static ClassNode getParameterizedSuperClass(ClassNode classNode) {
+        if (ClassHelper.OBJECT_TYPE.equals(classNode)) return null;
+        ClassNode superClass = classNode.getUnresolvedSuperClass();
+        if (superClass==null) {
+            return ClassHelper.OBJECT_TYPE;
+        }
+        if (!classNode.isUsingGenerics() || !superClass.isUsingGenerics()) return superClass;
+        GenericsType[] genericsTypes = classNode.getGenericsTypes();
+        GenericsType[] redirectGenericTypes = classNode.redirect().getGenericsTypes();
+        superClass = superClass.getPlainNodeReference();
+        if (genericsTypes==null || redirectGenericTypes==null || superClass.getGenericsTypes()==null) return superClass;
+        for (int i = 0, genericsTypesLength = genericsTypes.length; i < genericsTypesLength; i++) {
+            if (redirectGenericTypes[i].isPlaceholder()) {
+                final GenericsType genericsType = genericsTypes[i];
+                GenericsType[] superGenericTypes = superClass.getGenericsTypes();
+                for (int j = 0, superGenericTypesLength = superGenericTypes.length; j < superGenericTypesLength; j++) {
+                    final GenericsType superGenericType = superGenericTypes[j];
+                    if (superGenericType.isPlaceholder() && superGenericType.getName().equals(redirectGenericTypes[i].getName())) {
+                        superGenericTypes[j] = genericsType;
+                    }
+                }
+            }
+        }
+        return superClass;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/GroovyClassVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/GroovyClassVisitor.java b/src/main/java/org/codehaus/groovy/ast/GroovyClassVisitor.java
new file mode 100644
index 0000000..e5dff83
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/GroovyClassVisitor.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.ast;
+
+/**
+ * A special visitor for working with the structure of a class. In general, your 
+ * will want to use the Abstract class based on this class {@link ClassCodeVisitorSupport}. 
+ * 
+ * @see org.codehaus.groovy.ast.ClassNode
+ * @see org.codehaus.groovy.ast.ClassCodeVisitorSupport
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public interface GroovyClassVisitor {
+
+    /**
+    * Visit a ClassNode. 
+    */ 
+    void visitClass(ClassNode node);
+
+    /**
+    * Visit a ConstructorNode. 
+    */ 
+    void visitConstructor(ConstructorNode node);
+
+    /**
+    * Visit a MethodNode. 
+    */ 
+    void visitMethod(MethodNode node);
+
+    /**
+    * Visit a FieldNode. 
+    */ 
+    void visitField(FieldNode node);
+
+    /**
+    * Visit a PropertyNode. 
+    */ 
+    void visitProperty(PropertyNode node);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java
new file mode 100644
index 0000000..12787c0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java
@@ -0,0 +1,191 @@
+/*
+ *  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.ConstructorCallExpression;
+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.MethodCallExpression;
+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;
+
+/**
+ * An implementation of the visitor pattern for working with ASTNodes
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+
+public interface GroovyCodeVisitor {
+
+    // statements
+
+    //-------------------------------------------------------------------------
+
+    void visitBlockStatement(BlockStatement statement);
+
+    void visitForLoop(ForStatement forLoop);
+
+    void visitWhileLoop(WhileStatement loop);
+
+    void visitDoWhileLoop(DoWhileStatement loop);
+
+    void visitIfElse(IfStatement ifElse);
+
+    void visitExpressionStatement(ExpressionStatement statement);
+
+    void visitReturnStatement(ReturnStatement statement);
+
+    void visitAssertStatement(AssertStatement statement);
+
+    void visitTryCatchFinally(TryCatchStatement finally1);
+
+    void visitSwitch(SwitchStatement statement);
+
+    void visitCaseStatement(CaseStatement statement);
+
+    void visitBreakStatement(BreakStatement statement);
+
+    void visitContinueStatement(ContinueStatement statement);
+
+    void visitThrowStatement(ThrowStatement statement);
+
+    void visitSynchronizedStatement(SynchronizedStatement statement);
+    
+    void visitCatchStatement(CatchStatement statement);
+
+    // expressions
+
+    //-------------------------------------------------------------------------
+
+    void visitMethodCallExpression(MethodCallExpression call);
+
+    void visitStaticMethodCallExpression(StaticMethodCallExpression expression);
+
+    void visitConstructorCallExpression(ConstructorCallExpression expression);
+
+    void visitTernaryExpression(TernaryExpression expression);
+    
+    void visitShortTernaryExpression(ElvisOperatorExpression expression);
+
+    void visitBinaryExpression(BinaryExpression expression);
+
+    void visitPrefixExpression(PrefixExpression expression);
+
+    void visitPostfixExpression(PostfixExpression expression);
+
+    void visitBooleanExpression(BooleanExpression expression);
+
+    void visitClosureExpression(ClosureExpression expression);
+
+    void visitTupleExpression(TupleExpression expression);
+
+    void visitMapExpression(MapExpression expression);
+
+    void visitMapEntryExpression(MapEntryExpression expression);
+
+    void visitListExpression(ListExpression expression);
+
+    void visitRangeExpression(RangeExpression expression);
+
+    void visitPropertyExpression(PropertyExpression expression);
+
+    void visitAttributeExpression(AttributeExpression attributeExpression);
+
+    void visitFieldExpression(FieldExpression expression);
+
+    void visitMethodPointerExpression(MethodPointerExpression expression);
+
+    void visitConstantExpression(ConstantExpression expression);
+
+    void visitClassExpression(ClassExpression expression);
+
+    void visitVariableExpression(VariableExpression expression);
+
+    void visitDeclarationExpression(DeclarationExpression expression);
+
+    void visitGStringExpression(GStringExpression expression);
+
+    void visitArrayExpression(ArrayExpression expression);
+
+    void visitSpreadExpression(SpreadExpression expression);
+
+    void visitSpreadMapExpression(SpreadMapExpression expression);
+
+    void visitNotExpression(NotExpression expression);
+
+    void visitUnaryMinusExpression(UnaryMinusExpression expression);
+
+    void visitUnaryPlusExpression(UnaryPlusExpression expression);
+
+    void visitBitwiseNegationExpression(BitwiseNegationExpression expression);
+
+    void visitCastExpression(CastExpression expression);
+
+    void visitArgumentlistExpression(ArgumentListExpression expression);
+
+    void visitClosureListExpression(ClosureListExpression closureListExpression);
+
+    void visitBytecodeExpression(BytecodeExpression expression);
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ImportNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ImportNode.java b/src/main/java/org/codehaus/groovy/ast/ImportNode.java
new file mode 100644
index 0000000..5f01494
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ImportNode.java
@@ -0,0 +1,153 @@
+/*
+ *  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.objectweb.asm.Opcodes;
+
+/**
+ * Represents an import statement of a single class
+ *
+ * @author Jochen Theodorou
+ * @author Paul King
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ImportNode extends AnnotatedNode implements Opcodes {
+
+    private final ClassNode type;
+    private final String alias;
+    private final String fieldName;
+    // TODO use PackageNode instead here?
+    private final String packageName;
+    private final boolean isStar;
+    private final boolean isStatic;
+
+    /**
+     * Represent an import of an entire package, i.e.&#160;import package.Classname
+     *
+     * @param type  the referenced class
+     * @param alias optional alias
+     */
+    public ImportNode(ClassNode type, String alias) {
+        this.type = type;
+        this.alias = alias;
+        this.isStar = false;
+        this.isStatic = false;
+        this.packageName = null;
+        this.fieldName = null;
+    }
+
+    /**
+     * Represent an import of an entire package, i.e.&#160;import package.*
+     *
+     * @param packageName the name of the package
+     */
+    public ImportNode(String packageName) {
+        this.type = null;
+        this.alias = null;
+        this.isStar = true;
+        this.isStatic = false;
+        this.packageName = packageName;
+        this.fieldName = null;
+    }
+
+    /**
+     * Represent a static import of a Class, i.e.&#160;import static package.Classname.*
+     *
+     * @param type the referenced class
+     */
+    public ImportNode(ClassNode type) {
+        this.type = type;
+        this.alias = null;
+        this.isStar = true;
+        this.isStatic = true;
+        this.packageName = null;
+        this.fieldName = null;
+    }
+
+    /**
+     * Represent a static import of a field or method, i.e.&#160;import static package.Classname.name
+     *
+     * @param type      the referenced class
+     * @param fieldName the field name
+     * @param alias     optional alias
+     */
+    public ImportNode(ClassNode type, String fieldName, String alias) {
+        this.type = type;
+        this.alias = alias;
+        this.isStar = false;
+        this.isStatic = true;
+        this.packageName = null;
+        this.fieldName = fieldName;
+    }
+
+    /**
+     * @return the text display of this import
+     */
+    public String getText() {
+        String typeName = getClassName();
+        if (isStar && !isStatic) {
+            return "import " + packageName + "*";
+        }
+        if (isStar) {
+            return "import static " + typeName + ".*";
+        }
+        if (isStatic) {
+            if (alias != null && alias.length() != 0 && !alias.equals(fieldName)) {
+                return "import static " + typeName + "." + fieldName + " as " + alias;
+            }
+            return "import static " + typeName + "." + fieldName;
+        }
+        if (alias == null || alias.length() == 0) {
+            return "import " + typeName;
+        }
+        return "import " + typeName + " as " + alias;
+    }
+
+    public String getPackageName() {
+        return packageName;
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    public boolean isStar() {
+        return isStar;
+    }
+
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    public String getAlias() {
+        return alias;
+    }
+
+    public ClassNode getType() {
+        return type;
+    }
+
+    public String getClassName() {
+        return type == null ? null : type.getName();
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/InnerClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/InnerClassNode.java b/src/main/java/org/codehaus/groovy/ast/InnerClassNode.java
new file mode 100644
index 0000000..f20c457
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/InnerClassNode.java
@@ -0,0 +1,103 @@
+/*
+ *  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.stmt.Statement;
+
+import java.util.LinkedList;
+
+/**
+ * Represents an inner class declaration
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class InnerClassNode extends ClassNode {
+
+    private final ClassNode outerClass;
+    private VariableScope scope;
+    private boolean anonymous;
+
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superClass the base class name - use "java.lang.Object" if no direct base class
+     */
+    public InnerClassNode(ClassNode outerClass, String name, int modifiers, ClassNode superClass) {
+        this(outerClass, name, modifiers, superClass, ClassHelper.EMPTY_TYPE_ARRAY, MixinNode.EMPTY_ARRAY);
+    }
+
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superClass the base class name - use "java.lang.Object" if no direct base class
+     */
+    public InnerClassNode(ClassNode outerClass, String name, int modifiers, ClassNode superClass, ClassNode[] interfaces, MixinNode[] mixins) {
+        super(name, modifiers, superClass, interfaces, mixins);
+        this.outerClass = outerClass;
+
+        if (outerClass.innerClasses == null)
+            outerClass.innerClasses = new LinkedList<InnerClassNode> ();
+        outerClass.innerClasses.add(this);
+    }
+
+    public ClassNode getOuterClass() {
+        return outerClass;
+    }
+
+    public ClassNode getOuterMostClass()  {
+        ClassNode outerClass = getOuterClass();
+        while (outerClass instanceof InnerClassNode)  {
+            outerClass = outerClass.getOuterClass();
+        }
+        return outerClass;
+    }
+
+    /**
+     * @return the field node on the outer class or null if this is not an inner class
+     */
+    public FieldNode getOuterField(String name) {
+        return outerClass.getDeclaredField(name);
+    }
+    
+    public VariableScope getVariableScope() {
+        return scope;        
+    }
+    
+    public void setVariableScope(VariableScope scope) {
+        this.scope = scope;
+    }
+
+    public boolean isAnonymous() {
+        return anonymous;
+    }
+
+    public void setAnonymous(boolean anonymous) {
+        this.anonymous = anonymous;
+    }
+
+    @Override
+    public void addConstructor(final ConstructorNode node) {
+        super.addConstructor(node);
+    }
+
+    @Override
+    public ConstructorNode addConstructor(final int modifiers, final Parameter[] parameters, final ClassNode[] exceptions, final Statement code) {
+        return super.addConstructor(modifiers, parameters, exceptions, code);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/InterfaceHelperClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/InterfaceHelperClassNode.java b/src/main/java/org/codehaus/groovy/ast/InterfaceHelperClassNode.java
new file mode 100644
index 0000000..d2e952f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/InterfaceHelperClassNode.java
@@ -0,0 +1,51 @@
+/*
+ *  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.ArrayList;
+import java.util.List;
+
+/**
+ * Represents an inner class defined as helper for an interface
+ * 
+ * @author Roshan Dawrani
+ */
+public class InterfaceHelperClassNode extends InnerClassNode {
+
+    private List callSites = new ArrayList();
+    
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superClass the base class name - use "java.lang.Object" if no direct base class
+     * @param callSites list of callsites used in the interface
+     */
+    public InterfaceHelperClassNode(ClassNode outerClass, String name, int modifiers, ClassNode superClass, List<String> callSites) {
+        super(outerClass, name, modifiers, superClass, ClassHelper.EMPTY_TYPE_ARRAY, MixinNode.EMPTY_ARRAY);
+        setCallSites(callSites);
+    }
+    
+    public void setCallSites(List<String> cs) {
+        callSites = (cs != null) ? cs : new ArrayList<String>();
+    }
+    
+    public List<String> getCallSites() {
+        return callSites;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/MethodCallTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/MethodCallTransformation.java b/src/main/java/org/codehaus/groovy/ast/MethodCallTransformation.java
new file mode 100644
index 0000000..69ab6c0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/MethodCallTransformation.java
@@ -0,0 +1,116 @@
+/*
+ *  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.MissingPropertyException;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.transform.ASTTransformation;
+
+/**
+ *
+ * @author Hamlet D'Arcy
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+
+public abstract class MethodCallTransformation implements ASTTransformation {
+
+    public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
+
+        GroovyCodeVisitor transformer = getTransformer(nodes, sourceUnit);
+
+        if (nodes != null) {
+            for (ASTNode it : nodes) {
+                if (!(it instanceof AnnotationNode) && !(it instanceof ClassNode)) {
+                    it.visit(transformer);
+                }
+            }
+        }
+        if (sourceUnit.getAST() != null) {
+            sourceUnit.getAST().visit(transformer);
+            if (sourceUnit.getAST().getStatementBlock() != null) {
+                sourceUnit.getAST().getStatementBlock().visit(transformer);
+            }
+            if (sourceUnit.getAST().getClasses() != null) {
+                for (ClassNode classNode : sourceUnit.getAST().getClasses()) {
+                    if (classNode.getMethods() != null) {
+                        for (MethodNode node : classNode.getMethods()) {
+                            if (node != null && node.getCode() != null) {
+                                node.getCode().visit(transformer);
+                            }
+                        }
+                    }
+
+                    try {
+                        if (classNode.getDeclaredConstructors() != null) {
+                            for (MethodNode node : classNode.getDeclaredConstructors()) {
+                                if (node != null && node.getCode() != null) {
+                                    node.getCode().visit(transformer);
+                                }
+                            }
+                        }
+                    } catch (MissingPropertyException ignored) {
+                        // todo: inner class nodes don't have a constructors field available
+                    }
+
+                    // all properties are also always fields
+                    if (classNode.getFields() != null) {
+                        for (FieldNode node : classNode.getFields()) {
+                            if (node.getInitialValueExpression() != null) {
+                                node.getInitialValueExpression().visit(transformer);
+                            }
+                        }
+                    }
+
+                    try {
+                        if (classNode.getObjectInitializerStatements() != null) {
+                            for (Statement node : classNode.getObjectInitializerStatements()) {
+                                if (node != null) {
+                                    node.visit(transformer);
+                                }
+                            }
+                        }
+                    } catch (MissingPropertyException ignored) {
+                        // todo: inner class nodes don't have an objectInitializers field available
+                    }
+
+                    // todo: is there anything to do with the module ???
+                }
+            }
+            if (sourceUnit.getAST().getMethods() != null) {
+                for (MethodNode node : sourceUnit.getAST().getMethods()) {
+                    if (node != null) {
+                        if (node.getParameters() != null) {
+                            for (Parameter parameter : node.getParameters()) {
+                                if (parameter != null && parameter.getInitialExpression() != null) {
+                                    parameter.getInitialExpression().visit(transformer);
+                                }
+                            }
+                        }
+                        if (node.getCode() != null) {
+                            node.getCode().visit(transformer);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    protected abstract GroovyCodeVisitor getTransformer(ASTNode[] nodes, SourceUnit sourceUnit);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/MethodInvocationTrap.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/MethodInvocationTrap.java b/src/main/java/org/codehaus/groovy/ast/MethodInvocationTrap.java
new file mode 100644
index 0000000..9801c60
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/MethodInvocationTrap.java
@@ -0,0 +1,97 @@
+/*
+ *  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.ClosureExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.tools.ClosureUtils;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+/**
+ *
+ * @author Hamlet D'Arcy
+ * @author Sergei Egorov <bs...@gmail.com>
+ */
+public abstract class MethodInvocationTrap extends CodeVisitorSupport {
+
+    protected final ReaderSource source;
+    protected final SourceUnit sourceUnit;
+
+    public MethodInvocationTrap(ReaderSource source, SourceUnit sourceUnit) {
+        if (source == null) throw new IllegalArgumentException("Null: source");
+        if (sourceUnit == null) throw new IllegalArgumentException("Null: sourceUnit");
+        this.source = source;
+        this.sourceUnit = sourceUnit;
+    }
+
+    /**
+     * Attempts to find AstBuilder 'from code' invocations. When found, converts them into calls
+     * to the 'from string' approach.
+     *
+     * @param call the method call expression that may or may not be an AstBuilder 'from code' invocation.
+     */
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        boolean shouldContinueWalking = true;
+        
+        if (isBuildInvocation(call)) {
+            shouldContinueWalking = handleTargetMethodCallExpression(call);
+        }
+        
+        if(shouldContinueWalking) {
+            // continue normal tree walking
+            call.getObjectExpression().visit(this);
+            call.getMethod().visit(this);
+            call.getArguments().visit(this);
+        }
+    }
+
+    /**
+     * Reports an error back to the source unit.
+     *
+     * @param msg  the error message
+     * @param expr the expression that caused the error message.
+     */
+    protected void addError(String msg, ASTNode expr) {
+        sourceUnit.getErrorCollector().addErrorAndContinue(
+                new SyntaxErrorMessage(new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), sourceUnit)
+        );
+    }
+
+    /**
+     * Converts a ClosureExpression into the String source.
+     *
+     * @param expression a closure
+     * @return the source the closure was created from
+     */
+    protected String convertClosureToSource(ClosureExpression expression) {
+        try {
+            return ClosureUtils.convertClosureToSource(source, expression);
+        } catch(Exception e) {
+            addError(e.getMessage(), expression);
+        }
+        return null;
+    }
+
+    protected abstract boolean handleTargetMethodCallExpression(MethodCallExpression call);
+
+    protected abstract boolean isBuildInvocation(MethodCallExpression call);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/MethodNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/MethodNode.java b/src/main/java/org/codehaus/groovy/ast/MethodNode.java
new file mode 100644
index 0000000..a43286f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/MethodNode.java
@@ -0,0 +1,284 @@
+/*
+ *  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.groovydoc.Groovydoc;
+import groovy.lang.groovydoc.GroovydocHolder;
+import org.apache.groovy.ast.tools.MethodNodeUtils;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.objectweb.asm.Opcodes;
+
+import java.util.List;
+
+/**
+ * Represents a method declaration
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author Hamlet D'Arcy
+ */
+public class MethodNode extends AnnotatedNode implements Opcodes, GroovydocHolder<MethodNode> {
+
+    public static final String SCRIPT_BODY_METHOD_KEY = "org.codehaus.groovy.ast.MethodNode.isScriptBody";
+    private final String name;
+    private int modifiers;
+    private boolean syntheticPublic;
+    private ClassNode returnType;
+    private Parameter[] parameters;
+    private boolean hasDefaultValue = false;
+    private Statement code;
+    private boolean dynamicReturnType;
+    private VariableScope variableScope;
+    private final ClassNode[] exceptions;
+    private final boolean staticConstructor;
+
+    // type spec for generics
+    private GenericsType[] genericsTypes = null;
+    private boolean hasDefault;
+
+    // cached data
+    String typeDescriptor;
+
+    public MethodNode(String name, int modifiers, ClassNode returnType, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
+        this.name = name;
+        this.modifiers = modifiers;
+        this.code = code;
+        setReturnType(returnType);
+        VariableScope scope = new VariableScope();
+        setVariableScope(scope);
+        setParameters(parameters);
+        this.hasDefault = false;
+        this.exceptions = exceptions;
+        this.staticConstructor = (name != null && name.equals("<clinit>"));
+    }
+
+    /**
+     * The type descriptor for a method node is a string containing the name of the method, its return type,
+     * and its parameter types in a canonical form. For simplicity, we use the format of a Java declaration
+     * without parameter names or generics.
+     *
+     * @return the type descriptor
+     */
+    public String getTypeDescriptor() {
+        if (typeDescriptor == null) {
+            typeDescriptor = MethodNodeUtils.methodDescriptor(this);
+        }
+        return typeDescriptor;
+    }
+
+    private void invalidateCachedData() {
+        typeDescriptor = null;
+    }
+
+    public boolean isVoidMethod() {
+        return returnType == ClassHelper.VOID_TYPE;
+    }
+
+    public Statement getCode() {
+        return code;
+    }
+
+    public void setCode(Statement code) {
+        this.code = code;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public void setModifiers(int modifiers) {
+        invalidateCachedData();
+        this.modifiers = modifiers;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Parameter[] getParameters() {
+        return parameters;
+    }
+
+    public void setParameters(Parameter[] parameters) {
+        invalidateCachedData();
+        VariableScope scope = new VariableScope();
+        this.parameters = parameters;
+        if (parameters != null && parameters.length > 0) {
+            for (Parameter para : parameters) {
+                if (para.hasInitialExpression()) {
+                    this.hasDefaultValue = true;
+                }
+                para.setInStaticContext(isStatic());
+                scope.putDeclaredVariable(para);
+            }
+        }
+        setVariableScope(scope);
+    }
+
+    public ClassNode getReturnType() {
+        return returnType;
+    }
+
+    public VariableScope getVariableScope() {
+        return variableScope;
+    }
+
+    public void setVariableScope(VariableScope variableScope) {
+        this.variableScope = variableScope;
+        variableScope.setInStaticContext(isStatic());
+    }
+
+    public boolean isDynamicReturnType() {
+        return dynamicReturnType;
+    }
+
+    public boolean isAbstract() {
+        return (modifiers & ACC_ABSTRACT) != 0;
+    }
+
+    public boolean isStatic() {
+        return (modifiers & ACC_STATIC) != 0;
+    }
+
+    public boolean isPublic() {
+        return (modifiers & ACC_PUBLIC) != 0;
+    }
+
+    public boolean isPrivate() {
+        return (modifiers & ACC_PRIVATE) != 0;
+    }
+
+    public boolean isFinal() {
+        return (modifiers & ACC_FINAL) != 0;
+    }
+
+    public boolean isProtected() {
+        return (modifiers & ACC_PROTECTED) != 0;
+    }
+
+    public boolean hasDefaultValue() {
+        return this.hasDefaultValue;
+    }
+
+    /**
+     * @return true if this method is the run method from a script
+     */
+    public boolean isScriptBody() {
+        return getNodeMetaData(SCRIPT_BODY_METHOD_KEY) != null;
+    }
+
+    /**
+     * Set the metadata flag for this method to indicate that it is a script body implementation.
+     * @see ModuleNode createStatementsClass().
+     */
+    public void setIsScriptBody() {
+        setNodeMetaData(SCRIPT_BODY_METHOD_KEY, true);
+    }
+
+    public String toString() {
+        return "MethodNode@" + hashCode() + "[" + getDeclaringClass().getName() + "#" + getTypeDescriptor() + "]";
+    }
+
+    public void setReturnType(ClassNode returnType) {
+        invalidateCachedData();
+        dynamicReturnType |= ClassHelper.DYNAMIC_TYPE == returnType;
+        this.returnType = returnType;
+        if (returnType == null) this.returnType = ClassHelper.OBJECT_TYPE;
+    }
+
+    public ClassNode[] getExceptions() {
+        return exceptions;
+    }
+
+    public Statement getFirstStatement() {
+        if (code == null) return null;
+        Statement first = code;
+        while (first instanceof BlockStatement) {
+            List<Statement> list = ((BlockStatement) first).getStatements();
+            if (list.isEmpty()) {
+                first = null;
+            } else {
+                first = list.get(0);
+            }
+        }
+        return first;
+    }
+
+    public GenericsType[] getGenericsTypes() {
+        return genericsTypes;
+    }
+
+    public void setGenericsTypes(GenericsType[] genericsTypes) {
+        invalidateCachedData();
+        this.genericsTypes = genericsTypes;
+    }
+
+    public void setAnnotationDefault(boolean b) {
+        this.hasDefault = b;
+    }
+
+    public boolean hasAnnotationDefault() {
+        return hasDefault;
+    }
+
+    public boolean isStaticConstructor() {
+        return staticConstructor;
+    }
+
+    /**
+     * Indicates that this method has been "promoted" to public by
+     * Groovy when in fact there was no public modifier explicitly
+     * in the source code. I.e. it remembers that it has applied
+     * Groovy's "public methods by default" rule. This property is
+     * typically only of interest to AST transform writers.
+     *
+     * @return true if this class is public but had no explicit public modifier
+     */
+    public boolean isSyntheticPublic() {
+        return syntheticPublic;
+    }
+
+    public void setSyntheticPublic(boolean syntheticPublic) {
+        this.syntheticPublic = syntheticPublic;
+    }
+
+    /**
+     * Provides a nicely formatted string of the method definition. For simplicity, generic types on some of the elements
+     * are not displayed. 
+     * @return
+     *      string form of node with some generic elements suppressed
+     */
+    @Override
+    public String getText() {
+        String retType = AstToTextHelper.getClassText(returnType);
+        String exceptionTypes = AstToTextHelper.getThrowsClauseText(exceptions);
+        String parms = AstToTextHelper.getParametersText(parameters);
+        return AstToTextHelper.getModifiersText(modifiers) + " " + retType + " " + name + "(" + parms + ") " + exceptionTypes + " { ... }";
+    }
+
+    @Override
+    public Groovydoc getGroovydoc() {
+        return this.<Groovydoc>getNodeMetaData(DOC_COMMENT);
+    }
+
+    @Override
+    public MethodNode getInstance() {
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/MixinASTTransformation.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/MixinASTTransformation.java b/src/main/java/org/codehaus/groovy/ast/MixinASTTransformation.java
new file mode 100644
index 0000000..21bccce
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/MixinASTTransformation.java
@@ -0,0 +1,88 @@
+/*
+ *  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.Mixin;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.transform.AbstractASTTransformation;
+import org.codehaus.groovy.transform.GroovyASTTransformation;
+
+import static org.codehaus.groovy.ast.ClassHelper.make;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+
+/**
+ * @deprecated static mixins have been deprecated in favour of traits (trait keyword).
+ */
+@Deprecated
+@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
+public class MixinASTTransformation extends AbstractASTTransformation {
+    private static final ClassNode MY_TYPE = make(Mixin.class);
+
+    public void visit(ASTNode nodes[], SourceUnit source) {
+        init(nodes, source);
+        AnnotationNode node = (AnnotationNode) nodes[0];
+        AnnotatedNode parent = (AnnotatedNode) nodes[1];
+        if (!MY_TYPE.equals(node.getClassNode()))
+            return;
+
+        final Expression expr = node.getMember("value");
+        if (expr == null) {
+            return;
+        }
+
+        Expression useClasses = null;
+        if (expr instanceof ClassExpression) {
+            useClasses = expr;
+        } else if (expr instanceof ListExpression) {
+            ListExpression listExpression = (ListExpression) expr;
+            for (Expression ex : listExpression.getExpressions()) {
+                if (!(ex instanceof ClassExpression))
+                    return;
+            }
+            useClasses = expr;
+        }
+
+        if (useClasses == null)
+            return;
+
+        if (parent instanceof ClassNode) {
+            ClassNode annotatedClass = (ClassNode) parent;
+
+            final Parameter[] noparams = Parameter.EMPTY_ARRAY;
+            MethodNode clinit = annotatedClass.getDeclaredMethod("<clinit>", noparams);
+            if (clinit == null) {
+                clinit = annotatedClass.addMethod("<clinit>", ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.VOID_TYPE, noparams, null, new BlockStatement());
+                clinit.setSynthetic(true);
+            }
+
+            final BlockStatement code = (BlockStatement) clinit.getCode();
+            code.addStatement(
+                    stmt(callX(propX(classX(annotatedClass), "metaClass"), "mixin", useClasses))
+            );
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/MixinNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/MixinNode.java b/src/main/java/org/codehaus/groovy/ast/MixinNode.java
new file mode 100644
index 0000000..08dee7c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/MixinNode.java
@@ -0,0 +1,47 @@
+/*
+ *  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 mixin which can be applied to any ClassNode to implement mixins
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class MixinNode extends ClassNode {
+
+    public static final MixinNode[] EMPTY_ARRAY = {};
+    
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superType the base class name - use "java.lang.Object" if no direct base class
+     */
+    public MixinNode(String name, int modifiers, ClassNode superType) {
+        this(name, modifiers, superType, ClassHelper.EMPTY_TYPE_ARRAY);
+    }
+
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superType the base class name - use "java.lang.Object" if no direct base class
+     */
+    public MixinNode(String name, int modifiers, ClassNode superType, ClassNode[] interfaces) {
+        super(name, modifiers, superType, interfaces, MixinNode.EMPTY_ARRAY);
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java b/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
new file mode 100644
index 0000000..c493299
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/AnnotationNode.java
@@ -0,0 +1,189 @@
+/*
+ *  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.ast.expr.Expression;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Represents an annotation which can be attached to interfaces, classes, methods and fields.
+ */
+public class AnnotationNode extends ASTNode {
+    public static final int CONSTRUCTOR_TARGET = 1 << 1;
+    public static final int METHOD_TARGET = 1 << 2;
+    public static final int FIELD_TARGET = 1 << 3;
+    public static final int PARAMETER_TARGET =  1 << 4;
+    public static final int LOCAL_VARIABLE_TARGET = 1 << 5;
+    public static final int ANNOTATION_TARGET = 1 << 6;
+    public static final int PACKAGE_TARGET = 1 << 7;
+    public static final int TYPE_PARAMETER_TARGET = 1 << 8;
+    public static final int TYPE_USE_TARGET = 1 << 9;
+    public static final int TYPE_TARGET = 1 + ANNOTATION_TARGET;    //GROOVY-7151
+    private static final int ALL_TARGETS = TYPE_TARGET | CONSTRUCTOR_TARGET | METHOD_TARGET
+            | FIELD_TARGET | PARAMETER_TARGET | LOCAL_VARIABLE_TARGET | ANNOTATION_TARGET
+            | PACKAGE_TARGET | TYPE_PARAMETER_TARGET | TYPE_USE_TARGET;
+
+    private final ClassNode classNode;
+    private Map<String, Expression> members;
+    private boolean runtimeRetention= false, sourceRetention= false, classRetention = false;
+    private int allowedTargets = ALL_TARGETS;
+
+    public AnnotationNode(ClassNode classNode) {
+        this.classNode = classNode;
+    }
+
+    public ClassNode getClassNode() {
+        return classNode;
+    }
+
+    public Map<String, Expression> getMembers() {
+        if (members == null) {
+            return Collections.emptyMap();
+        }
+        return members;
+    }
+    
+    public Expression getMember(String name) {
+        if (members == null) {
+            return null;
+        }
+        return members.get(name);
+    }
+
+    private void assertMembers() {
+        if (members == null) {
+             members = new LinkedHashMap<String, Expression>();
+        }
+    }
+
+    public void addMember(String name, Expression value) {
+        assertMembers();
+        Expression oldValue = members.get(name);
+        if (oldValue == null) {
+            members.put(name, value);
+        }
+        else {
+            throw new GroovyBugError(String.format("Annotation member %s has already been added", name));
+        }
+    }
+
+    public void setMember(String name, Expression value) {
+        assertMembers();
+        members.put(name, value);
+    }
+    
+    public boolean isBuiltIn(){
+        return false;
+    }
+
+    /**
+     * Flag corresponding to <code>RetentionPolicy</code>.
+     * @return <tt>true</tt> if the annotation should be visible at runtime, 
+     *      <tt>false</tt> otherwise
+     */
+    public boolean hasRuntimeRetention() {
+        return this.runtimeRetention;
+    }
+
+    /**
+     * Sets the internal flag of this annotation runtime retention policy.
+     * If the current annotation has 
+     * <code>RetentionPolicy.RUNTIME</code> or if <tt>false</tt>
+     * if the <code>RetentionPolicy.CLASS</code>.
+     * @param flag if <tt>true</tt> then current annotation is marked as having
+     *     <code>RetentionPolicy.RUNTIME</code>. If <tt>false</tt> then
+     *     the annotation has <code>RetentionPolicy.CLASS</code>.
+     */
+    public void setRuntimeRetention(boolean flag) {
+        this.runtimeRetention = flag;
+    }
+    
+    /**
+     * Flag corresponding to <code>RetentionPolicy.SOURCE</code>.
+     * @return <tt>true</tt> if the annotation is only allowed in sources 
+     *      <tt>false</tt> otherwise
+     */
+    public boolean hasSourceRetention() {
+        if (!runtimeRetention && !classRetention) return true;
+        return this.sourceRetention;
+    }
+
+    /** Sets the internal flag if the current annotation has 
+     * <code>RetentionPolicy.SOURCE</code>.
+     */ 
+    public void setSourceRetention(boolean flag) {
+        this.sourceRetention = flag;
+    }
+
+    /**
+     * Flag corresponding to <code>RetentionPolicy.CLASS</code>.
+     * @return <tt>true</tt> if the annotation is recorded by the compiler,
+     *                       but not visible at runtime     *
+      *        <tt>false</tt> otherwise
+     */
+    public boolean hasClassRetention() {
+        return this.classRetention;
+    }
+
+    /** Sets the internal flag if the current annotation has
+     * <code>RetentionPolicy.CLASS</code>.
+     */
+    public void setClassRetention(boolean flag) {
+        this.classRetention = flag;
+    }
+
+    public void setAllowedTargets(int bitmap) {
+        this.allowedTargets = bitmap;
+    }
+    
+    public boolean isTargetAllowed(int target) {
+        return (this.allowedTargets & target) == target;
+    }
+    
+    public static String targetToName(int target) {
+        switch(target) {
+            case TYPE_TARGET:
+                return "TYPE";
+            case CONSTRUCTOR_TARGET:
+                return "CONSTRUCTOR";
+            case METHOD_TARGET:
+                return "METHOD";
+            case FIELD_TARGET:
+                return "FIELD";
+            case PARAMETER_TARGET:
+                return "PARAMETER";
+            case LOCAL_VARIABLE_TARGET:
+                return "LOCAL_VARIABLE";
+            case ANNOTATION_TARGET:
+                return "ANNOTATION";
+            case PACKAGE_TARGET:
+                return "PACKAGE";
+            case TYPE_PARAMETER_TARGET:
+                return "TYPE_PARAMETER";
+            case TYPE_USE_TARGET:
+                return "TYPE_USE";
+            default:
+                return "unknown target";
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java b/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
new file mode 100644
index 0000000..3599fbf
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/AstToTextHelper.java
@@ -0,0 +1,111 @@
+/*
+ *  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.lang.reflect.Modifier;
+
+/**
+ * Helper class for converting AST into text.
+ * @author Hamlet D'Arcy
+ */
+public class AstToTextHelper {
+
+    public static String getClassText(ClassNode node) {
+        if (node == null) return "<unknown>";
+        if (node.getName() == null) return "<unknown>";
+        return node.getName();
+    }
+
+    public static String getParameterText(Parameter node) {
+        if (node == null) return "<unknown>";
+
+        String name = node.getName() == null ? "<unknown>" : node.getName();
+        String type = getClassText(node.getType());
+        if (node.getInitialExpression() != null) {
+            return type + " " + name + " = " + node.getInitialExpression().getText();
+        }
+        return type + " " + name;
+    }
+
+    public static String getParametersText(Parameter[] parameters) {
+        if (parameters == null) return "";
+        if (parameters.length == 0) return "";
+        StringBuilder result = new StringBuilder();
+        int max = parameters.length;
+        for (int x = 0; x < max; x++) {
+            result.append(getParameterText(parameters[x]));
+            if (x < (max - 1)) {
+                result.append(", ");
+            }
+        }
+        return result.toString();
+    }
+
+    public static String getThrowsClauseText(ClassNode[] exceptions) {
+        if (exceptions == null) return "";
+        if (exceptions.length == 0) return "";
+        StringBuilder result = new StringBuilder("throws ");
+        int max = exceptions.length;
+        for (int x = 0; x < max; x++) {
+            result.append(getClassText(exceptions[x]));
+            if (x < (max - 1)) {
+                result.append(", "); 
+            }
+        }
+        return result.toString(); 
+    }
+
+    public static String getModifiersText(int modifiers) {
+        StringBuilder result = new StringBuilder();
+        if (Modifier.isPrivate(modifiers)) {
+            result.append("private ");
+        }
+        if (Modifier.isProtected(modifiers)) {
+            result.append("protected ");
+        }
+        if (Modifier.isPublic(modifiers)) {
+            result.append("public ");
+        }
+        if (Modifier.isStatic(modifiers)) {
+            result.append("static ");
+        }
+        if (Modifier.isAbstract(modifiers)) {
+            result.append("abstract ");
+        }
+        if (Modifier.isFinal(modifiers)) {
+            result.append("final ");
+        }
+        if (Modifier.isInterface(modifiers)) {
+            result.append("interface ");
+        }
+        if (Modifier.isNative(modifiers)) {
+            result.append("native ");
+        }
+        if (Modifier.isSynchronized(modifiers)) {
+            result.append("synchronized ");
+        }
+        if (Modifier.isTransient(modifiers)) {
+            result.append("transient ");
+        }
+        if (Modifier.isVolatile(modifiers)) {
+            result.append("volatile ");
+        }
+        return result.toString().trim();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java b/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java
new file mode 100644
index 0000000..06ef44d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ClassCodeExpressionTransformer.java
@@ -0,0 +1,146 @@
+/*
+ *  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.BooleanExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.stmt.AssertStatement;
+import org.codehaus.groovy.ast.stmt.CaseStatement;
+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.Statement;
+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.WhileStatement;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Visitor to transform expressions in a whole class.
+ * Transformed Expressions are usually not visited.
+ *
+ * @author Jochen Theodorou
+ */
+public abstract class ClassCodeExpressionTransformer extends ClassCodeVisitorSupport implements ExpressionTransformer {
+
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        for (Parameter p : node.getParameters()) {
+            if (p.hasInitialExpression()) {
+                Expression init = p.getInitialExpression();
+                p.setInitialExpression(transform(init));
+            }
+        }
+        super.visitConstructorOrMethod(node, isConstructor);
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        Expression exp = statement.getExpression();
+        statement.setExpression(transform(exp));
+        for (CaseStatement caseStatement : statement.getCaseStatements()) {
+            caseStatement.visit(this);
+        }
+        statement.getDefaultStatement().visit(this);
+    }
+
+    public void visitField(FieldNode node) {
+        visitAnnotations(node);
+        Expression init = node.getInitialExpression();
+        node.setInitialValueExpression(transform(init));
+    }
+
+    public void visitProperty(PropertyNode node) {
+        visitAnnotations(node);
+        Statement statement = node.getGetterBlock();
+        visitClassCodeContainer(statement);
+
+        statement = node.getSetterBlock();
+        visitClassCodeContainer(statement);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        ifElse.setBooleanExpression((BooleanExpression) (transform(ifElse.getBooleanExpression())));
+        ifElse.getIfBlock().visit(this);
+        ifElse.getElseBlock().visit(this);
+    }
+
+    public Expression transform(Expression exp) {
+        if (exp == null) return null;
+        return exp.transformExpression(this);
+    }
+
+    public void visitAnnotations(AnnotatedNode node) {
+        List<AnnotationNode> annotations = node.getAnnotations();
+        if (annotations.isEmpty()) return;
+        for (AnnotationNode an : annotations) {
+            // skip built-in properties
+            if (an.isBuiltIn()) continue;
+            for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+                member.setValue(transform(member.getValue()));
+            }
+        }
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        statement.setExpression(transform(statement.getExpression()));
+    }
+
+    public void visitAssertStatement(AssertStatement as) {
+        as.setBooleanExpression((BooleanExpression) (transform(as.getBooleanExpression())));
+        as.setMessageExpression(transform(as.getMessageExpression()));
+    }
+
+    public void visitCaseStatement(CaseStatement statement) {
+        statement.setExpression(transform(statement.getExpression()));
+        statement.getCode().visit(this);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        loop.setBooleanExpression((BooleanExpression) (transform(loop.getBooleanExpression())));
+        super.visitDoWhileLoop(loop);
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        forLoop.setCollectionExpression(transform(forLoop.getCollectionExpression()));
+        super.visitForLoop(forLoop);
+    }
+
+    public void visitSynchronizedStatement(SynchronizedStatement sync) {
+        sync.setExpression(transform(sync.getExpression()));
+        super.visitSynchronizedStatement(sync);
+    }
+
+    public void visitThrowStatement(ThrowStatement ts) {
+        ts.setExpression(transform(ts.getExpression()));
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        loop.setBooleanExpression((BooleanExpression) transform(loop.getBooleanExpression()));
+        super.visitWhileLoop(loop);
+    }
+
+    public void visitExpressionStatement(ExpressionStatement es) {
+        es.setExpression(transform(es.getExpression()));
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java b/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
new file mode 100644
index 0000000..378d2be
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ClassCodeVisitorSupport.java
@@ -0,0 +1,239 @@
+/*
+ *  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.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+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.Statement;
+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.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.transform.ErrorCollecting;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class ClassCodeVisitorSupport extends CodeVisitorSupport implements ErrorCollecting, GroovyClassVisitor {
+
+    public void visitClass(ClassNode node) {
+        visitAnnotations(node);
+        visitPackage(node.getPackage());
+        visitImports(node.getModule());
+        node.visitContents(this);
+        visitObjectInitializerStatements(node);
+    }
+    
+    protected void visitObjectInitializerStatements(ClassNode node) {
+        for (Statement element : node.getObjectInitializerStatements()) {
+            element.visit(this);
+        }
+    }
+
+    public void visitPackage(PackageNode node) {
+        if (node != null) {
+            visitAnnotations(node);
+            node.visit(this);
+        }
+    }
+
+    public void visitImports(ModuleNode node) {
+        if (node != null) {
+            for (ImportNode importNode : node.getImports()) {
+                visitAnnotations(importNode);
+                importNode.visit(this);
+            }
+            for (ImportNode importStarNode : node.getStarImports()) {
+                visitAnnotations(importStarNode);
+                importStarNode.visit(this);
+            }
+            for (ImportNode importStaticNode : node.getStaticImports().values()) {
+                visitAnnotations(importStaticNode);
+                importStaticNode.visit(this);
+            }
+            for (ImportNode importStaticStarNode : node.getStaticStarImports().values()) {
+                visitAnnotations(importStaticStarNode);
+                importStaticStarNode.visit(this);
+            }
+        }
+    }
+
+    public void visitAnnotations(AnnotatedNode node) {
+        List<AnnotationNode> annotations = node.getAnnotations();
+        if (annotations.isEmpty()) return;
+        for (AnnotationNode an : annotations) {
+            // skip built-in properties
+            if (an.isBuiltIn()) continue;
+            for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+                member.getValue().visit(this);
+            }
+        }
+    }
+
+    public void visitBlockStatement(BlockStatement block) {
+        visitStatement(block);
+        super.visitBlockStatement(block);
+    }
+
+    protected void visitClassCodeContainer(Statement code) {
+        if (code != null) code.visit(this);
+    }
+
+    @Override
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        visitAnnotations(expression);
+        super.visitDeclarationExpression(expression);
+    }
+
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        visitAnnotations(node);
+        visitClassCodeContainer(node.getCode());
+        for (Parameter param : node.getParameters()) {
+            visitAnnotations(param);
+        }
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+        visitConstructorOrMethod(node, true);
+    }
+
+    public void visitMethod(MethodNode node) {
+        visitConstructorOrMethod(node, false);
+    }
+
+    public void visitField(FieldNode node) {
+        visitAnnotations(node);
+        Expression init = node.getInitialExpression();
+        if (init != null) init.visit(this);
+    }
+
+    public void visitProperty(PropertyNode node) {
+        visitAnnotations(node);
+        Statement statement = node.getGetterBlock();
+        visitClassCodeContainer(statement);
+
+        statement = node.getSetterBlock();
+        visitClassCodeContainer(statement);
+
+        Expression init = node.getInitialExpression();
+        if (init != null) init.visit(this);
+    }
+
+    public void addError(String msg, ASTNode expr) {
+        SourceUnit source = getSourceUnit();
+        source.getErrorCollector().addErrorAndContinue(
+                new SyntaxErrorMessage(new SyntaxException(msg + '\n', expr.getLineNumber(), expr.getColumnNumber(), expr.getLastLineNumber(), expr.getLastColumnNumber()), source)
+        );
+    }
+
+    protected abstract SourceUnit getSourceUnit();
+
+    protected void visitStatement(Statement statement) {
+    }
+
+    public void visitAssertStatement(AssertStatement statement) {
+        visitStatement(statement);
+        super.visitAssertStatement(statement);
+    }
+
+    public void visitBreakStatement(BreakStatement statement) {
+        visitStatement(statement);
+        super.visitBreakStatement(statement);
+    }
+
+    public void visitCaseStatement(CaseStatement statement) {
+        visitStatement(statement);
+        super.visitCaseStatement(statement);
+    }
+
+    public void visitCatchStatement(CatchStatement statement) {
+        visitStatement(statement);
+        super.visitCatchStatement(statement);
+    }
+
+    public void visitContinueStatement(ContinueStatement statement) {
+        visitStatement(statement);
+        super.visitContinueStatement(statement);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        visitStatement(loop);
+        super.visitDoWhileLoop(loop);
+    }
+
+    public void visitExpressionStatement(ExpressionStatement statement) {
+        visitStatement(statement);
+        super.visitExpressionStatement(statement);
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        visitStatement(forLoop);
+        super.visitForLoop(forLoop);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        visitStatement(ifElse);
+        super.visitIfElse(ifElse);
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        visitStatement(statement);
+        super.visitReturnStatement(statement);
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        visitStatement(statement);
+        super.visitSwitch(statement);
+    }
+
+    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+        visitStatement(statement);
+        super.visitSynchronizedStatement(statement);
+    }
+
+    public void visitThrowStatement(ThrowStatement statement) {
+        visitStatement(statement);
+        super.visitThrowStatement(statement);
+    }
+
+    public void visitTryCatchFinally(TryCatchStatement statement) {
+        visitStatement(statement);
+        super.visitTryCatchFinally(statement);
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        visitStatement(loop);
+        super.visitWhileLoop(loop);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
new file mode 100644
index 0000000..60eaa47
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -0,0 +1,481 @@
+/*
+ *  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 groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.GroovyInterceptable;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.MetaClass;
+import groovy.lang.Range;
+import groovy.lang.Reference;
+import groovy.lang.Script;
+import org.codehaus.groovy.runtime.GeneratedClosure;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+import org.codehaus.groovy.transform.trait.Traits;
+import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ReferenceBundle;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.Modifier;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * This class is a Helper for ClassNode and classes handling ClassNodes.
+ * It does contain a set of predefined ClassNodes for the most used
+ * types and some code for cached ClassNode creation and basic
+ * ClassNode handling
+ */
+public class ClassHelper {
+
+    private static final Class[] classes = new Class[]{
+            Object.class, Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE,
+            Integer.TYPE, Long.TYPE, Double.TYPE, Float.TYPE, Void.TYPE,
+            Closure.class, GString.class, List.class, Map.class, Range.class,
+            Pattern.class, Script.class, String.class, Boolean.class,
+            Character.class, Byte.class, Short.class, Integer.class, Long.class,
+            Double.class, Float.class, BigDecimal.class, BigInteger.class,
+            Number.class, Void.class, Reference.class, Class.class, MetaClass.class,
+            Iterator.class, GeneratedClosure.class, GroovyObjectSupport.class
+    };
+
+    private static final String[] primitiveClassNames = new String[]{
+            "", "boolean", "char", "byte", "short",
+            "int", "long", "double", "float", "void"
+    };
+
+    public static final ClassNode
+            DYNAMIC_TYPE = makeCached(Object.class), OBJECT_TYPE = DYNAMIC_TYPE,
+            VOID_TYPE = makeCached(Void.TYPE), CLOSURE_TYPE = makeCached(Closure.class),
+            GSTRING_TYPE = makeCached(GString.class), LIST_TYPE = makeWithoutCaching(List.class),
+            MAP_TYPE = makeWithoutCaching(Map.class), RANGE_TYPE = makeCached(Range.class),
+            PATTERN_TYPE = makeCached(Pattern.class), STRING_TYPE = makeCached(String.class),
+            SCRIPT_TYPE = makeCached(Script.class), REFERENCE_TYPE = makeWithoutCaching(Reference.class),
+            BINDING_TYPE = makeCached(Binding.class),
+
+    boolean_TYPE = makeCached(boolean.class), char_TYPE = makeCached(char.class),
+            byte_TYPE = makeCached(byte.class), int_TYPE = makeCached(int.class),
+            long_TYPE = makeCached(long.class), short_TYPE = makeCached(short.class),
+            double_TYPE = makeCached(double.class), float_TYPE = makeCached(float.class),
+            Byte_TYPE = makeCached(Byte.class), Short_TYPE = makeCached(Short.class),
+            Integer_TYPE = makeCached(Integer.class), Long_TYPE = makeCached(Long.class),
+            Character_TYPE = makeCached(Character.class), Float_TYPE = makeCached(Float.class),
+            Double_TYPE = makeCached(Double.class), Boolean_TYPE = makeCached(Boolean.class),
+            BigInteger_TYPE = makeCached(java.math.BigInteger.class),
+            BigDecimal_TYPE = makeCached(java.math.BigDecimal.class),
+            Number_TYPE = makeCached(Number.class),
+
+    void_WRAPPER_TYPE = makeCached(Void.class), METACLASS_TYPE = makeCached(MetaClass.class),
+            Iterator_TYPE = makeCached(Iterator.class),
+
+    Enum_Type = makeWithoutCaching(Enum.class),
+            Annotation_TYPE = makeCached(Annotation.class),
+            ELEMENT_TYPE_TYPE = makeCached(ElementType.class),
+
+    // uncached constants.
+    CLASS_Type = makeWithoutCaching(Class.class), COMPARABLE_TYPE = makeWithoutCaching(Comparable.class),
+            GENERATED_CLOSURE_Type = makeWithoutCaching(GeneratedClosure.class),
+            GROOVY_OBJECT_SUPPORT_TYPE = makeWithoutCaching(GroovyObjectSupport.class),
+            GROOVY_OBJECT_TYPE = makeWithoutCaching(GroovyObject.class),
+            GROOVY_INTERCEPTABLE_TYPE = makeWithoutCaching(GroovyInterceptable.class);
+
+    private static final ClassNode[] types = new ClassNode[]{
+            OBJECT_TYPE,
+            boolean_TYPE, char_TYPE, byte_TYPE, short_TYPE,
+            int_TYPE, long_TYPE, double_TYPE, float_TYPE,
+            VOID_TYPE, CLOSURE_TYPE, GSTRING_TYPE,
+            LIST_TYPE, MAP_TYPE, RANGE_TYPE, PATTERN_TYPE,
+            SCRIPT_TYPE, STRING_TYPE, Boolean_TYPE, Character_TYPE,
+            Byte_TYPE, Short_TYPE, Integer_TYPE, Long_TYPE,
+            Double_TYPE, Float_TYPE, BigDecimal_TYPE, BigInteger_TYPE,
+            Number_TYPE,
+            void_WRAPPER_TYPE, REFERENCE_TYPE, CLASS_Type, METACLASS_TYPE,
+            Iterator_TYPE, GENERATED_CLOSURE_Type, GROOVY_OBJECT_SUPPORT_TYPE,
+            GROOVY_OBJECT_TYPE, GROOVY_INTERCEPTABLE_TYPE, Enum_Type, Annotation_TYPE
+    };
+
+    private static final int ABSTRACT_STATIC_PRIVATE =
+            Modifier.ABSTRACT | Modifier.PRIVATE | Modifier.STATIC;
+    private static final int VISIBILITY = 5; // public|protected
+
+    protected static final ClassNode[] EMPTY_TYPE_ARRAY = {};
+
+    public static final String OBJECT = "java.lang.Object";
+
+    public static ClassNode makeCached(Class c) {
+        final SoftReference<ClassNode> classNodeSoftReference = ClassHelperCache.classCache.get(c);
+        ClassNode classNode;
+        if (classNodeSoftReference == null || (classNode = classNodeSoftReference.get()) == null) {
+            classNode = new ClassNode(c);
+            ClassHelperCache.classCache.put(c, new SoftReference<ClassNode>(classNode));
+
+            VMPluginFactory.getPlugin().setAdditionalClassInformation(classNode);
+        }
+
+        return classNode;
+    }
+
+    /**
+     * Creates an array of ClassNodes using an array of classes.
+     * For each of the given classes a new ClassNode will be
+     * created
+     *
+     * @param classes an array of classes used to create the ClassNodes
+     * @return an array of ClassNodes
+     * @see #make(Class)
+     */
+    public static ClassNode[] make(Class[] classes) {
+        ClassNode[] cns = new ClassNode[classes.length];
+        for (int i = 0; i < cns.length; i++) {
+            cns[i] = make(classes[i]);
+        }
+
+        return cns;
+    }
+
+    /**
+     * Creates a ClassNode using a given class.
+     * A new ClassNode object is only created if the class
+     * is not one of the predefined ones
+     *
+     * @param c class used to created the ClassNode
+     * @return ClassNode instance created from the given class
+     */
+    public static ClassNode make(Class c) {
+        return make(c, true);
+    }
+
+    public static ClassNode make(Class c, boolean includeGenerics) {
+        for (int i = 0; i < classes.length; i++) {
+            if (c == classes[i]) return types[i];
+        }
+        if (c.isArray()) {
+            ClassNode cn = make(c.getComponentType(), includeGenerics);
+            return cn.makeArray();
+        }
+        return makeWithoutCaching(c, includeGenerics);
+    }
+
+    public static ClassNode makeWithoutCaching(Class c) {
+        return makeWithoutCaching(c, true);
+    }
+
+    public static ClassNode makeWithoutCaching(Class c, boolean includeGenerics) {
+        if (c.isArray()) {
+            ClassNode cn = makeWithoutCaching(c.getComponentType(), includeGenerics);
+            return cn.makeArray();
+        }
+
+        final ClassNode cached = makeCached(c);
+        if (includeGenerics) {
+            return cached;
+        } else {
+            ClassNode t = makeWithoutCaching(c.getName());
+            t.setRedirect(cached);
+            return t;
+        }
+    }
+
+
+    /**
+     * Creates a ClassNode using a given class.
+     * Unlike make(String) this method will not use the cache
+     * to create the ClassNode. This means the ClassNode created
+     * from this method using the same name will have a different
+     * reference
+     *
+     * @param name of the class the ClassNode is representing
+     * @see #make(String)
+     */
+    public static ClassNode makeWithoutCaching(String name) {
+        ClassNode cn = new ClassNode(name, Opcodes.ACC_PUBLIC, OBJECT_TYPE);
+        cn.isPrimaryNode = false;
+        return cn;
+    }
+
+    /**
+     * Creates a ClassNode using a given class.
+     * If the name is one of the predefined ClassNodes then the
+     * corresponding ClassNode instance will be returned. If the
+     * name is null or of length 0 the dynamic type is returned
+     *
+     * @param name of the class the ClassNode is representing
+     */
+    public static ClassNode make(String name) {
+        if (name == null || name.length() == 0) return DYNAMIC_TYPE;
+
+        for (int i = 0; i < primitiveClassNames.length; i++) {
+            if (primitiveClassNames[i].equals(name)) return types[i];
+        }
+
+        for (int i = 0; i < classes.length; i++) {
+            String cname = classes[i].getName();
+            if (name.equals(cname)) return types[i];
+        }
+        return makeWithoutCaching(name);
+    }
+
+    /**
+     * Creates a ClassNode containing the wrapper of a ClassNode
+     * of primitive type. Any ClassNode representing a primitive
+     * type should be created using the predefined types used in
+     * class. The method will check the parameter for known
+     * references of ClassNode representing a primitive type. If
+     * Reference is found, then a ClassNode will be contained that
+     * represents the wrapper class. For example for boolean, the
+     * wrapper class is java.lang.Boolean.
+     * <p>
+     * If the parameter is no primitive type, the redirected
+     * ClassNode will be returned
+     *
+     * @param cn the ClassNode containing a possible primitive type
+     * @see #make(Class)
+     * @see #make(String)
+     */
+    public static ClassNode getWrapper(ClassNode cn) {
+        cn = cn.redirect();
+        if (!isPrimitiveType(cn)) return cn;
+        if (cn == boolean_TYPE) {
+            return Boolean_TYPE;
+        } else if (cn == byte_TYPE) {
+            return Byte_TYPE;
+        } else if (cn == char_TYPE) {
+            return Character_TYPE;
+        } else if (cn == short_TYPE) {
+            return Short_TYPE;
+        } else if (cn == int_TYPE) {
+            return Integer_TYPE;
+        } else if (cn == long_TYPE) {
+            return Long_TYPE;
+        } else if (cn == float_TYPE) {
+            return Float_TYPE;
+        } else if (cn == double_TYPE) {
+            return Double_TYPE;
+        } else if (cn == VOID_TYPE) {
+            return void_WRAPPER_TYPE;
+        } else {
+            return cn;
+        }
+    }
+
+    public static ClassNode getUnwrapper(ClassNode cn) {
+        cn = cn.redirect();
+        if (isPrimitiveType(cn)) return cn;
+        if (cn == Boolean_TYPE) {
+            return boolean_TYPE;
+        } else if (cn == Byte_TYPE) {
+            return byte_TYPE;
+        } else if (cn == Character_TYPE) {
+            return char_TYPE;
+        } else if (cn == Short_TYPE) {
+            return short_TYPE;
+        } else if (cn == Integer_TYPE) {
+            return int_TYPE;
+        } else if (cn == Long_TYPE) {
+            return long_TYPE;
+        } else if (cn == Float_TYPE) {
+            return float_TYPE;
+        } else if (cn == Double_TYPE) {
+            return double_TYPE;
+        } else {
+            return cn;
+        }
+    }
+
+
+    /**
+     * Test to determine if a ClassNode is a primitive type.
+     * Note: this only works for ClassNodes created using a
+     * predefined ClassNode
+     *
+     * @param cn the ClassNode containing a possible primitive type
+     * @return true if the ClassNode is a primitive type
+     * @see #make(Class)
+     * @see #make(String)
+     */
+    public static boolean isPrimitiveType(ClassNode cn) {
+        return cn == boolean_TYPE ||
+                cn == char_TYPE ||
+                cn == byte_TYPE ||
+                cn == short_TYPE ||
+                cn == int_TYPE ||
+                cn == long_TYPE ||
+                cn == float_TYPE ||
+                cn == double_TYPE ||
+                cn == VOID_TYPE;
+    }
+
+    /**
+     * Test to determine if a ClassNode is a type belongs to the list of types which
+     * are allowed to initialize constants directly in bytecode instead of using &lt;cinit&gt;
+     * <p>
+     * Note: this only works for ClassNodes created using a
+     * predefined ClassNode
+     *
+     * @param cn the ClassNode to be tested
+     * @return true if the ClassNode is of int, float, long, double or String type
+     * @see #make(Class)
+     * @see #make(String)
+     */
+    public static boolean isStaticConstantInitializerType(ClassNode cn) {
+        return cn == int_TYPE ||
+                cn == float_TYPE ||
+                cn == long_TYPE ||
+                cn == double_TYPE ||
+                cn == STRING_TYPE ||
+                // the next items require conversion to int when initializing
+                cn == byte_TYPE ||
+                cn == char_TYPE ||
+                cn == short_TYPE;
+    }
+
+    public static boolean isNumberType(ClassNode cn) {
+        return cn == Byte_TYPE ||
+                cn == Short_TYPE ||
+                cn == Integer_TYPE ||
+                cn == Long_TYPE ||
+                cn == Float_TYPE ||
+                cn == Double_TYPE ||
+                cn == byte_TYPE ||
+                cn == short_TYPE ||
+                cn == int_TYPE ||
+                cn == long_TYPE ||
+                cn == float_TYPE ||
+                cn == double_TYPE;
+    }
+
+    public static ClassNode makeReference() {
+        return REFERENCE_TYPE.getPlainNodeReference();
+    }
+
+    public static boolean isCachedType(ClassNode type) {
+        for (ClassNode cachedType : types) {
+            if (cachedType == type) return true;
+        }
+        return false;
+    }
+
+    static class ClassHelperCache {
+        static ManagedConcurrentMap<Class, SoftReference<ClassNode>> classCache = new ManagedConcurrentMap<Class, SoftReference<ClassNode>>(ReferenceBundle.getWeakBundle());
+    }
+
+    public static boolean isSAMType(ClassNode type) {
+        return findSAM(type) != null;
+    }
+
+    /**
+     * Returns the single abstract method of a class node, if it is a SAM type, or null otherwise.
+     *
+     * @param type a type for which to search for a single abstract method
+     * @return the method node if type is a SAM type, null otherwise
+     */
+    public static MethodNode findSAM(ClassNode type) {
+        if (!Modifier.isAbstract(type.getModifiers())) return null;
+        if (type.isInterface()) {
+            List<MethodNode> methods = type.getMethods();
+            MethodNode found = null;
+            for (MethodNode mi : methods) {
+                // ignore methods, that are not abstract and from Object
+                if (!Modifier.isAbstract(mi.getModifiers())) continue;
+                // ignore trait methods which have a default implementation
+                if (Traits.hasDefaultImplementation(mi)) continue;
+                if (mi.getDeclaringClass().equals(OBJECT_TYPE)) continue;
+                if (OBJECT_TYPE.getDeclaredMethod(mi.getName(), mi.getParameters()) != null) continue;
+
+                // we have two methods, so no SAM
+                if (found != null) return null;
+                found = mi;
+            }
+            return found;
+
+        } else {
+
+            List<MethodNode> methods = type.getAbstractMethods();
+            MethodNode found = null;
+            if (methods != null) {
+                for (MethodNode mi : methods) {
+                    if (!hasUsableImplementation(type, mi)) {
+                        if (found != null) return null;
+                        found = mi;
+                    }
+                }
+            }
+            return found;
+        }
+    }
+
+    private static boolean hasUsableImplementation(ClassNode c, MethodNode m) {
+        if (c == m.getDeclaringClass()) return false;
+        MethodNode found = c.getDeclaredMethod(m.getName(), m.getParameters());
+        if (found == null) return false;
+        int asp = found.getModifiers() & ABSTRACT_STATIC_PRIVATE;
+        int visible = found.getModifiers() & VISIBILITY;
+        if (visible != 0 && asp == 0) return true;
+        if (c.equals(OBJECT_TYPE)) return false;
+        return hasUsableImplementation(c.getSuperClass(), m);
+    }
+
+    /**
+     * Returns a super class or interface for a given class depending on a given target.
+     * If the target is no super class or interface, then null will be returned.
+     * For a non-primitive array type, returns an array of the componentType's super class
+     * or interface if the target is also an array.
+     *
+     * @param clazz     the start class
+     * @param goalClazz the goal class
+     * @return the next super class or interface
+     */
+    public static ClassNode getNextSuperClass(ClassNode clazz, ClassNode goalClazz) {
+        if (clazz.isArray()) {
+            if (!goalClazz.isArray()) return null;
+            ClassNode cn = getNextSuperClass(clazz.getComponentType(), goalClazz.getComponentType());
+            if (cn != null) cn = cn.makeArray();
+            return cn;
+        }
+
+        if (!goalClazz.isInterface()) {
+            if (clazz.isInterface()) {
+                if (OBJECT_TYPE.equals(clazz)) return null;
+                return OBJECT_TYPE;
+            } else {
+                return clazz.getUnresolvedSuperClass();
+            }
+        }
+
+        ClassNode[] interfaces = clazz.getUnresolvedInterfaces();
+        for (ClassNode anInterface : interfaces) {
+            if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(anInterface, goalClazz)) {
+                return anInterface;
+            }
+        }
+        //none of the interfaces here match, so continue with super class
+        return clazz.getUnresolvedSuperClass();
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ErrorCollector.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ErrorCollector.java b/src/main/java/org/codehaus/groovy/control/ErrorCollector.java
new file mode 100644
index 0000000..b388caa
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ErrorCollector.java
@@ -0,0 +1,348 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.control.messages.ExceptionMessage;
+import org.codehaus.groovy.control.messages.LocatedMessage;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.control.messages.WarningMessage;
+import org.codehaus.groovy.syntax.CSTNode;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A base class for collecting messages and errors during processing.
+ * Each CompilationUnit should have an ErrorCollector, and the SourceUnits
+ * should share their ErrorCollector with the CompilationUnit.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class ErrorCollector {
+    
+    /**
+     * WarningMessages collected during processing
+     */
+    protected LinkedList warnings;
+    /**
+     * ErrorMessages collected during processing
+     */
+    protected LinkedList errors;
+    /**
+     * Configuration and other settings that control processing
+     */
+    protected CompilerConfiguration configuration;
+
+    /**
+     * Initialize the ErrorReporter.
+     */
+    public ErrorCollector(CompilerConfiguration configuration) {
+        this.warnings = null;
+        this.errors = null;
+        
+        this.configuration = configuration;
+    }
+    
+    public void addCollectorContents(ErrorCollector er) {
+        if (er.errors!=null) {
+            if (errors==null) {
+                errors = er.errors;
+            } else {
+                errors.addAll(er.errors);
+            }
+        }
+        if (er.warnings!=null) {
+            if (warnings==null) {
+                warnings = er.warnings;
+            } else {
+                warnings.addAll(er.warnings);
+            }            
+        }
+    }
+
+    public void addErrorAndContinue(SyntaxException error, SourceUnit source) throws CompilationFailedException {
+        addErrorAndContinue(Message.create(error, source));
+    }
+    
+    /**
+     * Adds an error to the message set, but does not cause a failure. The message is not required to have a source
+     * line and column specified, but it is best practice to try and include that information. 
+     */
+    public void addErrorAndContinue(Message message) {
+        if (this.errors == null) {
+            this.errors = new LinkedList();
+        }
+
+        this.errors.add(message);
+    }
+    
+    /**
+     * Adds a non-fatal error to the message set, which may cause a failure if the error threshold is exceeded.
+     * The message is not required to have a source line and column specified, but it is best practice to try
+     * and include that information.
+     */
+    public void addError(Message message) throws CompilationFailedException {
+        addErrorAndContinue(message);
+
+        if (errors!=null && this.errors.size() >= configuration.getTolerance()) {
+            failIfErrors();
+        }
+    }
+    
+    /**
+     * Adds an optionally-fatal error to the message set.
+     * The message is not required to have a source line and column specified, but it is best practice to try
+     * and include that information.
+     * @param fatal
+     *      if true then then processing will stop
+     */
+    public void addError(Message message, boolean fatal) throws CompilationFailedException {
+        if (fatal) {
+            addFatalError(message);
+        }
+        else {
+            addError(message);
+        }
+    }
+
+    
+    /**
+     * Convenience wrapper for addError().
+     */
+    public void addError(SyntaxException error, SourceUnit source) throws CompilationFailedException {
+        addError(Message.create(error, source), error.isFatal());
+    }
+
+
+    /**
+     * Convenience wrapper for addError().
+     */
+    public void addError(String text, CSTNode context, SourceUnit source) throws CompilationFailedException {
+        addError(new LocatedMessage(text, context, source));
+    }
+    
+    
+    /**
+     * Adds a fatal exception to the message set and throws
+     * the unit as a PhaseFailedException.
+     */
+    public void addFatalError(Message message) throws CompilationFailedException {
+        addError(message);
+        failIfErrors();
+    }
+
+
+    public void addException(Exception cause, SourceUnit source) throws CompilationFailedException {
+        addError(new ExceptionMessage(cause,configuration.getDebug(),source));
+        failIfErrors();
+    }
+
+    /**
+     * Returns true if there are any errors pending.
+     */
+    public boolean hasErrors() {
+        return this.errors != null;
+    }
+
+    /**
+     * @return the compiler configuration used to create this error collector
+     */
+    public CompilerConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    /**
+     * Returns true if there are any warnings pending.
+     */
+    public boolean hasWarnings() {
+        return this.warnings != null;
+    }
+    
+    /**
+     * Returns the list of warnings, or null if there are none.
+     */
+    public List getWarnings() {
+        return this.warnings;
+    }
+
+    /**
+     * Returns the list of errors, or null if there are none.
+     */
+    public List getErrors() {
+        return this.errors;
+    }
+
+    /**
+     * Returns the number of warnings.
+     */
+    public int getWarningCount() {
+        return ((this.warnings == null) ? 0 : this.warnings.size());
+    }
+
+    /**
+     * Returns the number of errors.
+     */
+    public int getErrorCount() {
+        return ((this.errors == null) ? 0 : this.errors.size());
+    }
+
+    /**
+     * Returns the specified warning message, or null.
+     */
+    public WarningMessage getWarning(int index) {
+        if (index < getWarningCount()) {
+            return (WarningMessage) this.warnings.get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the specified error message, or null.
+     */
+    public Message getError(int index) {
+        if (index < getErrorCount()) {
+            return (Message) this.errors.get(index);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the last error reported
+     */
+    public Message getLastError() {
+        return (Message) this.errors.getLast();
+    }
+    
+    /**
+     * Convenience routine to return the specified error's
+     * underlying SyntaxException, or null if it isn't one.
+     */
+    public SyntaxException getSyntaxError(int index) {
+        SyntaxException exception = null;
+
+        Message message = getError(index);
+        if (message != null && message instanceof SyntaxErrorMessage) {
+            exception = ((SyntaxErrorMessage) message).getCause();
+        }
+        return exception;
+    }
+
+    /**
+     * Convenience routine to return the specified error's
+     * underlying Exception, or null if it isn't one.
+     */
+    public Exception getException(int index) {
+        Exception exception = null;
+
+        Message message = getError(index);
+        if (message != null) {
+            if (message instanceof ExceptionMessage) {
+                exception = ((ExceptionMessage) message).getCause();
+            }
+            else if (message instanceof SyntaxErrorMessage) {
+                exception = ((SyntaxErrorMessage) message).getCause();
+            }
+        }
+        return exception;
+    }
+
+    /**
+     * Adds a WarningMessage to the message set.
+     */
+    public void addWarning(WarningMessage message) {
+        if (message.isRelevant(configuration.getWarningLevel())) {
+            if (this.warnings == null) {
+                this.warnings = new LinkedList();
+            }
+
+            this.warnings.add(message);
+        }
+    }
+
+
+    /**
+     * Convenience wrapper for addWarning() that won't create an object
+     * unless it is relevant.
+     */
+    public void addWarning(int importance, String text, CSTNode context, SourceUnit source) {
+        if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
+            addWarning(new WarningMessage(importance, text, context, source));
+        }
+    }
+    
+    
+    /**
+     * Convenience wrapper for addWarning() that won't create an object
+     * unless it is relevant.
+     */
+    public void addWarning(int importance, String text, Object data, CSTNode context, SourceUnit source) {
+        if (WarningMessage.isRelevant(importance, configuration.getWarningLevel())) {
+            addWarning(new WarningMessage(importance, text, data, context, source));
+        }
+    }
+   
+
+    /**
+     * Causes the current phase to fail by throwing a
+     * CompilationFailedException.
+     */
+    protected void failIfErrors() throws CompilationFailedException {
+        if (hasErrors()) {
+            throw new MultipleCompilationErrorsException(this);
+        }
+    }
+    
+    //---------------------------------------------------------------------------
+    // OUTPUT
+
+
+    private void write(PrintWriter writer, Janitor janitor, List messages, String txt) {
+        if (messages==null || messages.isEmpty()) return;
+        Iterator iterator = messages.iterator();
+        while (iterator.hasNext()) {
+            Message message = (Message) iterator.next();
+            message.write(writer, janitor);
+            
+            if (configuration.getDebug() && (message instanceof SyntaxErrorMessage)){
+                SyntaxErrorMessage sem = (SyntaxErrorMessage) message;
+                sem.getCause().printStackTrace(writer);
+            } 
+            writer.println();
+        }
+
+        writer.print(messages.size());
+        writer.print(" "+txt);
+        if (messages.size()>1) writer.print("s");
+        writer.println();
+    }
+    
+    /**
+     * Writes error messages to the specified PrintWriter.
+     */
+    public void write(PrintWriter writer, Janitor janitor) {
+        write(writer,janitor,warnings,"warning");
+        write(writer,janitor,errors,"error");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java b/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java
new file mode 100644
index 0000000..36ef5ea
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/GenericsVisitor.java
@@ -0,0 +1,188 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+
+/**
+ * class used to verify correct usage of generics in
+ * class header (class and superclass declaration)
+ *
+ * @author Jochen Theodorou
+ */
+public class GenericsVisitor extends ClassCodeVisitorSupport {
+    private final SourceUnit source;
+
+    public GenericsVisitor(SourceUnit source) {
+        this.source = source;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    @Override
+    public void visitClass(ClassNode node) {
+        boolean error = checkWildcard(node);
+        if (error) return;
+        boolean isAnon = node instanceof InnerClassNode && ((InnerClassNode)node).isAnonymous();
+        checkGenericsUsage(node.getUnresolvedSuperClass(false), node.getSuperClass(), isAnon ? true : null);
+        ClassNode[] interfaces = node.getInterfaces();
+        for (ClassNode anInterface : interfaces) {
+            checkGenericsUsage(anInterface, anInterface.redirect());
+        }
+        node.visitContents(this);
+    }
+
+    @Override
+    public void visitField(FieldNode node) {
+        ClassNode type = node.getType();
+        checkGenericsUsage(type, type.redirect());
+        super.visitField(node);
+    }
+
+    @Override
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        ClassNode type = call.getType();
+        boolean isAnon = type instanceof InnerClassNode && ((InnerClassNode)type).isAnonymous();
+        checkGenericsUsage(type, type.redirect(), isAnon);
+    }
+
+    @Override
+    public void visitMethod(MethodNode node) {
+        Parameter[] parameters = node.getParameters();
+        for (Parameter param : parameters) {
+            ClassNode paramType = param.getType();
+            checkGenericsUsage(paramType, paramType.redirect());
+        }
+        ClassNode returnType = node.getReturnType();
+        checkGenericsUsage(returnType, returnType.redirect());
+        super.visitMethod(node);
+    }
+
+    private boolean checkWildcard(ClassNode cn) {
+        ClassNode sn = cn.getUnresolvedSuperClass(false);
+        if (sn == null) return false;
+        GenericsType[] generics = sn.getGenericsTypes();
+        if (generics == null) return false;
+        boolean error = false;
+        for (GenericsType generic : generics) {
+            if (generic.isWildcard()) {
+                addError("A supertype may not specify a wildcard type", sn);
+                error = true;
+            }
+        }
+        return error;
+    }
+
+    private void checkGenericsUsage(ClassNode n, ClassNode cn) {
+        checkGenericsUsage(n, cn, null);
+    }
+
+    private void checkGenericsUsage(ClassNode n, ClassNode cn, Boolean isAnonInnerClass) {
+        if (n.isGenericsPlaceHolder()) return;
+        GenericsType[] nTypes = n.getGenericsTypes();
+        GenericsType[] cnTypes = cn.getGenericsTypes();
+        // raw type usage is always allowed
+        if (nTypes == null) return;
+        // you can't parameterize a non-generified type
+        if (cnTypes == null) {
+            String message = "The class " + getPrintName(n) + " (supplied with " + plural("type parameter", nTypes.length) +
+                    ") refers to the class " + getPrintName(cn) + " which takes no parameters";
+            if (nTypes.length == 0) {
+                message += " (invalid Diamond <> usage?)";
+            }
+            addError(message, n);
+            return;
+        }
+        // parameterize a type by using all of the parameters only
+        if (nTypes.length != cnTypes.length) {
+            if (Boolean.FALSE.equals(isAnonInnerClass) && nTypes.length == 0) {
+                return; // allow Diamond for non-AIC cases from CCE
+            }
+            String message;
+            if (Boolean.TRUE.equals(isAnonInnerClass) && nTypes.length == 0) {
+                message = "Cannot use diamond <> with anonymous inner classes";
+            } else {
+                message = "The class " + getPrintName(n) + " (supplied with " + plural("type parameter", nTypes.length) +
+                        ") refers to the class " + getPrintName(cn) +
+                        " which takes " + plural("parameter", cnTypes.length);
+                if (nTypes.length == 0) {
+                    message += " (invalid Diamond <> usage?)";
+                }
+            }
+            addError(message, n);
+            return;
+        }
+        // check bounds
+        for (int i = 0; i < nTypes.length; i++) {
+            ClassNode nType = nTypes[i].getType();
+            ClassNode cnType = cnTypes[i].getType();
+            if (!nType.isDerivedFrom(cnType)) {
+                if (cnType.isInterface() && nType.implementsInterface(cnType)) continue;
+                addError("The type " + nTypes[i].getName() +
+                        " is not a valid substitute for the bounded parameter <" +
+                        getPrintName(cnTypes[i]) + ">", n);
+            }
+        }
+    }
+
+    private String plural(String orig, int count) {
+        return "" + count + " " + (count == 1 ? orig : orig + "s");
+    }
+
+    private static String getPrintName(GenericsType gt) {
+        StringBuilder ret = new StringBuilder(gt.getName());
+        ClassNode[] upperBounds = gt.getUpperBounds();
+        ClassNode lowerBound = gt.getLowerBound();
+        if (upperBounds != null) {
+            if (upperBounds.length != 1 || !"java.lang.Object".equals(getPrintName(upperBounds[0]))) {
+                ret.append(" extends ");
+                for (int i = 0; i < upperBounds.length; i++) {
+                    ret.append(getPrintName(upperBounds[i]));
+                    if (i + 1 < upperBounds.length) ret.append(" & ");
+                }
+            }
+        } else if (lowerBound != null) {
+            ret.append(" super ").append(getPrintName(lowerBound));
+        }
+        return ret.toString();
+    }
+
+    private static String getPrintName(ClassNode cn) {
+        StringBuilder ret = new StringBuilder(cn.getName());
+        GenericsType[] gts = cn.getGenericsTypes();
+        if (gts != null) {
+            ret.append("<");
+            for (int i = 0; i < gts.length; i++) {
+                if (i != 0) ret.append(",");
+                ret.append(getPrintName(gts[i]));
+            }
+            ret.append(">");
+        }
+        return ret.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/HasCleanup.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/HasCleanup.java b/src/main/java/org/codehaus/groovy/control/HasCleanup.java
new file mode 100644
index 0000000..e7f2365
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/HasCleanup.java
@@ -0,0 +1,31 @@
+/*
+ *  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.control;
+
+/**
+ *  An interface for things that need to be cleaned up after
+ *  operations complete.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public interface HasCleanup 
+{
+    void cleanup();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/Janitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/Janitor.java b/src/main/java/org/codehaus/groovy/control/Janitor.java
new file mode 100644
index 0000000..8d08ebd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/Janitor.java
@@ -0,0 +1,55 @@
+/*
+ *  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.control;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ *  An agent that can be used to defer cleanup operations to 
+ *  a later time.  Users much implement the HasCleanup interface.  
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class Janitor implements HasCleanup
+{
+    private final Set pending = new HashSet();   // All objects pending cleanup
+    
+    public void register( HasCleanup object )
+    {
+        pending.add( object );
+    }
+    
+    public void cleanup()
+    {
+        Iterator iterator = pending.iterator();
+        while( iterator.hasNext() )
+        {
+            HasCleanup object = (HasCleanup)iterator.next();
+            
+            try { object.cleanup(); } catch( Exception e ) {
+                // Ignore
+            }
+        }
+        
+        pending.clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/LabelVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/LabelVerifier.java b/src/main/java/org/codehaus/groovy/control/LabelVerifier.java
new file mode 100644
index 0000000..1aea0be
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/LabelVerifier.java
@@ -0,0 +1,174 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.stmt.BreakStatement;
+import org.codehaus.groovy.ast.stmt.ContinueStatement;
+import org.codehaus.groovy.ast.stmt.DoWhileStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This class checks the handling of labels in the AST
+ *
+ * @author Jochen Theodorou
+ */
+public class LabelVerifier extends ClassCodeVisitorSupport {
+
+    private final SourceUnit source;
+    private LinkedList<String> visitedLabels;
+    private LinkedList<ContinueStatement> continueLabels;
+    private LinkedList<BreakStatement> breakLabels;
+    boolean inLoop = false;
+    boolean inSwitch = false;
+
+    public LabelVerifier(SourceUnit src) {
+        source = src;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    private void init() {
+        visitedLabels = new LinkedList<String>();
+        continueLabels = new LinkedList<ContinueStatement>();
+        breakLabels = new LinkedList<BreakStatement>();
+        inLoop = false;
+        inSwitch = false;
+    }
+
+    protected void visitClassCodeContainer(Statement code) {
+        init();
+        super.visitClassCodeContainer(code);
+        assertNoLabelsMissed();
+    }
+
+    public void visitStatement(Statement statement) {
+        List<String> labels = statement.getStatementLabels();
+
+        if (labels != null) {
+            for (String label : labels) {
+                if (breakLabels != null) {
+                    for (Iterator<BreakStatement> iter = breakLabels.iterator(); iter.hasNext(); ) {
+                        if (iter.next().getLabel().equals(label)) iter.remove();
+                    }
+                }
+                if (continueLabels != null) {
+                    for (Iterator<ContinueStatement> iter = continueLabels.iterator(); iter.hasNext(); ) {
+                        if (iter.next().getLabel().equals(label)) iter.remove();
+                    }
+                }
+                if (visitedLabels != null) {
+                    visitedLabels.add(label);
+                }
+            }
+        }
+
+        super.visitStatement(statement);
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitForLoop(forLoop);
+        inLoop = oldInLoop;
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitDoWhileLoop(loop);
+        inLoop = oldInLoop;
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        boolean oldInLoop = inLoop;
+        inLoop = true;
+        super.visitWhileLoop(loop);
+        inLoop = oldInLoop;
+    }
+
+    public void visitBreakStatement(BreakStatement statement) {
+        String label = statement.getLabel();
+        boolean hasNamedLabel = label != null;
+        if (!hasNamedLabel && !inLoop && !inSwitch) {
+            addError("the break statement is only allowed inside loops or switches", statement);
+        } else if (hasNamedLabel && !inLoop) {
+            addError("the break statement with named label is only allowed inside loops", statement);
+        }
+        if (label != null) {
+            boolean found = false;
+            for (String element : visitedLabels) {
+                if (element.equals(label)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) breakLabels.add(statement);
+        }
+
+        super.visitBreakStatement(statement);
+    }
+
+    public void visitContinueStatement(ContinueStatement statement) {
+        String label = statement.getLabel();
+        boolean hasNamedLabel = label != null;
+        if (!hasNamedLabel && !inLoop) {
+            addError("the continue statement is only allowed inside loops", statement);
+        }
+        if (label != null) {
+            boolean found = false;
+            for (String element : visitedLabels) {
+                if (element.equals(label)) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) continueLabels.add(statement);
+        }
+
+        super.visitContinueStatement(statement);
+    }
+
+    protected void assertNoLabelsMissed() {
+        //TODO: report multiple missing labels of the same name only once?
+        for (ContinueStatement element : continueLabels) {
+            addError("continue to missing label", element);
+        }
+        for (BreakStatement element : breakLabels) {
+            addError("break to missing label", element);
+        }
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        boolean oldInSwitch = inSwitch;
+        inSwitch = true;
+        super.visitSwitch(statement);
+        inSwitch = oldInSwitch;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java b/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
new file mode 100644
index 0000000..0d7dc3c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/MultipleCompilationErrorsException.java
@@ -0,0 +1,64 @@
+/*
+ *  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.control;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * @author Jochen Theodorou
+ */
+public class MultipleCompilationErrorsException extends
+        CompilationFailedException {
+    
+    protected ErrorCollector collector;
+    
+    public MultipleCompilationErrorsException(ErrorCollector ec) {
+        super(0, null);
+        if (ec == null) {
+            CompilerConfiguration config = super.getUnit() != null ?
+                super.getUnit().getConfiguration() :
+                new CompilerConfiguration();
+            collector = new ErrorCollector(config);
+        } else {
+            collector = ec;
+        }
+    }
+
+    public ErrorCollector getErrorCollector() {
+        return collector;
+    }
+    
+    public String getMessage() {
+        StringWriter data = new StringWriter();
+        PrintWriter writer = new PrintWriter(data);
+        Janitor janitor = new Janitor();
+
+        writer.write(super.getMessage());
+        writer.println(":");
+        try {
+            collector.write(writer, janitor);
+        }
+        finally {
+            janitor.cleanup();
+        }
+
+        return data.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java b/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java
new file mode 100644
index 0000000..6bb343b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/OptimizerVisitor.java
@@ -0,0 +1,149 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
+
+/**
+ * Visitor to produce several optimizations:
+ * <ul>
+ * <li>to replace numbered constants with references to static fields</li>
+ * <li>remove superfluous references to GroovyObject interface</li>
+ * </ul>
+ */
+public class OptimizerVisitor extends ClassCodeExpressionTransformer {
+    private ClassNode currentClass;
+    private SourceUnit source;
+
+    // TODO make @CS lookup smarter so that we don't need both these maps
+    private final Map<Object, FieldNode> const2Objects = new HashMap<Object, FieldNode>();
+    private final Map<Object, FieldNode> const2Prims = new HashMap<Object, FieldNode>();
+    private int index;
+    private final List<FieldNode> missingFields = new LinkedList<FieldNode>();
+
+    public OptimizerVisitor(CompilationUnit cu) {
+    }
+
+    public void visitClass(ClassNode node, SourceUnit source) {
+        this.currentClass = node;
+        this.source = source;
+        const2Objects.clear();
+        const2Prims.clear();
+        missingFields.clear();
+        index = 0;
+        super.visitClass(node);
+        addMissingFields();
+        pruneUnneededGroovyObjectInterface(node);
+    }
+
+    private void pruneUnneededGroovyObjectInterface(ClassNode node) {
+        ClassNode superClass = node.getSuperClass();
+        boolean isSuperGroovy = superClass.isDerivedFromGroovyObject();
+        if (isSuperGroovy) {
+            ClassNode[] interfaces = node.getInterfaces();
+            boolean needsFix = false;
+            for (ClassNode classNode : interfaces) {
+                if (classNode.equals(ClassHelper.GROOVY_OBJECT_TYPE)) {
+                    needsFix = true;
+                    break;
+                }
+            }
+            if (needsFix) {
+                List<ClassNode> newInterfaces = new ArrayList<ClassNode>(interfaces.length);
+                for (ClassNode classNode : interfaces) {
+                    if (!classNode.equals(ClassHelper.GROOVY_OBJECT_TYPE)) {
+                        newInterfaces.add(classNode);
+                    }
+                }
+                node.setInterfaces(newInterfaces.toArray(new ClassNode[newInterfaces.size()]));
+            }
+        }
+    }
+
+    private void addMissingFields() {
+        for (FieldNode f : missingFields) {
+            currentClass.addField(f);
+        }
+    }
+
+    private void setConstField(ConstantExpression constantExpression) {
+        final Object n = constantExpression.getValue();
+        if (!(n instanceof Number)) return;
+        if (n instanceof Integer || n instanceof Double) return;
+        if (n instanceof Long && (0L == (Long) n || 1L == (Long) n)) return; // LCONST_0, LCONST_1
+
+        boolean isPrimitive = isPrimitiveType(constantExpression.getType());
+        FieldNode field = isPrimitive ? const2Prims.get(n) : const2Objects.get(n);
+        if (field != null) {
+            constantExpression.setConstantName(field.getName());
+            return;
+        }
+        String name;
+        while (true) {
+            name = "$const$" + index++;
+            if (currentClass.getDeclaredField(name) == null) break;
+        }
+        field = new FieldNode(name,
+                Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL,
+                constantExpression.getType(),
+                currentClass,
+                constantExpression);
+        field.setSynthetic(true);
+        missingFields.add(field);
+        constantExpression.setConstantName(field.getName());
+        if (isPrimitive) {
+            const2Prims.put(n, field);
+        } else {
+            const2Objects.put(n, field);
+        }
+    }
+
+    public Expression transform(Expression exp) {
+        if (exp == null) return null;
+        if (!currentClass.isInterface() && exp.getClass() == ConstantExpression.class) {
+            setConstField((ConstantExpression) exp);
+        }
+        return exp.transformExpression(this);
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        /*
+         * GROOVY-3339 - do nothing - so that numbers don't get replaced by cached constants in closure classes
+         */
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ParserPlugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ParserPlugin.java b/src/main/java/org/codehaus/groovy/control/ParserPlugin.java
new file mode 100644
index 0000000..9b298d8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ParserPlugin.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control;
+
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.syntax.ParserException;
+import org.codehaus.groovy.syntax.Reduction;
+
+import java.io.Reader;
+
+/**
+ * A simple extension point to allow us to switch between the classic Groovy parser and the new Antlr based parser
+ * 
+ */
+public interface ParserPlugin {
+
+    Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException;
+
+    ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException;
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java b/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
new file mode 100644
index 0000000..1d7a994
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ParserPluginFactory.java
@@ -0,0 +1,93 @@
+/*
+ *  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.control;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.antlr.AntlrParserPluginFactory;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * A factory of parser plugin instances
+ *
+ */
+public abstract class ParserPluginFactory {
+    private static Class<?> ANTLR4_CLASS=null;
+
+    /**
+     * creates the ANTLR 4 parser
+     * @return the factory for the parser
+     */
+    public static ParserPluginFactory antlr4() {
+        if (ANTLR4_CLASS==null) {
+            String name = "org.apache.groovy.parser.antlr4.Antlr4PluginFactory";
+            try {
+                ANTLR4_CLASS =
+                        Class.forName(name, false, ParserPluginFactory.class.getClassLoader());
+            } catch (Exception e) {
+                throw new GroovyRuntimeException("Could not find or load parser plugin factory for antlr4", e);
+            }
+        }
+        try {
+            return AccessController.doPrivileged(new PrivilegedExceptionAction<ParserPluginFactory>() {
+                public ParserPluginFactory run() throws Exception {
+                    return (ParserPluginFactory) ANTLR4_CLASS.newInstance();
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw new GroovyRuntimeException("Could not create instance of parser plugin factory for antlr4", e.getCause());
+        }
+    }
+
+    /**
+     * creates the ANTLR 2.7 parser
+     * @return the factory for the parser
+     */
+    public static ParserPluginFactory antlr2() {
+        return new AntlrParserPluginFactory();
+    }
+
+    /**
+     * creates the ANTLR 2.7 parser. This method was used to switch between the pre JSR
+     * parser and the new ANTLR 2.7 based parser, but even before Groovy 1.0 this
+     * method was changed to always return the ANTLR 2.7 parser.
+     * @param useNewParser - ignored
+     * @return the ANTLR 2.7 based parser
+     */
+    @Deprecated
+    public static ParserPluginFactory newInstance(boolean useNewParser) {
+        return newInstance();
+    }
+
+    /**
+     * creates the ANTLR 2.7 parser. This method was used to switch between the pre JSR
+     * parser and the new ANTLR 2.7 based parser, but even before Groovy 1.0 this
+     * method was changed to always return the ANTLR 2.7 parser.
+     *
+     * @return the new parser factory.
+     */
+    @Deprecated
+    public static ParserPluginFactory newInstance() {
+        return antlr2();
+    }
+
+    public abstract ParserPlugin createParserPlugin();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ParserVersion.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ParserVersion.java b/src/main/java/org/codehaus/groovy/control/ParserVersion.java
new file mode 100644
index 0000000..8440611
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ParserVersion.java
@@ -0,0 +1,50 @@
+/*
+ *  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.control;
+
+/**
+ * Represents the version of a parser
+ *
+ * @since 2.6.0
+ */
+public enum ParserVersion {
+    /**
+     * Before Groovy 2.6.0(including 2.6.0), the default version of parser is v2
+     */
+    V_2,
+
+    /**
+     * After Groovy 3.0.0(including 3.0.0), the default version of parser is v4(i.e. the new parser Parrot)
+     */
+    V_4("Parrot");
+
+    private String name;
+
+    ParserVersion() {
+        this(null);
+    }
+
+    ParserVersion(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/Phases.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/Phases.java b/src/main/java/org/codehaus/groovy/control/Phases.java
new file mode 100644
index 0000000..47e421f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/Phases.java
@@ -0,0 +1,67 @@
+/*
+ *  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.control;
+
+
+
+
+/**
+ *  Compilation phase identifiers.  
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class Phases
+{
+    public static final int INITIALIZATION        = 1;   // Opening of files and such
+    public static final int PARSING               = 2;   // Lexing, parsing, and AST building
+    public static final int CONVERSION            = 3;   // CST to AST conversion
+    public static final int SEMANTIC_ANALYSIS     = 4;   // AST semantic analysis and elucidation
+    public static final int CANONICALIZATION      = 5;   // AST completion
+    public static final int INSTRUCTION_SELECTION = 6;   // Class generation, phase 1
+    public static final int CLASS_GENERATION      = 7;   // Class generation, phase 2
+    public static final int OUTPUT                = 8;   // Output of class to disk
+    public static final int FINALIZATION          = 9;   // Cleanup
+    public static final int ALL                   = 9;   // Synonym for full compilation
+    
+    public static final String[] descriptions = {
+          "startup"
+        , "initialization"
+        , "parsing"
+        , "conversion"
+        , "semantic analysis"
+        , "canonicalization"
+        , "instruction selection"
+        , "class generation"
+        , "output"
+        , "cleanup"
+    };
+    
+    
+    
+   /**
+    *  Returns a description of the specified phase.
+    */
+    
+    public static String getDescription( int phase )
+    {
+        return descriptions[phase];
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java b/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java
new file mode 100644
index 0000000..d95822d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ProcessingUnit.java
@@ -0,0 +1,180 @@
+/*
+ *  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.control;
+
+import groovy.lang.GroovyClassLoader;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * A base class for data structures that can collect messages and errors
+ * during processing.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public abstract class ProcessingUnit {
+
+    /**
+     * The current phase
+     */
+    protected int phase;
+    /**
+     * Set true if phase is finished
+     */
+    protected boolean phaseComplete;
+
+    /**
+     * Configuration and other settings that control processing
+     */
+    protected CompilerConfiguration configuration;
+  
+    /**
+     * The ClassLoader to use during processing
+     */
+    protected GroovyClassLoader classLoader;
+    
+    /**
+     * a helper to share errors and report them
+     */
+    protected ErrorCollector errorCollector;
+
+
+    /**
+     * Initialize the ProcessingUnit to the empty state.
+     */
+
+    public ProcessingUnit(CompilerConfiguration configuration, GroovyClassLoader classLoader, ErrorCollector er) {
+
+        this.phase = Phases.INITIALIZATION;
+        this.configuration = configuration;
+        this.setClassLoader(classLoader);
+        configure((configuration == null ? new CompilerConfiguration() : configuration));
+        if (er==null) er = new ErrorCollector(getConfiguration());
+        this.errorCollector = er;
+    }
+
+
+    /**
+     * Reconfigures the ProcessingUnit.
+     */
+    public void configure(CompilerConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+
+    public CompilerConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(CompilerConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    /**
+     * Returns the class loader in use by this ProcessingUnit.
+     */
+
+    public GroovyClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+
+    /**
+     * Sets the class loader for use by this ProcessingUnit.
+     */
+
+    public void setClassLoader(final GroovyClassLoader loader) {
+        // Classloaders should only be created inside doPrivileged block
+        // This code creates a classloader, which needs permission if a security manage is installed.
+        // If this code might be invoked by code that does not have security permissions, then the classloader creation needs to occur inside a doPrivileged block.
+        this.classLoader = AccessController.doPrivileged(new PrivilegedAction<GroovyClassLoader>() {
+            public GroovyClassLoader run() {
+                ClassLoader parent = Thread.currentThread().getContextClassLoader();
+                if (parent == null) parent = ProcessingUnit.class.getClassLoader();
+                return loader == null ? new GroovyClassLoader(parent, configuration) : loader;
+            }
+        });
+    }
+
+
+    /**
+     * Returns the current phase.
+     */
+
+    public int getPhase() {
+        return this.phase;
+    }
+
+
+    /**
+     * Returns the description for the current phase.
+     */
+
+    public String getPhaseDescription() {
+        return Phases.getDescription(this.phase);
+    }
+
+    /**
+     * Errors found during the compilation should be reported through the ErrorCollector.
+     * @return
+     *      the ErrorCollector for this ProcessingUnit
+     */
+    public ErrorCollector getErrorCollector() {
+        return errorCollector;
+    }
+    
+    //---------------------------------------------------------------------------
+    // PROCESSING
+
+
+    /**
+     * Marks the current phase complete and processes any
+     * errors.
+     */
+
+    public void completePhase() throws CompilationFailedException {       
+        errorCollector.failIfErrors();
+        phaseComplete = true;
+    }
+
+
+    /**
+     * A synonym for <code>gotoPhase( phase + 1 )</code>.
+     */
+    public void nextPhase() throws CompilationFailedException {
+        gotoPhase(this.phase + 1);
+    }
+
+
+    /**
+     * Wraps up any pending operations for the current phase
+     * and switches to the next phase.
+     */
+    public void gotoPhase(int phase) throws CompilationFailedException {
+        if (!this.phaseComplete) {
+            completePhase();
+        }
+
+        this.phase = phase;
+        this.phaseComplete = false;
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/NodePrinter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/NodePrinter.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/NodePrinter.java
new file mode 100644
index 0000000..2710f4d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/NodePrinter.java
@@ -0,0 +1,52 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+import java.io.PrintStream;
+
+/**
+ * A simple antlr AST visitor that outputs the tokenName of each node in a pseudo xml style.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public class NodePrinter extends VisitorAdapter {
+    private final String[] tokenNames;
+    private final PrintStream out;
+
+    /**
+     * A visitor that prints a pseudo xml output to the supplied PrintStream
+     * @param out supplied PrintStream to output nodes to
+     * @param tokenNames an array of token names to use
+     */
+    public NodePrinter(PrintStream out,String[] tokenNames) {
+        this.tokenNames = tokenNames;
+        this.out = out;
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            out.print("<"+ tokenNames[t.getType()] + ">");
+        } else {
+            out.print("</" + tokenNames[t.getType()] + ">");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/PreOrderTraversal.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/PreOrderTraversal.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/PreOrderTraversal.java
new file mode 100644
index 0000000..7cbd032
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/PreOrderTraversal.java
@@ -0,0 +1,45 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+
+/**
+ * A simple preorder traversal over the supplied antlr AST.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+public class PreOrderTraversal extends TraversalHelper {
+    
+    /**
+     * A simple preorder traversal over the supplied antlr AST.
+     * @param visitor the Visitor to call for each node visited 
+     */
+    public PreOrderTraversal(Visitor visitor) {
+        super(visitor);
+    }
+
+    public void accept(GroovySourceAST currentNode) {
+        push(currentNode);
+        openingVisit(currentNode);
+        acceptChildren(currentNode);
+        closingVisit(currentNode);
+        pop();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.java
new file mode 100644
index 0000000..ce2a236
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/SourceCodeTraversal.java
@@ -0,0 +1,260 @@
+/*
+ *  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.antlr.treewalker;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * A treewalker for the antlr generated AST that attempts to visit the
+ * AST nodes in the order needed to generate valid groovy source code.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+public class SourceCodeTraversal extends TraversalHelper {
+    /**
+     * Constructs a treewalker for the antlr generated AST that attempts to visit the
+     * AST nodes in the order needed to generate valid groovy source code.
+     * @param visitor the visitor implementation to call for each AST node.
+     */
+    public SourceCodeTraversal(Visitor visitor) {
+        super(visitor);
+    }
+
+    /**
+     * gather, sort and process all unvisited nodes
+     * @param t the AST to process
+     */
+    public void setUp(GroovySourceAST t) {
+        super.setUp(t);
+        
+        // gather and sort all unvisited AST nodes
+        unvisitedNodes = new ArrayList<GroovySourceAST>();
+        traverse(t);
+        Collections.sort(unvisitedNodes);
+    }
+
+    /**
+     * traverse an AST node
+     * @param t the AST node to traverse
+     */
+    private void traverse(GroovySourceAST t) {
+        if (t == null) { return; }
+        if (unvisitedNodes != null) {
+           unvisitedNodes.add(t);
+        }
+        GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
+        if (child != null) {
+            traverse(child);
+        }
+        GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
+        if (sibling != null) {
+            traverse(sibling);
+        }
+    }
+
+    protected void accept(GroovySourceAST currentNode) {
+        if (currentNode != null && unvisitedNodes != null && !unvisitedNodes.isEmpty()) {
+            GroovySourceAST t = currentNode;
+
+            if (!(unvisitedNodes.contains(currentNode))) {
+                return;
+            }
+            push(t);
+            switch (t.getType()) {
+                case GroovyTokenTypes.QUESTION: // expr?foo:bar
+                    accept_FirstChild_v_SecondChild_v_ThirdChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.CASE_GROUP: //
+                case GroovyTokenTypes.LITERAL_instanceof: // foo instanceof MyType
+                    accept_FirstChild_v_SecondChildsChildren_v(t);
+                    break;
+
+                case GroovyTokenTypes.ANNOTATION:
+                    accept_v_FirstChild_2ndv_SecondChild_v___LastChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.CLOSURE_LIST: // (a=1; a<10; a++)
+                case GroovyTokenTypes.ELIST: // a,b,c
+                case GroovyTokenTypes.PARAMETERS: // a,b,c
+                case GroovyTokenTypes.TYPE_ARGUMENTS: // <String, Object>
+                case GroovyTokenTypes.STRING_CONSTRUCTOR: // "foo${bar}wibble"
+                case GroovyTokenTypes.TYPE_PARAMETER: // class Foo<T extends F>
+                case GroovyTokenTypes.TYPE_PARAMETERS: // class Foo<T>
+                case GroovyTokenTypes.TYPE_UPPER_BOUNDS: // class Foo<T extends F>
+                    accept_v_FirstChild_v_SecondChild_v___LastChild_v(t);
+                    // todo : confirm that TYPE_LOWER_BOUNDS does not have multiple children
+                    break;
+
+                case GroovyTokenTypes.VARIABLE_PARAMETER_DEF: // void f(String ... others) {}
+                    accept_v_FirstChild_SecondChild_v_ThirdChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.INDEX_OP:
+                    //accept_FirstChild_v_SecondChild_v(t);
+                    accept_SecondChild_v_ThirdChild_v(t);
+                    break;
+
+                case GroovyTokenTypes.ENUM_CONSTANT_DEF: // enum Foo(THESE,ARE,THEY)
+                case GroovyTokenTypes.EXPR:
+                case GroovyTokenTypes.IMPORT:
+                case GroovyTokenTypes.STATIC_IMPORT:
+                case GroovyTokenTypes.VARIABLE_DEF:
+                case GroovyTokenTypes.METHOD_DEF:
+                case GroovyTokenTypes.OBJBLOCK: //class Foo {def bar()}  <-- this block
+                case GroovyTokenTypes.PARAMETER_DEF: // void f(String me) {}
+                case GroovyTokenTypes.SLIST: // list of expressions, variable defs etc
+                    accept_v_AllChildren_v(t);
+                    break;
+
+                case GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR: // @Blue(foo=123)
+                case GroovyTokenTypes.ASSIGN: // a = b
+                case GroovyTokenTypes.BAND_ASSIGN: // a &= b
+                case GroovyTokenTypes.BOR_ASSIGN: // a |= b
+                case GroovyTokenTypes.BSR_ASSIGN: // a >>>= b
+                case GroovyTokenTypes.BXOR_ASSIGN: // a ^= b
+                case GroovyTokenTypes.COMPARE_TO: // a <=> b
+                case GroovyTokenTypes.DIV_ASSIGN: // a /= b
+                case GroovyTokenTypes.EQUAL: // a == b
+                case GroovyTokenTypes.MINUS_ASSIGN: // a -= b
+                case GroovyTokenTypes.MOD_ASSIGN: // a %= b
+                case GroovyTokenTypes.NOT_EQUAL: // a != b
+                case GroovyTokenTypes.PLUS_ASSIGN: // a += b
+                case GroovyTokenTypes.REGEX_FIND: // a =~ b
+                case GroovyTokenTypes.REGEX_MATCH: // a ==~ b
+                case GroovyTokenTypes.SL_ASSIGN: // a <<= b
+                case GroovyTokenTypes.SR_ASSIGN: // a >>= b
+                case GroovyTokenTypes.STAR_ASSIGN: // a *= b
+                case GroovyTokenTypes.STAR_STAR_ASSIGN: // x **= 3
+                    if (t.childAt(1) != null) {
+                        accept_FirstChild_v_RestOfTheChildren(t);
+                    } else {
+                        accept_v_FirstChild_v_RestOfTheChildren(t);
+                    }
+                    break;
+
+                case GroovyTokenTypes.ANNOTATION_FIELD_DEF: // @interface Foo{ int bar()...
+                    accept_FirstSecondAndThirdChild_v_v_ForthChild(t);
+                    break;
+                    
+                case GroovyTokenTypes.ANNOTATION_DEF: // @interface Foo...
+                case GroovyTokenTypes.BAND: // 1 & 2
+                case GroovyTokenTypes.BOR: // 1 | 2
+                case GroovyTokenTypes.BSR: // 1 >>> 2
+                case GroovyTokenTypes.BXOR: // 1 ^ 2
+                case GroovyTokenTypes.CLASS_DEF: // class Foo...
+                case GroovyTokenTypes.CTOR_IDENT: // private Foo() {...
+                case GroovyTokenTypes.DIV: //  3/4
+                case GroovyTokenTypes.DOT: // foo.bar
+                case GroovyTokenTypes.ENUM_DEF: // enum Foo...
+                case GroovyTokenTypes.GE: // a >= b
+                case GroovyTokenTypes.GT: // a > b
+                case GroovyTokenTypes.INTERFACE_DEF: // interface Foo...
+                case GroovyTokenTypes.LABELED_ARG: // myMethod(name:"Jez")
+                case GroovyTokenTypes.LABELED_STAT: // foo:x=1                        
+                case GroovyTokenTypes.LAND: // true && false
+                case GroovyTokenTypes.LE: // a <= b
+                case GroovyTokenTypes.LITERAL_as: // foo as Bar
+                case GroovyTokenTypes.LITERAL_in: // if (i in myList) ...
+                case GroovyTokenTypes.LOR: // true && false
+                case GroovyTokenTypes.LT: // a < b
+                case GroovyTokenTypes.MEMBER_POINTER: // this.&foo()
+                case GroovyTokenTypes.MOD: //  4 % 3
+                case GroovyTokenTypes.MINUS: // 1 - 1
+                case GroovyTokenTypes.OPTIONAL_DOT: // foo?.bar
+                case GroovyTokenTypes.PACKAGE_DEF:
+                case GroovyTokenTypes.PLUS: // 1 + 1
+                case GroovyTokenTypes.RANGE_EXCLUSIVE: // [1..<10]
+                case GroovyTokenTypes.RANGE_INCLUSIVE: // [1..10]
+                case GroovyTokenTypes.SL: // a << b
+                case GroovyTokenTypes.SPREAD_DOT: // foo*.bar
+                case GroovyTokenTypes.SR: // a >> b
+                case GroovyTokenTypes.STAR: // a * b   or    import foo.*
+                case GroovyTokenTypes.STAR_STAR: // x ** 3
+                case GroovyTokenTypes.TRAIT_DEF: // trait Foo...
+                    accept_FirstChild_v_RestOfTheChildren(t);
+                    break;
+
+                case GroovyTokenTypes.CTOR_CALL:
+                case GroovyTokenTypes.METHOD_CALL:
+                    if (t.getNumberOfChildren() == 2 && t.childAt(1) != null && t.childAt(1).getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
+                        // myMethod {...
+                        accept_FirstChild_v_SecondChild(t);
+                    } else {
+                        GroovySourceAST lastChild = t.childAt(t.getNumberOfChildren() -1);
+                        if (lastChild != null && lastChild.getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
+                            // myMethod(a,b) {...
+                            accept_FirstChild_v_RestOfTheChildren_v_LastChild(t);
+                        } else {
+                            // myMethod(a,b)
+                            accept_FirstChild_v_RestOfTheChildren_v(t);
+                        }
+                    }
+                    break;
+
+                case GroovyTokenTypes.LITERAL_while:
+//deprecated                case GroovyTokenTypes.LITERAL_with:
+                case GroovyTokenTypes.TYPECAST: // (String)itr.next()
+                    accept_v_FirstChildsFirstChild_v_RestOfTheChildren(t);
+                    break;
+
+                case GroovyTokenTypes.LITERAL_if: // if (grandchild) {child1} else {child2} ...
+                    accept_v_FirstChildsFirstChild_v_Child2_Child3_v_Child4_v___v_LastChild(t);
+                    break;
+
+                case GroovyTokenTypes.CLOSABLE_BLOCK: // [1,2,3].each {foo(it)}  <-- Closure
+                    if (t.childAt(0) != null && t.childAt(0).getType() == GroovyTokenTypes.IMPLICIT_PARAMETERS) {
+                        accept_v_AllChildren_v(t);
+                    } else {
+                        accept_v_FirstChild_v_RestOfTheChildren_v(t);
+                    }
+                    break;
+
+                case GroovyTokenTypes.FOR_IN_ITERABLE:
+                case GroovyTokenTypes.LITERAL_for:
+                case GroovyTokenTypes.LITERAL_new:
+                case GroovyTokenTypes.LITERAL_switch:
+                    accept_v_FirstChild_v_RestOfTheChildren_v(t);
+                    break;
+ 
+                case GroovyTokenTypes.ANNOTATIONS: // just like modifiers but for package/enum declarations
+                case GroovyTokenTypes.LITERAL_assert:
+                case GroovyTokenTypes.LITERAL_catch:
+                case GroovyTokenTypes.LITERAL_synchronized:
+                case GroovyTokenTypes.LITERAL_try:
+                case GroovyTokenTypes.MODIFIERS:
+                    accept_v_FirstChild_v_RestOfTheChildren(t);
+                    break;
+                    
+                case GroovyTokenTypes.WILDCARD_TYPE:
+                    accept_v_Siblings_v(t);
+                    break;
+
+                default:
+                    accept_v_FirstChild_v(t);
+                    break;
+            }
+            pop();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java b/src/main/java/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java
new file mode 100644
index 0000000..3db3565
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/treewalker/SourcePrinter.java
@@ -0,0 +1,1097 @@
+/*
+ *  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.antlr.treewalker;
+
+import antlr.collections.AST;
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+
+import java.io.PrintStream;
+import java.util.Stack;
+
+/**
+ * An antlr AST visitor that prints groovy source code for each visited node
+ * to the supplied PrintStream.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+public class SourcePrinter extends VisitorAdapter {
+    private final String[] tokenNames;
+    private int tabLevel;
+    private int lastLinePrinted;
+    private final boolean newLines;
+    protected final PrintStream out;
+    private String className;
+    private final Stack stack;
+    private int stringConstructorCounter;
+
+    /**
+     * A visitor that prints groovy source code for each node visited.
+     * @param out where to print the source code to
+     * @param tokenNames an array of token names from antlr
+     */
+    public SourcePrinter(PrintStream out,String[] tokenNames) {
+        this(out,tokenNames,true);
+    }
+
+    /**
+     * A visitor that prints groovy source code for each node visited.
+     * @param out where to print the source code to
+     * @param tokenNames an array of token names from antlr
+     * @param newLines output newline character
+     */
+    public SourcePrinter(PrintStream out,String[] tokenNames, boolean newLines) {
+        this.tokenNames = tokenNames;
+        tabLevel = 0;
+        lastLinePrinted = 0;
+        this.out = out;
+        this.newLines = newLines;
+        this.stack = new Stack();
+    }
+    
+
+    public void visitAbstract(GroovySourceAST t, int visit) {
+        print(t,visit,"abstract ",null,null);
+    }
+
+    public void visitAnnotation(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            print(t,visit,"@");
+        }
+        if (visit == SECOND_VISIT) {
+            print(t,visit,"(");
+        }
+        if (visit == SUBSEQUENT_VISIT) {
+            print(t,visit,", ");
+        }
+        if (visit == CLOSING_VISIT) {
+            if (t.getNumberOfChildren() > 1) {
+                print(t,visit,") ");
+            } else {
+                print(t,visit," ");
+            }
+        }
+
+    }
+
+    public void visitAnnotations(GroovySourceAST t, int visit) {
+        // do nothing
+    }
+
+    public void visitAnnotationDef(GroovySourceAST t,int visit) {
+        print(t,visit,"@interface ",null,null);
+    }
+
+    public void visitAnnotationFieldDef(GroovySourceAST t, int visit) {
+        print(t,visit,"() ","default ",null);
+    }
+
+    public void visitAnnotationMemberValuePair(GroovySourceAST t, int visit) {
+        print(t,visit," = ",null,null);
+    }
+
+    public void visitArrayDeclarator(GroovySourceAST t, int visit) {
+        //<ARRAY_DECLARATOR>int</ARRAY_DECLARATOR> primes = new int(<ARRAY_DECLARATOR>5</ARRAY_DECLARATOR>)
+        if (getParentNode().getType() == GroovyTokenTypes.TYPE ||
+                getParentNode().getType() == GroovyTokenTypes.TYPECAST) { // ugly hack
+            // type definition, i.e.   int[] x;
+            print(t,visit,null,null,"[]");
+        } else {
+            // usually in new, i.e.   def y = new int[5];
+            print(t,visit,"[",null,"]");
+        }
+    }
+
+    public void visitAssign(GroovySourceAST t,int visit) {
+        print(t,visit," = ",null,null);
+    }
+    
+    // visitAt() ...
+    //   token type 'AT' should never be visited, as annotation definitions and usage, and
+    //   direct field access should have all moved this token out of the way. No test needed.
+
+    //   one of the BAND tokens is actually replaced by TYPE_UPPER_BOUNDS (e.g. class Foo<T extends C & I> {T t} )
+    public void visitBand(GroovySourceAST t, int visit) {
+        print(t,visit," & ",null,null);
+    }
+
+    public void visitBandAssign(GroovySourceAST t,int visit) {
+        print(t,visit," &= ",null,null);
+    }
+    
+    // visitBigSuffix() ...
+    //   token type BIG_SUFFIX never created/visited, NUM_BIG_INT, NUM_BIG_DECIMAL instead...    
+    
+    // visitBlock() ...
+    //   token type BLOCK never created/visited, see CLOSABLE_BLOCK etc...
+    
+    public void visitBnot(GroovySourceAST t, int visit) {
+        print(t,visit,"~",null,null);
+    }
+    
+    // Note: old closure syntax using BOR is deprecated, and also never creates/visits a BOR node
+    public void visitBor(GroovySourceAST t, int visit) {
+        print(t,visit," | ",null,null);
+    }
+    
+    public void visitBorAssign(GroovySourceAST t,int visit) {
+        print(t,visit," |= ",null,null);
+    }
+    
+    public void visitBsr(GroovySourceAST t, int visit) {
+        print(t,visit," >>> ",null,null);
+    }
+    
+    public void visitBsrAssign(GroovySourceAST t,int visit) {
+        print(t,visit," >>>= ",null,null);
+    }
+    
+    public void visitBxor(GroovySourceAST t, int visit) {
+        print(t,visit," ^ ",null,null);
+    }
+    
+    public void visitBxorAssign(GroovySourceAST t,int visit) {
+        print(t,visit," ^= ",null,null);
+    }
+    
+    public void visitCaseGroup(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            tabLevel++;
+        }
+        if (visit == CLOSING_VISIT) {
+            tabLevel--;
+        }
+    }
+
+    public void visitClassDef(GroovySourceAST t,int visit) {
+        print(t,visit,"class ",null,null);
+
+        if (visit == OPENING_VISIT) {
+            // store name of class away for use in constructor ident
+            className = t.childOfType(GroovyTokenTypes.IDENT).getText();
+        }
+    }
+
+    public void visitClosedBlock(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"{","-> ","}");
+    }
+    
+    public void visitClosureList(GroovySourceAST t, int visit) {
+        print(t,visit,"(","; ",")");
+    }
+    // visitClosureOp ...
+    //   token type CLOSABLE_BLOCK_OP never created/visited, see CLOSABLE_BLOCK...
+    
+
+    // visitColon ...
+    //   token type COLON never created/visited, see LABELED_STAT, FOR_IN_ITERABLE, 
+    //   ASSERT, CASE, QUESTION, MAP_CONSTRUCTOR, LABELED_ARG, SPREAD_MAP_ARG
+
+    // visitComma ...
+    //   token type COMMA never created/visited,
+    //   see TYPE_ARGUMENTS, ANNOTATION, many others ...
+    
+    public void visitCompareTo(GroovySourceAST t,int visit) {
+        print(t,visit," <=> ",null,null);
+    }
+
+    public void visitCtorCall(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t,visit,"this("," ",")");
+    }
+
+    public void visitCtorIdent(GroovySourceAST t, int visit) {
+        // use name of class for constructor from the class definition
+        print(t,visit,className,null,null);
+    }
+
+    public void visitDec(GroovySourceAST t, int visit) {
+        print(t,visit,"--",null,null);
+    }
+    
+    // visitDigit ...
+    //    never created/visited
+    
+    public void visitDiv(GroovySourceAST t, int visit) {
+        print(t,visit," / ",null,null);
+    }
+
+    public void visitDivAssign(GroovySourceAST t,int visit) {
+        print(t,visit," /= ",null,null);
+    }
+    
+    // visitDollar ...
+    //   token type DOLLAR never created/visited, see SCOPE_ESCAPE instead
+    
+    public void visitDot(GroovySourceAST t,int visit) {
+        print(t,visit,".",null,null);
+    }
+    
+    public void visitDynamicMember(GroovySourceAST t, int visit) {
+        if (t.childOfType(GroovyTokenTypes.STRING_CONSTRUCTOR) == null) {
+            printUpdatingTabLevel(t,visit,"(",null,")");
+        }
+    }
+    
+    public void visitElist(GroovySourceAST t,int visit) {
+        if (getParentNode().getType() == GroovyTokenTypes.ENUM_CONSTANT_DEF) {
+            print(t,visit,"(",", ",")");
+        } else {
+            print(t,visit,null,", ",null);
+        }
+    }
+
+    // visitEmptyStat ...
+    //   token type EMPTY_STAT obsolete and should be removed, never visited/created
+    
+    public void visitEnumConstantDef(GroovySourceAST t,int visit) {
+        GroovySourceAST sibling = (GroovySourceAST)t.getNextSibling();
+        if (sibling != null && sibling.getType() == GroovyTokenTypes.ENUM_CONSTANT_DEF) {
+            print(t,visit,null,null,", ");
+        }
+    }
+
+    public void visitEnumDef(GroovySourceAST t,int visit) {
+        print(t,visit,"enum ",null,null);
+    }
+
+    // visitEof ...
+    //   token type EOF never visited/created
+
+    public void visitEqual(GroovySourceAST t,int visit) {
+        print(t,visit," == ",null,null);
+    }
+
+    // visitExponent ...
+    //   token type EXPONENT only used by lexer, never visited/created
+    
+    public void visitExpr(GroovySourceAST t,int visit) {
+        // do nothing
+    }
+
+    public void visitExtendsClause(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            if (t.getNumberOfChildren() != 0) {
+                print(t,visit," extends ");
+            }
+        }
+    }
+    
+    public void visitFinal(GroovySourceAST t, int visit) {
+        print(t,visit,"final ",null,null);
+    }
+
+    // visitFloatSuffix ... never visited/created see NUM_DOUBLE or NUM_FLOAT instead
+    
+    public void visitForCondition(GroovySourceAST t, int visit) {
+        print(t,visit," ; ",null,null);
+    }
+    
+    // visitForEachClause ... 
+    //   FOR_EACH_CLAUSE obsolete and should be removed, never visited/created
+
+    public void visitForInit(GroovySourceAST t, int visit) {
+        print(t,visit,"(",null,null);
+    }
+    
+    public void visitForInIterable(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"("," in ",") ");
+    }
+
+    public void visitForIterator(GroovySourceAST t, int visit) {
+        print(t,visit," ; ",null,")");
+    }
+    
+    public void visitGe(GroovySourceAST t, int visit) {
+        print(t,visit," >= ",null,null);
+    }
+    
+    public void visitGt(GroovySourceAST t, int visit) {
+        print(t,visit," > ",null,null);
+    }
+
+    public void visitIdent(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitImplementsClause(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            if (t.getNumberOfChildren() != 0) {
+                print(t,visit," implements ");
+            }
+        }
+        if (visit == CLOSING_VISIT) {
+            //space between classdef and objblock
+            print(t,visit," ");
+        }
+    }
+
+    public void visitImplicitParameters(GroovySourceAST t, int visit) {
+        // do nothing
+    }
+
+    public void visitImport(GroovySourceAST t,int visit) {
+        print(t,visit,"import ",null,null);
+    }
+
+    public void visitInc(GroovySourceAST t, int visit) {
+        print(t,visit,"++",null,null);
+    }
+
+    public void visitIndexOp(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"[",null,"]");
+    }
+
+    public void visitInterfaceDef(GroovySourceAST t,int visit) {
+        print(t,visit,"interface ",null,null);
+    }
+
+    public void visitInstanceInit(GroovySourceAST t, int visit) {
+        // do nothing
+    }
+
+    public void visitLabeledArg(GroovySourceAST t, int visit) {
+        print(t,visit,":",null,null);
+    }
+
+    public void visitLabeledStat(GroovySourceAST t, int visit) {
+        print(t,visit,":",null,null);
+    }
+
+    public void visitLand(GroovySourceAST t, int visit) {
+        print(t,visit," && ",null,null);
+    }
+
+    // visit lbrack()
+    //   token type LBRACK only used inside parser, never visited/created
+
+    // visit lcurly()
+    //   token type LCURLY only used inside parser, never visited/created
+    
+    public void visitLe(GroovySourceAST t, int visit) {
+        print(t,visit," <= ",null,null);
+    }
+
+    // visitLetter ...
+    //   token type LETTER only used by lexer, never visited/created
+
+    public void visitListConstructor(GroovySourceAST t, int visit) {
+        printUpdatingTabLevel(t,visit,"[",null,"]");
+    }
+
+    public void visitLiteralAs(GroovySourceAST t,int visit) {
+        print(t,visit," as ",null,null);
+    }
+
+    public void visitLiteralAssert(GroovySourceAST t,int visit) {
+        if (t.getNumberOfChildren() > 1) {
+            print(t,visit,"assert ",null," : ");
+        } else {
+            print(t,visit,"assert ",null,null);
+        }
+    }
+
+    public void visitLiteralBoolean(GroovySourceAST t, int visit) {
+        print(t,visit,"boolean",null,null);
+    }
+
+    public void visitLiteralBreak(GroovySourceAST t, int visit) {
+        print(t,visit,"break ",null,null);
+    }
+
+    public void visitLiteralByte(GroovySourceAST t, int visit) {
+        print(t,visit,"byte",null,null);
+    }
+
+    public void visitLiteralCase(GroovySourceAST t, int visit) {
+        print(t,visit,"case ",null,":");
+    }
+
+    public void visitLiteralCatch(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t, visit, " catch (", null, ") ");
+    }
+
+    public void visitLiteralChar(GroovySourceAST t, int visit) {
+        print(t,visit,"char",null,null);
+    }
+
+    // visitLiteralClass ...
+    //   token type "class" only used by parser, never visited/created directly
+
+    public void visitLiteralContinue(GroovySourceAST t, int visit) {
+        print(t,visit,"continue ",null,null);
+    }
+
+    // visitLiteralDef ...
+    //   token type "def" only used by parser, never visited/created directly
+
+    public void visitLiteralDefault(GroovySourceAST t,int visit) {
+        print(t,visit,"default",null,":");
+    }
+
+    public void visitLiteralDouble(GroovySourceAST t, int visit) {
+        print(t,visit,"double",null,null);
+    }
+
+    // visitLiteralElse ...
+    //   token type "else" only used by parser, never visited/created directly
+
+    // visitLiteralEnum ...
+    //   token type "enum" only used by parser, never visited/created directly
+
+    // visitLiteralExtends
+    //   token type "extends" only used by parser, never visited/created directly
+    
+    public void visitLiteralFalse(GroovySourceAST t,int visit) {
+        print(t,visit,"false",null,null);
+    }
+
+    public void visitLiteralFinally(GroovySourceAST t,int visit) {
+        print(t,visit,"finally ",null,null);
+    }
+    public void visitLiteralFloat(GroovySourceAST t,int visit) {
+        print(t,visit,"float",null,null);
+    }
+
+    public void visitLiteralFor(GroovySourceAST t,int visit) {
+        print(t,visit,"for ",null,null);
+    }
+    
+    public void visitLiteralIf(GroovySourceAST t,int visit) {
+        // slightly strange as subsequent visit is done after closing visit
+        printUpdatingTabLevel(t,visit,"if ("," else ",") ");
+    }
+
+    // visitLiteralImplements
+    //   token type "implements" only used by parser, never visited/created directly
+
+    // visitLiteralImport
+    //   token type "import" only used by parser, never visited/created directly
+
+    public void visitLiteralIn(GroovySourceAST t, int visit) {
+        print(t,visit," in ",null,null);
+    }
+
+    public void visitLiteralInstanceof(GroovySourceAST t, int visit) {
+        print(t,visit," instanceof ",null,null);
+    }
+
+    public void visitLiteralInt(GroovySourceAST t,int visit) {
+        print(t,visit,"int",null,null);
+    }
+
+    // visitLiteralInterface
+    //   token type "interface" only used by parser, never visited/created directly
+
+    public void visitLiteralLong(GroovySourceAST t,int visit) {
+        print(t,visit,"long",null,null);
+    }
+
+    public void visitLiteralNative(GroovySourceAST t,int visit) {
+        print(t,visit,"native ",null,null);
+    }
+    public void visitLiteralNew(GroovySourceAST t,int visit) {
+        if (t.childOfType(GroovyTokenTypes.ARRAY_DECLARATOR) == null) {
+            // only print parenthesis if is not of form def x = new int[5]
+            print(t,visit,"new ","(",")");
+        } else {
+            print(t,visit,"new ",null,null);
+        }
+    }
+
+    public void visitLiteralNull(GroovySourceAST t, int visit) {
+        print(t,visit,"null",null,null);
+    }
+
+    // visitLiteralPackage
+    //   token type "package" only used by parser, never visited/created directly
+
+    public void visitLiteralPrivate(GroovySourceAST t,int visit) {
+        print(t,visit,"private ",null,null);
+    }
+
+    public void visitLiteralProtected(GroovySourceAST t,int visit) {
+        print(t,visit,"protected ",null,null);
+    }
+
+    public void visitLiteralPublic(GroovySourceAST t,int visit) {
+        print(t,visit,"public ",null,null);
+    }
+
+    public void visitLiteralReturn(GroovySourceAST t, int visit) {
+        print(t,visit,"return ",null,null);
+    }
+
+    public void visitLiteralShort(GroovySourceAST t,int visit) {
+        print(t,visit,"short",null,null);
+    }
+
+    public void visitLiteralStatic(GroovySourceAST t, int visit) {
+        print(t,visit,"static ",null,null);
+    }
+
+    public void visitLiteralSuper(GroovySourceAST t, int visit) {
+        // only visited when calling super() without parentheses, i.e. "super 99" is equivalent to "super(99)"
+        print(t,visit,"super",null,null);
+    }
+
+    public void visitLiteralSwitch(GroovySourceAST t, int visit) {
+        if (visit == OPENING_VISIT) {
+            print(t,visit,"switch (");
+            tabLevel++;
+        }
+        if (visit == SUBSEQUENT_VISIT) {
+            print(t,visit,") {");
+        }
+        if (visit == CLOSING_VISIT) {
+            tabLevel--;
+            print(t,visit,"}");
+        }
+    }
+
+    public void visitLiteralSynchronized(GroovySourceAST t,int visit) {
+        if (t.getNumberOfChildren() > 0) {
+            print(t,visit,"synchronized (",null,") ");
+        } else {
+            print(t,visit,"synchronized ",null,null);            
+        }
+    }
+
+    public void visitLiteralThis(GroovySourceAST t, int visit) {
+        print(t,visit,"this",null,null);
+    }
+
+    public void visitLiteralThreadsafe(GroovySourceAST t,int visit) {
+        print(t,visit,"threadsafe ",null,null);
+    }
+
+    public void visitLiteralThrow(GroovySourceAST t, int visit) {
+        print(t,visit,"throw ",null,null);
+    }
+
+    public void visitLiteralThrows(GroovySourceAST t, int visit) {
+        print(t,visit,"throws ",null,null);
+    }
+
+    public void visitLiteralTransient(GroovySourceAST t,int visit) {
+        print(t,visit,"transient ",null,null);
+    }
+
+    public void visitLiteralTrue(GroovySourceAST t,int visit) {
+        print(t,visit,"true",null,null);
+    }
+    public void visitLiteralTry(GroovySourceAST t,int visit) {
+        print(t,visit,"try ",null,null);
+    }
+    public void visitLiteralVoid(GroovySourceAST t,int visit) {
+        print(t,visit,"void",null,null);
+    }
+    public void visitLiteralVolatile(GroovySourceAST t,int visit) {
+        print(t,visit,"volatile ",null,null);
+    }
+    public void visitLiteralWhile(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t,visit,"while (",null,") ");
+    }
+
+//deprecated
+//  public void visitLiteralWith(GroovySourceAST t,int visit) {
+//        printUpdatingTabLevel(t,visit,"with (",null,") ");
+//    }
+    
+    public void visitLnot(GroovySourceAST t, int visit) {
+        print(t,visit,"!",null,null);
+    }
+
+    // Note: old closure syntax using LOR is deprecated, and also never creates/visits a LOR node
+    public void visitLor(GroovySourceAST t, int visit) {
+        print(t,visit," || ",null,null);
+    }
+
+    public void visitLt(GroovySourceAST t, int visit) {
+        print(t,visit," < ",null,null);
+    }
+
+    public void visitMapConstructor(GroovySourceAST t, int visit) {
+        if (t.getNumberOfChildren() == 0) {
+            print(t,visit,"[:]",null,null);
+        } else {
+            printUpdatingTabLevel(t,visit,"[",null,"]");
+        }
+    }
+
+    public void visitMemberPointer(GroovySourceAST t, int visit) {
+        print(t,visit,".&",null,null);
+    }
+
+    public void visitMethodCall(GroovySourceAST t,int visit) {
+        if ("<command>".equals(t.getText())) {
+            printUpdatingTabLevel(t,visit," "," ",null);
+        } else {
+            printUpdatingTabLevel(t,visit,"("," ",")");
+        }
+    }
+    public void visitMethodDef(GroovySourceAST t,int visit) {
+        //do nothing
+    }
+    public void visitMinus(GroovySourceAST t,int visit) {
+        print(t,visit," - ",null,null);
+    }
+    public void visitMinusAssign(GroovySourceAST t, int visit) {
+        print(t,visit," -= ",null,null);
+    }
+
+    // visitMlComment
+    //   multi-line comments are not created on the AST currently.
+
+    public void visitMod(GroovySourceAST t, int visit) {
+        print(t,visit," % ",null,null);
+    }
+
+    public void visitModifiers(GroovySourceAST t,int visit) {
+        //do nothing
+    }
+    public void visitModAssign(GroovySourceAST t, int visit) {
+        print(t,visit," %= ",null,null);
+    }
+
+    @Override
+    public void visitMultiCatch(final GroovySourceAST t, final int visit) {
+        if (visit == CLOSING_VISIT) {
+            final AST child = t.getFirstChild();
+            if ("MULTICATCH_TYPES".equals(child.getText())) {
+                print(t, visit, null, null, " "+child.getNextSibling().getText());
+            } else {
+                print(t, visit, null, null, " "+child.getFirstChild().getText());
+            }
+        }
+    }
+
+    @Override
+    public void visitMultiCatchTypes(final GroovySourceAST t, final int visit) {
+    }
+
+    // visitNls
+    //   new lines are used by parser, but are not created on the AST,
+    //   they can be implied by the source code line/column information
+
+    // visitNullTreeLookahead
+    //   not used explicitly by parser.
+    
+    
+    public void visitNotEqual(GroovySourceAST t, int visit) {
+        print(t,visit," != ",null,null);
+    }
+
+    public void visitNumBigDecimal(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumBigInt(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumDouble(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumInt(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumFloat(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitNumLong(GroovySourceAST t,int visit) {
+        print(t,visit,t.getText(),null,null);
+    }
+    public void visitObjblock(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            tabLevel++;
+            print(t,visit,"{");
+        } else {
+            tabLevel--;
+            print(t,visit,"}");
+        }
+    }
+
+    // visitOneNl
+    //   new lines are used by parser, but are not created on the AST,
+    //   they can be implied by the source code line/column information
+
+    public void visitOptionalDot(GroovySourceAST t,int visit) {
+        print(t,visit,"?.",null,null);
+    }
+    
+    public void visitPackageDef(GroovySourceAST t, int visit) {
+        print(t,visit,"package ",null,null);
+    }
+
+    public void visitParameterDef(GroovySourceAST t,int visit) {
+        //do nothing
+    }
+
+    public void visitParameters(GroovySourceAST t,int visit) {
+        if (getParentNode().getType() == GroovyTokenTypes.CLOSABLE_BLOCK) {
+            printUpdatingTabLevel(t,visit,null,","," ");
+        } else {
+            printUpdatingTabLevel(t,visit,"(",", ",") ");
+        }
+    }
+
+    public void visitPlus(GroovySourceAST t, int visit) {
+        print(t,visit," + ",null,null);
+    }
+    
+    public void visitPlusAssign(GroovySourceAST t, int visit) {
+        print(t,visit," += ",null,null);
+    }
+    public void visitPostDec(GroovySourceAST t, int visit) {
+        print(t,visit,null,null,"--");
+    }
+
+    public void visitPostInc(GroovySourceAST t, int visit) {
+        print(t,visit,null,null,"++");
+    }
+
+    public void visitQuestion(GroovySourceAST t, int visit) {
+        // ternary operator
+        print(t,visit,"?",":",null);
+    }
+
+    public void visitRangeExclusive(GroovySourceAST t, int visit) {
+        print(t,visit,"..<",null,null);
+    }
+
+    public void visitRangeInclusive(GroovySourceAST t, int visit) {
+        print(t,visit,"..",null,null);
+    }
+
+    // visit rbrack()
+    //   token type RBRACK only used inside parser, never visited/created
+
+    // visit rcurly()
+    //   token type RCURLY only used inside parser, never visited/created
+
+    // visit RegexpCtorEnd
+    // visit RegexpLiteral
+    // visit RegexpSymbol
+    //    token types REGEXP_CTOR_END, REGEXP_LITERAL, REGEXP_SYMBOL only used inside lexer
+    
+    public void visitRegexFind(GroovySourceAST t, int visit) {
+        print(t,visit," =~ ",null,null);
+    }
+    public void visitRegexMatch(GroovySourceAST t, int visit) {
+        print(t,visit," ==~ ",null,null);
+    }
+    // visit rparen()
+    //   token type RPAREN only used inside parser, never visited/created
+
+    public void visitSelectSlot(GroovySourceAST t, int visit) {
+        print(t,visit,"@",null,null);
+    }
+    
+    // visit semi()
+    //  SEMI only used inside parser, never visited/created (see visitForCondition(), visitForIterator())
+    
+    // visit ShComment()
+    //  never visited/created by parser
+    
+    public void visitSl(GroovySourceAST t, int visit) {
+        print(t,visit," << ",null,null);
+    }
+    public void visitSlAssign(GroovySourceAST t, int visit) {
+        print(t,visit," <<= ",null,null);
+    }
+    public void visitSlist(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            tabLevel++;
+            print(t,visit,"{");
+        } else {
+            tabLevel--;
+            print(t,visit,"}");
+        }
+    }
+
+    // visit SlComment()
+    //   never visited/created by parser
+    
+    public void visitSpreadArg(GroovySourceAST t,int visit) {
+        print(t,visit,"*",null,null);
+    }
+
+    public void visitSpreadDot(GroovySourceAST t,int visit) {
+    print(t,visit,"*.",null,null);
+    }
+
+    public void visitSpreadMapArg(GroovySourceAST t,int visit) {
+        print(t,visit,"*:",null,null);
+    }
+    
+    public void visitSr(GroovySourceAST t, int visit) {
+        print(t,visit," >> ",null,null);
+    }
+    public void visitSrAssign(GroovySourceAST t, int visit) {
+        print(t,visit," >>= ",null,null);
+    }
+
+    public void visitStar(GroovySourceAST t,int visit) {
+        print(t,visit,"*",null,null);
+    }
+    public void visitStarAssign(GroovySourceAST t, int visit) {
+        print(t,visit," *= ",null,null);
+    }
+    public void visitStarStar(GroovySourceAST t,int visit) {
+        print(t,visit,"**",null,null);
+    }
+    public void visitStarStarAssign(GroovySourceAST t, int visit) {
+        print(t,visit," **= ",null,null);
+    }
+    
+    public void visitStaticInit(GroovySourceAST t, int visit) {
+        print(t,visit,"static ",null,null);
+    }
+    public void visitStaticImport(GroovySourceAST t,int visit) {
+        print(t,visit,"import static ",null,null);
+    }
+    public void visitStrictfp(GroovySourceAST t,int visit) {
+        print(t,visit,"strictfp ",null,null);
+    }
+
+    // visitStringch
+    //   String characters only used by lexer, never visited/created directly
+
+
+    public void visitStringConstructor(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            stringConstructorCounter = 0;
+            print(t,visit,"\"");
+        }
+        if (visit == SUBSEQUENT_VISIT) {
+            // every other subsequent visit use an escaping $
+            if (stringConstructorCounter % 2 == 0) {
+               print(t,visit,"$");
+            }
+            stringConstructorCounter++;
+        }
+        if (visit == CLOSING_VISIT) {
+            print(t,visit,"\"");
+        }
+    }
+
+    public void visitStringLiteral(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            String theString = escape(t.getText());
+        if (getParentNode().getType() != GroovyTokenTypes.LABELED_ARG &&
+            getParentNode().getType() != GroovyTokenTypes.STRING_CONSTRUCTOR) {
+                theString = "\"" + theString + "\"";
+            }
+            print(t,visit,theString);
+        }
+    }
+
+    private static String escape(String literal) {
+        literal = literal.replaceAll("\n","\\\\<<REMOVE>>n"); // can't seem to do \n in one go with Java regex
+        literal = literal.replaceAll("<<REMOVE>>","");
+        return literal;
+    }
+
+    public void visitSuperCtorCall(GroovySourceAST t,int visit) {
+        printUpdatingTabLevel(t,visit,"super("," ",")");
+    }
+
+    public void visitTraitDef(GroovySourceAST t,int visit) {
+        print(t,visit,"trait ",null,null);
+
+        if (visit == OPENING_VISIT) {
+            // store name of class away for use in constructor ident
+            className = t.childOfType(GroovyTokenTypes.IDENT).getText();
+        }
+    }
+
+    // visit TripleDot, not used in the AST
+    
+    public void visitType(GroovySourceAST t,int visit) {
+        GroovySourceAST parent = getParentNode();
+        GroovySourceAST modifiers = parent.childOfType(GroovyTokenTypes.MODIFIERS);
+
+        // No need to print 'def' if we already have some modifiers
+        if (modifiers == null || modifiers.getNumberOfChildren() == 0) {
+
+            if (visit == OPENING_VISIT) {
+                if (t.getNumberOfChildren() == 0 && 
+                        parent.getType() != GroovyTokenTypes.PARAMETER_DEF) { // no need for 'def' if in a parameter list
+                    print(t,visit,"def");
+                }
+            } 
+            if (visit == CLOSING_VISIT) {
+                if (  parent.getType() == GroovyTokenTypes.VARIABLE_DEF         ||
+                      parent.getType() == GroovyTokenTypes.METHOD_DEF           ||
+                      parent.getType() == GroovyTokenTypes.ANNOTATION_FIELD_DEF ||
+                     (parent.getType() == GroovyTokenTypes.PARAMETER_DEF && t.getNumberOfChildren()!=0))             
+                {
+                    print(t,visit," ");
+                }
+            }
+            
+            /*if (visit == CLOSING_VISIT) {
+                print(t,visit," ");
+            }*/
+        } else {
+            if (visit == CLOSING_VISIT) {
+                if (t.getNumberOfChildren() != 0) {
+                    print(t,visit," ");
+                }
+            }
+        }
+    }
+    public void visitTypeArgument(GroovySourceAST t, int visit) {
+        // print nothing
+    }
+
+    public void visitTypeArguments(GroovySourceAST t, int visit) {
+        print(t,visit,"<",", ",">");
+    }
+
+    public void visitTypecast(GroovySourceAST t,int visit) {
+        print(t,visit,"(",null,")");
+    }
+    public void visitTypeLowerBounds(GroovySourceAST t,int visit) {
+        print(t,visit," super "," & ",null);
+    }
+    public void visitTypeParameter(GroovySourceAST t, int visit) {
+        // print nothing
+    }
+
+    public void visitTypeParameters(GroovySourceAST t, int visit) {
+        print(t,visit,"<",", ",">");
+    }
+
+    public void visitTypeUpperBounds(GroovySourceAST t,int visit) {
+        print(t,visit," extends "," & ",null);
+    }
+    public void visitUnaryMinus(GroovySourceAST t, int visit) {
+        print(t,visit,"-",null,null);
+    }
+    public void visitUnaryPlus(GroovySourceAST t, int visit) {
+        print(t,visit,"+",null,null);
+    }
+
+    // visit Unused "const", "do", "goto" - unsurprisingly these are unused by the AST.
+    
+    public void visitVariableDef(GroovySourceAST t,int visit) {
+        // do nothing
+    }
+
+    // a.k.a. "variable arity parameter" in the JLS
+    public void visitVariableParameterDef(GroovySourceAST t,int visit) {
+        print(t,visit,null,"... ",null);
+    }
+    
+    // visit Vocab - only used by Lexer
+    
+    public void visitWildcardType(GroovySourceAST t, int visit) {
+        print(t,visit,"?",null,null);
+    }
+
+    // visit WS - only used by lexer
+    
+    
+    
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            print(t,visit,"<" + tokenNames[t.getType()] + ">");
+            //out.print("<" + t.getType() + ">");
+        } else {
+            print(t,visit,"</" + tokenNames[t.getType()] + ">");
+            //out.print("</" + t.getType() + ">");
+        }
+    }
+
+    protected void printUpdatingTabLevel(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
+        if (visit == OPENING_VISIT && opening != null) {
+            print(t,visit,opening);
+            tabLevel++;
+        }
+        if (visit == SUBSEQUENT_VISIT && subsequent != null) {
+            print(t,visit,subsequent);
+        }
+        if (visit == CLOSING_VISIT && closing != null) {
+            tabLevel--;
+            print(t,visit,closing);
+        }
+    }
+
+    protected void print(GroovySourceAST t,int visit,String opening, String subsequent, String closing) {
+        if (visit == OPENING_VISIT && opening != null) {
+            print(t,visit,opening);
+        }
+        if (visit == SUBSEQUENT_VISIT && subsequent != null) {
+            print(t,visit,subsequent);
+        }
+        if (visit == CLOSING_VISIT && closing != null) {
+            print(t,visit,closing);
+        }
+    }
+    protected void print(GroovySourceAST t,int visit,String value) {
+        if(visit == OPENING_VISIT) {
+            printNewlineAndIndent(t, visit);
+        }
+        if (visit == CLOSING_VISIT) {
+            printNewlineAndIndent(t, visit);
+        }
+        out.print(value);
+    }
+
+    protected void printNewlineAndIndent(GroovySourceAST t, int visit) {
+        int currentLine = t.getLine();
+        if (lastLinePrinted == 0) { lastLinePrinted = currentLine; }
+        if (lastLinePrinted != currentLine) {
+            if (newLines) {
+                if (!(visit == OPENING_VISIT && t.getType() == GroovyTokenTypes.SLIST)) {
+                    for (int i=lastLinePrinted;i<currentLine;i++) {
+                        out.println();
+                    }
+                    if (lastLinePrinted > currentLine) {
+                        out.println();
+                        lastLinePrinted = currentLine;
+                    }
+                    if (visit == OPENING_VISIT || (visit == CLOSING_VISIT && lastLinePrinted > currentLine)) {
+                        for (int i=0;i<tabLevel;i++) {
+                            out.print("    ");
+                        }
+                    }
+                }
+            }
+            lastLinePrinted = Math.max(currentLine,lastLinePrinted);
+        }
+    }
+
+    public void push(GroovySourceAST t) {
+        stack.push(t);
+    }
+    public GroovySourceAST pop() {
+        if (!stack.empty()) {
+            return (GroovySourceAST) stack.pop();
+        }
+        return null;
+    }
+
+    private GroovySourceAST getParentNode() {
+        Object currentNode = stack.pop();
+        Object parentNode = stack.peek();
+        stack.push(currentNode);
+        return (GroovySourceAST) parentNode;
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
new file mode 100644
index 0000000..98ad092
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -0,0 +1,888 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+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.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.classgen.asm.CallSiteWriter;
+import org.codehaus.groovy.classgen.asm.CompileStack;
+import org.codehaus.groovy.classgen.asm.OperandStack;
+import org.codehaus.groovy.classgen.asm.TypeChooser;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.codehaus.groovy.ast.ClassHelper.BigDecimal_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.BigInteger_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.Boolean_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.CLASS_Type;
+import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.GROOVY_OBJECT_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.Integer_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.Iterator_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.LIST_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.Long_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.MAP_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.Number_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.STRING_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.getUnwrapper;
+import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
+import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
+import static org.codehaus.groovy.ast.ClassHelper.make;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.chooseBestMethod;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isClassClassNodeWrappingConcreteType;
+
+/**
+ * A call site writer which replaces call site caching with static calls. This means that the generated code
+ * looks more like Java code than dynamic Groovy code. Best effort is made to use JVM instructions instead of
+ * calls to helper methods.
+ *
+ * @author Cedric Champeau
+ */
+public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes {
+
+    private static final ClassNode INVOKERHELPER_TYPE = ClassHelper.make(InvokerHelper.class);
+    private static final MethodNode GROOVYOBJECT_GETPROPERTY_METHOD = GROOVY_OBJECT_TYPE.getMethod("getProperty", new Parameter[]{new Parameter(STRING_TYPE, "propertyName")});
+    private static final MethodNode INVOKERHELPER_GETPROPERTY_METHOD = INVOKERHELPER_TYPE.getMethod("getProperty", new Parameter[]{new Parameter(OBJECT_TYPE, "object"), new Parameter(STRING_TYPE, "propertyName")});
+    private static final MethodNode INVOKERHELPER_GETPROPERTYSAFE_METHOD = INVOKERHELPER_TYPE.getMethod("getPropertySafe", new Parameter[]{new Parameter(OBJECT_TYPE, "object"), new Parameter(STRING_TYPE, "propertyName")});
+    private static final MethodNode CLOSURE_GETTHISOBJECT_METHOD = CLOSURE_TYPE.getMethod("getThisObject", new Parameter[0]);
+    private static final ClassNode COLLECTION_TYPE = make(Collection.class);
+    private static final MethodNode COLLECTION_SIZE_METHOD = COLLECTION_TYPE.getMethod("size", Parameter.EMPTY_ARRAY);
+    private static final MethodNode MAP_GET_METHOD = MAP_TYPE.getMethod("get", new Parameter[] { new Parameter(OBJECT_TYPE, "key")});
+
+
+    private final StaticTypesWriterController controller;
+
+    public StaticTypesCallSiteWriter(final StaticTypesWriterController controller) {
+        super(controller);
+        this.controller = controller;
+    }
+
+    @Override
+    public void generateCallSiteArray() {
+        CallSiteWriter regularCallSiteWriter = controller.getRegularCallSiteWriter();
+        if (regularCallSiteWriter.hasCallSiteUse()) {
+            regularCallSiteWriter.generateCallSiteArray();
+        }
+    }
+
+    @Override
+    public void makeCallSite(final Expression receiver, final String message, final Expression arguments, final boolean safe, final boolean implicitThis, final boolean callCurrent, final boolean callStatic) {
+    }
+
+    @Override
+    public void makeGetPropertySite(Expression receiver, final String methodName, final boolean safe, final boolean implicitThis) {
+        Object dynamic = receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
+        if (dynamic !=null) {
+            makeDynamicGetProperty(receiver, methodName, safe);
+            return;
+        }
+        TypeChooser typeChooser = controller.getTypeChooser();
+        ClassNode classNode = controller.getClassNode();
+        ClassNode receiverType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
+        if (receiverType==null) {
+            receiverType = typeChooser.resolveType(receiver, classNode);
+        }
+        Object type = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
+        if (type==null && receiver instanceof VariableExpression) {
+            Variable variable = ((VariableExpression) receiver).getAccessedVariable();
+            if (variable instanceof Expression) {
+                type = ((Expression) variable).getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
+            }
+        }
+        if (type!=null) {
+            // in case a "flow type" is found, it is preferred to use it instead of
+            // the declaration type
+            receiverType = (ClassNode) type;
+        }
+        boolean isClassReceiver = false;
+        if (isClassClassNodeWrappingConcreteType(receiverType)) {
+            isClassReceiver = true;
+            receiverType = receiverType.getGenericsTypes()[0].getType();
+        }
+
+        if (isPrimitiveType(receiverType)) {
+            // GROOVY-6590: wrap primitive types
+            receiverType = getWrapper(receiverType);
+        }
+
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        if (receiverType.isArray() && methodName.equals("length")) {
+            receiver.visit(controller.getAcg());
+            ClassNode arrayGetReturnType = typeChooser.resolveType(receiver, classNode);
+            controller.getOperandStack().doGroovyCast(arrayGetReturnType);
+            mv.visitInsn(ARRAYLENGTH);
+            controller.getOperandStack().replace(int_TYPE);
+            return;
+        } else if (
+                (receiverType.implementsInterface(COLLECTION_TYPE)
+                        || COLLECTION_TYPE.equals(receiverType)) && ("size".equals(methodName) || "length".equals(methodName))) {
+            MethodCallExpression expr = new MethodCallExpression(
+                    receiver,
+                    "size",
+                    ArgumentListExpression.EMPTY_ARGUMENTS
+            );
+            expr.setMethodTarget(COLLECTION_SIZE_METHOD);
+            expr.setImplicitThis(implicitThis);
+            expr.setSafe(safe);
+            expr.visit(controller.getAcg());
+            return;
+        }
+
+        boolean isStaticProperty = receiver instanceof ClassExpression
+                && (receiverType.isDerivedFrom(receiver.getType()) || receiverType.implementsInterface(receiver.getType()));
+
+        if (!isStaticProperty && (receiverType.implementsInterface(MAP_TYPE) || MAP_TYPE.equals(receiverType))) {
+            // for maps, replace map.foo with map.get('foo')
+            writeMapDotProperty(receiver, methodName, mv, safe);
+            return;
+        }
+        if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis)) return;
+        if (makeGetField(receiver, receiverType, methodName, safe, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
+        if (receiver instanceof ClassExpression) {
+            if (makeGetField(receiver, receiver.getType(), methodName, safe, implicitThis, samePackages(receiver.getType().getPackageName(), classNode.getPackageName()))) return;
+            if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis)) return;
+            if (makeGetPrivateFieldWithBridgeMethod(receiver, receiver.getType(), methodName, safe, implicitThis)) return;
+        }
+        if (isClassReceiver) {
+            // we are probably looking for a property of the class
+            if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis)) return;
+            if (makeGetField(receiver, CLASS_Type, methodName, safe, false, true)) return;
+        }
+        if (receiverType.isEnum()) {
+            mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(receiverType), methodName, BytecodeHelper.getTypeDescription(receiverType));
+            controller.getOperandStack().push(receiverType);
+            return;
+        }
+        if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis)) return;
+
+        // GROOVY-5580, it is still possible that we're calling a superinterface property
+        String getterName = "get" + MetaClassHelper.capitalize(methodName);
+        String altGetterName = "is" + MetaClassHelper.capitalize(methodName);
+        if (receiverType.isInterface()) {
+            Set<ClassNode> allInterfaces = receiverType.getAllInterfaces();
+            MethodNode getterMethod = null;
+            for (ClassNode anInterface : allInterfaces) {
+                getterMethod = anInterface.getGetterMethod(getterName);
+                if (getterMethod == null) getterMethod = anInterface.getGetterMethod(altGetterName);
+                if (getterMethod != null) break;
+            }
+            // GROOVY-5585
+            if (getterMethod == null) {
+                getterMethod = OBJECT_TYPE.getGetterMethod(getterName);
+            }
+
+            if (getterMethod != null) {
+                MethodCallExpression call = new MethodCallExpression(
+                        receiver,
+                        getterName,
+                        ArgumentListExpression.EMPTY_ARGUMENTS
+                );
+                call.setMethodTarget(getterMethod);
+                call.setImplicitThis(false);
+                call.setSourcePosition(receiver);
+                call.setSafe(safe);
+                call.visit(controller.getAcg());
+                return;
+            }
+
+        }
+
+        // GROOVY-5568, we would be facing a DGM call, but instead of foo.getText(), have foo.text
+        List<MethodNode> methods = findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, getterName, ClassNode.EMPTY_ARRAY);
+        for (MethodNode m: findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), receiverType, altGetterName, ClassNode.EMPTY_ARRAY)) {
+            if (Boolean_TYPE.equals(getWrapper(m.getReturnType()))) methods.add(m);
+        }
+        if (!methods.isEmpty()) {
+            List<MethodNode> methodNodes = chooseBestMethod(receiverType, methods, ClassNode.EMPTY_ARRAY);
+            if (methodNodes.size() == 1) {
+                MethodNode getter = methodNodes.get(0);
+                MethodCallExpression call = new MethodCallExpression(
+                        receiver,
+                        getter.getName(),
+                        ArgumentListExpression.EMPTY_ARGUMENTS
+                );
+                call.setMethodTarget(getter);
+                call.setImplicitThis(false);
+                call.setSafe(safe);
+                call.setSourcePosition(receiver);
+                call.visit(controller.getAcg());
+                return;
+            }
+        }
+
+        if (!isStaticProperty && (receiverType.implementsInterface(LIST_TYPE) || LIST_TYPE.equals(receiverType))) {
+            writeListDotProperty(receiver, methodName, mv, safe);
+            return;
+        }
+
+        controller.getSourceUnit().addError(
+                new SyntaxException("Access to "+
+                                                (receiver instanceof ClassExpression ?receiver.getType():receiverType).toString(false)
+                                                +"#"+methodName+" is forbidden", receiver.getLineNumber(), receiver.getColumnNumber(), receiver.getLastLineNumber(), receiver.getLastColumnNumber())
+        );
+        controller.getMethodVisitor().visitInsn(ACONST_NULL);
+        controller.getOperandStack().push(OBJECT_TYPE);
+    }
+
+    private void makeDynamicGetProperty(final Expression receiver, final String methodName, final boolean safe) {
+        MethodNode target = safe?INVOKERHELPER_GETPROPERTYSAFE_METHOD:INVOKERHELPER_GETPROPERTY_METHOD;
+        MethodCallExpression mce = new MethodCallExpression(
+                new ClassExpression(INVOKERHELPER_TYPE),
+                target.getName(),
+                new ArgumentListExpression(receiver, new ConstantExpression(methodName))
+        );
+        mce.setSafe(false);
+        mce.setImplicitThis(false);
+        mce.setMethodTarget(target);
+        mce.visit(controller.getAcg());
+    }
+
+    private void writeMapDotProperty(final Expression receiver, final String methodName, final MethodVisitor mv, final boolean safe) {
+        receiver.visit(controller.getAcg()); // load receiver
+
+        Label exit = new Label();
+        if (safe) {
+            Label doGet = new Label();
+            mv.visitJumpInsn(IFNONNULL, doGet);
+            controller.getOperandStack().remove(1);
+            mv.visitInsn(ACONST_NULL);
+            mv.visitJumpInsn(GOTO, exit);
+            mv.visitLabel(doGet);
+            receiver.visit(controller.getAcg());
+        }
+
+        mv.visitLdcInsn(methodName); // load property name
+        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get", "(Ljava/lang/Object;)Ljava/lang/Object;", true);
+        if (safe) {
+            mv.visitLabel(exit);
+        }
+        controller.getOperandStack().replace(OBJECT_TYPE);
+    }
+
+    private void writeListDotProperty(final Expression receiver, final String methodName, final MethodVisitor mv, final boolean safe) {
+        ClassNode componentType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.COMPONENT_TYPE);
+        if (componentType==null) {
+            componentType = OBJECT_TYPE;
+        }
+        // for lists, replace list.foo with:
+        // def result = new ArrayList(list.size())
+        // for (e in list) { result.add (e.foo) }
+        // result
+        CompileStack compileStack = controller.getCompileStack();
+
+        Label exit = new Label();
+        if (safe) {
+            receiver.visit(controller.getAcg());
+            Label doGet = new Label();
+            mv.visitJumpInsn(IFNONNULL, doGet);
+            controller.getOperandStack().remove(1);
+            mv.visitInsn(ACONST_NULL);
+            mv.visitJumpInsn(GOTO, exit);
+            mv.visitLabel(doGet);
+        }
+
+        Variable tmpList = new VariableExpression("tmpList", make(ArrayList.class));
+        int var = compileStack.defineTemporaryVariable(tmpList, false);
+        Variable iterator = new VariableExpression("iterator", Iterator_TYPE);
+        int it = compileStack.defineTemporaryVariable(iterator, false);
+        Variable nextVar = new VariableExpression("next", componentType);
+        final int next = compileStack.defineTemporaryVariable(nextVar, false);
+
+        mv.visitTypeInsn(NEW, "java/util/ArrayList");
+        mv.visitInsn(DUP);
+        receiver.visit(controller.getAcg());
+        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "size", "()I", true);
+        controller.getOperandStack().remove(1);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "(I)V", false);
+        mv.visitVarInsn(ASTORE, var);
+        Label l1 = new Label();
+        mv.visitLabel(l1);
+        receiver.visit(controller.getAcg());
+        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "iterator", "()Ljava/util/Iterator;", true);
+        controller.getOperandStack().remove(1);
+        mv.visitVarInsn(ASTORE, it);
+        Label l2 = new Label();
+        mv.visitLabel(l2);
+        mv.visitVarInsn(ALOAD, it);
+        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true);
+        Label l3 = new Label();
+        mv.visitJumpInsn(IFEQ, l3);
+        mv.visitVarInsn(ALOAD, it);
+        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true);
+        mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(componentType));
+        mv.visitVarInsn(ASTORE, next);
+        Label l4 = new Label();
+        mv.visitLabel(l4);
+        mv.visitVarInsn(ALOAD, var);
+        final ClassNode finalComponentType = componentType;
+        PropertyExpression pexp = new PropertyExpression(new BytecodeExpression() {
+            @Override
+            public void visit(final MethodVisitor mv) {
+                mv.visitVarInsn(ALOAD, next);
+            }
+
+            @Override
+            public ClassNode getType() {
+                return finalComponentType;
+            }
+        }, methodName);
+        pexp.visit(controller.getAcg());
+        controller.getOperandStack().box();
+        controller.getOperandStack().remove(1);
+        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z", true);
+        mv.visitInsn(POP);
+        Label l5 = new Label();
+        mv.visitLabel(l5);
+        mv.visitJumpInsn(GOTO, l2);
+        mv.visitLabel(l3);
+        mv.visitVarInsn(ALOAD, var);
+        if (safe) {
+            mv.visitLabel(exit);
+        }
+        controller.getOperandStack().push(make(ArrayList.class));
+        controller.getCompileStack().removeVar(next);
+        controller.getCompileStack().removeVar(it);
+        controller.getCompileStack().removeVar(var);
+    }
+
+    @SuppressWarnings("unchecked")
+    private boolean makeGetPrivateFieldWithBridgeMethod(final Expression receiver, final ClassNode receiverType, final String fieldName, final boolean safe, final boolean implicitThis) {
+        FieldNode field = receiverType.getField(fieldName);
+        ClassNode outerClass = receiverType.getOuterClass();
+        if (field==null && implicitThis && outerClass !=null && !receiverType.isStaticClass()) {
+            Expression pexp;
+            if (controller.isInClosure()) {
+                MethodCallExpression mce = new MethodCallExpression(
+                        new VariableExpression("this"),
+                        "getThisObject",
+                        ArgumentListExpression.EMPTY_ARGUMENTS
+                );
+                mce.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, controller.getOutermostClass());
+                mce.setImplicitThis(true);
+                mce.setMethodTarget(CLOSURE_GETTHISOBJECT_METHOD);
+                pexp = new CastExpression(controller.getOutermostClass(),mce);
+            } else {
+                pexp = new PropertyExpression(
+                        new ClassExpression(outerClass),
+                        "this"
+                );
+                ((PropertyExpression)pexp).setImplicitThis(true);
+            }
+            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, outerClass);
+            pexp.setSourcePosition(receiver);
+            return makeGetPrivateFieldWithBridgeMethod(pexp, outerClass, fieldName, safe, true);
+        }
+        ClassNode classNode = controller.getClassNode();
+        if (field!=null && Modifier.isPrivate(field.getModifiers())
+                && (StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, classNode) || StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode,receiverType))
+                && !receiverType.equals(classNode)) {
+            Map<String, MethodNode> accessors = receiverType.redirect().getNodeMetaData(StaticCompilationMetadataKeys.PRIVATE_FIELDS_ACCESSORS);
+            if (accessors!=null) {
+                MethodNode methodNode = accessors.get(fieldName);
+                if (methodNode!=null) {
+                    MethodCallExpression mce = new MethodCallExpression(receiver, methodNode.getName(),
+                            new ArgumentListExpression(field.isStatic()?new ConstantExpression(null):receiver));
+                    mce.setMethodTarget(methodNode);
+                    mce.setSafe(safe);
+                    mce.setImplicitThis(implicitThis);
+                    mce.visit(controller.getAcg());
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void makeGroovyObjectGetPropertySite(final Expression receiver, final String methodName, final boolean safe, final boolean implicitThis) {
+        TypeChooser typeChooser = controller.getTypeChooser();
+        ClassNode classNode = controller.getClassNode();
+        ClassNode receiverType = typeChooser.resolveType(receiver, classNode);
+        if (receiver instanceof VariableExpression && ((VariableExpression) receiver).isThisExpression() && !controller.isInClosure()) {
+            receiverType = classNode;
+        }
+        
+        String property = methodName;
+        if (implicitThis) {
+            if (controller.getInvocationWriter() instanceof StaticInvocationWriter) {
+                MethodCallExpression currentCall = ((StaticInvocationWriter) controller.getInvocationWriter()).getCurrentCall();
+                if (currentCall != null && currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER) != null) {
+                    property = currentCall.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+                    String[] props = property.split("\\.");
+                    BytecodeExpression thisLoader = new BytecodeExpression() {
+                        @Override
+                        public void visit(final MethodVisitor mv) {
+                            mv.visitVarInsn(ALOAD, 0); // load this
+                        }
+                    };
+                    thisLoader.setType(CLOSURE_TYPE);
+                    Expression pexp = new PropertyExpression(thisLoader, new ConstantExpression(props[0]), safe);
+                    for (int i = 1, propsLength = props.length; i < propsLength; i++) {
+                        final String prop = props[i];
+                        pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, CLOSURE_TYPE);
+                        pexp = new PropertyExpression(pexp, prop);
+                    }
+                    pexp.visit(controller.getAcg());
+                    return;
+                }
+            }
+        }
+
+        if (makeGetPropertyWithGetter(receiver, receiverType, property, safe, implicitThis)) return;
+        if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, property, safe, implicitThis)) return;
+        if (makeGetField(receiver, receiverType, property, safe, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
+
+        MethodCallExpression call = new MethodCallExpression(
+                receiver,
+                "getProperty",
+                new ArgumentListExpression(new ConstantExpression(property))
+        );
+        call.setImplicitThis(implicitThis);
+        call.setSafe(safe);
+        call.setMethodTarget(GROOVYOBJECT_GETPROPERTY_METHOD);
+        call.visit(controller.getAcg());
+        return;
+    }
+
+    @Override
+    public void makeCallSiteArrayInitializer() {
+    }
+
+    private boolean makeGetPropertyWithGetter(final Expression receiver, final ClassNode receiverType, final String methodName, final boolean safe, final boolean implicitThis) {
+        // does a getter exists ?
+        String getterName = "get" + MetaClassHelper.capitalize(methodName);
+        MethodNode getterNode = receiverType.getGetterMethod(getterName);
+        if (getterNode==null) {
+            getterName = "is" + MetaClassHelper.capitalize(methodName);
+            getterNode = receiverType.getGetterMethod(getterName);
+        }
+        if (getterNode!=null && receiver instanceof ClassExpression && !CLASS_Type.equals(receiverType) && !getterNode.isStatic()) {
+            return false;
+        }
+
+        // GROOVY-5561: if two files are compiled in the same source unit
+        // and that one references the other, the getters for properties have not been
+        // generated by the compiler yet (generated by the Verifier)
+        PropertyNode propertyNode = receiverType.getProperty(methodName);
+        if (getterNode == null && propertyNode != null) {
+            // it is possible to use a getter
+            String prefix = "get";
+            if (boolean_TYPE.equals(propertyNode.getOriginType())) {
+                prefix = "is";
+            }
+            getterName = prefix + MetaClassHelper.capitalize(methodName);
+            getterNode = new MethodNode(
+                    getterName,
+                    ACC_PUBLIC,
+                    propertyNode.getOriginType(),
+                    Parameter.EMPTY_ARRAY,
+                    ClassNode.EMPTY_ARRAY,
+                    EmptyStatement.INSTANCE);
+            getterNode.setDeclaringClass(receiverType);
+            if (propertyNode.isStatic()) getterNode.setModifiers(ACC_PUBLIC + ACC_STATIC);
+        }
+        if (getterNode!=null) {
+            MethodCallExpression call = new MethodCallExpression(
+                    receiver,
+                    getterName,
+                    ArgumentListExpression.EMPTY_ARGUMENTS
+            );
+            call.setSourcePosition(receiver);
+            call.setMethodTarget(getterNode);
+            call.setImplicitThis(implicitThis);
+            call.setSafe(safe);
+            call.visit(controller.getAcg());
+            return true;
+        }
+
+        if (receiverType instanceof InnerClassNode && !receiverType.isStaticClass()) {
+            if (makeGetPropertyWithGetter(receiver,  receiverType.getOuterClass(), methodName,  safe, implicitThis)) {
+                return true;
+            }
+        }
+
+        // check direct interfaces (GROOVY-7149)
+        for (ClassNode node : receiverType.getInterfaces()) {
+            if (makeGetPropertyWithGetter(receiver, node, methodName, safe, implicitThis)) {
+                return true;
+            }
+        }
+        // go upper level
+        ClassNode superClass = receiverType.getSuperClass();
+        if (superClass !=null) {
+            return makeGetPropertyWithGetter(receiver, superClass, methodName, safe, implicitThis);
+        }
+
+        return false;
+    }
+
+    boolean makeGetField(final Expression receiver, final ClassNode receiverType, final String fieldName, final boolean safe, final boolean implicitThis, final boolean samePackage) {
+        FieldNode field = receiverType.getField(fieldName);
+        // direct access is allowed if we are in the same class as the declaring class
+        // or we are in an inner class
+        if (field !=null 
+                && isDirectAccessAllowed(field, controller.getClassNode(), samePackage)) {
+            CompileStack compileStack = controller.getCompileStack();
+            MethodVisitor mv = controller.getMethodVisitor();
+            ClassNode replacementType = field.getOriginType();
+            OperandStack operandStack = controller.getOperandStack();
+            if (field.isStatic()) {
+                mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(replacementType));
+                operandStack.push(replacementType);
+            } else {
+                if (implicitThis) {
+                    compileStack.pushImplicitThis(implicitThis);
+                }
+                receiver.visit(controller.getAcg());
+                if (implicitThis) compileStack.popImplicitThis();
+                Label exit = new Label();
+                if (safe) {
+                    mv.visitInsn(DUP);
+                    Label doGet = new Label();
+                    mv.visitJumpInsn(IFNONNULL, doGet);
+                    mv.visitInsn(POP);
+                    mv.visitInsn(ACONST_NULL);
+                    mv.visitJumpInsn(GOTO, exit);
+                    mv.visitLabel(doGet);
+                }
+                if (!operandStack.getTopOperand().isDerivedFrom(field.getOwner())) {
+                    mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(field.getOwner()));
+                }
+                mv.visitFieldInsn(GETFIELD, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(replacementType));
+                if (safe) {
+                    if (ClassHelper.isPrimitiveType(replacementType)) {
+                        operandStack.replace(replacementType);
+                        operandStack.box();
+                        replacementType = operandStack.getTopOperand();
+                    }
+                    mv.visitLabel(exit);
+                }
+            }
+            operandStack.replace(replacementType);
+            return true;
+        }
+
+        for (ClassNode intf : receiverType.getInterfaces()) {
+            // GROOVY-7039
+            if (intf!=receiverType && makeGetField(receiver, intf, fieldName, safe, implicitThis, false)) {
+                return true;
+            }
+        }
+
+        ClassNode superClass = receiverType.getSuperClass();
+        if (superClass !=null) {
+            return makeGetField(receiver, superClass, fieldName, safe, implicitThis, false);
+        }
+        return false;
+    }
+
+    private static boolean samePackages(final String pkg1, final String pkg2) {
+        return (
+                (pkg1 ==null && pkg2 ==null)
+                || pkg1 !=null && pkg1.equals(pkg2)
+                );
+    }
+
+    private static boolean isDirectAccessAllowed(FieldNode a, ClassNode receiver, boolean isSamePackage) {
+        ClassNode declaringClass = a.getDeclaringClass().redirect();
+        ClassNode receiverType = receiver.redirect();
+
+        // first, direct access from within the class or inner class nodes
+        if (declaringClass.equals(receiverType)) return true;
+        if (receiverType instanceof InnerClassNode) {
+            while (receiverType!=null && receiverType instanceof InnerClassNode) {
+                if (declaringClass.equals(receiverType)) return true;
+                receiverType = receiverType.getOuterClass();
+            }
+        }
+
+        // no getter
+        return a.isPublic() || (a.isProtected() && isSamePackage);
+    }
+
+    @Override
+    public void makeSiteEntry() {
+    }
+
+    @Override
+    public void prepareCallSite(final String message) {
+    }
+
+    @Override
+    public void makeSingleArgumentCall(final Expression receiver, final String message, final Expression arguments, boolean safe) {
+        TypeChooser typeChooser = controller.getTypeChooser();
+        ClassNode classNode = controller.getClassNode();
+        ClassNode rType = typeChooser.resolveType(receiver, classNode);
+        ClassNode aType = typeChooser.resolveType(arguments, classNode);
+        if (trySubscript(receiver, message, arguments, rType, aType, safe)) {
+            return;
+        }
+        // now try with flow type instead of declaration type
+        rType = receiver.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
+        if (receiver instanceof VariableExpression && rType == null) {
+            // TODO: can STCV be made smarter to avoid this check?
+            VariableExpression ve = (VariableExpression) ((VariableExpression)receiver).getAccessedVariable();
+            rType = ve.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
+        }
+        if (rType!=null && trySubscript(receiver, message, arguments, rType, aType, safe)) {
+            return;
+        }
+        // todo: more cases
+        throw new GroovyBugError(
+                "At line " + receiver.getLineNumber() + " column " + receiver.getColumnNumber() + "\n" +
+                "On receiver: " + receiver.getText() + " with message: " + message + " and arguments: " + arguments.getText() + "\n" +
+                "This method should not have been called. Please try to create a simple example reproducing\n" +
+                "this error and file a bug report at https://issues.apache.org/jira/browse/GROOVY");
+    }
+
+    private boolean trySubscript(final Expression receiver, final String message, final Expression arguments, ClassNode rType, final ClassNode aType, boolean safe) {
+        if (getWrapper(rType).isDerivedFrom(Number_TYPE)
+                && getWrapper(aType).isDerivedFrom(Number_TYPE)) {
+            if ("plus".equals(message) || "minus".equals(message) || "multiply".equals(message) || "div".equals(message)) {
+                writeNumberNumberCall(receiver, message, arguments);
+                return true;
+            } else if ("power".equals(message)) {
+                writePowerCall(receiver, arguments, rType, aType);
+                return true;
+            } else if ("mod".equals(message) || "leftShift".equals(message) || "rightShift".equals(message) || "rightShiftUnsigned".equals(message)
+                    || "and".equals(message) || "or".equals(message) || "xor".equals(message)) {
+                writeOperatorCall(receiver, arguments, message);
+                return true;
+            }
+        } else if (STRING_TYPE.equals(rType) && "plus".equals(message)) {
+            writeStringPlusCall(receiver, message, arguments);
+            return true;
+        } else if ("getAt".equals(message)) {
+            if (rType.isArray() && getWrapper(aType).isDerivedFrom(Number_TYPE) && !safe) {
+                writeArrayGet(receiver, arguments, rType, aType);
+                return true;
+            } else {
+                // check if a getAt method can be found on the receiver
+                ClassNode current = rType;
+                MethodNode getAtNode = null;
+                while (current!=null && getAtNode==null) {
+                    getAtNode = current.getDeclaredMethod("getAt", new Parameter[]{new Parameter(aType, "index")});
+                    if (getAtNode == null) {
+                        getAtNode = getCompatibleMethod(current, "getAt", aType);
+                    }
+                    if (getAtNode==null && isPrimitiveType(aType)) {
+                        getAtNode = current.getDeclaredMethod("getAt", new Parameter[]{new Parameter(getWrapper(aType), "index")});
+                        if (getAtNode == null) {
+                            getAtNode = getCompatibleMethod(current, "getAt", getWrapper(aType));
+                        }
+                    } else if (getAtNode==null && aType.isDerivedFrom(Number_TYPE)) {
+                        getAtNode = current.getDeclaredMethod("getAt", new Parameter[]{new Parameter(getUnwrapper(aType), "index")});
+                        if (getAtNode == null) {
+                            getAtNode = getCompatibleMethod(current, "getAt", getUnwrapper(aType));
+                        }
+                    }
+                    current = current.getSuperClass();
+                }
+                if (getAtNode!=null) {
+                    MethodCallExpression call = new MethodCallExpression(
+                            receiver,
+                            "getAt",
+                            arguments
+                    );
+
+                    call.setSafe(safe);
+                    call.setSourcePosition(arguments);
+                    call.setImplicitThis(false);
+                    call.setMethodTarget(getAtNode);
+                    call.visit(controller.getAcg());
+                    return true;
+                }
+
+                // make sure Map#getAt() and List#getAt handled with the bracket syntax are properly compiled
+                ClassNode[] args = {aType};
+                boolean acceptAnyMethod =
+                        MAP_TYPE.equals(rType) || rType.implementsInterface(MAP_TYPE)
+                        || LIST_TYPE.equals(rType) || rType.implementsInterface(LIST_TYPE);
+                List<MethodNode> nodes = StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), rType, message, args);
+                if (nodes.isEmpty()) {
+                    // retry with raw types
+                    rType = rType.getPlainNodeReference();
+                    nodes = StaticTypeCheckingSupport.findDGMMethodsByNameAndArguments(controller.getSourceUnit().getClassLoader(), rType, message, args);
+                }
+                nodes = StaticTypeCheckingSupport.chooseBestMethod(rType, nodes, args);
+                if (nodes.size()==1 || nodes.size()>1 && acceptAnyMethod) {
+                    MethodNode methodNode = nodes.get(0);
+                    MethodCallExpression call = new MethodCallExpression(
+                            receiver,
+                            message,
+                            arguments
+                    );
+
+                    call.setSafe(safe);
+                    call.setSourcePosition(arguments);
+                    call.setImplicitThis(false);
+                    call.setMethodTarget(methodNode);
+                    call.visit(controller.getAcg());
+                    return true;
+                }
+                if (implementsInterfaceOrIsSubclassOf(rType, MAP_TYPE)) {
+                    // fallback to Map#get
+                    MethodCallExpression call = new MethodCallExpression(
+                            receiver,
+                            "get",
+                            arguments
+                    );
+
+                    call.setSafe(safe);
+                    call.setMethodTarget(MAP_GET_METHOD);
+                    call.setSourcePosition(arguments);
+                    call.setImplicitThis(false);
+                    call.visit(controller.getAcg());
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private MethodNode getCompatibleMethod(ClassNode current, String getAt, ClassNode aType) {
+        // TODO this really should find "best" match or find all matches and complain about ambiguity if more than one
+        // TODO handle getAt with more than one parameter
+        // TODO handle default getAt methods on Java 8 interfaces
+        for (MethodNode methodNode : current.getDeclaredMethods("getAt")) {
+            if (methodNode.getParameters().length == 1) {
+                ClassNode paramType = methodNode.getParameters()[0].getType();
+                if (aType.isDerivedFrom(paramType) || aType.declaresInterface(paramType)) {
+                    return methodNode;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void writeArrayGet(final Expression receiver, final Expression arguments, final ClassNode rType, final ClassNode aType) {
+        OperandStack operandStack = controller.getOperandStack();
+        int m1 = operandStack.getStackLength();
+        // visit receiver
+        receiver.visit(controller.getAcg());
+        // visit arguments as array index
+        arguments.visit(controller.getAcg());
+        operandStack.doGroovyCast(int_TYPE);
+        int m2 = operandStack.getStackLength();
+        // array access
+        controller.getMethodVisitor().visitInsn(AALOAD);
+        operandStack.replace(rType.getComponentType(), m2-m1);
+    }
+
+    private void writeOperatorCall(Expression receiver, Expression arguments, String operator) {
+        prepareSiteAndReceiver(receiver, operator, false, controller.getCompileStack().isLHS());
+        controller.getOperandStack().doGroovyCast(Number_TYPE);
+        visitBoxedArgument(arguments);
+        controller.getOperandStack().doGroovyCast(Number_TYPE);
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/typehandling/NumberMath", operator, "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false);
+        controller.getOperandStack().replace(Number_TYPE, 2);
+    }
+
+    private void writePowerCall(Expression receiver, Expression arguments, final ClassNode rType, ClassNode aType) {
+        OperandStack operandStack = controller.getOperandStack();
+        int m1 = operandStack.getStackLength();
+        //slow Path
+        prepareSiteAndReceiver(receiver, "power", false, controller.getCompileStack().isLHS());
+        operandStack.doGroovyCast(getWrapper(rType));
+        visitBoxedArgument(arguments);
+        operandStack.doGroovyCast(getWrapper(aType));
+        int m2 = operandStack.getStackLength();
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (BigDecimal_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigDecimal;Ljava/lang/Integer;)Ljava/lang/Number;", false);
+        } else if (BigInteger_TYPE.equals(rType) && Integer_TYPE.equals(getWrapper(aType))) {
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/math/BigInteger;Ljava/lang/Integer;)Ljava/lang/Number;", false);
+        } else if (Long_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Long;Ljava/lang/Integer;)Ljava/lang/Number;", false);
+        } else if (Integer_TYPE.equals(getWrapper(rType)) && Integer_TYPE.equals(getWrapper(aType))) {
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Integer;Ljava/lang/Integer;)Ljava/lang/Number;", false);
+        } else {
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "power", "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false);
+        }
+        controller.getOperandStack().replace(Number_TYPE, m2 - m1);
+    }
+
+    private void writeStringPlusCall(final Expression receiver, final String message, final Expression arguments) {
+        // todo: performance would be better if we created a StringBuilder
+        OperandStack operandStack = controller.getOperandStack();
+        int m1 = operandStack.getStackLength();
+        //slow Path
+        prepareSiteAndReceiver(receiver, message, false, controller.getCompileStack().isLHS());
+        visitBoxedArgument(arguments);
+        int m2 = operandStack.getStackLength();
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "plus", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;", false);
+        controller.getOperandStack().replace(STRING_TYPE, m2-m1);
+    }
+
+    private void writeNumberNumberCall(final Expression receiver, final String message, final Expression arguments) {
+        OperandStack operandStack = controller.getOperandStack();
+        int m1 = operandStack.getStackLength();
+        //slow Path
+        prepareSiteAndReceiver(receiver, message, false, controller.getCompileStack().isLHS());
+        controller.getOperandStack().doGroovyCast(Number_TYPE);
+        visitBoxedArgument(arguments);
+        controller.getOperandStack().doGroovyCast(Number_TYPE);
+        int m2 = operandStack.getStackLength();
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/dgmimpl/NumberNumber" + MetaClassHelper.capitalize(message), message, "(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;", false);
+        controller.getOperandStack().replace(Number_TYPE, m2 - m1);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.java
new file mode 100644
index 0000000..fc26486
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.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.classgen.asm.sc;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.classgen.asm.ClosureWriter;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import org.objectweb.asm.Opcodes;
+
+import java.util.List;
+
+/**
+ * Writer responsible for generating closure classes in statically compiled mode.
+ *
+ * @author Cedric Champeau
+ */
+public class StaticTypesClosureWriter extends ClosureWriter {
+    public StaticTypesClosureWriter(WriterController wc) {
+        super(wc);
+    }
+
+    @Override
+    protected ClassNode createClosureClass(final ClosureExpression expression, final int mods) {
+        ClassNode closureClass = super.createClosureClass(expression, mods);
+        List<MethodNode> methods = closureClass.getDeclaredMethods("call");
+        List<MethodNode> doCall = closureClass.getMethods("doCall");
+        if (doCall.size() != 1) {
+            throw new GroovyBugError("Expected to find one (1) doCall method on generated closure, but found " + doCall.size());
+        }
+        MethodNode doCallMethod = doCall.get(0);
+        if (methods.isEmpty() && doCallMethod.getParameters().length == 1) {
+            createDirectCallMethod(closureClass, doCallMethod);
+        }
+        MethodTargetCompletionVisitor visitor = new MethodTargetCompletionVisitor(doCallMethod);
+        Object dynamic = expression.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION);
+        if (dynamic != null) {
+            doCallMethod.putNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION, dynamic);
+        }
+        for (MethodNode method : methods) {
+            visitor.visitMethod(method);
+        }
+        closureClass.putNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE, Boolean.TRUE);
+        return closureClass;
+    }
+
+    private static void createDirectCallMethod(final ClassNode closureClass, final MethodNode doCallMethod) {
+        // in case there is no "call" method on the closure, we can create a "fast invocation" paths
+        // to avoid going through ClosureMetaClass by call(Object...) method
+
+        // we can't have a specialized version of call(Object...) because the dispatch logic in ClosureMetaClass
+        // is too complex!
+
+        // call(Object)
+        Parameter args = new Parameter(ClassHelper.OBJECT_TYPE, "args");
+        MethodCallExpression doCall1arg = new MethodCallExpression(
+                new VariableExpression("this", closureClass),
+                "doCall",
+                new ArgumentListExpression(new VariableExpression(args))
+        );
+        doCall1arg.setImplicitThis(true);
+        doCall1arg.setMethodTarget(doCallMethod);
+        closureClass.addMethod(
+                new MethodNode("call",
+                        Opcodes.ACC_PUBLIC,
+                        ClassHelper.OBJECT_TYPE,
+                        new Parameter[]{args},
+                        ClassNode.EMPTY_ARRAY,
+                        new ReturnStatement(doCall1arg)));
+
+        // call()
+        MethodCallExpression doCallNoArgs = new MethodCallExpression(new VariableExpression("this", closureClass), "doCall", new ArgumentListExpression(new ConstantExpression(null)));
+        doCallNoArgs.setImplicitThis(true);
+        doCallNoArgs.setMethodTarget(doCallMethod);
+        closureClass.addMethod(
+                new MethodNode("call",
+                        Opcodes.ACC_PUBLIC,
+                        ClassHelper.OBJECT_TYPE,
+                        Parameter.EMPTY_ARRAY,
+                        ClassNode.EMPTY_ARRAY,
+                        new ReturnStatement(doCallNoArgs)));
+    }
+
+    private static final class MethodTargetCompletionVisitor extends ClassCodeVisitorSupport {
+
+        private final MethodNode doCallMethod;
+
+        private MethodTargetCompletionVisitor(final MethodNode doCallMethod) {
+            this.doCallMethod = doCallMethod;
+        }
+
+        @Override
+        protected SourceUnit getSourceUnit() {
+            return null;
+        }
+
+        @Override
+        public void visitMethodCallExpression(final MethodCallExpression call) {
+            super.visitMethodCallExpression(call);
+            MethodNode mn = call.getMethodTarget();
+            if (mn == null) {
+                call.setMethodTarget(doCallMethod);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
new file mode 100644
index 0000000..cabc3c4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
@@ -0,0 +1,299 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+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.ForStatement;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.asm.BytecodeVariable;
+import org.codehaus.groovy.classgen.asm.CompileStack;
+import org.codehaus.groovy.classgen.asm.MethodCaller;
+import org.codehaus.groovy.classgen.asm.OperandStack;
+import org.codehaus.groovy.classgen.asm.StatementWriter;
+import org.codehaus.groovy.classgen.asm.TypeChooser;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.Enumeration;
+
+import static org.objectweb.asm.Opcodes.AALOAD;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ARRAYLENGTH;
+import static org.objectweb.asm.Opcodes.BALOAD;
+import static org.objectweb.asm.Opcodes.CALOAD;
+import static org.objectweb.asm.Opcodes.DALOAD;
+import static org.objectweb.asm.Opcodes.DUP;
+import static org.objectweb.asm.Opcodes.FALOAD;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IALOAD;
+import static org.objectweb.asm.Opcodes.ICONST_0;
+import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.IFNULL;
+import static org.objectweb.asm.Opcodes.IF_ICMPGE;
+import static org.objectweb.asm.Opcodes.ILOAD;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static org.objectweb.asm.Opcodes.LALOAD;
+import static org.objectweb.asm.Opcodes.SALOAD;
+
+/**
+ * A class to write out the optimized statements
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class StaticTypesStatementWriter extends StatementWriter {
+
+    private static final ClassNode ITERABLE_CLASSNODE = ClassHelper.make(Iterable.class);
+    private static final ClassNode ENUMERATION_CLASSNODE = ClassHelper.make(Enumeration.class);
+    private static final MethodCaller ENUMERATION_NEXT_METHOD = MethodCaller.newInterface(Enumeration.class, "nextElement");
+    private static final MethodCaller ENUMERATION_HASMORE_METHOD = MethodCaller.newInterface(Enumeration.class, "hasMoreElements");
+
+    private final StaticTypesWriterController controller;
+
+    public StaticTypesStatementWriter(StaticTypesWriterController controller) {
+        super(controller);
+        this.controller = controller;
+    }
+    
+    @Override
+    public void writeBlockStatement(BlockStatement statement) {
+        controller.switchToFastPath();
+        super.writeBlockStatement(statement);
+        controller.switchToSlowPath();
+    }
+
+    @Override
+    protected void writeForInLoop(final ForStatement loop) {
+        controller.getAcg().onLineNumber(loop,"visitForLoop");
+        writeStatementLabel(loop);
+
+        CompileStack compileStack = controller.getCompileStack();
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+
+        compileStack.pushLoop(loop.getVariableScope(), loop.getStatementLabels());
+
+        // Identify type of collection
+        TypeChooser typeChooser = controller.getTypeChooser();
+        Expression collectionExpression = loop.getCollectionExpression();
+        ClassNode collectionType = typeChooser.resolveType(collectionExpression, controller.getClassNode());
+        Parameter loopVariable = loop.getVariable();
+        int size = operandStack.getStackLength();
+        if (collectionType.isArray() && loopVariable.getOriginType().equals(collectionType.getComponentType())) {
+            writeOptimizedForEachLoop(compileStack, operandStack, mv, loop, collectionExpression, collectionType, loopVariable);
+        } else if (ENUMERATION_CLASSNODE.equals(collectionType)) {
+            writeEnumerationBasedForEachLoop(compileStack, operandStack, mv, loop, collectionExpression, collectionType, loopVariable);
+        } else {
+            writeIteratorBasedForEachLoop(compileStack, operandStack, mv, loop, collectionExpression, collectionType, loopVariable);
+        }
+        operandStack.popDownTo(size);
+        compileStack.pop();
+    }
+
+    private void writeOptimizedForEachLoop(
+            CompileStack compileStack,
+            OperandStack operandStack,
+            MethodVisitor mv,
+            ForStatement loop,
+            Expression collectionExpression,
+            ClassNode collectionType,
+            Parameter loopVariable) {
+        BytecodeVariable variable = compileStack.defineVariable(loopVariable, false);
+
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+
+        AsmClassGenerator acg = controller.getAcg();
+
+        // load array on stack
+        collectionExpression.visit(acg);
+        mv.visitInsn(DUP);
+        int array = compileStack.defineTemporaryVariable("$arr", collectionType, true);
+        mv.visitJumpInsn(IFNULL, breakLabel);
+
+        // $len = array.length
+        mv.visitVarInsn(ALOAD, array);
+        mv.visitInsn(ARRAYLENGTH);
+        operandStack.push(ClassHelper.int_TYPE);
+        int arrayLen = compileStack.defineTemporaryVariable("$len", ClassHelper.int_TYPE, true);
+
+        // $idx = 0
+        mv.visitInsn(ICONST_0);
+        operandStack.push(ClassHelper.int_TYPE);
+        int loopIdx = compileStack.defineTemporaryVariable("$idx", ClassHelper.int_TYPE, true);
+
+        mv.visitLabel(continueLabel);
+        // $idx<$len?
+        mv.visitVarInsn(ILOAD, loopIdx);
+        mv.visitVarInsn(ILOAD, arrayLen);
+        mv.visitJumpInsn(IF_ICMPGE, breakLabel);
+
+        // get array element
+        loadFromArray(mv, variable, array, loopIdx);
+
+        // $idx++
+        mv.visitIincInsn(loopIdx, 1);
+
+        // loop body
+        loop.getLoopBlock().visit(acg);
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+
+        mv.visitLabel(breakLabel);
+
+        compileStack.removeVar(loopIdx);
+        compileStack.removeVar(arrayLen);
+        compileStack.removeVar(array);
+    }
+
+    private void loadFromArray(MethodVisitor mv, BytecodeVariable variable, int array, int iteratorIdx) {
+        OperandStack os = controller.getOperandStack();
+        mv.visitVarInsn(ALOAD, array);
+        mv.visitVarInsn(ILOAD, iteratorIdx);
+
+        ClassNode varType = variable.getType();
+        boolean primitiveType = ClassHelper.isPrimitiveType(varType);
+        boolean isByte = ClassHelper.byte_TYPE.equals(varType);
+        boolean isShort = ClassHelper.short_TYPE.equals(varType);
+        boolean isInt = ClassHelper.int_TYPE.equals(varType);
+        boolean isLong = ClassHelper.long_TYPE.equals(varType);
+        boolean isFloat = ClassHelper.float_TYPE.equals(varType);
+        boolean isDouble = ClassHelper.double_TYPE.equals(varType);
+        boolean isChar = ClassHelper.char_TYPE.equals(varType);
+        boolean isBoolean = ClassHelper.boolean_TYPE.equals(varType);
+
+        if (primitiveType) {
+            if (isByte) {
+                mv.visitInsn(BALOAD);
+            }
+            if (isShort) {
+                mv.visitInsn(SALOAD);
+            }
+            if (isInt || isChar || isBoolean) {
+                mv.visitInsn(isChar ? CALOAD : isBoolean ? BALOAD : IALOAD);
+            }
+            if (isLong) {
+                mv.visitInsn(LALOAD);
+            }
+            if (isFloat) {
+                mv.visitInsn(FALOAD);
+            }
+            if (isDouble) {
+                mv.visitInsn(DALOAD);
+            }
+        } else {
+            mv.visitInsn(AALOAD);
+        }
+        os.push(varType);
+        os.storeVar(variable);
+    }
+
+    private void writeIteratorBasedForEachLoop(
+            CompileStack compileStack,
+            OperandStack operandStack,
+            MethodVisitor mv,
+            ForStatement loop,
+            Expression collectionExpression,
+            ClassNode collectionType,
+            Parameter loopVariable) {
+        // Declare the loop counter.
+        BytecodeVariable variable = compileStack.defineVariable(loopVariable, false);
+
+        if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(collectionType, ITERABLE_CLASSNODE)) {
+            MethodCallExpression iterator = new MethodCallExpression(collectionExpression, "iterator", new ArgumentListExpression());
+            iterator.setMethodTarget(collectionType.getMethod("iterator", Parameter.EMPTY_ARRAY));
+            iterator.setImplicitThis(false);
+            iterator.visit(controller.getAcg());
+        } else {
+            collectionExpression.visit(controller.getAcg());
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "iterator", "(Ljava/lang/Object;)Ljava/util/Iterator;", false);
+            operandStack.replace(ClassHelper.Iterator_TYPE);
+        }
+
+        // Then get the iterator and generate the loop control
+
+        int iteratorIdx = compileStack.defineTemporaryVariable("iterator", ClassHelper.Iterator_TYPE, true);
+
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+
+        mv.visitLabel(continueLabel);
+        mv.visitVarInsn(ALOAD, iteratorIdx);
+        writeIteratorHasNext(mv);
+        // note: ifeq tests for ==0, a boolean is 0 if it is false
+        mv.visitJumpInsn(IFEQ, breakLabel);
+
+        mv.visitVarInsn(ALOAD, iteratorIdx);
+        writeIteratorNext(mv);
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        operandStack.storeVar(variable);
+
+        // Generate the loop body
+        loop.getLoopBlock().visit(controller.getAcg());
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+        mv.visitLabel(breakLabel);
+        compileStack.removeVar(iteratorIdx);
+    }
+
+    private void writeEnumerationBasedForEachLoop(
+            CompileStack compileStack,
+            OperandStack operandStack,
+            MethodVisitor mv,
+            ForStatement loop,
+            Expression collectionExpression,
+            ClassNode collectionType,
+            Parameter loopVariable) {
+        // Declare the loop counter.
+        BytecodeVariable variable = compileStack.defineVariable(loopVariable, false);
+
+        collectionExpression.visit(controller.getAcg());
+
+        // Then get the iterator and generate the loop control
+
+        int enumIdx = compileStack.defineTemporaryVariable("$enum", ENUMERATION_CLASSNODE, true);
+
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+
+        mv.visitLabel(continueLabel);
+        mv.visitVarInsn(ALOAD, enumIdx);
+        ENUMERATION_HASMORE_METHOD.call(mv);
+        // note: ifeq tests for ==0, a boolean is 0 if it is false
+        mv.visitJumpInsn(IFEQ, breakLabel);
+
+        mv.visitVarInsn(ALOAD, enumIdx);
+        ENUMERATION_NEXT_METHOD.call(mv);
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        operandStack.storeVar(variable);
+
+        // Generate the loop body
+        loop.getLoopBlock().visit(controller.getAcg());
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+        mv.visitLabel(breakLabel);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
new file mode 100644
index 0000000..a3e4551
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
@@ -0,0 +1,75 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.classgen.asm.StatementMetaTypeChooser;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+
+/**
+ * A {@link org.codehaus.groovy.classgen.asm.TypeChooser} which reads type information from node metadata
+ * generated by the {@link groovy.transform.CompileStatic} annotation.
+ *
+ * @author Cedric Champeau
+ */
+public class StaticTypesTypeChooser extends StatementMetaTypeChooser {
+    @Override
+    public ClassNode resolveType(final Expression exp, final ClassNode current) {
+        ASTNode target = exp instanceof VariableExpression ? getTarget((VariableExpression) exp) : exp;
+        ClassNode inferredType = target.getNodeMetaData(StaticTypesMarker.DECLARATION_INFERRED_TYPE);
+        if (inferredType == null) {
+            inferredType = target.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE);
+            if (inferredType == null && target instanceof VariableExpression && ((VariableExpression) target).getAccessedVariable() instanceof Parameter) {
+                target = (Parameter) ((VariableExpression) target).getAccessedVariable();
+                inferredType = ((Parameter) target).getOriginType();
+            }
+        }
+        if (inferredType != null) {
+            if (ClassHelper.VOID_TYPE == inferredType) {
+                // we are in a case of a type inference failure, probably because code was generated
+                // it is better to avoid using this
+                inferredType = super.resolveType(exp, current);
+            }
+            return inferredType;
+        }
+        if (target instanceof VariableExpression && ((VariableExpression) target).isThisExpression()) {
+            // AsmClassGenerator may create "this" expressions that the type checker knows nothing about
+            return current;
+        }
+        return super.resolveType(exp, current);
+    }
+
+    /**
+     * The inferred type, in case of a variable expression, can be set on the accessed variable, so we take it instead
+     * of the facade one.
+     *
+     * @param ve the variable expression for which to return the target expression
+     * @return the target variable expression
+     */
+    private static VariableExpression getTarget(VariableExpression ve) {
+        if (ve.getAccessedVariable() == null || ve.getAccessedVariable() == ve || (!(ve.getAccessedVariable() instanceof VariableExpression)))
+            return ve;
+        return getTarget((VariableExpression) ve.getAccessedVariable());
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java
new file mode 100644
index 0000000..73adb10
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesUnaryExpressionHelper.java
@@ -0,0 +1,178 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.expr.BitwiseNegationExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.UnaryMinusExpression;
+import org.codehaus.groovy.ast.expr.UnaryPlusExpression;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.codehaus.groovy.classgen.asm.TypeChooser;
+import org.codehaus.groovy.classgen.asm.UnaryExpressionHelper;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import static org.codehaus.groovy.ast.ClassHelper.boolean_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.byte_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.char_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.int_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveType;
+import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.short_TYPE;
+
+/**
+ * An unary expression helper which generates optimized bytecode depending on
+ * the current type on top of the operand stack.
+ *
+ * @author Cedric Champeau
+ */
+public class StaticTypesUnaryExpressionHelper extends UnaryExpressionHelper implements Opcodes {
+    private static final UnaryMinusExpression EMPTY_UNARY_MINUS = new UnaryMinusExpression(EmptyExpression.INSTANCE);
+    private static final UnaryPlusExpression EMPTY_UNARY_PLUS = new UnaryPlusExpression(EmptyExpression.INSTANCE);
+    private static final BitwiseNegationExpression EMPTY_BITWISE_NEGATE = new BitwiseNegationExpression(EmptyExpression.INSTANCE);
+
+    private final WriterController controller;
+
+    public StaticTypesUnaryExpressionHelper(final WriterController controller) {
+        super(controller);
+        this.controller = controller;
+    }
+
+    @Override
+    public void writeBitwiseNegate(final BitwiseNegationExpression expression) {
+        expression.getExpression().visit(controller.getAcg());
+        if (isPrimitiveOnTop()) {
+            final ClassNode top = getTopOperand();
+            if (top==int_TYPE || top==short_TYPE || top==byte_TYPE || top==char_TYPE || top==long_TYPE) {
+                BytecodeExpression bytecodeExpression = new BytecodeExpression() {
+                    @Override
+                    public void visit(final MethodVisitor mv) {
+                        if (long_TYPE==top) {
+                            mv.visitLdcInsn(-1);
+                            mv.visitInsn(LXOR);
+                        } else {
+                            mv.visitInsn(ICONST_M1);
+                            mv.visitInsn(IXOR);
+                            if (byte_TYPE==top) {
+                                mv.visitInsn(I2B);
+                            } else if (char_TYPE==top) {
+                                mv.visitInsn(I2C);
+                            } else if (short_TYPE==top) {
+                                mv.visitInsn(I2S);
+                            }
+                        }
+                    }
+                };
+                bytecodeExpression.visit(controller.getAcg());
+                controller.getOperandStack().remove(1);
+                return;
+            }
+        }
+        super.writeBitwiseNegate(EMPTY_BITWISE_NEGATE);
+    }
+
+    @Override
+    public void writeNotExpression(final NotExpression expression) {
+        TypeChooser typeChooser = controller.getTypeChooser();
+        Expression subExpression = expression.getExpression();
+        ClassNode classNode = controller.getClassNode();
+        if (typeChooser.resolveType(subExpression, classNode) == boolean_TYPE) {
+            subExpression.visit(controller.getAcg());
+            controller.getOperandStack().doGroovyCast(boolean_TYPE);
+            BytecodeExpression bytecodeExpression = new BytecodeExpression() {
+                @Override
+                public void visit(final MethodVisitor mv) {
+                    Label ne = new Label();
+                    mv.visitJumpInsn(IFNE, ne);
+                    mv.visitInsn(ICONST_1);
+                    Label out = new Label();
+                    mv.visitJumpInsn(GOTO, out);
+                    mv.visitLabel(ne);
+                    mv.visitInsn(ICONST_0);
+                    mv.visitLabel(out);
+                }
+            };
+            bytecodeExpression.visit(controller.getAcg());
+            controller.getOperandStack().remove(1);
+            return;
+        }
+        super.writeNotExpression(expression);
+    }
+
+    @Override
+    public void writeUnaryMinus(final UnaryMinusExpression expression) {
+        expression.getExpression().visit(controller.getAcg());
+        if (isPrimitiveOnTop()) {
+            final ClassNode top = getTopOperand();
+            if (top!=boolean_TYPE) {
+                BytecodeExpression bytecodeExpression = new BytecodeExpression() {
+                    @Override
+                    public void visit(final MethodVisitor mv) {
+                        if (int_TYPE == top || short_TYPE == top || byte_TYPE==top || char_TYPE==top) {
+                            mv.visitInsn(INEG);
+                            if (byte_TYPE==top) {
+                                mv.visitInsn(I2B);
+                            } else if (char_TYPE==top) {
+                                mv.visitInsn(I2C);
+                            } else if (short_TYPE==top) {
+                                mv.visitInsn(I2S);
+                            }
+                        } else if (long_TYPE == top) {
+                            mv.visitInsn(LNEG);
+                        } else if (float_TYPE == top) {
+                            mv.visitInsn(FNEG);
+                        } else if (double_TYPE == top) {
+                            mv.visitInsn(DNEG);
+                        }
+                    }
+                };
+                bytecodeExpression.visit(controller.getAcg());
+                controller.getOperandStack().remove(1);
+                return;
+            }
+        }
+        // we already visited the sub expression
+        super.writeUnaryMinus(EMPTY_UNARY_MINUS);
+    }
+
+    @Override
+    public void writeUnaryPlus(final UnaryPlusExpression expression) {
+        expression.getExpression().visit(controller.getAcg());
+        if (isPrimitiveOnTop()) {
+            // only visit the expression
+            return;
+        }
+        super.writeUnaryPlus(EMPTY_UNARY_PLUS);
+    }
+
+    private boolean isPrimitiveOnTop() {
+        return isPrimitiveType(getTopOperand());
+    }
+
+    private ClassNode getTopOperand() {
+        return controller.getOperandStack().getTopOperand();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.java
new file mode 100644
index 0000000..47ef3d4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterController.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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.classgen.asm.BinaryExpressionHelper;
+import org.codehaus.groovy.classgen.asm.BinaryExpressionMultiTypeDispatcher;
+import org.codehaus.groovy.classgen.asm.CallSiteWriter;
+import org.codehaus.groovy.classgen.asm.ClosureWriter;
+import org.codehaus.groovy.classgen.asm.DelegatingController;
+import org.codehaus.groovy.classgen.asm.InvocationWriter;
+import org.codehaus.groovy.classgen.asm.StatementWriter;
+import org.codehaus.groovy.classgen.asm.TypeChooser;
+import org.codehaus.groovy.classgen.asm.UnaryExpressionHelper;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.classgen.asm.indy.sc.IndyStaticTypesMultiTypeDispatcher;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.sc.StaticCompilationVisitor;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import org.objectweb.asm.ClassVisitor;
+
+
+/**
+ * An alternative {@link org.codehaus.groovy.classgen.asm.WriterController} which handles static types and method
+ * dispatch. In case of a "mixed mode" where only some methods are annotated with {@link groovy.transform.TypeChecked}
+ * then this writer will delegate to the classic writer controller.
+ *
+ * @author Cedric Champeau
+ */
+public class StaticTypesWriterController extends DelegatingController {
+
+    protected boolean isInStaticallyCheckedMethod;
+    private StaticTypesCallSiteWriter callSiteWriter;
+    private StaticTypesStatementWriter statementWriter;
+    private StaticTypesTypeChooser typeChooser;
+    private StaticInvocationWriter invocationWriter;
+    private BinaryExpressionMultiTypeDispatcher binaryExprHelper;
+    private UnaryExpressionHelper unaryExpressionHelper;
+    private ClosureWriter closureWriter;
+
+    public StaticTypesWriterController(WriterController normalController) {
+        super(normalController);
+        isInStaticallyCheckedMethod = false;
+    }
+
+    @Override
+    public void init(final AsmClassGenerator asmClassGenerator, final GeneratorContext gcon, final ClassVisitor cv, final ClassNode cn) {
+        super.init(asmClassGenerator, gcon, cv, cn);
+        this.callSiteWriter = new StaticTypesCallSiteWriter(this);
+        this.statementWriter = new StaticTypesStatementWriter(this);
+        this.typeChooser = new StaticTypesTypeChooser();
+        this.invocationWriter = new StaticInvocationWriter(this);
+        this.closureWriter = new StaticTypesClosureWriter(this);
+        this.unaryExpressionHelper = new StaticTypesUnaryExpressionHelper(this);
+
+        CompilerConfiguration config = cn.getCompileUnit().getConfig();
+        this.binaryExprHelper = config.isIndyEnabled()
+                ? new IndyStaticTypesMultiTypeDispatcher(this)
+                : new StaticTypesBinaryExpressionMultiTypeDispatcher(this);
+    }
+
+    @Override
+    public void setMethodNode(final MethodNode mn) {
+        updateStaticCompileFlag(mn);
+        super.setMethodNode(mn);
+    }
+
+    private void updateStaticCompileFlag(final MethodNode mn) {
+        ClassNode classNode = getClassNode();
+        AnnotatedNode node = mn;
+        if (classNode.implementsInterface(ClassHelper.GENERATED_CLOSURE_Type)) {
+            node = classNode.getOuterClass();
+        }
+
+        isInStaticallyCheckedMethod = mn != null && (
+                StaticCompilationVisitor.isStaticallyCompiled(node)
+                        || classNode.implementsInterface(ClassHelper.GENERATED_CLOSURE_Type)&&classNode.getNodeMetaData(StaticCompilationMetadataKeys.STATIC_COMPILE_NODE)!=null);
+    }
+
+    @Override
+    public void setConstructorNode(final ConstructorNode cn) {
+        updateStaticCompileFlag(cn);
+        super.setConstructorNode(cn);
+    }
+    
+    @Override
+    public boolean isFastPath() {
+        if (isInStaticallyCheckedMethod) return true;
+        return super.isFastPath();
+    }
+    
+    @Override
+    public CallSiteWriter getCallSiteWriter() {
+        MethodNode methodNode = getMethodNode();
+        if (methodNode !=null && methodNode.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION)==Boolean.TRUE) {
+            return super.getCallSiteWriter();
+        }
+        if (isInStaticallyCheckedMethod) {
+            return callSiteWriter;
+        }
+        return super.getCallSiteWriter();
+    }
+
+    public CallSiteWriter getRegularCallSiteWriter() {
+        return super.getCallSiteWriter();
+    }
+
+    @Override
+    public StatementWriter getStatementWriter() {
+        if (isInStaticallyCheckedMethod) {
+            return statementWriter;
+        } else {
+            return super.getStatementWriter();            
+        }
+    }
+    
+    @Override
+    public TypeChooser getTypeChooser() {
+        if (isInStaticallyCheckedMethod) {
+            return typeChooser;
+        } else {
+            return super.getTypeChooser();
+        }
+    }
+
+    @Override
+    public InvocationWriter getInvocationWriter() {
+        if (isInStaticallyCheckedMethod) {
+            return invocationWriter;
+        } else {
+            return super.getInvocationWriter();
+        }
+    }
+
+    public InvocationWriter getRegularInvocationWriter() {
+        return super.getInvocationWriter();
+    }
+
+    @Override
+    public BinaryExpressionHelper getBinaryExpressionHelper() {
+        if (isInStaticallyCheckedMethod) {
+            return binaryExprHelper;
+        } else {
+            return super.getBinaryExpressionHelper();
+        }
+    }
+
+    @Override
+    public UnaryExpressionHelper getUnaryExpressionHelper() {
+        if (isInStaticallyCheckedMethod) {
+            return unaryExpressionHelper;
+        }
+        return super.getUnaryExpressionHelper();
+    }
+
+    @Override
+    public ClosureWriter getClosureWriter() {
+        if (isInStaticallyCheckedMethod) {
+            return closureWriter;
+        }
+        return super.getClosureWriter();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterControllerFactoryImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterControllerFactoryImpl.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterControllerFactoryImpl.java
new file mode 100644
index 0000000..c68f635
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesWriterControllerFactoryImpl.java
@@ -0,0 +1,33 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.classgen.asm.WriterControllerFactory;
+
+/**
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class StaticTypesWriterControllerFactoryImpl implements WriterControllerFactory {
+
+    public WriterController makeController(WriterController normalController) {
+        return new StaticTypesWriterController(normalController);
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
new file mode 100644
index 0000000..895b5db
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -0,0 +1,1469 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+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.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+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.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.SpreadMapExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.control.ClassNodeResolver.LookupResult;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.trait.Traits;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.inSamePackage;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.isDefaultVisibility;
+
+/**
+ * Visitor to resolve Types and convert VariableExpression to
+ * ClassExpressions if needed. The ResolveVisitor will try to
+ * find the Class for a ClassExpression and prints an error if
+ * it fails to do so. Constructions like C[], foo as C, (C) foo
+ * will force creation of a ClassExpression for C
+ * <p>
+ * Note: the method to start the resolving is  startResolving(ClassNode, SourceUnit).
+ */
+public class ResolveVisitor extends ClassCodeExpressionTransformer {
+    private ClassNode currentClass;
+    // note: BigInteger and BigDecimal are also imported by default
+    public static final String[] DEFAULT_IMPORTS = {"java.lang.", "java.io.", "java.net.", "java.util.", "groovy.lang.", "groovy.util."};
+    private final CompilationUnit compilationUnit;
+    private SourceUnit source;
+    private VariableScope currentScope;
+
+    private boolean isTopLevelProperty = true;
+    private boolean inPropertyExpression = false;
+    private boolean inClosure = false;
+
+    private Map<String, GenericsType> genericParameterNames = new HashMap<String, GenericsType>();
+    private final Set<FieldNode> fieldTypesChecked = new HashSet<FieldNode>();
+    private boolean checkingVariableTypeInDeclaration = false;
+    private ImportNode currImportNode = null;
+    private MethodNode currentMethod;
+    private ClassNodeResolver classNodeResolver;
+
+    /**
+     * A ConstructedNestedClass consists of an outer class and a name part, denoting a
+     * nested class with an unknown number of levels down. This allows resolve tests to
+     * skip this node for further inner class searches and combinations with imports, since
+     * the outer class we know is already resolved.
+     */
+    private static class ConstructedNestedClass extends ClassNode {
+        final ClassNode knownEnclosingType;
+        public ConstructedNestedClass(ClassNode outer, String inner) {
+            super(outer.getName()+"$"+(inner=replacePoints(inner)), Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE);
+            this.knownEnclosingType = outer;
+            this.isPrimaryNode = false;
+        }
+        public boolean hasPackageName() {
+            if (redirect()!=this) return super.hasPackageName();
+            return knownEnclosingType.hasPackageName();
+        }
+        public String setName(String name) {
+            if (redirect()!=this) {
+                return super.setName(name);
+            } else {
+                throw new GroovyBugError("ConstructedNestedClass#setName should not be called");
+            }
+        }
+    }
+
+
+    private static String replacePoints(String name) {
+        return name.replace('.','$');
+    }
+
+    /**
+     * we use ConstructedClassWithPackage to limit the resolving the compiler
+     * does when combining package names and class names. The idea
+     * that if we use a package, then we do not want to replace the
+     * '.' with a '$' for the package part, only for the class name
+     * part. There is also the case of a imported class, so this logic
+     * can't be done in these cases...
+     */
+    private static class ConstructedClassWithPackage extends ClassNode {
+        final String prefix;
+        String className;
+        public ConstructedClassWithPackage(String pkg, String name) {
+            super(pkg+name, Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE);
+            isPrimaryNode = false;
+            this.prefix = pkg;
+            this.className = name;
+        }
+        public String getName() {
+            if (redirect()!=this) return super.getName();
+            return prefix+className;
+        }
+        public boolean hasPackageName() {
+            if (redirect()!=this) return super.hasPackageName();
+            return className.indexOf('.')!=-1;
+        }
+        public String setName(String name) {
+            if (redirect()!=this) {
+                return super.setName(name);
+            } else {
+                throw new GroovyBugError("ConstructedClassWithPackage#setName should not be called");
+            }
+        }
+    }
+
+     /**
+     * we use LowerCaseClass to limit the resolving the compiler
+     * does for vanilla names starting with a lower case letter. The idea
+     * that if we use a vanilla name with a lower case letter, that this
+     * is in most cases no class. If it is a class the class needs to be
+     * imported explicitly. The effect is that in an expression like
+     * "def foo = bar" we do not have to use a loadClass call to check the
+     * name foo and bar for being classes. Instead we will ask the module
+     * for an alias for this name which is much faster.
+     */
+    private static class LowerCaseClass extends ClassNode {
+        final String className;
+        public LowerCaseClass(String name) {
+            super(name, Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE);
+            isPrimaryNode = false;
+            this.className = name;
+        }
+        public String getName() {
+            if (redirect()!=this) return super.getName();
+            return className;
+        }
+        public boolean hasPackageName() {
+            if (redirect()!=this) return super.hasPackageName();
+            return false;
+        }
+        public String setName(String name) {
+            if (redirect()!=this) {
+                return super.setName(name);
+            } else {
+                throw new GroovyBugError("LowerCaseClass#setName should not be called");
+            }
+        }
+    }
+
+    public ResolveVisitor(CompilationUnit cu) {
+        compilationUnit = cu;
+        this.classNodeResolver = new ClassNodeResolver();
+    }
+
+    public void startResolving(ClassNode node, SourceUnit source) {
+        this.source = source;
+        visitClass(node);
+    }
+
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        VariableScope oldScope = currentScope;
+        currentScope = node.getVariableScope();
+        Map<String, GenericsType> oldPNames = genericParameterNames;
+        genericParameterNames = node.isStatic()
+                ? new HashMap<String, GenericsType>()
+                : new HashMap<String, GenericsType>(genericParameterNames);
+
+        resolveGenericsHeader(node.getGenericsTypes());
+
+        Parameter[] paras = node.getParameters();
+        for (Parameter p : paras) {
+            p.setInitialExpression(transform(p.getInitialExpression()));
+            resolveOrFail(p.getType(), p.getType());
+            visitAnnotations(p);
+        }
+        ClassNode[] exceptions = node.getExceptions();
+        for (ClassNode t : exceptions) {
+            resolveOrFail(t, node);
+        }
+        resolveOrFail(node.getReturnType(), node);
+
+        MethodNode oldCurrentMethod = currentMethod;
+        currentMethod = node;
+        super.visitConstructorOrMethod(node, isConstructor);
+
+        currentMethod = oldCurrentMethod;
+        genericParameterNames = oldPNames;
+        currentScope = oldScope;
+    }
+
+    public void visitField(FieldNode node) {
+        ClassNode t = node.getType();
+        if(!fieldTypesChecked.contains(node)) {
+            resolveOrFail(t, node);
+        }
+        super.visitField(node);
+    }
+
+    public void visitProperty(PropertyNode node) {
+        Map<String, GenericsType> oldPNames = genericParameterNames;
+        if (node.isStatic()) {
+            genericParameterNames = new HashMap<String, GenericsType>();
+        }
+
+        ClassNode t = node.getType();
+        resolveOrFail(t, node);
+        super.visitProperty(node);
+        fieldTypesChecked.add(node.getField());
+
+        genericParameterNames = oldPNames;
+    }
+
+    private boolean resolveToInner (ClassNode type) {
+        // we do not do our name mangling to find an inner class
+        // if the type is a ConstructedClassWithPackage, because in this case we
+        // are resolving the name at a different place already
+        if (type instanceof ConstructedClassWithPackage) return false;
+        if (type instanceof ConstructedNestedClass) return false;
+        String name = type.getName();
+        String saved = name;
+        while (true) {
+            int len = name.lastIndexOf('.');
+            if (len == -1) break;
+            name = name.substring(0,len) + "$" + name.substring(len+1);
+            type.setName(name);
+            if (resolve(type)) return true;
+        }
+        if(resolveToNestedOfCurrent(type)) return true;
+        
+        type.setName(saved);
+        return false;
+    }
+
+    private boolean resolveToNestedOfCurrent(ClassNode type) {
+        if (type instanceof ConstructedNestedClass) return false;
+        // GROOVY-3110: It may be an inner enum defined by this class itself, in which case it does not need to be
+        // explicitly qualified by the currentClass name
+        String name = type.getName();
+        if (currentClass != type && !name.contains(".") && type.getClass().equals(ClassNode.class)) {
+            ClassNode tmp = new ConstructedNestedClass(currentClass,name);
+            if (resolve(tmp)) {
+                type.setRedirect(tmp);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void resolveOrFail(ClassNode type, String msg, ASTNode node) {
+        if (resolve(type)) return;
+        if (resolveToInner(type)) return;
+        addError("unable to resolve class " + type.getName() + " " + msg, node);
+    }
+
+    private void resolveOrFail(ClassNode type, ASTNode node, boolean prefereImports) {
+        resolveGenericsTypes(type.getGenericsTypes());
+        if (prefereImports && resolveAliasFromModule(type)) return;
+        resolveOrFail(type, node);
+    }
+
+    private void resolveOrFail(ClassNode type, ASTNode node) {
+        resolveOrFail(type, "", node);
+    }
+
+    private boolean resolve(ClassNode type) {
+        return resolve(type, true, true, true);
+    }
+
+    private boolean resolve(ClassNode type, boolean testModuleImports, boolean testDefaultImports, boolean testStaticInnerClasses) {
+        resolveGenericsTypes(type.getGenericsTypes());
+        if (type.isResolved() || type.isPrimaryClassNode()) return true;
+        if (type.isArray()) {
+            ClassNode element = type.getComponentType();
+            boolean resolved = resolve(element, testModuleImports, testDefaultImports, testStaticInnerClasses);
+            if (resolved) {
+                ClassNode cn = element.makeArray();
+                type.setRedirect(cn);
+            }
+            return resolved;
+        }
+
+        // test if vanilla name is current class name
+        if (currentClass == type) return true;
+
+        if (genericParameterNames.get(type.getName()) != null) {
+            GenericsType gt = genericParameterNames.get(type.getName());
+            type.setRedirect(gt.getType());
+            type.setGenericsTypes(new GenericsType[]{gt});
+            type.setGenericsPlaceHolder(true);
+            return true;
+        }
+
+        if (currentClass.getNameWithoutPackage().equals(type.getName())) {
+            type.setRedirect(currentClass);
+            return true;
+        }
+
+        return resolveNestedClass(type) ||
+                resolveFromModule(type, testModuleImports) ||
+                resolveFromCompileUnit(type) ||
+                resolveFromDefaultImports(type, testDefaultImports) ||
+                resolveFromStaticInnerClasses(type, testStaticInnerClasses) ||
+                resolveToOuter(type);
+    }
+
+    private boolean resolveNestedClass(ClassNode type) {
+        if (type instanceof ConstructedNestedClass) return false;
+        // we have for example a class name A, are in class X
+        // and there is a nested class A$X. we want to be able 
+        // to access that class directly, so A becomes a valid
+        // name in X.
+        // GROOVY-4043: Do this check up the hierarchy, if needed
+        Map<String, ClassNode> hierClasses = new LinkedHashMap<String, ClassNode>();
+        ClassNode val;
+        for(ClassNode classToCheck = currentClass; classToCheck != ClassHelper.OBJECT_TYPE; 
+            classToCheck = classToCheck.getSuperClass()) {
+            if(classToCheck == null || hierClasses.containsKey(classToCheck.getName())) break;
+            hierClasses.put(classToCheck.getName(), classToCheck);
+        }
+
+        for (ClassNode classToCheck : hierClasses.values()) {
+            val = new ConstructedNestedClass(classToCheck,type.getName());
+            if (resolveFromCompileUnit(val)) {
+                type.setRedirect(val);
+                return true;
+            }
+            // also check interfaces in case we have interfaces with nested classes
+            for (ClassNode next : classToCheck.getAllInterfaces()) {
+                if (type.getName().contains(next.getName())) continue;
+                val = new ConstructedNestedClass(next,type.getName());
+                if (resolve(val, false, false, false)) {
+                    type.setRedirect(val);
+                    return true;
+                }
+            }
+        }
+
+        // another case we want to check here is if we are in a
+        // nested class A$B$C and want to access B without
+        // qualifying it by A.B. A alone will work, since that
+        // is the qualified (minus package) name of that class
+        // anyway. 
+        
+        // That means if the current class is not an InnerClassNode
+        // there is nothing to be done.
+        if (!(currentClass instanceof InnerClassNode)) return false;
+        
+        // since we have B and want to get A we start with the most 
+        // outer class, put them together and then see if that does
+        // already exist. In case of B from within A$B we are done 
+        // after the first step already. In case of for example
+        // A.B.C.D.E.F and accessing E from F we test A$E=failed, 
+        // A$B$E=failed, A$B$C$E=fail, A$B$C$D$E=success
+        
+        LinkedList<ClassNode> outerClasses = new LinkedList<ClassNode>();
+        ClassNode outer = currentClass.getOuterClass();
+        while (outer!=null) {
+            outerClasses.addFirst(outer);
+            outer = outer.getOuterClass();
+        }
+        // most outer class is now element 0
+        for (ClassNode testNode : outerClasses) {
+            val = new ConstructedNestedClass(testNode,type.getName());
+            if (resolveFromCompileUnit(val)) {
+                type.setRedirect(val);
+                return true;
+            }
+            // also check interfaces in case we have interfaces with nested classes
+            for (ClassNode next : testNode.getAllInterfaces()) {
+                if (type.getName().contains(next.getName())) continue;
+                val = new ConstructedNestedClass(next,type.getName());
+                if (resolve(val, false, false, false)) {
+                    type.setRedirect(val);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private static String replaceLastPoint(String name) {
+        int lastPoint = name.lastIndexOf('.');
+        name = new StringBuffer()
+                .append(name.substring(0, lastPoint))
+                .append("$")
+                .append(name.substring(lastPoint + 1))
+                .toString();
+        return name;
+    }
+
+    private boolean resolveFromStaticInnerClasses(ClassNode type, boolean testStaticInnerClasses) {
+        if (type instanceof ConstructedNestedClass) return false;
+
+        // a class consisting of a vanilla name can never be
+        // a static inner class, because at least one dot is
+        // required for this. Example: foo.bar -> foo$bar
+        if (type instanceof LowerCaseClass) return false;
+
+        // try to resolve a public static inner class' name
+        testStaticInnerClasses &= type.hasPackageName();
+        if (testStaticInnerClasses) {
+            if (type instanceof ConstructedClassWithPackage) {
+                // we replace '.' only in the className part
+                // with '$' to find an inner class. The case that
+                // the package is really a class is handled elsewhere
+                ConstructedClassWithPackage tmp = (ConstructedClassWithPackage) type;
+                String savedName = tmp.className;
+                tmp.className = replaceLastPoint(savedName);
+                if (resolve(tmp, false, true, true)) {
+                    type.setRedirect(tmp.redirect());
+                    return true;
+                }
+                tmp.className = savedName;
+            }   else {
+                String savedName = type.getName();
+                String replacedPointType = replaceLastPoint(savedName);
+                type.setName(replacedPointType);
+                if (resolve(type, false, true, true)) return true;
+                type.setName(savedName);
+            }
+        }
+        return false;
+    }
+
+    private boolean resolveFromDefaultImports(ClassNode type, boolean testDefaultImports) {
+        // test default imports
+        testDefaultImports &= !type.hasPackageName();
+        // we do not resolve a vanilla name starting with a lower case letter
+        // try to resolve against a default import, because we know that the
+        // default packages do not contain classes like these
+        testDefaultImports &= !(type instanceof LowerCaseClass);
+        if (testDefaultImports) {
+            for (int i = 0, size = DEFAULT_IMPORTS.length; i < size; i++) {
+                String packagePrefix = DEFAULT_IMPORTS[i];
+                String name = type.getName();
+                // We limit the inner class lookups here by using ConstructedClassWithPackage.
+                // This way only the name will change, the packagePrefix will
+                // not be included in the lookup. The case where the
+                // packagePrefix is really a class is handled elsewhere.
+                // WARNING: This code does not expect a class that has a static
+                //          inner class in DEFAULT_IMPORTS
+                ConstructedClassWithPackage tmp =  new ConstructedClassWithPackage(packagePrefix,name);
+                if (resolve(tmp, false, false, false)) {
+                    type.setRedirect(tmp.redirect());
+                    return true;
+                }
+            }
+            String name = type.getName();
+            if (name.equals("BigInteger")) {
+                type.setRedirect(ClassHelper.BigInteger_TYPE);
+                return true;
+            } else if (name.equals("BigDecimal")) {
+                type.setRedirect(ClassHelper.BigDecimal_TYPE);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean resolveFromCompileUnit(ClassNode type) {
+        // look into the compile unit if there is a class with that name
+        CompileUnit compileUnit = currentClass.getCompileUnit();
+        if (compileUnit == null) return false;
+        ClassNode cuClass = compileUnit.getClass(type.getName());
+        if (cuClass != null) {
+            if (type != cuClass) type.setRedirect(cuClass);
+            return true;
+        }
+        return false;
+    }
+
+    private void ambiguousClass(ClassNode type, ClassNode iType, String name) {
+        if (type.getName().equals(iType.getName())) {
+            addError("reference to " + name + " is ambiguous, both class " + type.getName() + " and " + iType.getName() + " match", type);
+        } else {
+            type.setRedirect(iType);
+        }
+    }
+
+    private boolean resolveAliasFromModule(ClassNode type) {
+        // In case of getting a ConstructedClassWithPackage here we do not do checks for partial
+        // matches with imported classes. The ConstructedClassWithPackage is already a constructed
+        // node and any subclass resolving will then take place elsewhere
+        if (type instanceof ConstructedClassWithPackage) return false;
+
+        ModuleNode module = currentClass.getModule();
+        if (module == null) return false;
+        String name = type.getName();
+
+        // check module node imports aliases
+        // the while loop enables a check for inner classes which are not fully imported,
+        // but visible as the surrounding class is imported and the inner class is public/protected static
+        String pname = name;
+        int index = name.length();
+        /*
+         * we have a name foo.bar and an import foo.foo. This means foo.bar is possibly
+         * foo.foo.bar rather than foo.bar. This means to cut at the dot in foo.bar and
+         * foo for import
+         */
+        while (true) {
+            pname = name.substring(0, index);
+            ClassNode aliasedNode = null;
+            ImportNode importNode = module.getImport(pname);
+            if (importNode != null && importNode != currImportNode) {
+                aliasedNode = importNode.getType();
+            }
+            if (aliasedNode == null) {
+                importNode = module.getStaticImports().get(pname);
+                if (importNode != null && importNode != currImportNode) {
+                    // static alias only for inner classes and must be at end of chain
+                    ClassNode tmp = new ConstructedNestedClass(importNode.getType(), importNode.getFieldName());
+                    if (resolve(tmp, false, false, true)) {
+                        if ((tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
+                            type.setRedirect(tmp.redirect());
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            if (aliasedNode != null) {
+                if (pname.length() == name.length()) {
+                    // full match
+
+                    // We can compare here by length, because pname is always
+                    // a substring of name, so same length means they are equal.
+                    type.setRedirect(aliasedNode);
+                    return true;
+                } else {
+                    //partial match
+
+                    // At this point we know that we have a match for pname. This may
+                    // mean, that name[pname.length()..<-1] is a static inner class.
+                    // For this the rest of the name does not need any dots in its name.
+                    // It is either completely a inner static class or it is not.
+                    // Since we do not want to have useless lookups we create the name
+                    // completely and use a ConstructedClassWithPackage to prevent lookups against the package.
+                    String className = aliasedNode.getNameWithoutPackage() + '$' +
+                            name.substring(pname.length() + 1).replace('.', '$');
+                    ConstructedClassWithPackage tmp = new ConstructedClassWithPackage(aliasedNode.getPackageName()+".", className);
+                    if (resolve(tmp, true, true, false)) {
+                        type.setRedirect(tmp.redirect());
+                        return true;
+                    }
+                }
+            }
+            index = pname.lastIndexOf('.');
+            if (index == -1) break;
+        }
+        return false;
+    }
+
+    private boolean resolveFromModule(ClassNode type, boolean testModuleImports) {
+        if (type instanceof ConstructedNestedClass) return false;
+
+        // we decided if we have a vanilla name starting with a lower case
+        // letter that we will not try to resolve this name against .*
+        // imports. Instead a full import is needed for these.
+        // resolveAliasFromModule will do this check for us. This method
+        // does also check the module contains a class in the same package
+        // of this name. This check is not done for vanilla names starting
+        // with a lower case letter anymore
+        if (type instanceof LowerCaseClass) {
+            return resolveAliasFromModule(type);
+        }
+
+        String name = type.getName();
+        ModuleNode module = currentClass.getModule();
+        if (module == null) return false;
+
+        boolean newNameUsed = false;
+        // we add a package if there is none yet and the module has one. But we
+        // do not add that if the type is a ConstructedClassWithPackage. The code in ConstructedClassWithPackage
+        // hasPackageName() will return true if ConstructedClassWithPackage#className has no dots.
+        // but since the prefix may have them and the code there does ignore that
+        // fact. We check here for ConstructedClassWithPackage.
+        if (!type.hasPackageName() && module.hasPackageName() && !(type instanceof ConstructedClassWithPackage)) {
+            type.setName(module.getPackageName() + name);
+            newNameUsed = true;
+        }
+        // look into the module node if there is a class with that name
+        List<ClassNode> moduleClasses = module.getClasses();
+        for (ClassNode mClass : moduleClasses) {
+            if (mClass.getName().equals(type.getName())) {
+                if (mClass != type) type.setRedirect(mClass);
+                return true;
+            }
+        }
+        if (newNameUsed) type.setName(name);
+
+        if (testModuleImports) {
+            if (resolveAliasFromModule(type)) return true;
+
+            if (module.hasPackageName()) {
+                // check package this class is defined in. The usage of ConstructedClassWithPackage here
+                // means, that the module package will not be involved when the
+                // compiler tries to find an inner class.
+                ConstructedClassWithPackage tmp =  new ConstructedClassWithPackage(module.getPackageName(), name);
+                if (resolve(tmp, false, false, false)) {
+                    ambiguousClass(type, tmp, name);
+                    type.setRedirect(tmp.redirect());
+                    return true;
+                }
+            }
+
+            // check module static imports (for static inner classes)
+            for (ImportNode importNode : module.getStaticImports().values()) {
+                if (importNode.getFieldName().equals(name)) {
+                    ClassNode tmp = new ConstructedNestedClass(importNode.getType(), name);
+                    if (resolve(tmp, false, false, true)) {
+                        if ((tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
+                            type.setRedirect(tmp.redirect());
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            // check module node import packages
+            for (ImportNode importNode : module.getStarImports()) {
+                String packagePrefix = importNode.getPackageName();
+                // We limit the inner class lookups here by using ConstructedClassWithPackage.
+                // This way only the name will change, the packagePrefix will
+                // not be included in the lookup. The case where the
+                // packagePrefix is really a class is handled elsewhere.
+                ConstructedClassWithPackage tmp = new ConstructedClassWithPackage(packagePrefix, name);
+                if (resolve(tmp, false, false, true)) {
+                    ambiguousClass(type, tmp, name);
+                    type.setRedirect(tmp.redirect());
+                    return true;
+                }
+            }
+
+            // check for star imports (import static pkg.Outer.*) matching static inner classes
+            for (ImportNode importNode : module.getStaticStarImports().values()) {
+                ClassNode tmp = new ConstructedNestedClass(importNode.getType(), name);
+                if (resolve(tmp, false, false, true)) {
+                    if ((tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
+                        ambiguousClass(type, tmp, name);
+                        type.setRedirect(tmp.redirect());
+                        return true;
+                    }
+                }
+
+            }
+        }
+        return false;
+    }
+
+    private boolean resolveToOuter(ClassNode type) {
+        String name = type.getName();
+
+        // We do not need to check instances of LowerCaseClass
+        // to be a Class, because unless there was an import for
+        // for this we do not lookup these cases. This was a decision
+        // made on the mailing list. To ensure we will not visit this
+        // method again we set a NO_CLASS for this name
+        if (type instanceof LowerCaseClass) {
+            classNodeResolver.cacheClass(name, ClassNodeResolver.NO_CLASS);
+            return false;
+        }
+
+        if (currentClass.getModule().hasPackageName() && name.indexOf('.') == -1) return false;
+        LookupResult lr = null;
+        lr = classNodeResolver.resolveName(name, compilationUnit);
+        if (lr!=null) {
+            if (lr.isSourceUnit()) {
+                SourceUnit su = lr.getSourceUnit();
+                currentClass.getCompileUnit().addClassNodeToCompile(type, su);
+            } else {
+                type.setRedirect(lr.getClassNode());
+            }
+            return true;
+        }
+        return false;
+    }
+
+
+    public Expression transform(Expression exp) {
+        if (exp == null) return null;
+        Expression ret = null;
+        if (exp instanceof VariableExpression) {
+            ret = transformVariableExpression((VariableExpression) exp);
+        } else if (exp.getClass() == PropertyExpression.class) {
+            ret = transformPropertyExpression((PropertyExpression) exp);
+        } else if (exp instanceof DeclarationExpression) {
+            ret = transformDeclarationExpression((DeclarationExpression) exp);
+        } else if (exp instanceof BinaryExpression) {
+            ret = transformBinaryExpression((BinaryExpression) exp);
+        } else if (exp instanceof MethodCallExpression) {
+            ret = transformMethodCallExpression((MethodCallExpression) exp);
+        } else if (exp instanceof ClosureExpression) {
+            ret = transformClosureExpression((ClosureExpression) exp);
+        } else if (exp instanceof ConstructorCallExpression) {
+            ret = transformConstructorCallExpression((ConstructorCallExpression) exp);
+        } else if (exp instanceof AnnotationConstantExpression) {
+            ret = transformAnnotationConstantExpression((AnnotationConstantExpression) exp);
+        } else {
+            resolveOrFail(exp.getType(), exp);
+            ret = exp.transformExpression(this);
+        }
+        if (ret!=null && ret!=exp) ret.setSourcePosition(exp);
+        return ret;
+    }
+
+    private static String lookupClassName(PropertyExpression pe) {
+        boolean doInitialClassTest=true;
+        String name = "";
+        // this loop builds a name from right to left each name part
+        // separated by "."
+        for (Expression it = pe; it != null; it = ((PropertyExpression) it).getObjectExpression()) {
+            if (it instanceof VariableExpression) {
+                VariableExpression ve = (VariableExpression) it;
+                // stop at super and this
+                if (ve.isSuperExpression() || ve.isThisExpression()) {
+                    return null;
+                }
+                String varName = ve.getName();
+                if (doInitialClassTest) {
+                    // we are at the first name part. This is the right most part.
+                    // If this part is in lower case, then we do not need a class
+                    // check. other parts of the property expression will be tested
+                    // by a different method call to this method, so foo.Bar.bar
+                    // can still be resolved to the class foo.Bar and the static
+                    // field bar.
+                    if (!testVanillaNameForClass(varName)) return null;
+                    doInitialClassTest = false;
+                    name = varName;
+                } else {
+                    name = varName + "." + name;
+                }
+                break;
+            }
+            // anything other than PropertyExpressions or
+            // VariableExpressions will stop resolving
+            else if (it.getClass() != PropertyExpression.class) {
+                return null;
+            } else {
+                PropertyExpression current = (PropertyExpression) it;
+                String propertyPart = current.getPropertyAsString();
+                // the class property stops resolving, dynamic property names too
+                if (propertyPart == null || propertyPart.equals("class")) {
+                    return null;
+                }
+                if (doInitialClassTest) {
+                    // we are at the first name part. This is the right most part.
+                    // If this part is in lower case, then we do not need a class
+                    // check. other parts of the property expression will be tested
+                    // by a different method call to this method, so foo.Bar.bar
+                    // can still be resolved to the class foo.Bar and the static
+                    // field bar.
+                    if (!testVanillaNameForClass(propertyPart)) return null;
+                    doInitialClassTest= false;
+                    name = propertyPart;
+                } else {
+                    name = propertyPart + "." + name;
+                }
+            }
+        }
+        if (name.length() == 0) return null;
+        return name;
+    }
+
+    // iterate from the inner most to the outer and check for classes
+    // this check will ignore a .class property, for Example Integer.class will be
+    // a PropertyExpression with the ClassExpression of Integer as objectExpression
+    // and class as property
+    private static Expression correctClassClassChain(PropertyExpression pe) {
+        LinkedList<Expression> stack = new LinkedList<Expression>();
+        ClassExpression found = null;
+        for (Expression it = pe; it != null; it = ((PropertyExpression) it).getObjectExpression()) {
+            if (it instanceof ClassExpression) {
+                found = (ClassExpression) it;
+                break;
+            } else if (!(it.getClass() == PropertyExpression.class)) {
+                return pe;
+            }
+            stack.addFirst(it);
+        }
+        if (found == null) return pe;
+
+        if (stack.isEmpty()) return pe;
+        Object stackElement = stack.removeFirst();
+        if (!(stackElement.getClass() == PropertyExpression.class)) return pe;
+        PropertyExpression classPropertyExpression = (PropertyExpression) stackElement;
+        String propertyNamePart = classPropertyExpression.getPropertyAsString();
+        if (propertyNamePart == null || !propertyNamePart.equals("class")) return pe;
+
+        found.setSourcePosition(classPropertyExpression);
+        if (stack.isEmpty()) return found;
+        stackElement = stack.removeFirst();
+        if (!(stackElement.getClass() == PropertyExpression.class)) return pe;
+        PropertyExpression classPropertyExpressionContainer = (PropertyExpression) stackElement;
+
+        classPropertyExpressionContainer.setObjectExpression(found);
+        return pe;
+    }
+
+    protected Expression transformPropertyExpression(PropertyExpression pe) {
+        boolean itlp = isTopLevelProperty;
+        boolean ipe = inPropertyExpression;
+
+        Expression objectExpression = pe.getObjectExpression();
+        inPropertyExpression = true;
+        isTopLevelProperty = (objectExpression.getClass() != PropertyExpression.class);
+        objectExpression = transform(objectExpression);
+        // we handle the property part as if it were not part of the property
+        inPropertyExpression = false;
+        Expression property = transform(pe.getProperty());
+        isTopLevelProperty = itlp;
+        inPropertyExpression = ipe;
+
+        boolean spreadSafe = pe.isSpreadSafe();
+        PropertyExpression old = pe;
+        pe = new PropertyExpression(objectExpression, property, pe.isSafe());
+        pe.setSpreadSafe(spreadSafe);
+        pe.setSourcePosition(old);
+
+        String className = lookupClassName(pe);
+        if (className != null) {
+            ClassNode type = ClassHelper.make(className);
+            if (resolve(type)) {
+                Expression ret =  new ClassExpression(type);
+                ret.setSourcePosition(pe);
+                return ret;
+            }
+        }
+        if (objectExpression instanceof ClassExpression && pe.getPropertyAsString() != null) {
+            // possibly an inner class (or inherited inner class)
+            ClassExpression ce = (ClassExpression) objectExpression;
+            ClassNode classNode = ce.getType();
+            while (classNode != null) {
+                ClassNode type = new ConstructedNestedClass(classNode, pe.getPropertyAsString());
+                if (resolve(type, false, false, false)) {
+                    if (classNode == ce.getType() || isVisibleNestedClass(type, ce.getType())) {
+                        Expression ret = new ClassExpression(type);
+                        ret.setSourcePosition(ce);
+                        return ret;
+                    }
+                }
+                classNode = classNode.getSuperClass();
+            }
+        }
+        Expression ret = pe;
+        checkThisAndSuperAsPropertyAccess(pe);
+        if (isTopLevelProperty) ret = correctClassClassChain(pe);
+        return ret;
+    }
+
+    private boolean isVisibleNestedClass(ClassNode type, ClassNode ceType) {
+        if (!type.isRedirectNode()) return false;
+        ClassNode redirect = type.redirect();
+        if (Modifier.isPublic(redirect.getModifiers()) || Modifier.isProtected(redirect.getModifiers())) return true;
+        // package local
+        return isDefaultVisibility(redirect.getModifiers()) && inSamePackage(ceType, redirect);
+    }
+
+    private boolean directlyImplementsTrait(ClassNode trait) {
+        ClassNode[] interfaces = currentClass.getInterfaces();
+        if (interfaces==null) {
+            return currentClass.getSuperClass().equals(trait);
+        }
+        for (ClassNode node : interfaces) {
+            if (node.equals(trait)) {
+                return true;
+            }
+        }
+        return currentClass.getSuperClass().equals(trait);
+    }
+
+    private void checkThisAndSuperAsPropertyAccess(PropertyExpression expression) {
+        if (expression.isImplicitThis()) return;
+        String prop = expression.getPropertyAsString();
+        if (prop == null) return;
+        if (!prop.equals("this") && !prop.equals("super")) return;
+
+        ClassNode type = expression.getObjectExpression().getType();
+        if (expression.getObjectExpression() instanceof ClassExpression) {
+            if (!(currentClass instanceof InnerClassNode) && !Traits.isTrait(type)) {
+                addError("The usage of 'Class.this' and 'Class.super' is only allowed in nested/inner classes.", expression);
+                return;
+            }
+            if (currentScope!=null && !currentScope.isInStaticContext() && Traits.isTrait(type) && "super".equals(prop) && directlyImplementsTrait(type)) {
+                return;
+            }
+            ClassNode iterType = currentClass;
+            while (iterType != null) {
+                if (iterType.equals(type)) break;
+                iterType = iterType.getOuterClass();
+            }
+            if (iterType == null) {
+                addError("The class '" + type.getName() + "' needs to be an outer class of '" +
+                        currentClass.getName() + "' when using '.this' or '.super'.", expression);
+            }
+            if ((currentClass.getModifiers() & Opcodes.ACC_STATIC) == 0) return;
+            if (currentScope != null && !currentScope.isInStaticContext()) return;
+            addError("The usage of 'Class.this' and 'Class.super' within static nested class '" +
+                    currentClass.getName() + "' is not allowed in a static context.", expression);
+        }
+    }
+
+    protected Expression transformVariableExpression(VariableExpression ve) {
+        visitAnnotations(ve);
+        Variable v = ve.getAccessedVariable();
+        
+        if(!(v instanceof DynamicVariable) && !checkingVariableTypeInDeclaration) {
+            /*
+             *  GROOVY-4009: when a normal variable is simply being used, there is no need to try to 
+             *  resolve its type. Variable type resolve should proceed only if the variable is being declared. 
+             */
+            return ve;
+        }
+        if (v instanceof DynamicVariable){
+            String name = ve.getName();
+            ClassNode t = ClassHelper.make(name);
+            // asking isResolved here allows to check if a primitive
+            // type name like "int" was used to make t. In such a case
+            // we have nothing left to do.
+            boolean isClass = t.isResolved();
+            if (!isClass) {
+                // It was no primitive type, so next we see if the name,
+                // which is a vanilla name, starts with a lower case letter.
+                // In that case we change it to a LowerCaseClass to let the
+                // compiler skip the resolving at several places in this class.
+                if (Character.isLowerCase(name.charAt(0))) {
+                  t = new LowerCaseClass(name);
+                }
+                isClass = resolve(t);
+                if(!isClass) isClass = resolveToNestedOfCurrent(t);
+            }
+            if (isClass) {
+                // the name is a type so remove it from the scoping
+                // as it is only a classvariable, it is only in
+                // referencedClassVariables, but must be removed
+                // for each parentscope too
+                for (VariableScope scope = currentScope; scope != null && !scope.isRoot(); scope = scope.getParent()) {
+                    if (scope.isRoot()) break;
+                    if (scope.removeReferencedClassVariable(ve.getName()) == null) break;
+                }
+                ClassExpression ce = new ClassExpression(t);
+                ce.setSourcePosition(ve);
+                return ce;
+            }
+        }
+        resolveOrFail(ve.getType(), ve);
+        ClassNode origin = ve.getOriginType();
+        if (origin!=ve.getType()) resolveOrFail(origin, ve);
+        return ve;
+    }
+
+    private static boolean testVanillaNameForClass(String name) {
+        if (name==null || name.length()==0) return false;
+        return !Character.isLowerCase(name.charAt(0));
+    }
+
+    private static boolean isLeftSquareBracket(int op) {
+        return op == Types.ARRAY_EXPRESSION
+                || op == Types.LEFT_SQUARE_BRACKET
+                || op == Types.SYNTH_LIST
+                || op == Types.SYNTH_MAP;
+    }
+
+    protected Expression transformBinaryExpression(BinaryExpression be) {
+        Expression left = transform(be.getLeftExpression());
+        int type = be.getOperation().getType();
+        if ((type == Types.ASSIGNMENT_OPERATOR || type == Types.EQUAL) &&
+                left instanceof ClassExpression) {
+            ClassExpression ce = (ClassExpression) left;
+            String error = "you tried to assign a value to the class '" + ce.getType().getName() + "'";
+            if (ce.getType().isScript()) {
+                error += ". Do you have a script with this name?";
+            }
+            addError(error, be.getLeftExpression());
+            return be;
+        }
+        if (left instanceof ClassExpression && isLeftSquareBracket(type)) {
+            if (be.getRightExpression() instanceof ListExpression) {
+                ListExpression list = (ListExpression) be.getRightExpression();
+                if (list.getExpressions().isEmpty()) {
+                    // we have C[] if the list is empty -> should be an array then!
+                    final ClassExpression ce = new ClassExpression(left.getType().makeArray());
+                    ce.setSourcePosition(be);
+                    return ce;
+                }
+                else {
+                    // may be we have C[k1:v1, k2:v2] -> should become (C)([k1:v1, k2:v2])
+                    boolean map = true;
+                    for (Expression expression : list.getExpressions()) {
+                        if(!(expression instanceof MapEntryExpression)) {
+                            map = false;
+                            break;
+                        }
+                    }
+
+                    if (map) {
+                        final MapExpression me = new MapExpression();
+                        for (Expression expression : list.getExpressions()) {
+                            me.addMapEntryExpression((MapEntryExpression) transform(expression));
+                        }
+                        me.setSourcePosition(list);
+                        final CastExpression ce = new CastExpression(left.getType(), me);
+                        ce.setSourcePosition(be);
+                        return ce;
+                    }
+                }
+            } else if (be.getRightExpression() instanceof SpreadMapExpression) {
+                // we have C[*:map] -> should become (C) map
+                SpreadMapExpression mapExpression = (SpreadMapExpression) be.getRightExpression();
+                Expression right = transform(mapExpression.getExpression());
+                Expression ce = new CastExpression(left.getType(), right);
+                ce.setSourcePosition(be);
+                return ce;
+            }
+
+            if (be.getRightExpression() instanceof MapEntryExpression) {
+                // may be we have C[k1:v1] -> should become (C)([k1:v1])
+                final MapExpression me = new MapExpression();
+                me.addMapEntryExpression((MapEntryExpression) transform(be.getRightExpression()));
+                me.setSourcePosition(be.getRightExpression());
+                final CastExpression ce = new CastExpression(left.getType(), me);
+                ce.setSourcePosition(be);
+                return ce;
+            }
+        }
+        Expression right = transform(be.getRightExpression());
+        be.setLeftExpression(left);
+        be.setRightExpression(right);
+        return be;
+    }
+
+    protected Expression transformClosureExpression(ClosureExpression ce) {
+        boolean oldInClosure = inClosure;
+        inClosure = true;
+        Parameter[] paras = ce.getParameters();
+        if (paras != null) {
+            for (Parameter para : paras) {
+                ClassNode t = para.getType();
+                resolveOrFail(t, ce);
+                visitAnnotations(para);
+                if (para.hasInitialExpression()) {
+                    Object initialVal = para.getInitialExpression();
+                    if (initialVal instanceof Expression) {
+                        para.setInitialExpression(transform((Expression) initialVal));
+                    }
+                }
+                visitAnnotations(para);
+            }
+        }
+        Statement code = ce.getCode();
+        if (code != null) code.visit(this);
+        inClosure = oldInClosure;
+        return ce;
+    }
+
+    protected Expression transformConstructorCallExpression(ConstructorCallExpression cce) {
+        ClassNode type = cce.getType();
+        resolveOrFail(type, cce);
+        if (Modifier.isAbstract(type.getModifiers())) {
+            addError("You cannot create an instance from the abstract " + getDescription(type) + ".", cce);
+        }
+
+        Expression ret = cce.transformExpression(this);
+        return ret;
+    }
+
+    private static String getDescription(ClassNode node) {
+        return (node.isInterface() ? "interface" : "class") + " '" + node.getName() + "'";
+    }
+    
+    protected Expression transformMethodCallExpression(MethodCallExpression mce) {
+        Expression args = transform(mce.getArguments());
+        Expression method = transform(mce.getMethod());
+        Expression object = transform(mce.getObjectExpression());
+
+        resolveGenericsTypes(mce.getGenericsTypes());
+        
+        MethodCallExpression result = new MethodCallExpression(object, method, args);
+        result.setSafe(mce.isSafe());
+        result.setImplicitThis(mce.isImplicitThis());
+        result.setSpreadSafe(mce.isSpreadSafe());
+        result.setSourcePosition(mce);
+        result.setGenericsTypes(mce.getGenericsTypes());
+        result.setMethodTarget(mce.getMethodTarget());
+        return result;
+    }
+    
+    protected Expression transformDeclarationExpression(DeclarationExpression de) {
+        visitAnnotations(de);
+        Expression oldLeft = de.getLeftExpression();
+        checkingVariableTypeInDeclaration = true;
+        Expression left = transform(oldLeft);
+        checkingVariableTypeInDeclaration = false;
+        if (left instanceof ClassExpression) {
+            ClassExpression ce = (ClassExpression) left;
+            addError("you tried to assign a value to the class " + ce.getType().getName(), oldLeft);
+            return de;
+        }
+        Expression right = transform(de.getRightExpression());
+        if (right == de.getRightExpression()) {
+            fixDeclaringClass(de);
+            return de;
+        }
+        DeclarationExpression newDeclExpr = new DeclarationExpression(left, de.getOperation(), right);
+        newDeclExpr.setDeclaringClass(de.getDeclaringClass());
+        fixDeclaringClass(newDeclExpr);
+        newDeclExpr.setSourcePosition(de);
+        newDeclExpr.addAnnotations(de.getAnnotations());
+        return newDeclExpr;
+    }
+
+    // TODO get normal resolving to set declaring class
+    private void fixDeclaringClass(DeclarationExpression newDeclExpr) {
+        if (newDeclExpr.getDeclaringClass() == null && currentMethod != null) {
+            newDeclExpr.setDeclaringClass(currentMethod.getDeclaringClass());
+        }
+    }
+
+    protected Expression transformAnnotationConstantExpression(AnnotationConstantExpression ace) {
+        AnnotationNode an = (AnnotationNode) ace.getValue();
+        ClassNode type = an.getClassNode();
+        resolveOrFail(type, ", unable to find class for annotation", an);
+        for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+            member.setValue(transform(member.getValue()));
+        }
+        return ace;
+    }
+
+    public void visitAnnotations(AnnotatedNode node) {
+        List<AnnotationNode> annotations = node.getAnnotations();
+        if (annotations.isEmpty()) return;
+        Map<String, AnnotationNode> tmpAnnotations = new HashMap<String, AnnotationNode>();
+        ClassNode annType;
+        for (AnnotationNode an : annotations) {
+            // skip built-in properties
+            if (an.isBuiltIn()) continue;
+            annType = an.getClassNode();
+            resolveOrFail(annType, ",  unable to find class for annotation", an);
+            for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+                Expression newValue = transform(member.getValue());
+                newValue = transformInlineConstants(newValue);
+                member.setValue(newValue);
+                checkAnnotationMemberValue(newValue);
+            }
+            if(annType.isResolved()) {
+                Class annTypeClass = annType.getTypeClass();
+                Retention retAnn = (Retention) annTypeClass.getAnnotation(Retention.class);
+                if (retAnn != null && retAnn.value().equals(RetentionPolicy.RUNTIME)) {
+                    AnnotationNode anyPrevAnnNode = tmpAnnotations.put(annTypeClass.getName(), an);
+                    if(anyPrevAnnNode != null) {
+                        addError("Cannot specify duplicate annotation on the same member : " + annType.getName(), an);
+                    }
+                }
+            }
+        }
+    }
+
+    // resolve constant-looking expressions statically (do here as gets transformed away later)
+    private Expression transformInlineConstants(Expression exp) {
+        if (exp instanceof PropertyExpression) {
+            PropertyExpression pe = (PropertyExpression) exp;
+            if (pe.getObjectExpression() instanceof ClassExpression) {
+                ClassExpression ce = (ClassExpression) pe.getObjectExpression();
+                ClassNode type = ce.getType();
+                if (type.isEnum())
+                    return exp;
+
+                FieldNode fn = type.getField(pe.getPropertyAsString());
+                if (fn != null && !fn.isEnum() && fn.isStatic() && fn.isFinal()) {
+                    if (fn.getInitialValueExpression() instanceof ConstantExpression) {
+                        return fn.getInitialValueExpression();
+                    }
+                }
+            }
+        } else if (exp instanceof ListExpression) {
+            ListExpression le = (ListExpression) exp;
+            ListExpression result = new ListExpression();
+            for (Expression e : le.getExpressions()) {
+                result.addExpression(transformInlineConstants(e));
+            }
+            return result;
+        } else if (exp instanceof AnnotationConstantExpression) {
+            ConstantExpression ce = (ConstantExpression) exp;
+            if (ce.getValue() instanceof AnnotationNode) {
+                // replicate a little bit of AnnotationVisitor here
+                // because we can't wait until later to do this
+                AnnotationNode an = (AnnotationNode) ce.getValue();
+                for (Map.Entry<String, Expression> member : an.getMembers().entrySet()) {
+                    member.setValue(transformInlineConstants(member.getValue()));
+                }
+
+            }
+        }
+        return exp;
+    }
+
+    private void checkAnnotationMemberValue(Expression newValue) {
+        if (newValue instanceof PropertyExpression) {
+            PropertyExpression pe = (PropertyExpression) newValue;
+            if (!(pe.getObjectExpression() instanceof ClassExpression)) {
+                addError("unable to find class '" + pe.getText() + "' for annotation attribute constant", pe.getObjectExpression());
+            }
+        } else if (newValue instanceof ListExpression) {
+            ListExpression le = (ListExpression) newValue;
+            for (Expression e : le.getExpressions()) {
+                checkAnnotationMemberValue(e);
+            }
+        }
+    }
+
+    public void visitClass(ClassNode node) {
+        ClassNode oldNode = currentClass;
+
+        if (node instanceof InnerClassNode) {
+            if (Modifier.isStatic(node.getModifiers())) {
+                genericParameterNames = new HashMap<String, GenericsType>();
+            }
+        } else {
+            genericParameterNames = new HashMap<String, GenericsType>();
+        }
+        currentClass = node;
+        resolveGenericsHeader(node.getGenericsTypes());
+
+        ModuleNode module = node.getModule();
+        if (!module.hasImportsResolved()) {
+            for (ImportNode importNode : module.getImports()) {
+                currImportNode = importNode;
+                ClassNode type = importNode.getType();
+                if (resolve(type, false, false, true)) {
+                    currImportNode = null;
+                    continue;
+                }
+                currImportNode = null;
+                addError("unable to resolve class " + type.getName(), type);
+            }
+            for (ImportNode importNode : module.getStaticStarImports().values()) {
+                ClassNode type = importNode.getType();
+                if (resolve(type, false, false, true)) continue;
+                // Maybe this type belongs in the same package as the node that is doing the
+                // static import. In that case, the package may not have been explicitly specified.
+                // Try with the node's package too. If still not found, revert to original type name.
+                if (type.getPackageName() == null && node.getPackageName() != null) {
+                    String oldTypeName = type.getName();
+                    type.setName(node.getPackageName() + "." + oldTypeName);
+                    if (resolve(type, false, false, true)) continue;
+                    type.setName(oldTypeName);
+                }
+                addError("unable to resolve class " + type.getName(), type);
+            }
+            for (ImportNode importNode : module.getStaticImports().values()) {
+                ClassNode type = importNode.getType();
+                if (resolve(type, true, true, true)) continue;
+                addError("unable to resolve class " + type.getName(), type);
+            }
+            for (ImportNode importNode : module.getStaticStarImports().values()) {
+                ClassNode type = importNode.getType();
+                if (resolve(type, true, true, true)) continue;
+                addError("unable to resolve class " + type.getName(), type);
+            }
+            module.setImportsResolved(true);
+        }
+
+        ClassNode sn = node.getUnresolvedSuperClass();
+        if (sn != null) resolveOrFail(sn, node, true);
+
+        for (ClassNode anInterface : node.getInterfaces()) {
+            resolveOrFail(anInterface, node, true);
+        }
+
+        checkCyclicInheritance(node, node.getUnresolvedSuperClass(), node.getInterfaces());
+        
+        super.visitClass(node);
+
+        currentClass = oldNode;
+    }
+    
+    private void checkCyclicInheritance(ClassNode originalNode, ClassNode parentToCompare, ClassNode[] interfacesToCompare) {
+        if(!originalNode.isInterface()) {
+            if(parentToCompare == null) return;
+            if(originalNode == parentToCompare.redirect()) {
+                addError("Cyclic inheritance involving " + parentToCompare.getName() + " in class " + originalNode.getName(), originalNode);
+                return;
+            }
+            if(interfacesToCompare != null && interfacesToCompare.length > 0) {
+                for(ClassNode intfToCompare : interfacesToCompare) {
+                    if(originalNode == intfToCompare.redirect()) {
+                        addError("Cycle detected: the type " + originalNode.getName() + " cannot implement itself" , originalNode);
+                        return;
+                    }
+                }
+            }
+            if(parentToCompare == ClassHelper.OBJECT_TYPE) return;
+            checkCyclicInheritance(originalNode, parentToCompare.getUnresolvedSuperClass(), null);
+        } else {
+            if(interfacesToCompare != null && interfacesToCompare.length > 0) {
+                // check interfaces at this level first
+                for(ClassNode intfToCompare : interfacesToCompare) {
+                    if(originalNode == intfToCompare.redirect()) {
+                        addError("Cyclic inheritance involving " + intfToCompare.getName() + " in interface " + originalNode.getName(), originalNode);
+                        return;
+                    }
+                }
+                // check next level of interfaces
+                for(ClassNode intf : interfacesToCompare) {
+                    checkCyclicInheritance(originalNode, null, intf.getInterfaces());
+                }
+            } else {
+                return;
+            }
+        }
+    }
+
+    public void visitCatchStatement(CatchStatement cs) {
+        resolveOrFail(cs.getExceptionType(), cs);
+        if (cs.getExceptionType() == ClassHelper.DYNAMIC_TYPE) {
+            cs.getVariable().setType(ClassHelper.make(Exception.class));
+        }
+        super.visitCatchStatement(cs);
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        resolveOrFail(forLoop.getVariableType(), forLoop);
+        super.visitForLoop(forLoop);
+    }
+
+    public void visitBlockStatement(BlockStatement block) {
+        VariableScope oldScope = currentScope;
+        currentScope = block.getVariableScope();
+        super.visitBlockStatement(block);
+        currentScope = oldScope;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    private boolean resolveGenericsTypes(GenericsType[] types) {
+        if (types == null) return true;
+        currentClass.setUsingGenerics(true);
+        boolean resolved = true;
+        for (GenericsType type : types) {
+            // attempt resolution on all types, so don't short-circuit and stop if we've previously failed
+            resolved = resolveGenericsType(type) && resolved;
+        }
+        return resolved;
+    }
+
+    private void resolveGenericsHeader(GenericsType[] types) {
+        if (types == null) return;
+        currentClass.setUsingGenerics(true);
+        for (GenericsType type : types) {
+            ClassNode classNode = type.getType();
+            String name = type.getName();
+            ClassNode[] bounds = type.getUpperBounds();
+            if (bounds != null) {
+                boolean nameAdded = false;
+                for (ClassNode upperBound : bounds) {
+                    if (!nameAdded && upperBound != null || !resolve(classNode)) {
+                        genericParameterNames.put(name, type);
+                        type.setPlaceholder(true);
+                        classNode.setRedirect(upperBound);
+                        nameAdded = true;
+                    }
+                    resolveOrFail(upperBound, classNode);
+                }
+            } else {
+                genericParameterNames.put(name, type);
+                classNode.setRedirect(ClassHelper.OBJECT_TYPE);
+                type.setPlaceholder(true);
+            }
+        }
+    }
+
+    private boolean resolveGenericsType(GenericsType genericsType) {
+        if (genericsType.isResolved()) return true;
+        currentClass.setUsingGenerics(true);
+        ClassNode type = genericsType.getType();
+        // save name before redirect
+        String name = type.getName();
+        ClassNode[] bounds = genericsType.getUpperBounds();
+        if (!genericParameterNames.containsKey(name)) {
+            if (bounds != null) {
+                for (ClassNode upperBound : bounds) {
+                    resolveOrFail(upperBound, genericsType);
+                    type.setRedirect(upperBound);
+                    resolveGenericsTypes(upperBound.getGenericsTypes());
+                }
+            } else if (genericsType.isWildcard()) {
+                type.setRedirect(ClassHelper.OBJECT_TYPE);
+            } else {
+                resolveOrFail(type, genericsType);
+            }
+        } else {
+            GenericsType gt = genericParameterNames.get(name);
+            type.setRedirect(gt.getType());
+            genericsType.setPlaceholder(true);
+        }
+
+        if (genericsType.getLowerBound() != null) {
+            resolveOrFail(genericsType.getLowerBound(), genericsType);
+        }
+
+        if (resolveGenericsTypes(type.getGenericsTypes())) {
+            genericsType.setResolved(genericsType.getType().isResolved());
+        }
+        return genericsType.isResolved();
+
+    }
+
+    public void setClassNodeResolver(ClassNodeResolver classNodeResolver) {
+        this.classNodeResolver = classNodeResolver;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java b/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java
new file mode 100644
index 0000000..a12cae1
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/SourceExtensionHandler.java
@@ -0,0 +1,66 @@
+/*
+ *  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.control;
+
+import groovy.lang.GroovyRuntimeException;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Looks for source file extensions in META-INF/services/org.codehaus.groovy.source.Extensions
+ */
+public class SourceExtensionHandler {
+
+    public static Set<String> getRegisteredExtensions(ClassLoader loader) {
+        Set<String> extensions = new LinkedHashSet<String>();
+        extensions.add("groovy");
+        try {
+            Enumeration<URL> globalServices = loader.getResources("META-INF/services/org.codehaus.groovy.source.Extensions");
+            while (globalServices.hasMoreElements()) {
+                BufferedReader svcIn = null;
+                URL service = globalServices.nextElement();
+                try {
+                    svcIn = new BufferedReader(new InputStreamReader(service.openStream()));
+                    String extension = svcIn.readLine();
+                    while (extension != null) {
+                        extension = extension.trim();
+                        if (!extension.startsWith("#") && extension.length() > 0) {
+                            extensions.add(extension);
+                        }
+                        extension = svcIn.readLine();
+                    }
+                } catch (IOException ex) {
+                    throw new GroovyRuntimeException("IO Exception attempting to load registered source extension " +
+                            service.toExternalForm() + ". Exception: " + ex.toString());
+                } finally {
+                    if (svcIn != null) svcIn.close();
+                }
+            }
+        } catch (IOException ex) {
+            throw new GroovyRuntimeException("IO Exception getting registered source extensions. Exception: " + ex.toString());
+        }
+        return extensions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/SourceUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/SourceUnit.java b/src/main/java/org/codehaus/groovy/control/SourceUnit.java
new file mode 100644
index 0000000..8f3ce5e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/SourceUnit.java
@@ -0,0 +1,344 @@
+/*
+ *  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.control;
+
+import antlr.CharScanner;
+import antlr.MismatchedCharException;
+import antlr.MismatchedTokenException;
+import antlr.NoViableAltException;
+import antlr.NoViableAltForCharException;
+import groovy.lang.GroovyClassLoader;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.control.io.FileReaderSource;
+import org.codehaus.groovy.control.io.ReaderSource;
+import org.codehaus.groovy.control.io.StringReaderSource;
+import org.codehaus.groovy.control.io.URLReaderSource;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SimpleMessage;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.Reduction;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.tools.Utilities;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Provides an anchor for a single source unit (usually a script file)
+ * as it passes through the compiler system.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ */
+
+public class SourceUnit extends ProcessingUnit {
+
+    /**
+     * The pluggable parser used to generate the AST - we allow
+     * pluggability currently as we need to have Classic and JSR support
+     */
+    private ParserPlugin parserPlugin;
+
+    /**
+     * Where we can get Readers for our source unit
+     */
+    protected ReaderSource source;
+
+    /**
+     * A descriptive name of the source unit. This name shouldn't
+     * be used for controlling the SourceUnit, it is only for error
+     * messages and to determine the name of the class for
+     * a script.
+     */
+    protected String name;
+
+    /**
+     * A Concrete Syntax Tree of the source
+     */
+    protected Reduction cst;
+
+    /**
+     * The root of the Abstract Syntax Tree for the source
+     */
+    protected ModuleNode ast;
+
+    /**
+     * Initializes the SourceUnit from existing machinery.
+     */
+    public SourceUnit(String name, ReaderSource source, CompilerConfiguration flags,
+                      GroovyClassLoader loader, ErrorCollector er) {
+        super(flags, loader, er);
+
+        this.name = name;
+        this.source = source;
+    }
+
+    /**
+     * Initializes the SourceUnit from the specified file.
+     */
+    public SourceUnit(File source, CompilerConfiguration configuration, GroovyClassLoader loader, ErrorCollector er) {
+        this(source.getPath(), new FileReaderSource(source, configuration), configuration, loader, er);
+    }
+
+    /**
+     * Initializes the SourceUnit from the specified URL.
+     */
+    public SourceUnit(URL source, CompilerConfiguration configuration, GroovyClassLoader loader, ErrorCollector er) {
+        this(source.toExternalForm(), new URLReaderSource(source, configuration), configuration, loader, er);
+    }
+
+    /**
+     * Initializes the SourceUnit for a string of source.
+     */
+    public SourceUnit(String name, String source, CompilerConfiguration configuration,
+                      GroovyClassLoader loader, ErrorCollector er) {
+        this(name, new StringReaderSource(source, configuration), configuration, loader, er);
+    }
+
+    /**
+     * Returns the name for the SourceUnit. This name shouldn't
+     * be used for controlling the SourceUnit, it is only for error
+     * messages
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     * Returns the Concrete Syntax Tree produced during parse()ing.
+     */
+    public Reduction getCST() {
+        return this.cst;
+    }
+
+    /**
+     * Returns the Abstract Syntax Tree produced during convert()ing
+     * and expanded during later phases.
+     */
+    public ModuleNode getAST() {
+        return this.ast;
+    }
+
+
+    /**
+     * Convenience routine, primarily for use by the InteractiveShell,
+     * that returns true if parse() failed with an unexpected EOF.
+     */
+    public boolean failedWithUnexpectedEOF() {
+        // Implementation note - there are several ways for the Groovy compiler
+        // to report an unexpected EOF. Perhaps this implementation misses some.
+        // If you find another way, please add it.
+        if (getErrorCollector().hasErrors()) {
+            Message last = (Message) getErrorCollector().getLastError();
+            Throwable cause = null;
+            if (last instanceof SyntaxErrorMessage) {
+                cause = ((SyntaxErrorMessage) last).getCause().getCause();
+            }
+            if (cause != null) {
+                if (cause instanceof NoViableAltException) {
+                    return isEofToken(((NoViableAltException) cause).token);
+                } else if (cause instanceof NoViableAltForCharException) {
+                    char badChar = ((NoViableAltForCharException) cause).foundChar;
+                    return badChar == CharScanner.EOF_CHAR;
+                } else if (cause instanceof MismatchedCharException) {
+                    char badChar = (char) ((MismatchedCharException) cause).foundChar;
+                    return badChar == CharScanner.EOF_CHAR;
+                } else if (cause instanceof MismatchedTokenException) {
+                    return isEofToken(((MismatchedTokenException) cause).token);
+                }
+            }
+        }
+        return false;
+    }
+
+    protected boolean isEofToken(antlr.Token token) {
+        return token.getType() == antlr.Token.EOF_TYPE;
+    }
+
+
+    //---------------------------------------------------------------------------
+    // FACTORIES
+
+
+    /**
+     * A convenience routine to create a standalone SourceUnit on a String
+     * with defaults for almost everything that is configurable.
+     */
+    public static SourceUnit create(String name, String source) {
+        CompilerConfiguration configuration = new CompilerConfiguration();
+        configuration.setTolerance(1);
+
+        return new SourceUnit(name, source, configuration, null, new ErrorCollector(configuration));
+    }
+
+
+    /**
+     * A convenience routine to create a standalone SourceUnit on a String
+     * with defaults for almost everything that is configurable.
+     */
+    public static SourceUnit create(String name, String source, int tolerance) {
+        CompilerConfiguration configuration = new CompilerConfiguration();
+        configuration.setTolerance(tolerance);
+
+        return new SourceUnit(name, source, configuration, null, new ErrorCollector(configuration));
+    }
+
+    //---------------------------------------------------------------------------
+    // PROCESSING
+
+    /**
+     * Parses the source to a CST.  You can retrieve it with getCST().
+     */
+    public void parse() throws CompilationFailedException {
+        if (this.phase > Phases.PARSING) {
+            throw new GroovyBugError("parsing is already complete");
+        }
+
+        if (this.phase == Phases.INITIALIZATION) {
+            nextPhase();
+        }
+
+        //
+        // Create a reader on the source and run the parser.
+
+        try (Reader reader = source.getReader()) {
+            // let's recreate the parser each time as it tends to keep around state
+            parserPlugin = getConfiguration().getPluginFactory().createParserPlugin();
+
+            cst = parserPlugin.parseCST(this, reader);
+        } catch (IOException e) {
+            getErrorCollector().addFatalError(new SimpleMessage(e.getMessage(), this));
+        }
+    }
+
+    /**
+     * Generates an AST from the CST.  You can retrieve it with getAST().
+     */
+    public void convert() throws CompilationFailedException {
+        if (this.phase == Phases.PARSING && this.phaseComplete) {
+            gotoPhase(Phases.CONVERSION);
+        }
+
+        if (this.phase != Phases.CONVERSION) {
+            throw new GroovyBugError("SourceUnit not ready for convert()");
+        }
+
+        //
+        // Build the AST
+
+        try {
+            this.ast = parserPlugin.buildAST(this, this.classLoader, this.cst);
+            this.ast.setDescription(this.name);
+        }
+        catch (SyntaxException e) {
+            if (this.ast == null) {
+                // Create a dummy ModuleNode to represent a failed parse - in case a later phase attempts to use the ast
+                this.ast = new ModuleNode(this);
+            }
+            getErrorCollector().addError(new SyntaxErrorMessage(e, this));
+        }
+
+        String property = (String) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                return System.getProperty("groovy.ast");
+            }
+        });
+
+        if ("xml".equals(property)) {
+            saveAsXML(name, ast);
+        }
+    }
+
+    private static void saveAsXML(String name, ModuleNode ast) {
+        XStreamUtils.serialize(name, ast);
+    }
+
+    //---------------------------------------------------------------------------    // SOURCE SAMPLING
+
+    /**
+     * Returns a sampling of the source at the specified line and column,
+     * or null if it is unavailable.
+     */
+    public String getSample(int line, int column, Janitor janitor) {
+        String sample = null;
+        String text = source.getLine(line, janitor);
+
+        if (text != null) {
+            if (column > 0) {
+                String marker = Utilities.repeatString(" ", column - 1) + "^";
+
+                if (column > 40) {
+                    int start = column - 30 - 1;
+                    int end = (column + 10 > text.length() ? text.length() : column + 10 - 1);
+                    sample = "   " + text.substring(start, end) + Utilities.eol() + "   " +
+                            marker.substring(start, marker.length());
+                } else {
+                    sample = "   " + text + Utilities.eol() + "   " + marker;
+                }
+            } else {
+                sample = text;
+            }
+        }
+
+        return sample;
+    }
+
+    /**
+     * This method adds an exception to the error collector. The Exception most likely has no line number attached to it.
+     * For this reason you should use this method sparingly. Prefer using addError for syntax errors or add an error
+     * to the {@link ErrorCollector} directly by retrieving it with getErrorCollector().
+     * @param e
+     *      the exception that occurred
+     * @throws CompilationFailedException
+     *      on error
+     */
+    public void addException(Exception e) throws CompilationFailedException {
+        getErrorCollector().addException(e, this);
+    }
+
+    /**
+     * This method adds a SyntaxException to the error collector. The exception should specify the line and column
+     * number of the error.  This method should be reserved for real errors in the syntax of the SourceUnit. If
+     * your error is not in syntax, and is a semantic error, or more general error, then use addException or use
+     * the error collector directly by retrieving it with getErrorCollector().
+     * @param se
+     *      the exception, which should have line and column information
+     * @throws CompilationFailedException
+     *      on error
+     */
+    public void addError(SyntaxException se) throws CompilationFailedException {
+        getErrorCollector().addError(se, this);
+    }
+
+    public void addErrorAndContinue(SyntaxException se) throws CompilationFailedException {
+        getErrorCollector().addErrorAndContinue(se, this);
+    }
+
+    public ReaderSource getSource() { return source; }
+
+    public void setSource(ReaderSource source) {
+        this.source = source;
+    }
+}


[59/62] [abbrv] groovy git commit: Consistently create manifests

Posted by cc...@apache.org.
Consistently create manifests

This commit is a build cache optimization: while we don't really care about the manifest of
the "raw" cache, it's better to consistently create one that does **not** include the OSGI
last modified entry, as it will trigger unnecessary rebuilds, because of cache misses.


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/e7ee1f2d
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/e7ee1f2d
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/e7ee1f2d

Branch: refs/heads/GROOVY_2_6_X
Commit: e7ee1f2da24adf7f2f32cf55eb82933ef2e36128
Parents: 386389d
Author: Cedric Champeau <cc...@apache.org>
Authored: Fri Dec 15 09:29:32 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:53:23 2017 +0100

----------------------------------------------------------------------
 gradle/assemble.gradle | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/e7ee1f2d/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index e56fd2b..c02659c 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -113,7 +113,7 @@ ext.groovyOsgiManifest = {
     // Exclude the Bnd-LastModified attribute as it always triggers a rebuild without being really needed.
     from(allManifest) {
         eachEntry { details ->
-            if (excludedFromManifest.any { it == details.key}) {
+            if (excludedFromManifest.any { it == details.key }) {
                 details.exclude()
             }
         }
@@ -143,6 +143,15 @@ allprojects {
     def producedJars = [jar]
     jar {
         appendix = 'raw'
+        manifest {
+            from(allManifest) {
+                eachEntry { details ->
+                    if (excludedFromManifest.any { it == details.key }) {
+                        details.exclude()
+                    }
+                }
+            }
+        }
     }
     if (rootProject.indyCapable()) {
         task jarWithIndy(type: Jar) {


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
new file mode 100644
index 0000000..1c14da8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -0,0 +1,928 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.tools.WideningCategories;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.StatementMeta;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeMap;
+
+import static org.objectweb.asm.Opcodes.AALOAD;
+import static org.objectweb.asm.Opcodes.ACONST_NULL;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ATHROW;
+import static org.objectweb.asm.Opcodes.CHECKCAST;
+import static org.objectweb.asm.Opcodes.DUP;
+import static org.objectweb.asm.Opcodes.DUP2_X1;
+import static org.objectweb.asm.Opcodes.DUP_X1;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static org.objectweb.asm.Opcodes.NEW;
+import static org.objectweb.asm.Opcodes.POP;
+import static org.objectweb.asm.Opcodes.SWAP;
+
+public class InvocationWriter {
+
+    // method invocation
+    public static final MethodCallerMultiAdapter invokeMethodOnCurrent = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "invokeMethodOnCurrent", true, false);
+    public static final MethodCallerMultiAdapter invokeMethodOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "invokeMethodOnSuper", true, false);
+    public static final MethodCallerMultiAdapter invokeMethod = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "invokeMethod", true, false);
+    public static final MethodCallerMultiAdapter invokeStaticMethod = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "invokeStaticMethod", true, true);
+    public static final MethodCaller invokeClosureMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeClosure");
+    public static final MethodCaller castToVargsArray = MethodCaller.newStatic(DefaultTypeTransformation.class, "castToVargsArray");
+    private static final MethodNode CLASS_FOR_NAME_STRING = ClassHelper.CLASS_Type.getDeclaredMethod("forName", new Parameter[]{new Parameter(ClassHelper.STRING_TYPE,"name")});
+
+    // type conversions
+    private static final MethodCaller
+        asTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "asType"),
+        castToTypeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "castToType"),
+        castToClassMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToClass"),
+        castToStringMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToString"),
+        castToEnumMethod = MethodCaller.newStatic(ShortTypeHandling.class, "castToEnum");
+
+    // constructor calls with this() and super()
+    static final MethodCaller selectConstructorAndTransformArguments = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "selectConstructorAndTransformArguments");
+
+    private final WriterController controller;
+    
+    public InvocationWriter(WriterController wc) {
+        this.controller = wc;
+    }
+
+    private void makeInvokeMethodCall(MethodCallExpression call, boolean useSuper, MethodCallerMultiAdapter adapter) {
+        // receiver
+        // we operate on GroovyObject if possible
+        Expression objectExpression = call.getObjectExpression();
+        // message name
+        Expression messageName = new CastExpression(ClassHelper.STRING_TYPE, call.getMethod());
+        if (useSuper) {
+            ClassNode classNode = controller.isInClosure() ? controller.getOutermostClass() : controller.getClassNode(); // GROOVY-4035 
+            ClassNode superClass = classNode.getSuperClass();
+            makeCall(call, new ClassExpression(superClass),
+                    objectExpression, messageName,
+                    call.getArguments(), adapter,
+                    call.isSafe(), call.isSpreadSafe(),
+                    false
+            );
+        } else {
+            makeCall(call, objectExpression, messageName,
+                    call.getArguments(), adapter,
+                    call.isSafe(), call.isSpreadSafe(),
+                    call.isImplicitThis()
+            );
+        }
+    }
+    
+    public void makeCall(
+            Expression origin,
+            Expression receiver, Expression message, Expression arguments,
+            MethodCallerMultiAdapter adapter,
+            boolean safe, boolean spreadSafe, boolean implicitThis
+    ) {
+        ClassNode cn = controller.getClassNode();
+        if (controller.isInClosure() && !implicitThis && AsmClassGenerator.isThisExpression(receiver)) cn=cn.getOuterClass();
+        makeCall(origin, new ClassExpression(cn), receiver, message, arguments,
+                adapter, safe, spreadSafe, implicitThis);
+    }
+    
+    protected boolean writeDirectMethodCall(MethodNode target, boolean implicitThis,  Expression receiver, TupleExpression args) {
+        if (target==null) return false;
+        
+        String methodName = target.getName();
+        CompileStack compileStack = controller.getCompileStack();
+        OperandStack operandStack = controller.getOperandStack();
+        ClassNode declaringClass = target.getDeclaringClass();
+        ClassNode classNode = controller.getClassNode();
+
+        MethodVisitor mv = controller.getMethodVisitor();
+        int opcode = INVOKEVIRTUAL;
+        if (target.isStatic()) {
+            opcode = INVOKESTATIC;
+        } else if (target.isPrivate() || ((receiver instanceof VariableExpression && ((VariableExpression) receiver).isSuperExpression()))) {
+            opcode = INVOKESPECIAL;
+        } else if (declaringClass.isInterface()) {
+            opcode = INVOKEINTERFACE;
+        }
+
+        // handle receiver
+        int argumentsToRemove = 0;
+        if (opcode!=INVOKESTATIC) {
+            if (receiver!=null) {
+                // load receiver if not static invocation
+                // todo: fix inner class case
+                if (implicitThis
+                        && !classNode.isDerivedFrom(declaringClass)
+                        && !classNode.implementsInterface(declaringClass)
+                        && classNode instanceof InnerClassNode) {
+                    // we are calling an outer class method
+                    compileStack.pushImplicitThis(false);
+                    if (controller.isInClosure()) {
+                        new VariableExpression("thisObject").visit(controller.getAcg());
+                    } else {
+                        Expression expr = new PropertyExpression(new ClassExpression(declaringClass), "this");
+                        expr.visit(controller.getAcg());
+                    }
+                } else {
+                    compileStack.pushImplicitThis(implicitThis);
+                    receiver.visit(controller.getAcg());
+                }
+                operandStack.doGroovyCast(declaringClass);
+                compileStack.popImplicitThis();
+                argumentsToRemove++;
+            } else {
+                mv.visitIntInsn(ALOAD,0);
+                operandStack.push(classNode);
+                argumentsToRemove++;
+            }
+        }
+
+        int stackSize = operandStack.getStackLength();
+
+        String owner = BytecodeHelper.getClassInternalName(declaringClass);
+        ClassNode receiverType = receiver!=null?controller.getTypeChooser().resolveType(receiver, classNode):declaringClass;
+        if (opcode == INVOKEVIRTUAL && ClassHelper.OBJECT_TYPE.equals(declaringClass)) {
+            // avoid using a narrowed type if the method is defined on object because it can interfere
+            // with delegate type inference in static compilation mode and trigger a ClassCastException
+            receiverType = declaringClass;
+        }
+        if (opcode == INVOKEVIRTUAL) {
+            if (!receiverType.equals(declaringClass)
+                    && !ClassHelper.OBJECT_TYPE.equals(declaringClass)
+                    && !receiverType.isArray()
+                    && !receiverType.isInterface()
+                    && !ClassHelper.isPrimitiveType(receiverType) // e.g int.getClass()
+                    && receiverType.isDerivedFrom(declaringClass)) {
+
+                owner = BytecodeHelper.getClassInternalName(receiverType);
+                ClassNode top = operandStack.getTopOperand();
+                if (!receiverType.equals(top)) {
+                    mv.visitTypeInsn(CHECKCAST, owner);
+                }
+            } else if (target.isPublic()
+                    && (!Modifier.isPublic(declaringClass.getModifiers())
+                    && !receiverType.equals(declaringClass))
+                    && receiverType.isDerivedFrom(declaringClass)
+                    && !receiverType.getPackageName().equals(classNode.getPackageName())) {
+                // package private class, public method
+                // see GROOVY-6962
+                owner = BytecodeHelper.getClassInternalName(receiverType);
+            }
+        }
+
+        loadArguments(args.getExpressions(), target.getParameters());
+
+        String desc = BytecodeHelper.getMethodDescriptor(target.getReturnType(), target.getParameters());
+        mv.visitMethodInsn(opcode, owner, methodName, desc, opcode == INVOKEINTERFACE);
+        ClassNode ret = target.getReturnType().redirect();
+        if (ret==ClassHelper.VOID_TYPE) {
+            ret = ClassHelper.OBJECT_TYPE;
+            mv.visitInsn(ACONST_NULL);
+        }
+        argumentsToRemove += (operandStack.getStackLength()-stackSize);
+        controller.getOperandStack().remove(argumentsToRemove);
+        controller.getOperandStack().push(ret);
+        return true;
+    }
+
+    private boolean lastIsArray(List<Expression> argumentList, int pos) {
+        Expression last = argumentList.get(pos);
+        ClassNode type = controller.getTypeChooser().resolveType(last, controller.getClassNode());
+        return type.isArray();
+    }
+    
+    // load arguments
+    protected void loadArguments(List<Expression> argumentList, Parameter[] para) {
+        if (para.length==0) return;
+        ClassNode lastParaType = para[para.length - 1].getOriginType();
+        AsmClassGenerator acg = controller.getAcg();
+        OperandStack operandStack = controller.getOperandStack();
+        if (lastParaType.isArray()
+                && (argumentList.size()>para.length || argumentList.size()==para.length-1 || !lastIsArray(argumentList, para.length-1))) {
+            int stackLen = operandStack.getStackLength()+argumentList.size();
+            MethodVisitor mv = controller.getMethodVisitor();
+            //mv = new org.objectweb.asm.util.TraceMethodVisitor(mv);
+            controller.setMethodVisitor(mv);
+            // varg call
+            // first parameters as usual
+            for (int i = 0; i < para.length-1; i++) {
+                argumentList.get(i).visit(acg);
+                operandStack.doGroovyCast(para[i].getType());
+            }
+            // last parameters wrapped in an array
+            List<Expression> lastParams = new LinkedList<Expression>();
+            for (int i=para.length-1; i<argumentList.size();i++) {
+                lastParams.add(argumentList.get(i));
+            }
+            ArrayExpression array = new ArrayExpression(
+                    lastParaType.getComponentType(),
+                    lastParams
+            );
+            array.visit(acg);
+            // adjust stack length
+            while (operandStack.getStackLength()<stackLen) {
+                operandStack.push(ClassHelper.OBJECT_TYPE);
+            }
+            if (argumentList.size()==para.length-1) {
+                operandStack.remove(1);
+            }
+        } else {
+            for (int i = 0; i < argumentList.size(); i++) {
+                argumentList.get(i).visit(acg);
+                operandStack.doGroovyCast(para[i].getType());
+            }
+        }
+    }
+
+    protected boolean makeDirectCall(
+        Expression origin, Expression receiver, 
+        Expression message, Expression arguments,
+        MethodCallerMultiAdapter adapter,
+        boolean implicitThis, boolean containsSpreadExpression
+    ) {
+        if (makeClassForNameCall(origin, receiver, message, arguments)) return true;
+
+        // optimization path
+        boolean fittingAdapter =   adapter == invokeMethodOnCurrent ||
+                                    adapter == invokeStaticMethod;
+        if (fittingAdapter && controller.optimizeForInt && controller.isFastPath()) {
+            String methodName = getMethodName(message);
+            if (methodName != null) {
+                TupleExpression args;
+                if (arguments instanceof TupleExpression) {
+                    args = (TupleExpression) arguments;
+                } else {
+                    args = new TupleExpression(receiver);
+                }
+
+                StatementMeta meta = null;
+                if (origin!=null) meta = origin.getNodeMetaData(StatementMeta.class);
+                MethodNode mn = null;
+                if (meta!=null) mn = meta.target;
+
+                if (writeDirectMethodCall(mn, true, null, args)) return true;
+            }
+        }
+
+        if (containsSpreadExpression) return false;
+        if (origin instanceof MethodCallExpression) {
+            MethodCallExpression mce = (MethodCallExpression) origin;
+            MethodNode target = mce.getMethodTarget();
+            return writeDirectMethodCall(target, implicitThis, receiver, makeArgumentList(arguments));
+        }
+        return false;
+    }
+
+    protected boolean makeCachedCall(
+            Expression origin, ClassExpression sender,
+            Expression receiver, Expression message, Expression arguments,
+            MethodCallerMultiAdapter adapter,
+            boolean safe, boolean spreadSafe, boolean implicitThis,
+            boolean containsSpreadExpression
+    ) {
+        // prepare call site
+        if ((adapter == invokeMethod || adapter == invokeMethodOnCurrent || adapter == invokeStaticMethod) && !spreadSafe) {
+            String methodName = getMethodName(message);
+
+            if (methodName != null) {
+                controller.getCallSiteWriter().makeCallSite(
+                        receiver, methodName, arguments, safe, implicitThis, 
+                        adapter == invokeMethodOnCurrent, 
+                        adapter == invokeStaticMethod);
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    protected void makeUncachedCall(
+            Expression origin, ClassExpression sender,
+            Expression receiver, Expression message, Expression arguments,
+            MethodCallerMultiAdapter adapter,
+            boolean safe, boolean spreadSafe, boolean implicitThis,
+            boolean containsSpreadExpression
+    ) {
+        OperandStack operandStack = controller.getOperandStack();
+        CompileStack compileStack = controller.getCompileStack();
+        AsmClassGenerator acg = controller.getAcg();
+        
+        // ensure VariableArguments are read, not stored
+        compileStack.pushLHS(false);
+
+        // sender only for call sites
+        if (adapter == AsmClassGenerator.setProperty) {
+            ConstantExpression.NULL.visit(acg);
+        } else {
+            sender.visit(acg);
+        }
+
+        String methodName = getMethodName(message);
+        if (adapter == invokeMethodOnSuper && methodName != null) {
+            controller.getSuperMethodNames().add(methodName);
+        }
+        
+        // receiver
+        compileStack.pushImplicitThis(implicitThis);
+        receiver.visit(acg);
+        operandStack.box();
+        compileStack.popImplicitThis();
+        
+        
+        int operandsToRemove = 2;
+        // message
+        if (message != null) {
+            message.visit(acg);
+            operandStack.box();
+            operandsToRemove++;
+        }
+
+        // arguments
+        int numberOfArguments = containsSpreadExpression ? -1 : AsmClassGenerator.argumentSize(arguments);
+        if (numberOfArguments > MethodCallerMultiAdapter.MAX_ARGS || containsSpreadExpression) {
+            ArgumentListExpression ae = makeArgumentList(arguments);
+            if (containsSpreadExpression) {
+                acg.despreadList(ae.getExpressions(), true);
+            } else {
+                ae.visit(acg);
+            }
+        } else if (numberOfArguments > 0) {
+            operandsToRemove += numberOfArguments;
+            TupleExpression te = (TupleExpression) arguments;
+            for (int i = 0; i < numberOfArguments; i++) {
+                Expression argument = te.getExpression(i);
+                argument.visit(acg);
+                operandStack.box();
+                if (argument instanceof CastExpression) acg.loadWrapper(argument);
+            }
+        }
+
+        if (adapter==null) adapter = invokeMethod;
+        adapter.call(controller.getMethodVisitor(), numberOfArguments, safe, spreadSafe);
+
+        compileStack.popLHS();
+        operandStack.replace(ClassHelper.OBJECT_TYPE,operandsToRemove);
+    }
+    
+    protected void makeCall(
+            Expression origin, ClassExpression sender,
+            Expression receiver, Expression message, Expression arguments,
+            MethodCallerMultiAdapter adapter,
+            boolean safe, boolean spreadSafe, boolean implicitThis
+    ) {
+        // direct method call paths
+        boolean containsSpreadExpression = AsmClassGenerator.containsSpreadExpression(arguments);
+
+        if (makeDirectCall(origin, receiver, message, arguments, adapter, implicitThis, containsSpreadExpression)) return;
+
+        // normal path
+        if (makeCachedCall(origin, sender, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis, containsSpreadExpression)) return;
+
+        // path through ScriptBytecodeAdapter
+        makeUncachedCall(origin, sender, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis, containsSpreadExpression);
+    }
+
+    /**
+     * if Class.forName(x) is recognized, make a direct method call
+     */
+    protected boolean makeClassForNameCall(Expression origin, Expression receiver, Expression message, Expression arguments) {
+        if (! (receiver instanceof ClassExpression)) return false;
+        ClassExpression ce = (ClassExpression) receiver;
+        if (!ClassHelper.CLASS_Type.equals(ce.getType())) return false;
+        String msg = getMethodName(message);
+        if (!"forName".equals(msg)) return false;
+        ArgumentListExpression ae = makeArgumentList(arguments);
+        if (ae.getExpressions().size()!=1) return false;
+        return writeDirectMethodCall(CLASS_FOR_NAME_STRING,false, receiver, ae);
+    }
+
+    public static ArgumentListExpression makeArgumentList(Expression arguments) {
+        ArgumentListExpression ae;
+        if (arguments instanceof ArgumentListExpression) {
+            ae = (ArgumentListExpression) arguments;
+        } else if (arguments instanceof TupleExpression) {
+            TupleExpression te = (TupleExpression) arguments;
+            ae = new ArgumentListExpression(te.getExpressions());
+        } else {
+            ae = new ArgumentListExpression();
+            ae.addExpression(arguments);
+        }
+        return ae;
+    }
+
+    protected String getMethodName(Expression message) {
+        String methodName = null;
+        if (message instanceof CastExpression) {
+            CastExpression msg = (CastExpression) message;
+            if (msg.getType() == ClassHelper.STRING_TYPE) {
+                final Expression methodExpr = msg.getExpression();
+                if (methodExpr instanceof ConstantExpression)
+                  methodName = methodExpr.getText();
+            }
+        }
+
+        if (methodName == null && message instanceof ConstantExpression) {
+            ConstantExpression constantExpression = (ConstantExpression) message;
+            methodName = constantExpression.getText();
+        }
+        return methodName;
+    }
+
+    public void writeInvokeMethod(MethodCallExpression call) {
+        if (isClosureCall(call)) {
+            // let's invoke the closure method
+            invokeClosure(call.getArguments(), call.getMethodAsString());
+        } else {
+            boolean isSuperMethodCall = usesSuper(call);
+            MethodCallerMultiAdapter adapter = invokeMethod;
+            if (isSuperMethodCall && call.isSafe()) {
+                // safe is not necessary here because "super" is always not null
+                // but keeping the flag would trigger a VerifyError (see GROOVY-6045)
+                call.setSafe(false);
+            }
+            if (AsmClassGenerator.isThisExpression(call.getObjectExpression())) adapter = invokeMethodOnCurrent;
+            if (isSuperMethodCall) adapter = invokeMethodOnSuper;
+            if (isStaticInvocation(call)) adapter = invokeStaticMethod;
+            makeInvokeMethodCall(call, isSuperMethodCall, adapter);
+        }
+    }
+
+    private boolean isClosureCall(MethodCallExpression call) {
+        // are we a local variable?
+        // it should not be an explicitly "this" qualified method call
+        // and the current class should have a possible method
+
+        ClassNode classNode = controller.getClassNode();
+        String methodName = call.getMethodAsString();
+        if (methodName==null) return false;
+        if (!call.isImplicitThis()) return false;
+        if (!AsmClassGenerator.isThisExpression(call.getObjectExpression())) return false;
+        FieldNode field = classNode.getDeclaredField(methodName);
+        if (field == null) return false;
+        if (isStaticInvocation(call) && !field.isStatic()) return false;
+        Expression arguments = call.getArguments();
+        return ! classNode.hasPossibleMethod(methodName, arguments);
+    }
+
+    private void invokeClosure(Expression arguments, String methodName) {
+        AsmClassGenerator acg = controller.getAcg();
+        acg.visitVariableExpression(new VariableExpression(methodName));
+        controller.getOperandStack().box();
+        if (arguments instanceof TupleExpression) {
+            arguments.visit(acg);
+        } else {
+            new TupleExpression(arguments).visit(acg);
+        }
+        invokeClosureMethod.call(controller.getMethodVisitor());
+        controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE);
+    }
+
+    private boolean isStaticInvocation(MethodCallExpression call) {
+        if (!AsmClassGenerator.isThisExpression(call.getObjectExpression())) return false;
+        if (controller.isStaticMethod()) return true;
+        return controller.isStaticContext() && !call.isImplicitThis();
+    }
+    
+    private static boolean usesSuper(MethodCallExpression call) {
+        Expression expression = call.getObjectExpression();
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            String variable = varExp.getName();
+            return variable.equals("super");
+        }
+        return false;
+    }
+
+    public void writeInvokeStaticMethod(StaticMethodCallExpression call) {
+        makeCall(call,
+                new ClassExpression(call.getOwnerType()),
+                new ConstantExpression(call.getMethod()),
+                call.getArguments(),
+                InvocationWriter.invokeStaticMethod,
+                false, false, false);
+    }
+    
+    private boolean writeDirectConstructorCall(ConstructorCallExpression call) {
+        if (!controller.isFastPath()) return false;
+        
+        StatementMeta meta = call.getNodeMetaData(StatementMeta.class);
+        ConstructorNode cn = null;
+        if (meta!=null) cn = (ConstructorNode) meta.target;
+        if (cn==null) return false;
+        
+        String ownerDescriptor = prepareConstructorCall(cn);
+        TupleExpression args = makeArgumentList(call.getArguments());
+        loadArguments(args.getExpressions(), cn.getParameters());
+        finnishConstructorCall(cn, ownerDescriptor, args.getExpressions().size());
+        
+        return true;
+    }
+    
+    protected String prepareConstructorCall(ConstructorNode cn) {
+        String owner = BytecodeHelper.getClassInternalName(cn.getDeclaringClass());
+        MethodVisitor mv = controller.getMethodVisitor();
+        
+        mv.visitTypeInsn(NEW, owner);
+        mv.visitInsn(DUP);
+        return owner;
+    }
+    
+    protected void finnishConstructorCall(ConstructorNode cn, String ownerDescriptor, int argsToRemove) {
+        String desc = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, cn.getParameters());
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitMethodInsn(INVOKESPECIAL, ownerDescriptor, "<init>", desc, false);
+        
+        controller.getOperandStack().remove(argsToRemove);
+        controller.getOperandStack().push(cn.getDeclaringClass());
+    }
+
+    protected void writeNormalConstructorCall(ConstructorCallExpression call) {
+        Expression arguments = call.getArguments();
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tupleExpression = (TupleExpression) arguments;
+            int size = tupleExpression.getExpressions().size();
+            if (size == 0) {
+                arguments = MethodCallExpression.NO_ARGUMENTS;
+            }
+        }
+
+        Expression receiverClass = new ClassExpression(call.getType());
+        controller.getCallSiteWriter().makeCallSite(
+                receiverClass, CallSiteWriter.CONSTRUCTOR,
+                arguments, false, false, false,
+                false);
+    }
+    
+    public void writeInvokeConstructor(ConstructorCallExpression call) {
+        if (writeDirectConstructorCall(call)) return;
+        if (writeAICCall(call)) return;
+        writeNormalConstructorCall(call);
+    }
+
+    protected boolean writeAICCall(ConstructorCallExpression call) {
+        if (!call.isUsingAnonymousInnerClass()) return false;
+        ConstructorNode cn = call.getType().getDeclaredConstructors().get(0);
+        OperandStack os = controller.getOperandStack();
+        
+        String ownerDescriptor = prepareConstructorCall(cn);
+        
+        List<Expression> args = makeArgumentList(call.getArguments()).getExpressions();
+        Parameter[] params = cn.getParameters();
+        // if a this appears as parameter here, then it should be
+        // not static, unless we are in a static method. But since 
+        // ACG#visitVariableExpression does the opposite for this case, we
+        // push here an explicit this. This should not have any negative effect
+        // sine visiting a method call or property with implicit this will push
+        // a new value for this again.
+        controller.getCompileStack().pushImplicitThis(true);
+        for (int i=0; i<params.length; i++) {
+            Parameter p = params[i];
+            Expression arg = args.get(i);
+            if (arg instanceof VariableExpression) {
+                VariableExpression var = (VariableExpression) arg;
+                loadVariableWithReference(var);
+            } else {
+                arg.visit(controller.getAcg());
+            }
+            os.doGroovyCast(p.getType());
+        }
+        controller.getCompileStack().popImplicitThis();
+        finnishConstructorCall(cn, ownerDescriptor, args.size());
+        return true;
+    }
+    
+    private void loadVariableWithReference(VariableExpression var) {
+        if (!var.isUseReferenceDirectly()) {
+            var.visit(controller.getAcg());
+        } else {
+            ClosureWriter.loadReference(var.getName(), controller);
+        }
+    }
+
+    public final void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) {
+        makeSingleArgumentCall(receiver, message, arguments, false);
+    }
+
+    public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) {
+        controller.getCallSiteWriter().makeSingleArgumentCall(receiver, message, arguments, safe);
+    }
+
+    public void writeSpecialConstructorCall(final ConstructorCallExpression call) {
+        controller.getCompileStack().pushInSpecialConstructorCall();
+        visitSpecialConstructorCall(call);
+        controller.getCompileStack().pop();
+    }
+
+    private void visitSpecialConstructorCall(ConstructorCallExpression call) {
+        if (controller.getClosureWriter().addGeneratedClosureConstructorCall(call)) return;
+        ClassNode callNode = controller.getClassNode();
+        if (call.isSuperCall()) callNode = callNode.getSuperClass();
+        List<ConstructorNode> constructors = sortConstructors(call, callNode);
+        if (!makeDirectConstructorCall(constructors, call, callNode)) {
+            makeMOPBasedConstructorCall(constructors, call, callNode);
+        }
+    }
+
+    private static List<ConstructorNode> sortConstructors(ConstructorCallExpression call, ClassNode callNode) {
+        // sort in a new list to prevent side effects
+        List<ConstructorNode> constructors = new ArrayList<ConstructorNode>(callNode.getDeclaredConstructors());
+        Comparator comp = new Comparator() {
+            public int compare(Object arg0, Object arg1) {
+                ConstructorNode c0 = (ConstructorNode) arg0;
+                ConstructorNode c1 = (ConstructorNode) arg1;
+                String descriptor0 = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, c0.getParameters());
+                String descriptor1 = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, c1.getParameters());
+                return descriptor0.compareTo(descriptor1);
+            }
+        };
+        Collections.sort(constructors, comp);
+        return constructors;
+    }
+
+    private boolean makeDirectConstructorCall(List<ConstructorNode> constructors, ConstructorCallExpression call, ClassNode callNode) {
+        if (!controller.isConstructor()) return false;
+
+        Expression arguments = call.getArguments();
+        List<Expression> argumentList;
+        if (arguments instanceof TupleExpression) {
+            argumentList = ((TupleExpression) arguments).getExpressions();
+        } else {
+            argumentList = new ArrayList();
+            argumentList.add(arguments);
+        }
+        for (Expression expression : argumentList) {
+            if (expression instanceof SpreadExpression) return false;
+        }
+
+        ConstructorNode cn = getMatchingConstructor(constructors, argumentList);
+        if (cn==null) return false;
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+        Parameter[] params = cn.getParameters();
+
+        mv.visitVarInsn(ALOAD, 0);
+        for (int i=0; i<params.length; i++) {
+            Expression expression = argumentList.get(i);
+            expression.visit(controller.getAcg());
+            if (!AsmClassGenerator.isNullConstant(expression)) {
+                operandStack.doGroovyCast(params[i].getType());
+            }
+            operandStack.remove(1);
+        }
+        String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, params);
+        mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
+
+        return true;
+    }
+
+    private void makeMOPBasedConstructorCall(List<ConstructorNode> constructors, ConstructorCallExpression call, ClassNode callNode) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+        call.getArguments().visit(controller.getAcg());
+        // keep Object[] on stack
+        mv.visitInsn(DUP);
+        // to select the constructor we need also the number of
+        // available constructors and the class we want to make
+        // the call on
+        BytecodeHelper.pushConstant(mv, -1);
+        controller.getAcg().visitClassExpression(new ClassExpression(callNode));
+        operandStack.remove(1);
+        // removes one Object[] leaves the int containing the
+        // call flags and the constructor number
+        selectConstructorAndTransformArguments.call(mv);
+        //load "this"
+        if (controller.isConstructor()) {
+            mv.visitVarInsn(ALOAD, 0);
+        } else {
+            mv.visitTypeInsn(NEW, BytecodeHelper.getClassInternalName(callNode));
+        }
+        mv.visitInsn(SWAP);
+        TreeMap<Integer,ConstructorNode> sortedConstructors = new TreeMap<Integer, ConstructorNode>();
+        for (ConstructorNode constructor : constructors) {
+            String typeDescriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, constructor.getParameters());
+            int hash = BytecodeHelper.hashCode(typeDescriptor);
+            ConstructorNode sameHashNode = sortedConstructors.put(hash, constructor);
+            if (sameHashNode!=null) {
+                controller.getSourceUnit().addError(
+                        new SyntaxException("Unable to compile class "+controller.getClassNode().getName() + " due to hash collision in constructors", call.getLineNumber(), call.getColumnNumber()));
+            }
+        }
+        Label[] targets = new Label[constructors.size()];
+        int[] indices = new int[constructors.size()];
+        Iterator<Integer> hashIt = sortedConstructors.keySet().iterator();
+        Iterator<ConstructorNode> constructorIt = sortedConstructors.values().iterator();
+        for (int i = 0; i < targets.length; i++) {
+            targets[i] = new Label();
+            indices[i] = hashIt.next();
+        }
+
+        // create switch targets
+        Label defaultLabel = new Label();
+        Label afterSwitch = new Label();
+        mv.visitLookupSwitchInsn(defaultLabel, indices, targets);
+        for (int i = 0; i < targets.length; i++) {
+            mv.visitLabel(targets[i]);
+            // to keep the stack height, we need to leave
+            // one Object[] on the stack as last element. At the
+            // same time, we need the Object[] on top of the stack
+            // to extract the parameters.
+            if (controller.isConstructor()) {
+                // in this case we need one "this", so a SWAP will exchange
+                // "this" and Object[], a DUP_X1 will then copy the Object[]
+                /// to the last place in the stack:
+                //     Object[],this -SWAP-> this,Object[]
+                //     this,Object[] -DUP_X1-> Object[],this,Object[]
+                mv.visitInsn(SWAP);
+                mv.visitInsn(DUP_X1);
+            } else {
+                // in this case we need two "this" in between and the Object[]
+                // at the bottom of the stack as well as on top for our invokeSpecial
+                // So we do DUP_X1, DUP2_X1, POP
+                //     Object[],this -DUP_X1-> this,Object[],this
+                //     this,Object[],this -DUP2_X1-> Object[],this,this,Object[],this
+                //     Object[],this,this,Object[],this -POP->  Object[],this,this,Object[]
+                mv.visitInsn(DUP_X1);
+                mv.visitInsn(DUP2_X1);
+                mv.visitInsn(POP);
+            }
+
+            ConstructorNode cn = constructorIt.next();
+            String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, cn.getParameters());
+
+            // unwrap the Object[] and make transformations if needed
+            // that means, to duplicate the Object[], make a cast with possible
+            // unboxing and then swap it with the Object[] for each parameter
+            // vargs need special attention and transformation though
+            Parameter[] parameters = cn.getParameters();
+            int lengthWithoutVargs = parameters.length;
+            if (parameters.length>0 && parameters[parameters.length-1].getType().isArray()) {
+                lengthWithoutVargs--;
+            }
+            for (int p = 0; p < lengthWithoutVargs; p++) {
+                loadAndCastElement(operandStack, mv, parameters, p);
+            }
+            if (parameters.length>lengthWithoutVargs) {
+                ClassNode type = parameters[lengthWithoutVargs].getType();
+                BytecodeHelper.pushConstant(mv, lengthWithoutVargs);
+                controller.getAcg().visitClassExpression(new ClassExpression(type));
+                operandStack.remove(1);
+                castToVargsArray.call(mv);
+                BytecodeHelper.doCast(mv, type);
+            } else {
+                // at the end we remove the Object[]
+                // the vargs case simply the last swap so no pop is needed
+                mv.visitInsn(POP);
+            }
+            // make the constructor call
+            mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
+            mv.visitJumpInsn(GOTO, afterSwitch);
+        }
+        mv.visitLabel(defaultLabel);
+        // this part should never be reached!
+        mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+        mv.visitInsn(DUP);
+        mv.visitLdcInsn("This class has been compiled with a super class which is binary incompatible with the current super class found on classpath. You should recompile this class with the new version.");
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V", false);
+        mv.visitInsn(ATHROW);
+        mv.visitLabel(afterSwitch);
+
+        // For a special constructor call inside a constructor we don't need
+        // any result object on the stack, for outside the constructor we do.
+        // to keep the stack height for the able we kept one object as dummy
+        // result on the stack, which we can remove now if inside a constructor.
+        if (!controller.isConstructor()) {
+            // in case we are not in a constructor we have an additional
+            // object on the stack, the result of our constructor call
+            // which we want to keep, so we swap with the dummy object and
+            // do normal removal of it. In the end, the call result will be
+            // on the stack then
+            mv.visitInsn(SWAP);
+            operandStack.push(callNode); // for call result
+        }
+        mv.visitInsn(POP);
+    }
+
+    private static void loadAndCastElement(OperandStack operandStack, MethodVisitor mv, Parameter[] parameters, int p) {
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        mv.visitInsn(DUP);
+        BytecodeHelper.pushConstant(mv, p);
+        mv.visitInsn(AALOAD);
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        ClassNode type = parameters[p].getType();
+        operandStack.doGroovyCast(type);
+        operandStack.swap();
+        operandStack.remove(2);
+    }
+
+    // we match only on the number of arguments, not anything else
+    private static ConstructorNode getMatchingConstructor(List<ConstructorNode> constructors, List<Expression> argumentList) {
+        ConstructorNode lastMatch = null;
+        for (int i=0; i<constructors.size(); i++) {
+            ConstructorNode cn = constructors.get(i);
+            Parameter[] params = cn.getParameters();
+            // if number of parameters does not match we have no match
+            if (argumentList.size()!=params.length) continue;
+            if (lastMatch==null) {
+                lastMatch = cn;
+            } else {
+                // we already had a match so we don't make a direct call at all
+                return null;
+            }
+        }
+        return lastMatch;
+    }
+
+    /**
+     * This converts sourceType to a non primitive by using Groovy casting.
+     * sourceType might be a primitive
+     * This might be done using SBA#castToType
+     */
+    public void castToNonPrimitiveIfNecessary(final ClassNode sourceType, final ClassNode targetType) {
+        OperandStack os = controller.getOperandStack();
+        ClassNode boxedType = os.box();
+        if (WideningCategories.implementsInterfaceOrSubclassOf(boxedType, targetType)) return;
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (ClassHelper.CLASS_Type.equals(targetType)) {
+            castToClassMethod.call(mv);
+        } else if (ClassHelper.STRING_TYPE.equals(targetType)) {
+            castToStringMethod.call(mv);
+        } else if (targetType.isDerivedFrom(ClassHelper.Enum_Type)) {
+            (new ClassExpression(targetType)).visit(controller.getAcg());
+            os.remove(1);
+            castToEnumMethod.call(mv);
+            BytecodeHelper.doCast(mv, targetType);
+        } else {
+            (new ClassExpression(targetType)).visit(controller.getAcg());
+            os.remove(1);
+            castToTypeMethod.call(mv);
+        }
+    }
+
+    public void castNonPrimitiveToBool(ClassNode last) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        BytecodeHelper.unbox(mv, ClassHelper.boolean_TYPE);
+    }
+
+    public void coerce(ClassNode from, ClassNode target) {
+        if (from.isDerivedFrom(target)) return;
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack os = controller.getOperandStack();
+        os.box();
+        (new ClassExpression(target)).visit(controller.getAcg());
+        os.remove(1);
+        asTypeMethod.call(mv);
+        BytecodeHelper.doCast(mv,target);
+        os.replace(target);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java
new file mode 100644
index 0000000..bc40952
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java
@@ -0,0 +1,88 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.classgen.ClassGeneratorException;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Method;
+
+/**
+ * A helper class to invoke methods more easily in ASM
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class MethodCaller implements Opcodes {
+
+    private int opcode;
+    private String internalName;
+    private String name;
+    private Class theClass;
+    private String methodDescriptor;
+
+    public static MethodCaller newStatic(Class theClass, String name) {
+        return new MethodCaller(INVOKESTATIC, theClass, name);
+    }
+
+    public static MethodCaller newInterface(Class theClass, String name) {
+        return new MethodCaller(INVOKEINTERFACE, theClass, name);
+    }
+
+    public static MethodCaller newVirtual(Class theClass, String name) {
+        return new MethodCaller(INVOKEVIRTUAL, theClass, name);
+    }
+
+    /**
+     * @since 2.5.0
+     */
+    protected MethodCaller() {}
+
+    public MethodCaller(int opcode, Class theClass, String name) {
+        this.opcode = opcode;
+        this.internalName = Type.getInternalName(theClass);
+        this.theClass = theClass;
+        this.name = name;
+
+    }
+
+    public void call(MethodVisitor methodVisitor) {
+        methodVisitor.visitMethodInsn(opcode, internalName, name, getMethodDescriptor(), opcode == Opcodes.INVOKEINTERFACE);
+    }
+
+    public String getMethodDescriptor() {
+        if (methodDescriptor == null) {
+            Method method = getMethod();
+            methodDescriptor = Type.getMethodDescriptor(method);
+        }
+        return methodDescriptor;
+    }
+
+    protected Method getMethod() {
+        Method[] methods = theClass.getMethods();
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+            if (method.getName().equals(name)) {
+                return method;
+            }
+        }
+        throw new ClassGeneratorException("Could not find method: " + name + " on class: " + theClass);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/MethodCallerMultiAdapter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/MethodCallerMultiAdapter.java b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCallerMultiAdapter.java
new file mode 100644
index 0000000..1802028
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCallerMultiAdapter.java
@@ -0,0 +1,83 @@
+/*
+ *  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.classgen.asm;
+
+import org.objectweb.asm.MethodVisitor;
+
+public class MethodCallerMultiAdapter {
+    private MethodCaller[] methods;
+    boolean skipSpreadSafeAndSafe;
+
+    public static final int MAX_ARGS = 0;
+
+    public static MethodCallerMultiAdapter newStatic(Class theClass, String baseName, boolean createNArgs, boolean skipSpreadSafeAndSafe) {
+        MethodCallerMultiAdapter mcma = new MethodCallerMultiAdapter();
+        mcma.skipSpreadSafeAndSafe = skipSpreadSafeAndSafe;
+        if (createNArgs) {
+            int numberOfBaseMethods = mcma.numberOfBaseMethods();
+            mcma.methods = new MethodCaller[(MAX_ARGS + 2) * numberOfBaseMethods];
+            for (int i = 0; i <= MAX_ARGS; i++) {
+                mcma.methods[i * numberOfBaseMethods] = MethodCaller.newStatic(theClass, baseName + i);
+                if (skipSpreadSafeAndSafe) continue;
+                mcma.methods[i * numberOfBaseMethods + 1] = MethodCaller.newStatic(theClass, baseName + i + "Safe");
+                mcma.methods[i * numberOfBaseMethods + 2] = MethodCaller.newStatic(theClass, baseName + i + "SpreadSafe");
+            }
+            mcma.methods[(MAX_ARGS + 1) * numberOfBaseMethods] = MethodCaller.newStatic(theClass, baseName + "N");
+            if (!skipSpreadSafeAndSafe) {
+                mcma.methods[(MAX_ARGS + 1) * numberOfBaseMethods + 1] = MethodCaller.newStatic(theClass, baseName + "N" + "Safe");
+                mcma.methods[(MAX_ARGS + 1) * numberOfBaseMethods + 2] = MethodCaller.newStatic(theClass, baseName + "N" + "SpreadSafe");
+            }
+
+        } else if (!skipSpreadSafeAndSafe) {
+            mcma.methods = new MethodCaller[]{
+                    MethodCaller.newStatic(theClass, baseName),
+                    MethodCaller.newStatic(theClass, baseName + "Safe"),
+                    MethodCaller.newStatic(theClass, baseName + "SpreadSafe")
+            };
+        } else {
+            mcma.methods = new MethodCaller[]{
+                    MethodCaller.newStatic(theClass, baseName)
+            };
+        }
+        return mcma;
+    }
+
+    /**
+     * @param methodVisitor
+     * @param numberOfArguments a value >0 describing how many arguments are additionally used for the method call
+     * @param safe
+     * @param spreadSafe
+     */
+    public void call(MethodVisitor methodVisitor, int numberOfArguments, boolean safe, boolean spreadSafe) {
+        int offset = 0;
+        if (safe && !skipSpreadSafeAndSafe) offset = 1;
+        if (spreadSafe && !skipSpreadSafeAndSafe) offset = 2;
+        if (numberOfArguments > MAX_ARGS || numberOfArguments < 0) {
+            offset += (MAX_ARGS + 1) * numberOfBaseMethods();
+        } else {
+            offset += numberOfArguments * numberOfBaseMethods();
+        }
+        methods[offset].call(methodVisitor);
+    }
+
+    private int numberOfBaseMethods() {
+        if (skipSpreadSafeAndSafe) return 1;
+        return 3;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/MopWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/MopWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/MopWriter.java
new file mode 100644
index 0000000..4f8f48c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/MopWriter.java
@@ -0,0 +1,223 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.objectweb.asm.MethodVisitor;
+
+import java.lang.reflect.Modifier;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
+import static org.objectweb.asm.Opcodes.ACC_BRIDGE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+
+public class MopWriter {
+    public interface Factory {
+        MopWriter create(WriterController controller);
+    }
+
+    public static final Factory FACTORY = new Factory() {
+        @Override
+        public MopWriter create(final WriterController controller) {
+            return new MopWriter(controller);
+        }
+    };
+
+    private static class MopKey {
+        final int hash;
+        final String name;
+        final Parameter[] params;
+
+        MopKey(String name, Parameter[] params) {
+            this.name = name;
+            this.params = params;
+            hash = name.hashCode() << 2 + params.length;
+        }
+
+        public int hashCode() {
+            return hash;
+        }
+
+        public boolean equals(Object obj) {
+            MopKey other = (MopKey) obj;
+            return other.name.equals(name) && equalParameterTypes(other.params,params);
+        }
+    }
+    
+    private final WriterController controller;
+    
+    public MopWriter(WriterController wc) {
+        controller = wc;
+    }
+    
+    public void createMopMethods() {
+        ClassNode classNode = controller.getClassNode();
+        if (classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type)) {
+            return;
+        }
+        Set<MopKey> currentClassSignatures = buildCurrentClassSignatureSet(classNode.getMethods());
+        visitMopMethodList(classNode.getMethods(), true, Collections.EMPTY_SET, Collections.EMPTY_LIST);
+        visitMopMethodList(classNode.getSuperClass().getAllDeclaredMethods(), false, currentClassSignatures, controller.getSuperMethodNames());
+    }
+
+    private static Set<MopKey> buildCurrentClassSignatureSet(List<MethodNode> methods) {
+        if (methods.isEmpty()) return Collections.EMPTY_SET;
+        Set<MopKey> result = new HashSet<MopKey>(methods.size());
+        for (MethodNode mn : methods) {
+            MopKey key = new MopKey(mn.getName(), mn.getParameters());
+            result.add(key);
+        }
+        return result;
+    }
+    
+    /**
+     * filters a list of method for MOP methods. For all methods that are no
+     * MOP methods a MOP method is created if the method is not public and the
+     * call would be a call on "this" (isThis == true). If the call is not on
+     * "this", then the call is a call on "super" and all methods are used,
+     * unless they are already a MOP method
+     *
+     * @param methods unfiltered list of methods for MOP
+     * @param isThis  if true, then we are creating a MOP method on "this", "super" else
+     * @see #generateMopCalls(LinkedList, boolean)
+     */
+    private void visitMopMethodList(List<MethodNode> methods, boolean isThis, Set<MopKey> useOnlyIfDeclaredHereToo, List<String> orNameMentionedHere) {
+        Map<MopKey, MethodNode> mops = new HashMap<MopKey, MethodNode>();
+        LinkedList<MethodNode> mopCalls = new LinkedList<MethodNode>();
+        for (MethodNode mn : methods) {
+            // mop methods are helper for this and super calls and do direct calls
+            // to the target methods. Such a method cannot be abstract or a bridge
+            if ((mn.getModifiers() & (ACC_ABSTRACT | ACC_BRIDGE)) != 0) continue;
+            if (mn.isStatic()) continue;
+            // no this$ methods for non-private isThis=true
+            // super$ method for non-private isThis=false
+            // --> results in XOR
+            boolean isPrivate = Modifier.isPrivate(mn.getModifiers());
+            if (isThis ^ isPrivate) continue;
+            String methodName = mn.getName();
+            if (isMopMethod(methodName)) {
+                mops.put(new MopKey(methodName, mn.getParameters()), mn);
+                continue;
+            }
+            if (methodName.startsWith("<")) continue;
+            if (!useOnlyIfDeclaredHereToo.contains(new MopKey(methodName, mn.getParameters())) &&
+                !orNameMentionedHere.contains(methodName))
+            {
+                continue;
+            }
+            String name = getMopMethodName(mn, isThis);
+            MopKey key = new MopKey(name, mn.getParameters());
+            if (mops.containsKey(key)) continue;
+            mops.put(key, mn);
+            mopCalls.add(mn);
+        }
+        generateMopCalls(mopCalls, isThis);
+        mopCalls.clear();
+        mops.clear();
+    }
+
+    /**
+     * creates a MOP method name from a method
+     *
+     * @param method  the method to be called by the mop method
+     * @param useThis if true, then it is a call on "this", "super" else
+     * @return the mop method name
+     */
+    public static String getMopMethodName(MethodNode method, boolean useThis) {
+        ClassNode declaringNode = method.getDeclaringClass();
+        int distance = 0;
+        for (; declaringNode != null; declaringNode = declaringNode.getSuperClass()) {
+            distance++;
+        }
+        return (useThis ? "this" : "super") + "$" + distance + "$" + method.getName();
+    }
+
+    /**
+     * method to determine if a method is a MOP method. This is done by the
+     * method name. If the name starts with "this$" or "super$" but does not 
+     * contain "$dist$", then it is an MOP method
+     *
+     * @param methodName name of the method to test
+     * @return true if the method is a MOP method
+     */
+    public static boolean isMopMethod(String methodName) {
+        return (methodName.startsWith("this$") ||
+                methodName.startsWith("super$")) && !methodName.contains("$dist$");
+    }
+
+    /**
+     * generates a Meta Object Protocol method, that is used to call a non public
+     * method, or to make a call to super.
+     *
+     * @param mopCalls list of methods a mop call method should be generated for
+     * @param useThis  true if "this" should be used for the naming
+     */
+    protected void generateMopCalls(LinkedList<MethodNode> mopCalls, boolean useThis) {
+        for (MethodNode method : mopCalls) {
+            String name = getMopMethodName(method, useThis);
+            Parameter[] parameters = method.getParameters();
+            String methodDescriptor = BytecodeHelper.getMethodDescriptor(method.getReturnType(), method.getParameters());
+            MethodVisitor mv = controller.getClassVisitor().visitMethod(ACC_PUBLIC | ACC_SYNTHETIC, name, methodDescriptor, null, null);
+            controller.setMethodVisitor(mv);
+            mv.visitVarInsn(ALOAD, 0);
+            int newRegister = 1;
+            OperandStack operandStack = controller.getOperandStack();
+            for (Parameter parameter : parameters) {
+                ClassNode type = parameter.getType();
+                operandStack.load(parameter.getType(), newRegister);
+                // increment to next register, double/long are using two places
+                newRegister++;
+                if (type == ClassHelper.double_TYPE || type == ClassHelper.long_TYPE) newRegister++;
+            }
+            operandStack.remove(parameters.length);
+            ClassNode declaringClass = method.getDeclaringClass();
+            // JDK 8 support for default methods in interfaces
+            // this should probably be strenghtened when we support the A.super.foo() syntax
+            int opcode = declaringClass.isInterface()?INVOKEINTERFACE:INVOKESPECIAL;
+            mv.visitMethodInsn(opcode, BytecodeHelper.getClassInternalName(declaringClass), method.getName(), methodDescriptor, opcode == INVOKEINTERFACE);
+            BytecodeHelper.doReturn(mv, method.getReturnType());
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+            controller.getClassNode().addMethod(name, ACC_PUBLIC | ACC_SYNTHETIC, method.getReturnType(), parameters, null, null);
+        }
+    }
+
+    public static boolean equalParameterTypes(Parameter[] p1, Parameter[] p2) {
+        if (p1.length != p2.length) return false;
+        for (int i = 0; i < p1.length; i++) {
+            if (!p1[i].getType().equals(p2[i].getType())) return false;
+        }
+        return true;
+    }
+
+}


[55/62] [abbrv] groovy git commit: Remove doubtful `finalizedBy`

Posted by cc...@apache.org.
Remove doubtful `finalizedBy`


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/41133d7e
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/41133d7e
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/41133d7e

Branch: refs/heads/GROOVY_2_6_X
Commit: 41133d7ec8807f715b00e568fdb99b9cebe9bc30
Parents: 5abfec7
Author: Cedric Champeau <cc...@apache.org>
Authored: Thu Dec 14 15:01:38 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:52:20 2017 +0100

----------------------------------------------------------------------
 gradle/assemble.gradle | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/41133d7e/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index 706953f..97ec669 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -288,7 +288,6 @@ allprojects {
                 target.delete()
             }
         }
-        jarjar.finalizedBy(grooidjar)
     }
 }
 


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
new file mode 100644
index 0000000..199b4ad
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -0,0 +1,610 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.NamedArgumentListExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.syntax.Types;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.groovy.ast.tools.ClassNodeUtils.getPropNameForAccessor;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticMethod;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticProperty;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.hasStaticProperty;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.isInnerClass;
+import static org.apache.groovy.ast.tools.ClassNodeUtils.isValidAccessorName;
+import static org.codehaus.groovy.runtime.MetaClassHelper.capitalize;
+
+/**
+ * Visitor to resolve constants and method calls from static Imports
+ */
+public class StaticImportVisitor extends ClassCodeExpressionTransformer {
+    private ClassNode currentClass;
+    private MethodNode currentMethod;
+    private SourceUnit source;
+    private boolean inSpecialConstructorCall;
+    private boolean inClosure;
+    private boolean inPropertyExpression;
+    private Expression foundConstant;
+    private Expression foundArgs;
+    private boolean inAnnotation;
+    private boolean inLeftExpression;
+
+    public void visitClass(ClassNode node, SourceUnit source) {
+        this.currentClass = node;
+        this.source = source;
+        super.visitClass(node);
+    }
+
+    @Override
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        this.currentMethod = node;
+        super.visitConstructorOrMethod(node, isConstructor);
+        this.currentMethod = null;
+    }
+
+    @Override
+    public void visitAnnotations(AnnotatedNode node) {
+        boolean oldInAnnotation = inAnnotation;
+        inAnnotation = true;
+        super.visitAnnotations(node);
+        inAnnotation = oldInAnnotation;
+    }
+
+    public Expression transform(Expression exp) {
+        if (exp == null) return null;
+        if (exp.getClass() == VariableExpression.class) {
+            return transformVariableExpression((VariableExpression) exp);
+        }
+        if (exp.getClass() == BinaryExpression.class) {
+            return transformBinaryExpression((BinaryExpression) exp);
+        }
+        if (exp.getClass() == PropertyExpression.class) {
+            return transformPropertyExpression((PropertyExpression) exp);
+        }
+        if (exp.getClass() == MethodCallExpression.class) {
+            return transformMethodCallExpression((MethodCallExpression) exp);
+        }
+        if (exp.getClass() == ClosureExpression.class) {
+            return transformClosureExpression((ClosureExpression) exp);
+        }
+        if (exp.getClass() == ConstructorCallExpression.class) {
+            return transformConstructorCallExpression((ConstructorCallExpression) exp);
+        }
+        if (exp.getClass() == ArgumentListExpression.class) {
+            Expression result = exp.transformExpression(this);
+            if (inPropertyExpression) {
+                foundArgs = result;
+            }
+            return result;
+        }
+        if (exp instanceof ConstantExpression) {
+            Expression result = exp.transformExpression(this);
+            if (inPropertyExpression) {
+                foundConstant = result;
+            }
+            if (inAnnotation && exp instanceof AnnotationConstantExpression) {
+                ConstantExpression ce = (ConstantExpression) result;
+                if (ce.getValue() instanceof AnnotationNode) {
+                    // replicate a little bit of AnnotationVisitor here
+                    // because we can't wait until later to do this
+                    AnnotationNode an = (AnnotationNode) ce.getValue();
+                    Map<String, Expression> attributes = an.getMembers();
+                    for (Map.Entry<String, Expression> entry : attributes.entrySet()) {
+                        Expression attrExpr = transform(entry.getValue());
+                        entry.setValue(attrExpr);
+                    }
+
+                }
+            }
+            return result;
+        }
+        return exp.transformExpression(this);
+    }
+
+    // if you have a Bar class with a static foo property, and this:
+    //   import static Bar.foo as baz
+    // then this constructor (not normal usage of statics):
+    //   new Bar(baz:1)
+    // will become:
+    //   new Bar(foo:1)
+
+    private Expression transformMapEntryExpression(MapEntryExpression me, ClassNode constructorCallType) {
+        Expression key = me.getKeyExpression();
+        Expression value = me.getValueExpression();
+        ModuleNode module = currentClass.getModule();
+        if (module != null && key instanceof ConstantExpression) {
+            Map<String, ImportNode> importNodes = module.getStaticImports();
+            if (importNodes.containsKey(key.getText())) {
+                ImportNode importNode = importNodes.get(key.getText());
+                if (importNode.getType().equals(constructorCallType)) {
+                    String newKey = importNode.getFieldName();
+                    return new MapEntryExpression(new ConstantExpression(newKey), value.transformExpression(this));
+                }
+            }
+        }
+        return me;
+    }
+
+    protected Expression transformBinaryExpression(BinaryExpression be) {
+        int type = be.getOperation().getType();
+        boolean oldInLeftExpression;
+        Expression right = transform(be.getRightExpression());
+        be.setRightExpression(right);
+        Expression left;
+        if (type == Types.EQUAL && be.getLeftExpression() instanceof VariableExpression) {
+            oldInLeftExpression = inLeftExpression;
+            inLeftExpression = true;
+            left = transform(be.getLeftExpression());
+            inLeftExpression = oldInLeftExpression;
+            if (left instanceof StaticMethodCallExpression) {
+                StaticMethodCallExpression smce = (StaticMethodCallExpression) left;
+                StaticMethodCallExpression result = new StaticMethodCallExpression(smce.getOwnerType(), smce.getMethod(), right);
+                setSourcePosition(result, be);
+                return result;
+            }
+        } else {
+            left = transform(be.getLeftExpression());
+        }
+        be.setLeftExpression(left);
+        return be;
+    }
+
+    protected Expression transformVariableExpression(VariableExpression ve) {
+        Variable v = ve.getAccessedVariable();
+        if (v != null && v instanceof DynamicVariable) {
+            Expression result = findStaticFieldOrPropAccessorImportFromModule(v.getName());
+            if (result != null) {
+                setSourcePosition(result, ve);
+                if (inAnnotation) {
+                    result = transformInlineConstants(result);
+                }
+                return result;
+            }
+        }
+        return ve;
+    }
+
+    /**
+     * Set the source position of toSet including its property expression if it has one.
+     *
+     * @param toSet resulting node
+     * @param origNode original node
+     */
+    private static void setSourcePosition(Expression toSet, Expression origNode) {
+        toSet.setSourcePosition(origNode);
+        if (toSet instanceof PropertyExpression) {
+            ((PropertyExpression) toSet).getProperty().setSourcePosition(origNode);
+        }
+    }
+
+    // resolve constant-looking expressions statically (do here as gets transformed away later)
+
+    private Expression transformInlineConstants(Expression exp) {
+        if (exp instanceof PropertyExpression) {
+            PropertyExpression pe = (PropertyExpression) exp;
+            if (pe.getObjectExpression() instanceof ClassExpression) {
+                ClassExpression ce = (ClassExpression) pe.getObjectExpression();
+                ClassNode type = ce.getType();
+                if (type.isEnum()) return exp;
+                Expression constant = findConstant(getField(type, pe.getPropertyAsString()));
+                if (constant != null) return constant;
+            }
+        } else if (exp instanceof ListExpression) {
+            ListExpression le = (ListExpression) exp;
+            ListExpression result = new ListExpression();
+            for (Expression e : le.getExpressions()) {
+                result.addExpression(transformInlineConstants(e));
+            }
+            return result;
+        }
+
+        return exp;
+    }
+
+    private static Expression findConstant(FieldNode fn) {
+        if (fn != null && !fn.isEnum() && fn.isStatic() && fn.isFinal()) {
+            if (fn.getInitialValueExpression() instanceof ConstantExpression) {
+                return fn.getInitialValueExpression();
+            }
+        }
+        return null;
+    }
+
+    protected Expression transformMethodCallExpression(MethodCallExpression mce) {
+        Expression args = transform(mce.getArguments());
+        Expression method = transform(mce.getMethod());
+        Expression object = transform(mce.getObjectExpression());
+        boolean isExplicitThisOrSuper = false;
+        boolean isExplicitSuper = false;
+        if (object instanceof VariableExpression) {
+            VariableExpression ve = (VariableExpression) object;
+            isExplicitThisOrSuper = !mce.isImplicitThis() && (ve.isThisExpression() || ve.isSuperExpression());
+            isExplicitSuper = ve.isSuperExpression();
+        }
+
+        if (mce.isImplicitThis() || isExplicitThisOrSuper) {
+            if (mce.isImplicitThis()) {
+                Expression ret = findStaticMethodImportFromModule(method, args);
+                if (ret != null) {
+                    setSourcePosition(ret, mce);
+                    return ret;
+                }
+                if (method instanceof ConstantExpression && !inLeftExpression) {
+                    // could be a closure field
+                    String methodName = (String) ((ConstantExpression) method).getValue();
+                    ret = findStaticFieldOrPropAccessorImportFromModule(methodName);
+                    if (ret != null) {
+                        ret = new MethodCallExpression(ret, "call", args);
+                        setSourcePosition(ret, mce);
+                        return ret;
+                    }
+                }
+            } else if (currentMethod!=null && currentMethod.isStatic() && isExplicitSuper) {
+                MethodCallExpression ret = new MethodCallExpression(new ClassExpression(currentClass.getSuperClass()), method, args);
+                setSourcePosition(ret, mce);
+                return ret;
+            }
+
+            if (method instanceof ConstantExpression) {
+                ConstantExpression ce = (ConstantExpression) method;
+                Object value = ce.getValue();
+                if (value instanceof String) {
+                    boolean foundInstanceMethod = false;
+                    String methodName = (String) value;
+                    boolean inInnerClass = isInnerClass(currentClass);
+                    if (currentMethod != null && !currentMethod.isStatic()) {
+                        if (currentClass.hasPossibleMethod(methodName, args)) {
+                            foundInstanceMethod = true;
+                        }
+                    }
+                    boolean lookForPossibleStaticMethod = !methodName.equals("call");
+                    lookForPossibleStaticMethod &= !foundInstanceMethod;
+                    lookForPossibleStaticMethod |= inSpecialConstructorCall;
+                    lookForPossibleStaticMethod &= !inInnerClass;
+                    if (!inClosure && lookForPossibleStaticMethod &&
+                            (hasPossibleStaticMethod(currentClass, methodName, args, true))
+                            || hasPossibleStaticProperty(currentClass, methodName)) {
+                        StaticMethodCallExpression smce = new StaticMethodCallExpression(currentClass, methodName, args);
+                        setSourcePosition(smce, mce);
+                        return smce;
+                    }
+                    if (!inClosure && inInnerClass && inSpecialConstructorCall && mce.isImplicitThis() && !foundInstanceMethod) {
+                        if (currentClass.getOuterClass().hasPossibleMethod(methodName, args)) {
+                            object = new PropertyExpression(new ClassExpression(currentClass.getOuterClass()), new ConstantExpression("this"));
+                        } else if (hasPossibleStaticMethod(currentClass.getOuterClass(), methodName, args, true)
+                                || hasPossibleStaticProperty(currentClass.getOuterClass(), methodName)) {
+                            StaticMethodCallExpression smce = new StaticMethodCallExpression(currentClass.getOuterClass(), methodName, args);
+                            setSourcePosition(smce, mce);
+                            return smce;
+                        }
+                    }
+                }
+            }
+        }
+
+        MethodCallExpression result = new MethodCallExpression(object, method, args);
+        result.setSafe(mce.isSafe());
+        result.setImplicitThis(mce.isImplicitThis());
+        result.setSpreadSafe(mce.isSpreadSafe());
+        result.setMethodTarget(mce.getMethodTarget());
+        // GROOVY-6757
+        result.setGenericsTypes(mce.getGenericsTypes());
+        setSourcePosition(result, mce);
+        return result;
+    }
+
+    protected Expression transformConstructorCallExpression(ConstructorCallExpression cce) {
+        inSpecialConstructorCall = cce.isSpecialCall();
+        Expression expression = cce.getArguments();
+        if (expression instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) expression;
+            if (tuple.getExpressions().size() == 1) {
+                expression = tuple.getExpression(0);
+                if (expression instanceof NamedArgumentListExpression) {
+                    NamedArgumentListExpression namedArgs = (NamedArgumentListExpression) expression;
+                    List<MapEntryExpression> entryExpressions = namedArgs.getMapEntryExpressions();
+                    for (int i = 0; i < entryExpressions.size(); i++) {
+                        entryExpressions.set(i, (MapEntryExpression) transformMapEntryExpression(entryExpressions.get(i), cce.getType()));
+                    }
+                }
+            }
+        }
+        Expression ret = cce.transformExpression(this);
+        inSpecialConstructorCall = false;
+        return ret;
+    }
+
+    protected Expression transformClosureExpression(ClosureExpression ce) {
+        boolean oldInClosure = inClosure;
+        inClosure = true;
+        if (ce.getParameters() != null) {
+            for (Parameter p : ce.getParameters()) {
+                if (p.hasInitialExpression()) {
+                    p.setInitialExpression(transform(p.getInitialExpression()));
+                }
+            }
+        }
+        Statement code = ce.getCode();
+        if (code != null) code.visit(this);
+        inClosure = oldInClosure;
+        return ce;
+    }
+
+    protected Expression transformPropertyExpression(PropertyExpression pe) {
+        if (currentMethod!=null && currentMethod.isStatic()
+                && pe.getObjectExpression() instanceof VariableExpression
+                && ((VariableExpression) pe.getObjectExpression()).isSuperExpression()) {
+            PropertyExpression pexp = new PropertyExpression(
+                    new ClassExpression(currentClass.getSuperClass()),
+                    transform(pe.getProperty())
+            );
+            pexp.setSourcePosition(pe);
+            return pexp;
+        }
+        boolean oldInPropertyExpression = inPropertyExpression;
+        Expression oldFoundArgs = foundArgs;
+        Expression oldFoundConstant = foundConstant;
+        inPropertyExpression = true;
+        foundArgs = null;
+        foundConstant = null;
+        Expression objectExpression = transform(pe.getObjectExpression());
+        boolean candidate = false;
+        if (objectExpression instanceof MethodCallExpression) {
+            candidate = ((MethodCallExpression)objectExpression).isImplicitThis();
+        }
+
+        if (foundArgs != null && foundConstant != null && candidate) {
+            Expression result = findStaticMethodImportFromModule(foundConstant, foundArgs);
+            if (result != null) {
+                objectExpression = result;
+                objectExpression.setSourcePosition(pe);
+            }
+        }
+        inPropertyExpression = oldInPropertyExpression;
+        foundArgs = oldFoundArgs;
+        foundConstant = oldFoundConstant;
+        pe.setObjectExpression(objectExpression);
+        return pe;
+    }
+
+    private Expression findStaticFieldOrPropAccessorImportFromModule(String name) {
+        ModuleNode module = currentClass.getModule();
+        if (module == null) return null;
+        Map<String, ImportNode> importNodes = module.getStaticImports();
+        Expression expression;
+        String accessorName = getAccessorName(name);
+        // look for one of these:
+        //   import static MyClass.setProp [as setOtherProp]
+        //   import static MyClass.getProp [as getOtherProp]
+        // when resolving prop reference
+        if (importNodes.containsKey(accessorName)) {
+            expression = findStaticProperty(importNodes, accessorName);
+            if (expression != null) return expression;
+        }
+        if (accessorName.startsWith("get")) {
+            accessorName = "is" + accessorName.substring(3);
+            if (importNodes.containsKey(accessorName)) {
+                expression = findStaticProperty(importNodes, accessorName);
+                if (expression != null) return expression;
+            }
+        }
+
+        // look for one of these:
+        //   import static MyClass.prop [as otherProp]
+        // when resolving prop or field reference
+        if (importNodes.containsKey(name)) {
+            ImportNode importNode = importNodes.get(name);
+            expression = findStaticPropertyAccessor(importNode.getType(), importNode.getFieldName());
+            if (expression != null) return expression;
+            expression = findStaticField(importNode.getType(), importNode.getFieldName());
+            if (expression != null) return expression;
+        }
+        // look for one of these:
+        //   import static MyClass.*
+        // when resolving prop or field reference
+        for (ImportNode importNode : module.getStaticStarImports().values()) {
+            ClassNode node = importNode.getType();
+            expression = findStaticPropertyAccessor(node, name);
+            if (expression != null) return expression;
+            expression = findStaticField(node, name);
+            if (expression != null) return expression;
+        }
+        return null;
+    }
+
+    private Expression findStaticProperty(Map<String, ImportNode> importNodes, String accessorName) {
+        Expression result = null;
+        ImportNode importNode = importNodes.get(accessorName);
+        ClassNode importClass = importNode.getType();
+        String importMember = importNode.getFieldName();
+        result = findStaticPropertyAccessorByFullName(importClass, importMember);
+        if (result == null) {
+            result = findStaticPropertyAccessor(importClass, getPropNameForAccessor(importMember));
+        }
+        return result;
+    }
+
+    private Expression findStaticMethodImportFromModule(Expression method, Expression args) {
+        ModuleNode module = currentClass.getModule();
+        if (module == null || !(method instanceof ConstantExpression)) return null;
+        Map<String, ImportNode> importNodes = module.getStaticImports();
+        ConstantExpression ce = (ConstantExpression) method;
+        Expression expression;
+        Object value = ce.getValue();
+        // skip non-Strings, e.g. Integer
+        if (!(value instanceof String)) return null;
+        final String name = (String) value;
+        // look for one of these:
+        //   import static SomeClass.method [as otherName]
+        // when resolving methodCall() or getProp() or setProp()
+        if (importNodes.containsKey(name)) {
+            ImportNode importNode = importNodes.get(name);
+            expression = findStaticMethod(importNode.getType(), importNode.getFieldName(), args);
+            if (expression != null) return expression;
+            expression = findStaticPropertyAccessorGivenArgs(importNode.getType(), getPropNameForAccessor(importNode.getFieldName()), args);
+            if (expression != null) {
+                return new StaticMethodCallExpression(importNode.getType(), importNode.getFieldName(), args);
+            }
+        }
+        // look for one of these:
+        //   import static SomeClass.someProp [as otherName]
+        // when resolving getProp() or setProp()
+        if (isValidAccessorName(name)) {
+            String propName = getPropNameForAccessor(name);
+            if (importNodes.containsKey(propName)) {
+                ImportNode importNode = importNodes.get(propName);
+                ClassNode importClass = importNode.getType();
+                String importMember = importNode.getFieldName();
+                expression = findStaticMethod(importClass, prefix(name) + capitalize(importMember), args);
+                if (expression != null) return expression;
+                expression = findStaticPropertyAccessorGivenArgs(importClass, importMember, args);
+                if (expression != null) {
+                    return new StaticMethodCallExpression(importClass, prefix(name) + capitalize(importMember), args);
+                }
+            }
+        }
+        Map<String, ImportNode> starImports = module.getStaticStarImports();
+        ClassNode starImportType;
+        if (currentClass.isEnum() && starImports.containsKey(currentClass.getName())) {
+            ImportNode importNode = starImports.get(currentClass.getName());
+            starImportType = importNode == null ? null : importNode.getType();
+            expression = findStaticMethod(starImportType, name, args);
+            if (expression != null) return expression;
+        } else {
+            for (ImportNode importNode : starImports.values()) {
+                starImportType = importNode == null ? null : importNode.getType();
+                expression = findStaticMethod(starImportType, name, args);
+                if (expression != null) return expression;
+                expression = findStaticPropertyAccessorGivenArgs(starImportType, getPropNameForAccessor(name), args);
+                if (expression != null) {
+                    return new StaticMethodCallExpression(starImportType, name, args);
+                }
+            }
+        }
+        return null;
+    }
+
+    private static String prefix(String name) {
+        return name.startsWith("is") ? "is" : name.substring(0, 3);
+    }
+
+    private String getAccessorName(String name) {
+        return (inLeftExpression ? "set" : "get") + capitalize(name);
+    }
+
+    private Expression findStaticPropertyAccessorGivenArgs(ClassNode staticImportType, String propName, Expression args) {
+        // TODO validate args?
+        return findStaticPropertyAccessor(staticImportType, propName);
+    }
+
+    private Expression findStaticPropertyAccessor(ClassNode staticImportType, String propName) {
+        String accessorName = getAccessorName(propName);
+        Expression accessor = findStaticPropertyAccessorByFullName(staticImportType, accessorName);
+        if (accessor == null && accessorName.startsWith("get")) {
+            accessor = findStaticPropertyAccessorByFullName(staticImportType, "is" + accessorName.substring(3));
+        }
+        if (accessor == null && hasStaticProperty(staticImportType, propName)) {
+            // args will be replaced
+            if (inLeftExpression)
+                accessor = new StaticMethodCallExpression(staticImportType, accessorName, ArgumentListExpression.EMPTY_ARGUMENTS);
+            else
+                accessor = new PropertyExpression(new ClassExpression(staticImportType), propName);
+        }
+        return accessor;
+    }
+
+    private Expression findStaticPropertyAccessorByFullName(ClassNode staticImportType, String accessorMethodName) {
+        // anything will do as we only check size == 1
+        ArgumentListExpression dummyArgs = new ArgumentListExpression();
+        dummyArgs.addExpression(EmptyExpression.INSTANCE);
+        return findStaticMethod(staticImportType, accessorMethodName, (inLeftExpression ? dummyArgs : ArgumentListExpression.EMPTY_ARGUMENTS));
+    }
+
+    private static Expression findStaticField(ClassNode staticImportType, String fieldName) {
+        if (staticImportType.isPrimaryClassNode() || staticImportType.isResolved()) {
+            FieldNode field = getField(staticImportType, fieldName);
+            if (field != null && field.isStatic())
+                return new PropertyExpression(new ClassExpression(staticImportType), fieldName);
+        }
+        return null;
+    }
+
+    private static FieldNode getField(ClassNode classNode, String fieldName) {
+        ClassNode node = classNode;
+        Set<String> visited = new HashSet<String>();
+        while (node != null) {
+            FieldNode fn = node.getDeclaredField(fieldName);
+            if (fn != null) return fn;
+            ClassNode[] interfaces = node.getInterfaces();
+            for (ClassNode iNode : interfaces) {
+                if (visited.contains(iNode.getName())) continue;
+                FieldNode ifn = getField(iNode, fieldName);
+                visited.add(iNode.getName());
+                if (ifn != null) return ifn;
+            }
+            node = node.getSuperClass();
+        }
+        return null;
+    }
+
+    private static Expression findStaticMethod(ClassNode staticImportType, String methodName, Expression args) {
+        if (staticImportType.isPrimaryClassNode() || staticImportType.isResolved()) {
+            if (staticImportType.hasPossibleStaticMethod(methodName, args)) {
+                return new StaticMethodCallExpression(staticImportType, methodName, args);
+            }
+        }
+        return null;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/StaticVerifier.java b/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
new file mode 100644
index 0000000..53706f9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/StaticVerifier.java
@@ -0,0 +1,204 @@
+/*
+ *  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.control;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.DynamicVariable;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.apache.groovy.ast.tools.ClassNodeUtils.isInnerClass;
+
+/**
+ * Verifier to check non-static access in static contexts
+ */
+public class StaticVerifier extends ClassCodeVisitorSupport {
+    private boolean inSpecialConstructorCall;
+    private boolean inPropertyExpression; // TODO use it or lose it
+    private boolean inClosure;
+    private MethodNode currentMethod;
+    private SourceUnit source;
+
+    public void visitClass(ClassNode node, SourceUnit source) {
+        this.source = source;
+        super.visitClass(node);
+    }
+
+    @Override
+    public void visitVariableExpression(VariableExpression ve) {
+        Variable v = ve.getAccessedVariable();
+        if (v != null && v instanceof DynamicVariable) {
+            if (!inPropertyExpression || inSpecialConstructorCall) addStaticVariableError(ve);
+        }
+    }
+
+    @Override
+    public void visitClosureExpression(ClosureExpression ce) {
+        boolean oldInClosure = inClosure;
+        inClosure = true;
+        super.visitClosureExpression(ce);
+        inClosure = oldInClosure;
+    }
+
+    @Override
+    public void visitConstructorCallExpression(ConstructorCallExpression cce) {
+        boolean oldIsSpecialConstructorCall = inSpecialConstructorCall;
+        inSpecialConstructorCall = cce.isSpecialCall();
+        super.visitConstructorCallExpression(cce);
+        inSpecialConstructorCall = oldIsSpecialConstructorCall;
+    }
+
+    @Override
+    public void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        MethodNode oldCurrentMethod = currentMethod;
+        currentMethod = node;
+        super.visitConstructorOrMethod(node, isConstructor);
+        if (isConstructor) {
+            final Set<String> exceptions = new HashSet<String>();
+            for (final Parameter param : node.getParameters()) {
+                exceptions.add(param.getName());
+                if (param.hasInitialExpression()) {
+                    param.getInitialExpression().visit(new CodeVisitorSupport() {
+                        @Override
+                        public void visitVariableExpression(VariableExpression ve) {
+                            if (exceptions.contains(ve.getName())) return;
+                            Variable av = ve.getAccessedVariable();
+                            if (av instanceof DynamicVariable || !av.isInStaticContext()) {
+                                addVariableError(ve);
+                            }
+                        }
+
+                        @Override
+                        public void visitMethodCallExpression(MethodCallExpression call) {
+                            Expression objectExpression = call.getObjectExpression();
+                            if (objectExpression instanceof VariableExpression) {
+                                VariableExpression ve = (VariableExpression) objectExpression;
+                                if (ve.isThisExpression()) {
+                                    addError("Can't access instance method '" + call.getMethodAsString() + "' for a constructor parameter default value", param);
+                                    return;
+                                }
+                            }
+                            super.visitMethodCallExpression(call);
+                        }
+
+                        @Override
+                        public void visitClosureExpression(ClosureExpression expression) {
+                            //skip contents, because of dynamic scope
+                        }
+                    });
+                }
+            }
+        }
+        currentMethod = oldCurrentMethod;
+    }
+
+    @Override
+    public void visitMethodCallExpression(MethodCallExpression mce) {
+        if (inSpecialConstructorCall && !isInnerClass(currentMethod.getDeclaringClass())) {
+            Expression objectExpression = mce.getObjectExpression();
+            if (objectExpression instanceof VariableExpression) {
+                VariableExpression ve = (VariableExpression) objectExpression;
+                if (ve.isThisExpression()) {
+                    addError("Can't access instance method '" + mce.getMethodAsString() + "' before the class is constructed", mce);
+                    return;
+                }
+            }
+        }
+        super.visitMethodCallExpression(mce);
+    }
+
+    @Override
+    public void visitPropertyExpression(PropertyExpression pe) {
+        if (!inSpecialConstructorCall) checkStaticScope(pe);
+    }
+
+    @Override
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+
+    private void checkStaticScope(PropertyExpression pe) {
+        if (inClosure) return;
+        for (Expression it = pe; it != null; it = ((PropertyExpression) it).getObjectExpression()) {
+            if (it instanceof PropertyExpression) continue;
+            if (it instanceof VariableExpression) {
+                addStaticVariableError((VariableExpression) it);
+            }
+            return;
+        }
+    }
+
+    private void addStaticVariableError(VariableExpression ve) {
+        // closures are always dynamic
+        // propertyExpressions will handle the error a bit differently
+        if (!inSpecialConstructorCall && (inClosure || !ve.isInStaticContext())) return;
+        if (ve.isThisExpression() || ve.isSuperExpression()) return;
+        Variable v = ve.getAccessedVariable();
+        if (currentMethod != null && currentMethod.isStatic()) {
+            FieldNode fieldNode = getDeclaredOrInheritedField(currentMethod.getDeclaringClass(), ve.getName());
+            if (fieldNode != null && fieldNode.isStatic()) return;
+        }
+        if (v != null && !(v instanceof DynamicVariable) && v.isInStaticContext()) return;
+        addVariableError(ve);
+    }
+
+    private void addVariableError(VariableExpression ve) {
+        addError("Apparent variable '" + ve.getName() + "' was found in a static scope but doesn't refer" +
+                " to a local variable, static field or class. Possible causes:\n" +
+                "You attempted to reference a variable in the binding or an instance variable from a static context.\n" +
+                "You misspelled a classname or statically imported field. Please check the spelling.\n" +
+                "You attempted to use a method '" + ve.getName() +
+                "' but left out brackets in a place not allowed by the grammar.", ve);
+    }
+
+    private static FieldNode getDeclaredOrInheritedField(ClassNode cn, String fieldName) {
+        ClassNode node = cn;
+        while (node != null) {
+            FieldNode fn = node.getDeclaredField(fieldName);
+            if (fn != null) return fn;
+            List<ClassNode> interfacesToCheck = new ArrayList<ClassNode>(Arrays.asList(node.getInterfaces()));
+            while (!interfacesToCheck.isEmpty()) {
+                ClassNode nextInterface = interfacesToCheck.remove(0);
+                fn = nextInterface.getDeclaredField(fieldName);
+                if (fn != null) return fn;
+                interfacesToCheck.addAll(Arrays.asList(nextInterface.getInterfaces()));
+            }
+            node = node.getSuperClass();
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/XStreamUtils.java b/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
new file mode 100644
index 0000000..3f7ccd3
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
@@ -0,0 +1,68 @@
+/*
+ *  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.control;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.StaxDriver;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.net.URI;
+
+public abstract class XStreamUtils {
+
+    public static void serialize(final String name, final Object ast) {
+        if (name == null || name.length() == 0) return;
+
+        XStream xstream = new XStream(new StaxDriver());
+        FileWriter astFileWriter = null;
+        try {
+            File astFile = astFile(name);
+            if (astFile == null) {
+                System.out.println("File-name for writing " + name + " AST could not be determined!");
+                return;
+            }
+            astFileWriter = new FileWriter(astFile, false);
+            xstream.toXML(ast, astFileWriter);
+            System.out.println("Written AST to " + name + ".xml");
+
+        } catch (Exception e) {
+            System.out.println("Couldn't write to " + name + ".xml");
+            e.printStackTrace();
+        } finally {
+            DefaultGroovyMethods.closeQuietly(astFileWriter);
+        }
+    }
+
+    /**
+     * Takes the incoming file-name and checks whether this is a URI using the <tt>file:</tt> protocol or a non-URI and treats
+     * it accordingly.
+     *
+     * @return a file-name {@link java.io.File} representation or <tt>null</tt> if the file-name was in an invalid URI format
+     */
+    private static File astFile(final String uriOrFileName) {
+        try {
+            final String astFileName = uriOrFileName + ".xml";
+            return uriOrFileName.startsWith("file:") ? new File(URI.create(astFileName)) : new File(astFileName);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java b/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
new file mode 100644
index 0000000..8f9e81c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/CompilationCustomizer.java
@@ -0,0 +1,45 @@
+/*
+ *  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.control.customizers;
+
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.CompilePhase;
+
+/**
+ * Users wanting to customize the configuration process such as adding imports, restricting the
+ * language features or apply AST transformations by default should implement this class, then
+ * call the {@link org.codehaus.groovy.control.CompilerConfiguration#addCompilationCustomizers(CompilationCustomizer...)}
+ * method.
+ *
+ * @author Cedric Champeau
+ *
+ * @since 1.8.0
+ *
+ */
+public abstract class CompilationCustomizer extends CompilationUnit.PrimaryClassNodeOperation {
+    private final CompilePhase phase;
+
+    public CompilationCustomizer(CompilePhase phase) {
+        this.phase = phase;
+    }
+
+    public CompilePhase getPhase() {
+        return phase;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java b/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java
new file mode 100644
index 0000000..0f6af6a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/DelegatingCustomizer.java
@@ -0,0 +1,45 @@
+/*
+ *  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.control.customizers;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.SourceUnit;
+
+/**
+ * Base class for compilation customizers which delegate to another customizer. The phase this
+ * customizer runs at is retrieved from the phase of the delegate.
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+public abstract class DelegatingCustomizer extends CompilationCustomizer {
+    protected final CompilationCustomizer delegate;
+
+    public DelegatingCustomizer(CompilationCustomizer delegate) {
+        super(delegate.getPhase());
+        this.delegate = delegate;
+    }
+
+    @Override
+    public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+        delegate.call(source, context, classNode);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java b/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java
new file mode 100644
index 0000000..780b554
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/ImportCustomizer.java
@@ -0,0 +1,169 @@
+/*
+ *  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.control.customizers;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * This compilation customizer allows addiing various types of imports to the compilation unit. Supports adding :
+ * <ul>
+ *     <li>standard imports thanks to {@link #addImport(String)}, {@link #addImport(String, String)} or {@link #addImports(String...)}</li>
+ *     <li>star imports thanks to {@link #addStarImport(String)} or {@link #addStarImports(String...)}</li>
+ *     <li>static imports thanks to {@link #addStaticImport(String, String)} or {@link #addStaticImport(String, String, String)}</li>
+ *     <li>static star imports thanks to {@link #addStaticStar(String)} or {@link #addStaticStars(String...)}</li>
+ * </ul>
+ *
+ * @author Cedric Champeau
+ *
+ * @since 1.8.0
+ *
+ */
+public class ImportCustomizer extends CompilationCustomizer {
+
+    private final List<Import> imports = new LinkedList<Import>();
+
+    public ImportCustomizer() {
+        super(CompilePhase.CONVERSION);
+    }
+
+    @Override
+    public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+        final ModuleNode ast = source.getAST();
+        for (Import anImport : imports) {
+            switch (anImport.type) {
+                case regular:
+                    ast.addImport(anImport.alias, anImport.classNode);
+                    break;
+                case staticImport:
+                    ast.addStaticImport(anImport.classNode, anImport.field, anImport.alias);
+                    break;
+                case staticStar:
+                    ast.addStaticStarImport(anImport.alias, anImport.classNode);
+                    break;
+                case star:
+                    ast.addStarImport(anImport.star);
+                    break;
+            }
+        }
+    }
+
+    public ImportCustomizer addImport(final String alias, final String className) {
+        imports.add(new Import(ImportType.regular, alias, ClassHelper.make(className)));
+        return this;
+    }
+
+    public ImportCustomizer addStaticImport(final String className, final String fieldName) {
+        final ClassNode node = ClassHelper.make(className);
+        imports.add(new Import(ImportType.staticImport, fieldName, node, fieldName));
+        return this;
+    }
+
+    public ImportCustomizer addStaticStars(final String... classNames) {
+        for (String className : classNames) {
+            addStaticStar(className);
+        }
+        return this;
+    }
+
+    public ImportCustomizer addStaticImport(final String alias, final String className, final String fieldName) {
+        imports.add(new Import(ImportCustomizer.ImportType.staticImport, alias, ClassHelper.make(className), fieldName));
+        return this;
+    }
+
+    public ImportCustomizer addImports(final String... imports) {
+            for (String anImport : imports) {
+                addImport(anImport);
+            }
+        return this;
+    }
+
+    public ImportCustomizer addStarImports(final String... packageNames) {
+            for (String packageName : packageNames) {
+                addStarImport(packageName);
+            }
+        return this;
+    }
+
+    private void addImport(final String className) {
+        final ClassNode node = ClassHelper.make(className);
+        imports.add(new Import(ImportType.regular, node.getNameWithoutPackage(), node));
+    }
+
+    private void addStaticStar(final String className) {
+        imports.add(new Import(ImportCustomizer.ImportType.staticStar, className, ClassHelper.make(className)));
+    }
+
+    private void addStarImport(final String packagename) {
+        final String packageNameEndingWithDot = packagename.endsWith(".")?packagename:packagename+'.';
+        imports.add(new Import(ImportType.star,packageNameEndingWithDot));
+    }
+
+    // -------------------- Helper classes -------------------------
+
+    /**
+     * Represents imports which are possibly aliased.
+     */
+    private static final class Import {
+        final ImportType type;
+        final ClassNode classNode;
+        final String alias;
+        final String field;
+        final String star; // only used for star imports
+
+        private Import(final ImportType type, final String alias, final ClassNode classNode, final String field) {
+            this.alias = alias;
+            this.classNode = classNode;
+            this.field = field;
+            this.type = type;
+            this.star = null;
+        }
+
+        private Import(final ImportType type, final String alias, final ClassNode classNode) {
+            this.alias = alias;
+            this.classNode = classNode;
+            this.type = type;
+            this.field = null;
+            this.star = null;
+        }
+
+        private Import(final ImportType type, final String star) {
+            this.type = type;
+            this.star = star;
+            this.alias = null;
+            this.classNode = null;
+            this.field = null;
+        }
+    }
+
+    private enum ImportType {
+        regular,
+        staticImport,
+        staticStar,
+        star
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java b/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java
new file mode 100644
index 0000000..e621729
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/ReflectionUtils.java
@@ -0,0 +1,140 @@
+/*
+ *  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.reflection;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class contains utility methods to determine which class called the
+ * current class to multiple levels of depth.  Calls used to handle the
+ * groovy MOP are excluded from the level counting.
+ */
+public class ReflectionUtils {
+
+    // these are packages in the call stack that are only part of the groovy MOP
+    private static final Set<String> IGNORED_PACKAGES = new HashSet<String>();
+
+    static {
+        //IGNORED_PACKAGES.add("java.lang.reflect");
+        IGNORED_PACKAGES.add("groovy.lang");
+        IGNORED_PACKAGES.add("org.codehaus.groovy.reflection");
+        IGNORED_PACKAGES.add("org.codehaus.groovy.runtime.callsite");
+        IGNORED_PACKAGES.add("org.codehaus.groovy.runtime.metaclass");
+        IGNORED_PACKAGES.add("org.codehaus.groovy.runtime");
+        IGNORED_PACKAGES.add("sun.reflect");
+        IGNORED_PACKAGES.add("java.lang.invoke");
+        IGNORED_PACKAGES.add("org.codehaus.groovy.vmplugin.v7");
+    }
+
+    private static final ClassContextHelper HELPER = new ClassContextHelper();
+
+    /**
+     * Determine whether or not the getCallingClass methods will return
+     * any sensible results.  On JVMs that are not Sun derived i.e.
+     * (gcj, Harmony) this will likely return false.  When not available
+     * all getCallingClass methods will return null.
+     *
+     * @return true if getCallingClass can return anything but null, false if
+     *         it will only return null.
+     */
+    public static boolean isCallingClassReflectionAvailable() {
+        return true;
+    }
+
+    /**
+     * Get the immediate calling class, ignoring MOP frames.
+     *
+     * @return The Class of the caller
+     */
+    public static Class getCallingClass() {
+        return getCallingClass(1);
+    }
+
+    /**
+     * Get the called that is matchLevel stack frames before the call,
+     * ignoring MOP frames.
+     *
+     * @param matchLevel how may call stacks down to look.
+     *                   If it is less than 1 it is treated as though it was 1.
+     * @return The Class of the matched caller, or null if there aren't
+     *         enough stackframes to satisfy matchLevel
+     */
+    public static Class getCallingClass(int matchLevel) {
+        return getCallingClass(matchLevel, Collections.EMPTY_SET);
+    }
+
+    /**
+     * Get the called that is matchLevel stack frames before the call,
+     * ignoring MOP frames and desired exclude packages.
+     *
+     * @param matchLevel           how may call stacks down to look.
+     *                             If it is less than 1 it is treated as though it was 1.
+     * @param extraIgnoredPackages A collection of string names of packages to exclude
+     *                             in addition to the MOP packages when counting stack frames.
+     * @return The Class of the matched caller, or null if there aren't
+     *         enough stackframes to satisfy matchLevel
+     */
+    public static Class getCallingClass(int matchLevel, Collection<String> extraIgnoredPackages) {
+        Class[] classContext = HELPER.getClassContext();
+
+        int depth = 0;
+        try {
+            Class c;
+            // this super class stuff is for Java 1.4 support only
+            // it isn't needed on a 5.0 VM
+            Class sc;
+            do {
+                do {
+                    c = classContext[depth++];
+                    if (c != null) {
+                        sc = c.getSuperclass();
+                    } else {
+                        sc = null;
+                    }
+                } while (classShouldBeIgnored(c, extraIgnoredPackages)
+                        || superClassShouldBeIgnored(sc));
+            } while (c != null && matchLevel-- > 0 && depth<classContext.length);
+            return c;
+        } catch (Throwable t) {
+            return null;
+        }
+    }
+
+    private static boolean superClassShouldBeIgnored(Class sc) {
+        return ((sc != null) && (sc.getPackage() != null) && "org.codehaus.groovy.runtime.callsite".equals(sc.getPackage().getName()));
+    }
+
+    private static boolean classShouldBeIgnored(Class c, Collection<String> extraIgnoredPackages) {
+        return ((c != null)
+                && (c.isSynthetic()
+                    || (c.getPackage() != null
+                        && (IGNORED_PACKAGES.contains(c.getPackage().getName())
+                          || extraIgnoredPackages.contains(c.getPackage().getName())))));
+    }
+
+    private static class ClassContextHelper extends SecurityManager {
+        @Override
+        public Class[] getClassContext() {
+            return super.getClassContext();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java b/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java
new file mode 100644
index 0000000..0a6a082
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/SunClassLoader.java
@@ -0,0 +1,117 @@
+/*
+ *  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.reflection;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Special class loader, which when running on Sun VM allows to generate accessor classes for any method
+ */
+public class SunClassLoader extends ClassLoader implements Opcodes {
+    protected final Map<String,Class> knownClasses = new HashMap<String,Class>();
+
+    protected static final SunClassLoader sunVM;
+
+    static {
+        SunClassLoader res;
+        try {
+            res = AccessController.doPrivileged(new PrivilegedAction<SunClassLoader>() {
+                public SunClassLoader run() {
+                    try {
+                        return new SunClassLoader();
+                    } catch (Throwable e) {
+                        return null;
+                    }
+                }
+            });
+        }
+        catch (Throwable e) {
+            res = null;
+        }
+        sunVM = res;
+    }
+
+    protected SunClassLoader() throws Throwable {
+        super (SunClassLoader.class.getClassLoader());
+
+        final Class magic = ClassLoader.getSystemClassLoader().loadClass("sun.reflect.MagicAccessorImpl");
+        knownClasses.put("sun.reflect.MagicAccessorImpl", magic);
+        loadMagic ();
+    }
+
+    private void loadMagic() {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        cw.visit(Opcodes.V1_4, Opcodes.ACC_PUBLIC, "sun/reflect/GroovyMagic", null, "sun/reflect/MagicAccessorImpl", null);
+        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitCode();
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "sun/reflect/MagicAccessorImpl", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0,0);
+        mv.visitEnd();
+        cw.visitEnd();
+
+        define(cw.toByteArray(), "sun.reflect.GroovyMagic");
+    }
+
+    protected void loadFromRes(String name) throws IOException {
+        final InputStream asStream = SunClassLoader.class.getClassLoader().getResourceAsStream(resName(name));
+        ClassReader reader = new ClassReader(asStream);
+        final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        reader.accept(cw, ClassWriter.COMPUTE_MAXS);
+        asStream.close();
+        define(cw.toByteArray(), name);
+    }
+
+    protected static String resName(String s) {
+        return s.replace('.','/') + ".class";
+    }
+
+    protected void define(byte[] bytes, final String name) {
+        knownClasses.put(name, defineClass(name, bytes, 0, bytes.length));
+    }
+
+    protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        final Class aClass = knownClasses.get(name);
+        if (aClass != null)
+          return aClass;
+        else {
+            try {
+                return super.loadClass(name, resolve);
+            }
+            catch (ClassNotFoundException e) {
+                return getClass().getClassLoader().loadClass(name);
+            }
+        }
+    }
+
+    public Class doesKnow(String name) {
+        return knownClasses.get(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java b/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java
new file mode 100644
index 0000000..67416e9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/android/AndroidSupport.java
@@ -0,0 +1,38 @@
+/*
+ *  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.reflection.android;
+
+public abstract class AndroidSupport {
+    private static final boolean IS_ANDROID;
+
+    static {
+        boolean isAndroid = true;
+        try {
+            Class.forName("android.app.Activity", false, AndroidSupport.class.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            isAndroid = false;
+        }
+        IS_ANDROID = isAndroid;
+    }
+
+    public static boolean isRunningAndroid() {
+        return IS_ANDROID;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/package.html b/src/main/java/org/codehaus/groovy/reflection/package.html
new file mode 100644
index 0000000..a01a2dd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.reflection.*</title>
+  </head>
+  <body>
+    <p>Internal classes for assisting with reflection.</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java
new file mode 100644
index 0000000..fcf2908
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ArrayCachedClass.java
@@ -0,0 +1,55 @@
+/*
+ *  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.reflection.stdclasses;
+
+import groovy.lang.GString;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class ArrayCachedClass extends CachedClass {
+    public ArrayCachedClass(Class klazz, ClassInfo classInfo) {
+        super(klazz, classInfo);
+    }
+
+    public Object coerceArgument(Object argument) {
+        Class argumentClass = argument.getClass();
+        if (argumentClass.getName().charAt(0) != '[') return argument;
+        Class argumentComponent = argumentClass.getComponentType();
+
+        Class paramComponent = getTheClass().getComponentType();
+        if (paramComponent.isPrimitive()) {
+            argument = DefaultTypeTransformation.convertToPrimitiveArray(argument, paramComponent);
+        } else if (paramComponent == String.class && argument instanceof GString[]) {
+            GString[] strings = (GString[]) argument;
+            String[] ret = new String[strings.length];
+            for (int i = 0; i < strings.length; i++) {
+                ret[i] = strings[i].toString();
+            }
+            argument = ret;
+        } else if (paramComponent==Object.class && argumentComponent.isPrimitive()){
+            argument = DefaultTypeTransformation.primitiveArrayBox(argument);
+        }
+        return argument;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java
new file mode 100644
index 0000000..45a1c85
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigDecimalCachedClass.java
@@ -0,0 +1,52 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class BigDecimalCachedClass extends DoubleCachedClass {
+    public BigDecimalCachedClass(Class klazz, ClassInfo classInfo) {
+        super(klazz, classInfo, true);
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return argument instanceof BigDecimal;
+    }
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof BigDecimal) {
+            return argument;
+        } else if (argument instanceof Long) {
+            return new BigDecimal((Long) argument);
+        } else if (argument instanceof BigInteger) {
+            return new BigDecimal((BigInteger) argument);
+        }
+
+        if (argument instanceof Number) {
+            return new BigDecimal(((Number) argument).doubleValue());
+        }
+        return argument;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java
new file mode 100644
index 0000000..573fc42
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BigIntegerCachedClass.java
@@ -0,0 +1,50 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+import java.math.BigInteger;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class BigIntegerCachedClass extends NumberCachedClass {
+    public BigIntegerCachedClass(Class klazz, ClassInfo classInfo) {
+        super(klazz, classInfo);
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return argument instanceof BigInteger;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return classToTransformFrom == null
+            || classToTransformFrom == Integer.class
+            || classToTransformFrom == Short.class
+            || classToTransformFrom == Byte.class
+            || classToTransformFrom == BigInteger.class
+            || classToTransformFrom == Long.class
+            || classToTransformFrom == Integer.TYPE
+            || classToTransformFrom == Short.TYPE
+            || classToTransformFrom == Byte.TYPE
+            || classToTransformFrom == Long.TYPE
+            || BigInteger.class.isAssignableFrom(classToTransformFrom);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java
new file mode 100644
index 0000000..9dacdf4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/BooleanCachedClass.java
@@ -0,0 +1,43 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ClassInfo;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class BooleanCachedClass extends CachedClass {
+    private final boolean allowNull;
+    public BooleanCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Boolean;
+     }
+    
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+              || classToTransformFrom == Boolean.class
+              || classToTransformFrom == Boolean.TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java
new file mode 100644
index 0000000..21abd59
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ByteCachedClass.java
@@ -0,0 +1,53 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class ByteCachedClass extends NumberCachedClass {
+    private final boolean allowNull;
+    public ByteCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Byte) {
+            return argument;
+        }
+
+        if (argument instanceof Number) {
+            return ((Number) argument).byteValue();
+        }
+        return argument;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Byte;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+            || classToTransformFrom == Byte.class
+            || classToTransformFrom == Byte.TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java
new file mode 100644
index 0000000..7dcaed0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedClosureClass.java
@@ -0,0 +1,61 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.CachedMethod;
+import org.codehaus.groovy.reflection.ClassInfo;
+
+public class CachedClosureClass extends CachedClass {
+    private final Class[] parameterTypes;
+    private final int maximumNumberOfParameters;
+
+    public CachedClosureClass(Class klazz, ClassInfo classInfo) {
+        super(klazz, classInfo);
+
+        CachedMethod methods [] = getMethods();
+
+        // set it to -1 for starters so parameterTypes will always get a type
+        int maximumNumberOfParameters = -1;
+        Class[] parameterTypes = null;
+
+        for (CachedMethod method : methods) {
+            if ("doCall".equals(method.getName())) {
+                final Class[] pt = method.getNativeParameterTypes();
+                if (pt.length > maximumNumberOfParameters) {
+                    parameterTypes = pt;
+                    maximumNumberOfParameters = parameterTypes.length;
+                }
+            }
+        }
+        // this line should be useless, but well, just in case
+        maximumNumberOfParameters = Math.max(maximumNumberOfParameters,0);
+
+        this.maximumNumberOfParameters = maximumNumberOfParameters;
+        this.parameterTypes = parameterTypes;
+    }
+
+    public Class[] getParameterTypes() {
+        return parameterTypes;
+    }
+
+    public int getMaximumNumberOfParameters() {
+        return maximumNumberOfParameters;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java
new file mode 100644
index 0000000..6364f40
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java
@@ -0,0 +1,203 @@
+/*
+ *  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.reflection.stdclasses;
+
+import groovy.lang.Closure;
+import groovy.util.ProxyGenerator;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.runtime.ConvertedClosure;
+import org.codehaus.groovy.transform.trait.Traits;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+public class CachedSAMClass extends CachedClass {
+
+    private static final int ABSTRACT_STATIC_PRIVATE =
+            Modifier.ABSTRACT|Modifier.PRIVATE|Modifier.STATIC;
+    private static final int VISIBILITY = 5; // public|protected
+    private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
+    private final Method method;
+
+    public CachedSAMClass(Class klazz, ClassInfo classInfo) {
+        super(klazz, classInfo);
+        method = getSAMMethod(klazz);
+        if (method==null) throw new GroovyBugError("assigned method should not have been null!");
+    }
+
+    @Override
+    public boolean isAssignableFrom(Class argument) {
+        return argument == null ||
+                Closure.class.isAssignableFrom(argument) ||
+                ReflectionCache.isAssignableFrom(getTheClass(), argument);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Object coerceToSAM(Closure argument, Method method, Class clazz, boolean isInterface) {
+        if (argument!=null && clazz.isAssignableFrom(argument.getClass())) {
+            return argument;
+        }
+        if (isInterface) {
+            if (Traits.isTrait(clazz)) {
+                Map<String,Closure> impl = Collections.singletonMap(
+                        method.getName(),
+                        argument
+                );
+                return ProxyGenerator.INSTANCE.instantiateAggregate(impl,Collections.singletonList(clazz));
+            }
+            return Proxy.newProxyInstance(
+                    clazz.getClassLoader(),
+                    new Class[]{clazz},
+                    new ConvertedClosure(argument));
+        } else {
+            Map<String, Object> m = new HashMap<String,Object>();
+            m.put(method.getName(), argument);
+            return ProxyGenerator.INSTANCE.
+                    instantiateAggregateFromBaseClass(m, clazz);
+        }
+    }
+    
+    @Override
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Closure) {
+            Class clazz = getTheClass();
+            return coerceToSAM((Closure) argument, method, clazz, clazz.isInterface()); 
+        } else {
+            return argument;
+        }
+    }
+
+    private static Method[] getDeclaredMethods(final Class c) {
+        try {
+            Method[] methods = AccessController.doPrivileged(new PrivilegedAction<Method[]>() {
+                public Method[] run() {
+                    return c.getDeclaredMethods();
+                }
+            });
+            if (methods!=null) return methods;
+        } catch (java.security.AccessControlException ace) {
+            // swallow and do as if no method is available
+        }
+        return EMPTY_METHOD_ARRAY;
+    }
+
+    private static void getAbstractMethods(Class c, List<Method> current) {
+        if (c==null || !Modifier.isAbstract(c.getModifiers())) return;
+        getAbstractMethods(c.getSuperclass(), current);
+        for (Class ci : c.getInterfaces()) {
+            getAbstractMethods(ci, current);
+        }
+        for (Method m : getDeclaredMethods(c)) {
+            if (Modifier.isPrivate(m.getModifiers())) continue;
+            if (Modifier.isAbstract(m.getModifiers())) current.add(m);
+        }
+    }
+
+    private static boolean hasUsableImplementation(Class c, Method m) {
+        if (c==m.getDeclaringClass()) return false;
+        Method found;
+        try {
+            found = c.getMethod(m.getName(), m.getParameterTypes());
+            int asp = found.getModifiers() & ABSTRACT_STATIC_PRIVATE;
+            int visible = found.getModifiers() & VISIBILITY;
+            if (visible !=0 && asp == 0) return true;
+        } catch (NoSuchMethodException e) {/*ignore*/}
+        if (c==Object.class) return false;
+        return hasUsableImplementation(c.getSuperclass(), m);
+    }
+
+    private static Method getSingleNonDuplicateMethod(List<Method> current) {
+        if (current.isEmpty()) return null;
+        if (current.size()==1) return current.get(0);
+        Method m = current.remove(0);
+        for (Method m2 : current) {
+            if (m.getName().equals(m2.getName()) && 
+                Arrays.equals(m.getParameterTypes(), m2.getParameterTypes()))
+            {
+                continue;
+            }
+            return null;
+        }
+        return m;
+    }
+
+    /**
+     * returns the abstract method from a SAM type, if it is a SAM type.
+     * @param c the SAM class
+     * @return null if nothing was found, the method otherwise
+     */
+    public static Method getSAMMethod(Class<?> c) {
+      try {
+        return getSAMMethodImpl(c);
+      } catch (NoClassDefFoundError ignore) {
+        return null;
+      }
+    }
+
+    private static Method getSAMMethodImpl(Class<?> c) {
+        // SAM = single public abstract method
+        // if the class is not abstract there is no abstract method
+        if (!Modifier.isAbstract(c.getModifiers())) return null;
+        if (c.isInterface()) {
+            Method[] methods = c.getMethods();
+            // res stores the first found abstract method
+            Method res = null;
+            for (Method mi : methods) {
+                // ignore methods, that are not abstract and from Object
+                if (!Modifier.isAbstract(mi.getModifiers())) continue;
+                // ignore trait methods which have a default implementation
+                if (mi.getAnnotation(Traits.Implemented.class)!=null) continue;
+                try {
+                    Object.class.getMethod(mi.getName(), mi.getParameterTypes());
+                    continue;
+                } catch (NoSuchMethodException e) {/*ignore*/}
+
+                // we have two methods, so no SAM
+                if (res!=null) return null;
+                res = mi;
+            }
+            return res;
+
+        } else {
+
+            LinkedList<Method> methods = new LinkedList();
+            getAbstractMethods(c, methods);
+            if (methods.isEmpty()) return null;
+            ListIterator<Method> it = methods.listIterator();
+            while (it.hasNext()) {
+                Method m = it.next();
+                if (hasUsableImplementation(c, m)) it.remove();
+            }
+            return getSingleNonDuplicateMethod(methods);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java
new file mode 100644
index 0000000..619332e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/CharacterCachedClass.java
@@ -0,0 +1,44 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ClassInfo;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class CharacterCachedClass extends CachedClass {
+    private final boolean allowNull;
+
+    public CharacterCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Character;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+                || classToTransformFrom == Character.class
+                || classToTransformFrom == Character.TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java
new file mode 100644
index 0000000..4a0f5c6
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/DoubleCachedClass.java
@@ -0,0 +1,76 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class DoubleCachedClass extends NumberCachedClass { // Double, double
+    private final boolean allowNull;
+
+    public DoubleCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Double;
+    }
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Double) {
+            return argument;
+        }
+
+        if (argument instanceof Number) {
+            Double res = ((Number) argument).doubleValue();
+            if (argument instanceof BigDecimal && res.isInfinite()) {
+                throw new IllegalArgumentException(Double.class + " out of range while converting from BigDecimal");
+            }
+            return res;
+        }
+        return argument;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+                || classToTransformFrom == Double.class
+                || classToTransformFrom == Integer.class
+                || classToTransformFrom == Long.class
+                || classToTransformFrom == Short.class
+                || classToTransformFrom == Byte.class
+                || classToTransformFrom == Float.class
+                || classToTransformFrom == Double.TYPE
+                || classToTransformFrom == Integer.TYPE
+                || classToTransformFrom == Long.TYPE
+                || classToTransformFrom == Short.TYPE
+                || classToTransformFrom == Byte.TYPE
+                || classToTransformFrom == Float.TYPE
+                || classToTransformFrom == BigDecimal.class
+                || classToTransformFrom == BigInteger.class
+                || (classToTransformFrom!=null && BigDecimal.class.isAssignableFrom(classToTransformFrom))
+                || (classToTransformFrom!=null && BigInteger.class.isAssignableFrom(classToTransformFrom))
+                ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java
new file mode 100644
index 0000000..a579028
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/FloatCachedClass.java
@@ -0,0 +1,71 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class FloatCachedClass extends NumberCachedClass {
+    private final boolean allowNull;
+
+    public FloatCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Float) {
+            return argument;
+        }
+
+        if (argument instanceof Number) {
+            Float res = ((Number) argument).floatValue();
+            if (argument instanceof BigDecimal && res.isInfinite()) {
+                throw new IllegalArgumentException(Float.class + " out of range while converting from BigDecimal");
+            }
+            return res;
+        }
+        return argument;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Float;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+                || classToTransformFrom == Float.class
+                || classToTransformFrom == Integer.class
+                || classToTransformFrom == Long.class
+                || classToTransformFrom == Short.class
+                || classToTransformFrom == Byte.class
+                || classToTransformFrom == Float.TYPE
+                || classToTransformFrom == Integer.TYPE
+                || classToTransformFrom == Long.TYPE
+                || classToTransformFrom == Short.TYPE
+                || classToTransformFrom == Byte.TYPE
+                || classToTransformFrom == BigDecimal.class
+                || classToTransformFrom == BigInteger.class;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java
new file mode 100644
index 0000000..334a3ab
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/IntegerCachedClass.java
@@ -0,0 +1,61 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+import java.math.BigInteger;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class IntegerCachedClass extends NumberCachedClass {  // int, Integer
+    private final boolean allowNull;
+
+    public IntegerCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Integer) {
+            return argument;
+        }
+
+        if (argument instanceof Number) {
+            return ((Number) argument).intValue();
+        }
+        return argument;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Integer;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+                || classToTransformFrom == Integer.class
+                || classToTransformFrom == Short.class
+                || classToTransformFrom == Byte.class
+                || classToTransformFrom == BigInteger.class
+                || classToTransformFrom == Integer.TYPE
+                || classToTransformFrom == Short.TYPE
+                || classToTransformFrom == Byte.TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java
new file mode 100644
index 0000000..5d42b0c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/LongCachedClass.java
@@ -0,0 +1,61 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class LongCachedClass extends NumberCachedClass {
+    private final boolean allowNull;
+
+    public LongCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Long) {
+            return argument;
+        }
+
+        if (argument instanceof Number) {
+            return ((Number) argument).longValue();
+        }
+        return argument;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Long;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+                || classToTransformFrom == Integer.class
+                || classToTransformFrom == Long.class
+                || classToTransformFrom == Short.class
+                || classToTransformFrom == Byte.class
+                || classToTransformFrom == Integer.TYPE
+                || classToTransformFrom == Long.TYPE
+                || classToTransformFrom == Short.TYPE
+                || classToTransformFrom == Byte.TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java
new file mode 100644
index 0000000..311cbc2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/NumberCachedClass.java
@@ -0,0 +1,65 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ClassInfo;
+
+import java.math.BigInteger;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class NumberCachedClass extends CachedClass {
+
+    public NumberCachedClass(Class klazz, ClassInfo classInfo) {
+        super(klazz, classInfo);
+    }
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Number) {
+            return coerceNumber(argument);
+        }
+        return argument;
+
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return classToTransformFrom == null
+            || Number.class.isAssignableFrom(classToTransformFrom)
+            || classToTransformFrom == Byte.TYPE
+            || classToTransformFrom == Short.TYPE
+            || classToTransformFrom == Integer.TYPE
+            || classToTransformFrom == Long.TYPE
+            || classToTransformFrom == Float.TYPE
+            || classToTransformFrom == Double.TYPE
+                ;
+    }
+
+    private Object coerceNumber(Object argument) {
+        Class param = getTheClass();
+        if (param == Byte.class /*|| param == Byte.TYPE*/) {
+            argument = Byte.valueOf(((Number) argument).byteValue());
+        } else if (param == BigInteger.class) {
+            argument = new BigInteger(String.valueOf((Number) argument));
+        }
+
+        return argument;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java
new file mode 100644
index 0000000..f29acf7
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ObjectCachedClass.java
@@ -0,0 +1,39 @@
+/*
+ *  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.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ClassInfo;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class ObjectCachedClass extends CachedClass {
+    public ObjectCachedClass(ClassInfo classInfo) {
+        super(Object.class,classInfo);
+    }
+
+    public synchronized CachedClass getCachedSuperClass() {
+        return null;
+    }
+
+    public boolean isAssignableFrom(Class argument) {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java
new file mode 100644
index 0000000..f6cccf1
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/ShortCachedClass.java
@@ -0,0 +1,56 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.reflection.stdclasses;
+
+import org.codehaus.groovy.reflection.ClassInfo;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class ShortCachedClass extends NumberCachedClass {
+    private final boolean allowNull;
+
+    public ShortCachedClass(Class klazz, ClassInfo classInfo, boolean allowNull) {
+        super(klazz, classInfo);
+        this.allowNull = allowNull;
+    }
+
+    public Object coerceArgument(Object argument) {
+        if (argument instanceof Short) {
+            return argument;
+        }
+
+        if (argument instanceof Number) {
+            return ((Number) argument).shortValue();
+        }
+        return argument;
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return (allowNull && argument == null) || argument instanceof Short;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return (allowNull && classToTransformFrom == null)
+                || classToTransformFrom == Short.class
+                || classToTransformFrom == Byte.class
+                || classToTransformFrom == Short.TYPE
+                || classToTransformFrom == Byte.TYPE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java b/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java
new file mode 100644
index 0000000..a3039ad
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/stdclasses/StringCachedClass.java
@@ -0,0 +1,50 @@
+/*
+ *  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.reflection.stdclasses;
+
+import groovy.lang.GString;
+import org.codehaus.groovy.reflection.CachedClass;
+import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.reflection.ReflectionCache;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class StringCachedClass extends CachedClass {
+    private static final Class STRING_CLASS = String.class;
+    private static final Class GSTRING_CLASS = GString.class;
+
+    public StringCachedClass(ClassInfo classInfo) {
+        super(STRING_CLASS, classInfo);
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return argument instanceof String;
+    }
+
+    public boolean isAssignableFrom(Class classToTransformFrom) {
+        return  classToTransformFrom == null
+              || classToTransformFrom == STRING_CLASS
+              || ReflectionCache.isAssignableFrom(GSTRING_CLASS,classToTransformFrom);
+    }
+
+    public Object coerceArgument(Object argument) {
+        return argument instanceof GString ? argument.toString() : argument;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java b/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java
new file mode 100644
index 0000000..a964a3e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java
@@ -0,0 +1,37 @@
+/*
+ *  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.reflection.v7;
+
+import org.codehaus.groovy.reflection.GroovyClassValue;
+
+/** GroovyClassValue implementaion that simply delegates to Java 7's java.lang.ClassValue
+ * @see java.lang.ClassValue
+ *
+ * @param <T>
+*/
+public class GroovyClassValueJava7<T> extends ClassValue<T> implements GroovyClassValue<T> {
+   private final ComputeValue<T> computeValue;
+   public GroovyClassValueJava7(ComputeValue<T> computeValue){
+      this.computeValue = computeValue;
+   }
+   @Override
+   protected T computeValue(Class<?> type) {
+      return computeValue.computeValue(type);
+   }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java b/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java
new file mode 100644
index 0000000..7c977cd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/AbstractComparator.java
@@ -0,0 +1,30 @@
+/*
+ *  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.runtime;
+
+import java.util.Comparator;
+
+/**
+ * @author Andres Almiray
+ */
+public abstract class AbstractComparator<T> implements Comparator<T> {
+    public boolean equals(Object obj) {
+        return this == obj;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java b/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java
new file mode 100644
index 0000000..2a6e409
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ArrayTypeUtils.java
@@ -0,0 +1,98 @@
+/*
+ *  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.runtime;
+
+/**
+ * Utilities for handling array types
+ *
+ * @author <a href="mailto:realbluesun@hotmail.com">Daniel.Sun</a>
+ * Created on 2016/10/28
+ */
+public class ArrayTypeUtils {
+
+    /**
+     * Calculate the dimension of array
+     *
+     * @param clazz the type of array
+     * @return the dimension of array
+     */
+    public static int dimension(Class clazz) {
+        checkArrayType(clazz);
+
+        int result = 0;
+        while (clazz.isArray()) {
+            result++;
+            clazz = clazz.getComponentType();
+        }
+
+        return result;
+    }
+
+    /**
+     * Get the type of array elements
+     *
+     * @param clazz the type of array
+     * @return the type of elements
+     */
+    public static Class elementType(Class clazz) {
+        checkArrayType(clazz);
+
+        while (clazz.isArray()) {
+            clazz = clazz.getComponentType();
+        }
+
+        return clazz;
+    }
+
+    /**
+     * Reduce the dimension of array
+     *
+     * @param clazz the type of array
+     * @param dim the target dimension
+     * @return the result array
+     */
+    public static Class reduceDimension(Class clazz, int dim) {
+        checkArrayType(clazz);
+
+        if (dim < 0) {
+            throw new IllegalArgumentException("The target dimension should not be less than zero: " + dim);
+        }
+
+        while (clazz.isArray() && dimension(clazz) > dim) {
+            clazz = clazz.getComponentType();
+        }
+
+        return clazz;
+    }
+
+    /**
+     * Check whether the type passed in is array type.
+     * If the type is not array type, throw IllegalArgumentException.
+     */
+    private static void checkArrayType(Class clazz) {
+        if (null == clazz) {
+            throw new IllegalArgumentException("clazz can not be null");
+        }
+
+        if (!clazz.isArray()) {
+            throw new IllegalArgumentException(clazz.getCanonicalName() + " is not array type");
+        }
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/CallSiteWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/CallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/CallSiteWriter.java
new file mode 100644
index 0000000..716f97e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/CallSiteWriter.java
@@ -0,0 +1,387 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.InterfaceHelperClassNode;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.runtime.callsite.CallSite;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.objectweb.asm.Opcodes.AALOAD;
+import static org.objectweb.asm.Opcodes.AASTORE;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
+import static org.objectweb.asm.Opcodes.ACONST_NULL;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ANEWARRAY;
+import static org.objectweb.asm.Opcodes.ARETURN;
+import static org.objectweb.asm.Opcodes.ASTORE;
+import static org.objectweb.asm.Opcodes.CHECKCAST;
+import static org.objectweb.asm.Opcodes.DUP;
+import static org.objectweb.asm.Opcodes.GETFIELD;
+import static org.objectweb.asm.Opcodes.GETSTATIC;
+import static org.objectweb.asm.Opcodes.IFNONNULL;
+import static org.objectweb.asm.Opcodes.IFNULL;
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static org.objectweb.asm.Opcodes.NEW;
+import static org.objectweb.asm.Opcodes.PUTSTATIC;
+import static org.objectweb.asm.Opcodes.RETURN;
+
+/**
+ * This class represents non public API used by AsmClassGenerator. Don't
+ * use this class in your code
+ */
+public class CallSiteWriter {
+    
+    private static String [] sig = new String [255];
+    private static String getCreateArraySignature(int numberOfArguments) {
+        if (sig[numberOfArguments] == null) {
+            StringBuilder sb = new StringBuilder("(");
+            for (int i = 0; i != numberOfArguments; ++i) {
+                sb.append("Ljava/lang/Object;");
+            }
+            sb.append(")[Ljava/lang/Object;");
+            sig[numberOfArguments] = sb.toString();
+        }
+        return sig[numberOfArguments];
+    }
+    private static final int
+        MOD_PRIVSS = ACC_PRIVATE+ACC_STATIC+ACC_SYNTHETIC,
+        MOD_PUBSS  = ACC_PUBLIC+ACC_STATIC+ACC_SYNTHETIC;
+    private static final ClassNode CALLSITE_ARRAY_NODE = ClassHelper.make(CallSite[].class);
+    private static final String
+        GET_CALLSITE_METHOD     = "$getCallSiteArray",
+        CALLSITE_CLASS          = "org/codehaus/groovy/runtime/callsite/CallSite",
+        CALLSITE_DESC           = "[Lorg/codehaus/groovy/runtime/callsite/CallSite;",
+        GET_CALLSITE_DESC       = "()"+CALLSITE_DESC,
+        CALLSITE_ARRAY_CLASS    = "org/codehaus/groovy/runtime/callsite/CallSiteArray",
+        GET_CALLSITEARRAY_DESC  = "()Lorg/codehaus/groovy/runtime/callsite/CallSiteArray;",
+        CALLSITE_FIELD          = "$callSiteArray",
+        REF_CLASS               = "java/lang/ref/SoftReference",
+        REF_DESC                = "L"+REF_CLASS+";",
+        METHOD_OO_DESC          = "(Ljava/lang/Object;)Ljava/lang/Object;",
+        CREATE_CSA_METHOD       = "$createCallSiteArray";
+    public static final String CONSTRUCTOR = "<$constructor$>";
+    
+    private final List callSites = new ArrayList(32);
+    private int callSiteArrayVarIndex = -1;
+    private final WriterController controller;
+
+    public CallSiteWriter(WriterController wc) {
+        this.controller = wc;
+        ClassNode node = controller.getClassNode();
+        if(node instanceof InterfaceHelperClassNode) {
+            InterfaceHelperClassNode ihcn = (InterfaceHelperClassNode) node;
+            callSites.addAll(ihcn.getCallSites());
+        }
+    }
+    
+    public void makeSiteEntry() {
+        if (controller.isNotClinit()) {
+            controller.getMethodVisitor().visitMethodInsn(INVOKESTATIC, controller.getInternalClassName(), GET_CALLSITE_METHOD, GET_CALLSITE_DESC, false);
+            controller.getOperandStack().push(CALLSITE_ARRAY_NODE);
+            callSiteArrayVarIndex = controller.getCompileStack().defineTemporaryVariable("$local$callSiteArray", CALLSITE_ARRAY_NODE, true);
+        }
+    }
+    
+    public void generateCallSiteArray() {
+        if (!controller.getClassNode().isInterface()) {
+            controller.getClassVisitor().visitField(MOD_PRIVSS, CALLSITE_FIELD, REF_DESC, null, null);
+            generateCreateCallSiteArray();
+            generateGetCallSiteArray();
+        }
+    }
+
+    private void generateGetCallSiteArray() {
+        int visibility = (controller.getClassNode() instanceof InterfaceHelperClassNode) ? MOD_PUBSS : MOD_PRIVSS;
+        MethodVisitor mv = controller.getClassVisitor().visitMethod(visibility, GET_CALLSITE_METHOD, GET_CALLSITE_DESC, null, null);
+        controller.setMethodVisitor(mv);
+        mv.visitCode();
+        mv.visitFieldInsn(GETSTATIC, controller.getInternalClassName(), "$callSiteArray", "Ljava/lang/ref/SoftReference;");
+        Label l0 = new Label();
+        mv.visitJumpInsn(IFNULL, l0);
+        mv.visitFieldInsn(GETSTATIC, controller.getInternalClassName(), "$callSiteArray", "Ljava/lang/ref/SoftReference;");
+        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ref/SoftReference", "get", "()Ljava/lang/Object;", false);
+        mv.visitTypeInsn(CHECKCAST, "org/codehaus/groovy/runtime/callsite/CallSiteArray");
+        mv.visitInsn(DUP);
+        mv.visitVarInsn(ASTORE, 0);
+        Label l1 = new Label();
+        mv.visitJumpInsn(IFNONNULL, l1);
+        mv.visitLabel(l0);
+        mv.visitMethodInsn(INVOKESTATIC, controller.getInternalClassName(), "$createCallSiteArray", "()Lorg/codehaus/groovy/runtime/callsite/CallSiteArray;", false);
+        mv.visitVarInsn(ASTORE, 0);
+        mv.visitTypeInsn(NEW, "java/lang/ref/SoftReference");
+        mv.visitInsn(DUP);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/ref/SoftReference", "<init>", "(Ljava/lang/Object;)V", false);
+        mv.visitFieldInsn(PUTSTATIC, controller.getInternalClassName(), "$callSiteArray", "Ljava/lang/ref/SoftReference;");
+        mv.visitLabel(l1);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitFieldInsn(GETFIELD, "org/codehaus/groovy/runtime/callsite/CallSiteArray", "array", "[Lorg/codehaus/groovy/runtime/callsite/CallSite;");
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+    }
+        
+    private void generateCreateCallSiteArray() { 
+        List<String> callSiteInitMethods = new LinkedList<String>(); 
+        int index = 0; 
+        int methodIndex = 0; 
+        final int size = callSites.size(); 
+        final int maxArrayInit = 5000; 
+        // create array initialization methods
+        while (index < size) { 
+            methodIndex++; 
+            String methodName = "$createCallSiteArray_" + methodIndex; 
+            callSiteInitMethods.add(methodName); 
+            MethodVisitor mv = controller.getClassVisitor().visitMethod(MOD_PRIVSS, methodName, "([Ljava/lang/String;)V", null, null);
+            controller.setMethodVisitor(mv);
+            mv.visitCode(); 
+            int methodLimit = size; 
+            // check if the next block is over the max allowed
+            if ((methodLimit - index) > maxArrayInit) { 
+                methodLimit = index + maxArrayInit; 
+            } 
+            for (; index < methodLimit; index++) { 
+                mv.visitVarInsn(ALOAD, 0); 
+                mv.visitLdcInsn(index); 
+                mv.visitLdcInsn(callSites.get(index)); 
+                mv.visitInsn(AASTORE); 
+            } 
+            mv.visitInsn(RETURN); 
+            mv.visitMaxs(2,1); 
+            mv.visitEnd(); 
+        }
+        // create base createCallSiteArray method
+        MethodVisitor mv = controller.getClassVisitor().visitMethod(MOD_PRIVSS, CREATE_CSA_METHOD, GET_CALLSITEARRAY_DESC, null, null);
+        controller.setMethodVisitor(mv);
+        mv.visitCode(); 
+        mv.visitLdcInsn(size); 
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); 
+        mv.visitVarInsn(ASTORE, 0); 
+        for (String methodName : callSiteInitMethods) { 
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitMethodInsn(INVOKESTATIC, controller.getInternalClassName(), methodName, "([Ljava/lang/String;)V", false);
+        } 
+
+        mv.visitTypeInsn(NEW, CALLSITE_ARRAY_CLASS); 
+        mv.visitInsn(DUP); 
+        controller.getAcg().visitClassExpression(new ClassExpression(controller.getClassNode())); 
+
+        mv.visitVarInsn(ALOAD, 0);
+
+        mv.visitMethodInsn(INVOKESPECIAL, CALLSITE_ARRAY_CLASS, "<init>", "(Ljava/lang/Class;[Ljava/lang/String;)V", false);
+        mv.visitInsn(ARETURN); 
+        mv.visitMaxs(0,0); 
+        mv.visitEnd(); 
+    } 
+    
+    private int allocateIndex(String name) {
+        callSites.add(name);
+        return callSites.size()-1;
+    }
+
+    private void invokeSafe(boolean safe, String unsafeMethod, String safeMethod) {
+        String method = unsafeMethod;
+        if (safe) method = safeMethod;
+        controller.getMethodVisitor().visitMethodInsn(INVOKEINTERFACE, CALLSITE_CLASS, method, METHOD_OO_DESC, true);
+        controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE);
+    }
+
+    public void prepareCallSite(String message) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (controller.isNotClinit()) {
+            mv.visitVarInsn(ALOAD, callSiteArrayVarIndex);
+        } else {
+            mv.visitMethodInsn(INVOKESTATIC, controller.getClassName(), GET_CALLSITE_METHOD, GET_CALLSITE_DESC, false);
+        }
+        final int index = allocateIndex(message);
+        mv.visitLdcInsn(index);
+        mv.visitInsn(AALOAD);
+    }
+    
+    private void prepareSiteAndReceiver(Expression receiver, String methodName, boolean implicitThis) {
+        prepareSiteAndReceiver(receiver, methodName, implicitThis, false);
+    }
+    
+    protected void prepareSiteAndReceiver(Expression receiver, String methodName, boolean implicitThis, boolean lhs) {
+        //site
+        prepareCallSite(methodName);
+
+        // receiver
+        CompileStack compileStack = controller.getCompileStack();
+        compileStack.pushImplicitThis(implicitThis);
+        compileStack.pushLHS(lhs);
+        receiver.visit(controller.getAcg());
+        controller.getOperandStack().box();
+        compileStack.popLHS();
+        compileStack.popImplicitThis();
+    }
+    
+    protected void visitBoxedArgument(Expression exp) {
+        exp.visit(controller.getAcg());
+        if (!(exp instanceof TupleExpression)) {
+            // we are not in a tuple, so boxing might be missing for
+            // this single argument call
+            controller.getOperandStack().box();
+        }
+    }
+
+    public final void makeSingleArgumentCall(Expression receiver, String message, Expression arguments) {
+        makeSingleArgumentCall(receiver, message, arguments, false);
+    }
+
+    public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) {
+        OperandStack operandStack = controller.getOperandStack();
+        int m1 = operandStack.getStackLength();
+        //slow Path
+        prepareSiteAndReceiver(receiver, message, false, controller.getCompileStack().isLHS());
+        visitBoxedArgument(arguments);
+        int m2 = operandStack.getStackLength();
+        controller.getMethodVisitor().visitMethodInsn(INVOKEINTERFACE, "org/codehaus/groovy/runtime/callsite/CallSite", safe ? "callSafe" : "call", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", true);
+        operandStack.replace(ClassHelper.OBJECT_TYPE, m2-m1);
+    }
+    
+    public void makeGroovyObjectGetPropertySite(Expression receiver, String methodName, boolean safe, boolean implicitThis) {
+        prepareSiteAndReceiver(receiver, methodName, implicitThis);
+        invokeSafe(safe, "callGroovyObjectGetProperty", "callGroovyObjectGetPropertySafe");
+    }
+    
+    public void makeGetPropertySite(Expression receiver, String methodName, boolean safe, boolean implicitThis) {
+        prepareSiteAndReceiver(receiver, methodName, implicitThis);
+        invokeSafe(safe, "callGetProperty", "callGetPropertySafe");
+    }
+    
+    public void makeCallSite(Expression receiver, String message, Expression arguments, boolean safe, boolean implicitThis, boolean callCurrent, boolean callStatic) {
+        prepareSiteAndReceiver(receiver, message, implicitThis);
+
+        CompileStack compileStack = controller.getCompileStack();
+        compileStack.pushImplicitThis(implicitThis);
+        compileStack.pushLHS(false);
+        boolean constructor = message.equals(CONSTRUCTOR);
+        OperandStack operandStack = controller.getOperandStack();
+        
+        // arguments
+        boolean containsSpreadExpression = AsmClassGenerator.containsSpreadExpression(arguments);
+        int numberOfArguments = containsSpreadExpression ? -1 : AsmClassGenerator.argumentSize(arguments);
+        int operandsToReplace = 1;
+        if (numberOfArguments > MethodCallerMultiAdapter.MAX_ARGS || containsSpreadExpression) {
+            ArgumentListExpression ae;
+            if (arguments instanceof ArgumentListExpression) {
+                ae = (ArgumentListExpression) arguments;
+            } else if (arguments instanceof TupleExpression) {
+                TupleExpression te = (TupleExpression) arguments;
+                ae = new ArgumentListExpression(te.getExpressions());
+            } else {
+                ae = new ArgumentListExpression();
+                ae.addExpression(arguments);
+            }
+            controller.getCompileStack().pushImplicitThis(false);
+            if (containsSpreadExpression) {
+                numberOfArguments = -1;
+                controller.getAcg().despreadList(ae.getExpressions(), true);
+            } else {
+                numberOfArguments = ae.getExpressions().size();
+                for (int i = 0; i < numberOfArguments; i++) {
+                    Expression argument = ae.getExpression(i);
+                    argument.visit(controller.getAcg());
+                    operandStack.box();
+                    if (argument instanceof CastExpression) controller.getAcg().loadWrapper(argument);
+                }
+                operandsToReplace += numberOfArguments;
+            }
+            controller.getCompileStack().popImplicitThis();
+        }
+        controller.getCompileStack().popLHS();
+        controller.getCompileStack().popImplicitThis();
+        
+        MethodVisitor mv = controller.getMethodVisitor();
+        
+        if (numberOfArguments > 4) {
+            final String createArraySignature = getCreateArraySignature(numberOfArguments);
+            mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/ArrayUtil", "createArray", createArraySignature, false);
+            //TODO: use pre-generated Object[]
+            operandStack.replace(ClassHelper.OBJECT_TYPE.makeArray(),numberOfArguments);
+            operandsToReplace = operandsToReplace-numberOfArguments+1;
+        }
+
+        final String desc = getDescForParamNum(numberOfArguments);
+        if (callStatic) {
+            mv.visitMethodInsn(INVOKEINTERFACE, CALLSITE_CLASS, "callStatic", "(Ljava/lang/Class;" + desc, true);
+        } else if (constructor) {
+            mv.visitMethodInsn(INVOKEINTERFACE, CALLSITE_CLASS, "callConstructor", "(Ljava/lang/Object;" + desc, true);
+        } else if (callCurrent) {
+            mv.visitMethodInsn(INVOKEINTERFACE, CALLSITE_CLASS, "callCurrent", "(Lgroovy/lang/GroovyObject;" + desc, true);
+        } else if (safe) {
+            mv.visitMethodInsn(INVOKEINTERFACE, CALLSITE_CLASS, "callSafe", "(Ljava/lang/Object;" + desc, true);
+        } else {
+            mv.visitMethodInsn(INVOKEINTERFACE, CALLSITE_CLASS, "call", "(Ljava/lang/Object;" + desc, true);
+        }
+        operandStack.replace(ClassHelper.OBJECT_TYPE,operandsToReplace);
+    }
+    
+    private static String getDescForParamNum(int numberOfArguments) {
+        switch (numberOfArguments) {
+            case 0:
+              return ")Ljava/lang/Object;";
+            case 1:
+              return "Ljava/lang/Object;)Ljava/lang/Object;";
+            case 2:
+                return "Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
+            case 3:
+                return "Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
+            case 4:
+                return "Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;";
+            default:
+                return "[Ljava/lang/Object;)Ljava/lang/Object;";
+        }
+    }
+
+    public List<String> getCallSites() {
+        return callSites;
+    }
+
+    public void makeCallSiteArrayInitializer() {
+        final String classInternalName = BytecodeHelper.getClassInternalName(controller.getClassNode());
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitInsn(ACONST_NULL);
+        mv.visitFieldInsn(PUTSTATIC, classInternalName, "$callSiteArray", "Ljava/lang/ref/SoftReference;");
+    }
+
+    public boolean hasCallSiteUse() {
+        return callSiteArrayVarIndex>=0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
new file mode 100644
index 0000000..af305ba
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/ClosureWriter.java
@@ -0,0 +1,392 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+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.ReturnStatement;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.Verifier;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.DUP;
+import static org.objectweb.asm.Opcodes.GETFIELD;
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
+import static org.objectweb.asm.Opcodes.NEW;
+
+public class ClosureWriter {
+
+    protected interface UseExistingReference {}
+
+    private final Map<Expression,ClassNode> closureClassMap;
+    private final WriterController controller;
+    private final WriterControllerFactory factory;
+
+    public ClosureWriter(WriterController wc) {
+        this.controller = wc;
+        closureClassMap = new HashMap<Expression,ClassNode>();
+        factory = new WriterControllerFactory() {
+            public WriterController makeController(final WriterController normalController) {
+                return controller;
+            }
+        };
+    }
+
+    public void writeClosure(ClosureExpression expression) {
+        CompileStack compileStack = controller.getCompileStack();
+        MethodVisitor mv = controller.getMethodVisitor();
+        ClassNode classNode = controller.getClassNode();
+        AsmClassGenerator acg = controller.getAcg();
+
+        // generate closure as public class to make sure it can be properly invoked by classes of the
+        // Groovy runtime without circumventing JVM access checks (see CachedMethod for example).
+        int mods = ACC_PUBLIC;
+        if (classNode.isInterface()) {
+            mods |= ACC_STATIC;
+        }
+        ClassNode closureClass = getOrAddClosureClass(expression, mods);
+        String closureClassinternalName = BytecodeHelper.getClassInternalName(closureClass);
+        List constructors = closureClass.getDeclaredConstructors();
+        ConstructorNode node = (ConstructorNode) constructors.get(0);
+
+        Parameter[] localVariableParams = node.getParameters();
+
+        mv.visitTypeInsn(NEW, closureClassinternalName);
+        mv.visitInsn(DUP);
+        if (controller.isStaticMethod() || compileStack.isInSpecialConstructorCall()) {
+            (new ClassExpression(classNode)).visit(acg);
+            (new ClassExpression(controller.getOutermostClass())).visit(acg);
+        } else {
+            mv.visitVarInsn(ALOAD, 0);
+            controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
+            loadThis();
+        }
+
+        // now let's load the various parameters we're passing
+        // we start at index 2 because the first variable we pass
+        // is the owner instance and at this point it is already
+        // on the stack
+        for (int i = 2; i < localVariableParams.length; i++) {
+            Parameter param = localVariableParams[i];
+            String name = param.getName();
+            loadReference(name, controller);
+            if (param.getNodeMetaData(ClosureWriter.UseExistingReference.class)==null) {
+                param.setNodeMetaData(ClosureWriter.UseExistingReference.class,Boolean.TRUE);
+            }
+        }
+
+        // we may need to pass in some other constructors
+        //cv.visitMethodInsn(INVOKESPECIAL, innerClassinternalName, "<init>", prototype + ")V");
+        mv.visitMethodInsn(INVOKESPECIAL, closureClassinternalName, "<init>", BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, localVariableParams), false);
+        controller.getOperandStack().replace(ClassHelper.CLOSURE_TYPE, localVariableParams.length);
+    }
+    
+    public static void loadReference(String name, WriterController controller) {
+        CompileStack compileStack = controller.getCompileStack();
+        MethodVisitor mv = controller.getMethodVisitor();
+        ClassNode classNode = controller.getClassNode();
+        AsmClassGenerator acg = controller.getAcg();
+        
+        // compileStack.containsVariable(name) means to ask if the variable is already declared
+        // compileStack.getScope().isReferencedClassVariable(name) means to ask if the variable is a field
+        // If it is no field and is not yet declared, then it is either a closure shared variable or
+        // an already declared variable.
+        if (!compileStack.containsVariable(name) && compileStack.getScope().isReferencedClassVariable(name)) {
+            acg.visitFieldExpression(new FieldExpression(classNode.getDeclaredField(name)));
+        } else {
+            BytecodeVariable v = compileStack.getVariable(name, !classNodeUsesReferences(controller.getClassNode()));
+            if (v == null) {
+                // variable is not on stack because we are
+                // inside a nested Closure and this variable
+                // was not used before
+                // then load it from the Closure field
+                FieldNode field = classNode.getDeclaredField(name);
+                mv.visitVarInsn(ALOAD, 0);
+                mv.visitFieldInsn(GETFIELD, controller.getInternalClassName(), name, BytecodeHelper.getTypeDescription(field.getType()));
+            } else {
+                mv.visitVarInsn(ALOAD, v.getIndex());
+            }
+            controller.getOperandStack().push(ClassHelper.REFERENCE_TYPE);
+        }
+    }
+
+    public ClassNode getOrAddClosureClass(ClosureExpression expression, int mods) {
+        ClassNode closureClass = closureClassMap.get(expression);
+        if (closureClass == null) {
+            closureClass = createClosureClass(expression, mods);
+            closureClassMap.put(expression, closureClass);
+            controller.getAcg().addInnerClass(closureClass);
+            closureClass.addInterface(ClassHelper.GENERATED_CLOSURE_Type);
+            closureClass.putNodeMetaData(WriterControllerFactory.class, factory);
+        }
+        return closureClass;
+    }
+
+    private static boolean classNodeUsesReferences(ClassNode classNode) {
+        boolean ret = classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE;
+        if (ret) return ret;
+        if (classNode instanceof InnerClassNode) {
+            InnerClassNode inner = (InnerClassNode) classNode;
+            return inner.isAnonymous();
+        }
+        return false;
+    }
+    
+    protected ClassNode createClosureClass(ClosureExpression expression, int mods) {
+        ClassNode classNode = controller.getClassNode();
+        ClassNode outerClass = controller.getOutermostClass();
+        MethodNode methodNode = controller.getMethodNode();
+        String name = classNode.getName() + "$"
+                + controller.getContext().getNextClosureInnerName(outerClass, classNode, methodNode); // add a more informative name
+        boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass();
+
+        Parameter[] parameters = expression.getParameters();
+        if (parameters == null) {
+            parameters = Parameter.EMPTY_ARRAY;
+        } else if (parameters.length == 0) {
+            // let's create a default 'it' parameter
+            Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
+            parameters = new Parameter[]{it};
+            Variable ref = expression.getVariableScope().getDeclaredVariable("it");
+            if (ref!=null) it.setClosureSharedVariable(ref.isClosureSharedVariable());
+        }
+
+        Parameter[] localVariableParams = getClosureSharedVariables(expression);
+        removeInitialValues(localVariableParams);
+
+        InnerClassNode answer = new InnerClassNode(classNode, name, mods, ClassHelper.CLOSURE_TYPE.getPlainNodeReference()); 
+        answer.setEnclosingMethod(controller.getMethodNode());
+        answer.setSynthetic(true);
+        answer.setUsingGenerics(outerClass.isUsingGenerics());
+        answer.setSourcePosition(expression);
+
+        if (staticMethodOrInStaticClass) {
+            answer.setStaticClass(true);
+        }
+        if (controller.isInScriptBody()) {
+            answer.setScriptBody(true);
+        }
+        MethodNode method =
+                answer.addMethod("doCall", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, parameters, ClassNode.EMPTY_ARRAY, expression.getCode());
+        method.setSourcePosition(expression);
+
+        VariableScope varScope = expression.getVariableScope();
+        if (varScope == null) {
+            throw new RuntimeException(
+                    "Must have a VariableScope by now! for expression: " + expression + " class: " + name);
+        } else {
+            method.setVariableScope(varScope.copy());
+        }
+        if (parameters.length > 1
+                || (parameters.length == 1
+                && parameters[0].getType() != null
+                && parameters[0].getType() != ClassHelper.OBJECT_TYPE
+                && !ClassHelper.OBJECT_TYPE.equals(parameters[0].getType().getComponentType())))
+        {
+
+            // let's add a typesafe call method
+            MethodNode call = answer.addMethod(
+                    "call",
+                    ACC_PUBLIC,
+                    ClassHelper.OBJECT_TYPE,
+                    parameters,
+                    ClassNode.EMPTY_ARRAY,
+                    new ReturnStatement(
+                            new MethodCallExpression(
+                                    VariableExpression.THIS_EXPRESSION,
+                                    "doCall",
+                                    new ArgumentListExpression(parameters))));
+            call.setSourcePosition(expression);
+        }
+
+        // let's make the constructor
+        BlockStatement block = new BlockStatement();
+        // this block does not get a source position, because we don't
+        // want this synthetic constructor to show up in corbertura reports
+        VariableExpression outer = new VariableExpression("_outerInstance");
+        outer.setSourcePosition(expression);
+        block.getVariableScope().putReferencedLocalVariable(outer);
+        VariableExpression thisObject = new VariableExpression("_thisObject");
+        thisObject.setSourcePosition(expression);
+        block.getVariableScope().putReferencedLocalVariable(thisObject);
+        TupleExpression conArgs = new TupleExpression(outer, thisObject);
+        block.addStatement(
+                new ExpressionStatement(
+                        new ConstructorCallExpression(
+                                ClassNode.SUPER,
+                                conArgs)));
+
+        // let's assign all the parameter fields from the outer context
+        for (Parameter param : localVariableParams) {
+            String paramName = param.getName();
+            ClassNode type = param.getType();
+            if (true) {
+                VariableExpression initialValue = new VariableExpression(paramName);
+                initialValue.setAccessedVariable(param);
+                initialValue.setUseReferenceDirectly(true);
+                ClassNode realType = type;
+                type = ClassHelper.makeReference();
+                param.setType(ClassHelper.makeReference());
+                FieldNode paramField = answer.addField(paramName, ACC_PRIVATE | ACC_SYNTHETIC, type, initialValue);
+                paramField.setOriginType(ClassHelper.getWrapper(param.getOriginType()));
+                paramField.setHolder(true);
+                String methodName = Verifier.capitalize(paramName);
+
+                // let's add a getter & setter
+                Expression fieldExp = new FieldExpression(paramField);
+                answer.addMethod(
+                        "get" + methodName,
+                        ACC_PUBLIC,
+                        realType.getPlainNodeReference(),
+                        Parameter.EMPTY_ARRAY,
+                        ClassNode.EMPTY_ARRAY,
+                        new ReturnStatement(fieldExp));
+            }
+        }
+
+        Parameter[] params = new Parameter[2 + localVariableParams.length];
+        params[0] = new Parameter(ClassHelper.OBJECT_TYPE, "_outerInstance");
+        params[1] = new Parameter(ClassHelper.OBJECT_TYPE, "_thisObject");
+        System.arraycopy(localVariableParams, 0, params, 2, localVariableParams.length);
+
+        ASTNode sn = answer.addConstructor(ACC_PUBLIC, params, ClassNode.EMPTY_ARRAY, block);
+        sn.setSourcePosition(expression);
+        
+        correctAccessedVariable(answer,expression);
+        
+        return answer;
+    }
+
+    private static void correctAccessedVariable(final InnerClassNode closureClass, ClosureExpression ce) {
+        CodeVisitorSupport visitor = new CodeVisitorSupport() {
+            @Override
+            public void visitVariableExpression(VariableExpression expression) {
+                Variable v = expression.getAccessedVariable(); 
+                if (v==null) return;
+                if (!(v instanceof FieldNode)) return;
+                String name = expression.getName();
+                FieldNode fn = closureClass.getDeclaredField(name);
+                if (fn != null) { // only overwrite if we find something more specific
+                    expression.setAccessedVariable(fn);
+                }
+            }  
+        };
+        visitor.visitClosureExpression(ce);
+    }
+
+    /*
+     * this method is called for local variables shared between scopes.
+     * These variables must not have init values because these would
+     * then in later steps be used to create multiple versions of the
+     * same method, in this case the constructor. A closure should not
+     * have more than one constructor!
+     */
+    private static void removeInitialValues(Parameter[] params) {
+        for (int i = 0; i < params.length; i++) {
+            if (params[i].hasInitialExpression()) {
+                Parameter p = new Parameter(params[i].getType(), params[i].getName());
+                p.setOriginType(p.getOriginType());
+                params[i] = p;
+            }
+        }
+    }
+
+    public boolean addGeneratedClosureConstructorCall(ConstructorCallExpression call) {
+        ClassNode classNode = controller.getClassNode();
+        if (!classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type)) return false;
+
+        AsmClassGenerator acg = controller.getAcg();
+        OperandStack operandStack = controller.getOperandStack();
+        
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitVarInsn(ALOAD, 0);
+        ClassNode callNode = classNode.getSuperClass();
+        TupleExpression arguments = (TupleExpression) call.getArguments();
+        if (arguments.getExpressions().size()!=2) throw new GroovyBugError("expected 2 arguments for closure constructor super call, but got"+arguments.getExpressions().size());
+        arguments.getExpression(0).visit(acg);
+        operandStack.box();
+        arguments.getExpression(1).visit(acg);
+        operandStack.box();
+        //TODO: replace with normal String, p not needed
+        Parameter p = new Parameter(ClassHelper.OBJECT_TYPE,"_p");
+        String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, new Parameter[]{p,p});
+        mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
+        operandStack.remove(2);
+        return true;
+    }
+
+    protected Parameter[] getClosureSharedVariables(ClosureExpression ce) {
+        VariableScope scope = ce.getVariableScope();
+        Parameter[] ret = new Parameter[scope.getReferencedLocalVariablesCount()];
+        int index = 0;
+        for (Iterator iter = scope.getReferencedLocalVariablesIterator(); iter.hasNext();) {
+            Variable element = (org.codehaus.groovy.ast.Variable) iter.next();
+            Parameter p = new Parameter(element.getType(), element.getName());
+            p.setOriginType(element.getOriginType());
+            p.setClosureSharedVariable(element.isClosureSharedVariable());
+            ret[index] = p;
+            index++;
+        }
+        return ret;
+    }
+    
+    private void loadThis() {
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitVarInsn(ALOAD, 0);
+        if (controller.isInClosure()) {
+            mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Closure", "getThisObject", "()Ljava/lang/Object;", false);
+            controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
+        } else {
+            controller.getOperandStack().push(controller.getClassNode());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/CompileStack.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/CompileStack.java b/src/main/java/org/codehaus/groovy/classgen/asm/CompileStack.java
new file mode 100644
index 0000000..35133bb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/CompileStack.java
@@ -0,0 +1,872 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.VariableScope;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+/**
+ * This class is a helper for AsmClassGenerator. It manages
+ * different aspects of the code of a code block like
+ * handling labels, defining variables, and scopes.
+ * After a MethodNode is visited clear should be called, for
+ * initialization the method init should be used.
+ * <p>
+ * Some Notes:
+ * <ul>
+ * <li> every push method will require a later pop call
+ * <li> method parameters may define a category 2 variable, so
+ *      don't ignore the type stored in the variable object
+ * <li> the index of the variable may not be as assumed when
+ *      the variable is a parameter of a method because the
+ *      parameter may be used in a closure, so don't ignore
+ *      the stored variable index
+ * <li> the names of temporary variables can be ignored. The names
+ *      are only used for debugging and do not conflict with each
+ *      other or normal variables. For accessing, the index of the
+ *      variable must be used.
+ * <li> never mix temporary and normal variables by changes to this class.
+ *      While the name is very important for a normal variable, it is only a
+ *      helper construct for temporary variables. That means for example a
+ *      name for a temporary variable can be used multiple times without
+ *      conflict. So mixing them both may lead to the problem that a normal
+ *      or temporary variable is hidden or even removed.  That must not happen!
+ * </ul>
+ *
+ *
+ * @see org.codehaus.groovy.classgen.AsmClassGenerator
+ * @author Jochen Theodorou
+ */
+public class CompileStack implements Opcodes {
+    /**
+     * TODO: remove optimization of this.foo -> this.@foo
+     *
+     */
+
+    // state flag
+    private boolean clear=true;
+    // current scope
+    private VariableScope scope;
+    // current label for continue
+    private Label continueLabel;
+    // current label for break
+    private Label breakLabel;
+    // available variables on stack
+    private Map stackVariables = new HashMap();
+    // index of the last variable on stack
+    private int currentVariableIndex = 1;
+    // index for the next variable on stack
+    private int nextVariableIndex = 1;
+    // currently temporary variables in use
+    private final LinkedList temporaryVariables = new LinkedList();
+    // overall used variables for a method/constructor
+    private final LinkedList usedVariables = new LinkedList();
+    // map containing named labels of parenting blocks
+    private Map superBlockNamedLabels = new HashMap();
+    // map containing named labels of current block
+    private Map currentBlockNamedLabels = new HashMap();
+    // list containing finally blocks
+    // such a block is created by synchronized or finally and
+    // must be called for break/continue/return
+    private LinkedList<BlockRecorder> finallyBlocks = new LinkedList<BlockRecorder>();
+    private final LinkedList<BlockRecorder> visitedBlocks = new LinkedList<BlockRecorder>();
+
+    private Label thisStartLabel, thisEndLabel;
+
+//    private MethodVisitor mv;
+
+    // helper to handle different stack based variables
+    private final LinkedList stateStack = new LinkedList();
+
+    // handle different states for the implicit "this"
+    private final LinkedList<Boolean> implicitThisStack = new LinkedList<Boolean>();
+    // handle different states for being on the left hand side
+    private final LinkedList<Boolean> lhsStack = new LinkedList<Boolean>();
+    {
+        implicitThisStack.add(false);
+        lhsStack.add(false);
+    }
+
+    // defines the first variable index usable after
+    // all parameters of a method
+    private int localVariableOffset;
+    // this is used to store the goals for a "break foo" call
+    // in a loop where foo is a label.
+    private final Map namedLoopBreakLabel = new HashMap();
+    // this is used to store the goals for a "continue foo" call
+    // in a loop where foo is a label.
+    private final Map namedLoopContinueLabel = new HashMap();
+    private String className;
+    private final LinkedList<ExceptionTableEntry> typedExceptions = new LinkedList<ExceptionTableEntry>();
+    private final LinkedList<ExceptionTableEntry> untypedExceptions = new LinkedList<ExceptionTableEntry>();
+    // stores if on left-hand-side during compilation
+    private boolean lhs;
+    // stores if implicit or explicit this is used.
+    private boolean implicitThis;
+    private final WriterController controller;
+    private boolean inSpecialConstructorCall;
+
+    protected static class LabelRange {
+        public Label start;
+        public Label end;
+    }
+
+    public static class BlockRecorder {
+        private boolean isEmpty = true;
+        public Runnable excludedStatement;
+        public final LinkedList<LabelRange> ranges;
+        public BlockRecorder() {
+            ranges = new LinkedList<LabelRange>();
+        }
+        public BlockRecorder(Runnable excludedStatement) {
+            this();
+            this.excludedStatement = excludedStatement;
+        }
+        public void startRange(Label start) {
+            LabelRange range = new LabelRange();
+            range.start = start;
+            ranges.add(range);
+            isEmpty = false;
+        }
+        public void closeRange(Label end) {
+            ranges.getLast().end = end;
+        }
+    }
+
+    private static class ExceptionTableEntry {
+        Label start,end,goal;
+        String sig;
+    }
+
+    private class StateStackElement {
+        final VariableScope scope;
+        final Label continueLabel;
+        final Label breakLabel;
+        final Map stackVariables;
+        final Map currentBlockNamedLabels;
+        final LinkedList<BlockRecorder> finallyBlocks;
+        final boolean inSpecialConstructorCall;
+
+        StateStackElement() {
+            scope = CompileStack.this.scope;
+            continueLabel = CompileStack.this.continueLabel;
+            breakLabel = CompileStack.this.breakLabel;
+            stackVariables = CompileStack.this.stackVariables;
+            currentBlockNamedLabels = CompileStack.this.currentBlockNamedLabels;
+            finallyBlocks = CompileStack.this.finallyBlocks;
+            inSpecialConstructorCall = CompileStack.this.inSpecialConstructorCall;
+        }
+    }
+
+    public CompileStack(WriterController wc) {
+        this.controller = wc;
+    }
+
+    public void pushState() {
+        stateStack.add(new StateStackElement());
+        stackVariables = new HashMap(stackVariables);
+        finallyBlocks = new LinkedList(finallyBlocks);
+    }
+
+    private void popState() {
+        if (stateStack.isEmpty()) {
+             throw new GroovyBugError("Tried to do a pop on the compile stack without push.");
+        }
+        StateStackElement element = (StateStackElement) stateStack.removeLast();
+        scope = element.scope;
+        continueLabel = element.continueLabel;
+        breakLabel = element.breakLabel;
+        stackVariables = element.stackVariables;
+        finallyBlocks = element.finallyBlocks;
+        inSpecialConstructorCall = element.inSpecialConstructorCall;
+    }
+
+    public Label getContinueLabel() {
+        return continueLabel;
+    }
+
+    public Label getBreakLabel() {
+        return breakLabel;
+    }
+
+    public void removeVar(int tempIndex) {
+        final BytecodeVariable head = (BytecodeVariable) temporaryVariables.removeFirst();
+        if (head.getIndex() != tempIndex) {
+            temporaryVariables.addFirst(head);
+            MethodNode methodNode = controller.getMethodNode();
+            if (methodNode==null) {
+                methodNode = controller.getConstructorNode();
+            }
+            throw new GroovyBugError(
+                    "In method "+ (methodNode!=null?methodNode.getText():"<unknown>") + ", " +
+                    "CompileStack#removeVar: tried to remove a temporary " +
+                    "variable with index "+ tempIndex + " in wrong order. " +
+                    "Current temporary variables=" + temporaryVariables);
+        }
+    }
+
+    private void setEndLabels(){
+        Label endLabel = new Label();
+        controller.getMethodVisitor().visitLabel(endLabel);
+        for (Iterator iter = stackVariables.values().iterator(); iter.hasNext();) {
+            BytecodeVariable var = (BytecodeVariable) iter.next();
+            var.setEndLabel(endLabel);
+        }
+        thisEndLabel = endLabel;
+    }
+
+    public void pop() {
+        setEndLabels();
+        popState();
+    }
+
+    public VariableScope getScope() {
+        return scope;
+    }
+
+    /**
+     * creates a temporary variable.
+     *
+     * @param var defines type and name
+     * @param store defines if the toplevel argument of the stack should be stored
+     * @return the index used for this temporary variable
+     */
+    public int defineTemporaryVariable(Variable var, boolean store) {
+        return defineTemporaryVariable(var.getName(), var.getType(),store);
+    }
+
+    public BytecodeVariable getVariable(String variableName ) {
+        return getVariable(variableName, true);
+    }
+
+    /**
+     * Returns a normal variable.
+     * <p>
+     * If <code>mustExist</code> is true and the normal variable doesn't exist,
+     * then this method will throw a GroovyBugError. It is not the intention of
+     * this method to let this happen! And the exception should not be used for
+     * flow control - it is just acting as an assertion. If the exception is thrown
+     * then it indicates a bug in the class using CompileStack.
+     * This method can also not be used to return a temporary variable.
+     * Temporary variables are not normal variables.
+     *
+     * @param variableName name of the variable
+     * @param mustExist    throw exception if variable does not exist
+     * @return the normal variable or null if not found (and <code>mustExist</code> not true)
+     */
+    public BytecodeVariable getVariable(String variableName, boolean mustExist) {
+        if (variableName.equals("this")) return BytecodeVariable.THIS_VARIABLE;
+        if (variableName.equals("super")) return BytecodeVariable.SUPER_VARIABLE;
+        BytecodeVariable v = (BytecodeVariable) stackVariables.get(variableName);
+        if (v == null && mustExist)
+            throw new GroovyBugError("tried to get a variable with the name " + variableName + " as stack variable, but a variable with this name was not created");
+        return v;
+    }
+
+    /**
+     * creates a temporary variable.
+     *
+     * @param name defines type and name
+     * @param store defines if the top-level argument of the stack should be stored
+     * @return the index used for this temporary variable
+     */
+    public int defineTemporaryVariable(String name,boolean store) {
+        return defineTemporaryVariable(name, ClassHelper.DYNAMIC_TYPE,store);
+    }
+
+    /**
+     * creates a temporary variable.
+     *
+     * @param name defines the name
+     * @param node defines the node
+     * @param store defines if the top-level argument of the stack should be stored
+     * @return the index used for this temporary variable
+     */
+    public int defineTemporaryVariable(String name, ClassNode node, boolean store) {
+        BytecodeVariable answer = defineVar(name, node, false, false);
+        temporaryVariables.addFirst(answer); // TRICK: we add at the beginning so when we find for remove or get we always have the last one
+        usedVariables.removeLast();
+
+        if (store) controller.getOperandStack().storeVar(answer);
+
+        return answer.getIndex();
+    }
+
+    private void resetVariableIndex(boolean isStatic) {
+        temporaryVariables.clear();
+        if (!isStatic) {
+            currentVariableIndex=1;
+            nextVariableIndex=1;
+        } else {
+            currentVariableIndex=0;
+            nextVariableIndex=0;
+        }
+    }
+
+    /**
+     * Clears the state of the class. This method should be called
+     * after a MethodNode is visited. Note that a call to init will
+     * fail if clear is not called before
+     */
+    public void clear() {
+        if (stateStack.size()>1) {
+            int size = stateStack.size()-1;
+            throw new GroovyBugError("the compile stack contains "+size+" more push instruction"+(size==1?"":"s")+" than pops.");
+        }
+        if (lhsStack.size()>1) {
+            int size = lhsStack.size()-1;
+            throw new GroovyBugError("lhs stack is supposed to be empty, but has " +
+                                     size + " elements left.");
+        }
+        if (implicitThisStack.size()>1) {
+            int size = implicitThisStack.size()-1;
+            throw new GroovyBugError("implicit 'this' stack is supposed to be empty, but has " +
+                                     size + " elements left.");
+        }
+        clear = true;
+        MethodVisitor mv = controller.getMethodVisitor();
+        // br experiment with local var table so debuggers can retrieve variable names
+        if (true) {//AsmClassGenerator.CREATE_DEBUG_INFO) {
+            if (thisEndLabel==null) setEndLabels();
+
+            if (!scope.isInStaticContext()) {
+                // write "this"
+                mv.visitLocalVariable("this", className, null, thisStartLabel, thisEndLabel, 0);
+            }
+
+            for (Iterator iterator = usedVariables.iterator(); iterator.hasNext();) {
+                BytecodeVariable v = (BytecodeVariable) iterator.next();
+                ClassNode t = v.getType();
+                if (v.isHolder()) t = ClassHelper.REFERENCE_TYPE;
+                String type = BytecodeHelper.getTypeDescription(t);
+                Label start = v.getStartLabel();
+                Label end = v.getEndLabel();
+                mv.visitLocalVariable(v.getName(), type, null, start, end, v.getIndex());
+            }
+        }
+
+        //exception table writing
+        for (ExceptionTableEntry ep : typedExceptions) {
+            mv.visitTryCatchBlock(ep.start, ep.end, ep.goal, ep.sig);
+        }
+        //exception table writing
+        for (ExceptionTableEntry ep : untypedExceptions) {
+            mv.visitTryCatchBlock(ep.start, ep.end, ep.goal, ep.sig);
+        }
+
+
+        pop();
+        typedExceptions.clear();
+        untypedExceptions.clear();
+        stackVariables.clear();
+        usedVariables.clear();
+        scope = null;
+        finallyBlocks.clear();
+        resetVariableIndex(false);
+        superBlockNamedLabels.clear();
+        currentBlockNamedLabels.clear();
+        namedLoopBreakLabel.clear();
+        namedLoopContinueLabel.clear();
+        continueLabel=null;
+        breakLabel=null;
+        thisStartLabel=null;
+        thisEndLabel=null;
+        mv = null;
+    }
+
+    public void addExceptionBlock (Label start, Label end, Label goal,
+                                   String sig)
+    {
+        // this code is in an extra method to avoid
+        // lazy initialization issues
+        ExceptionTableEntry ep = new ExceptionTableEntry();
+        ep.start = start;
+        ep.end = end;
+        ep.sig = sig;
+        ep.goal = goal;
+        if (sig==null) {
+            untypedExceptions.add(ep);
+        } else {
+            typedExceptions.add(ep);
+        }
+    }
+
+    /**
+     * initializes this class for a MethodNode. This method will
+     * automatically define variables for the method parameters
+     * and will create references if needed.  The created variables
+     * can be accessed by calling getVariable().
+     *
+     */
+    public void init(VariableScope el, Parameter[] parameters) {
+        if (!clear) throw new GroovyBugError("CompileStack#init called without calling clear before");
+        clear=false;
+        pushVariableScope(el);
+        defineMethodVariables(parameters,el.isInStaticContext());
+        this.className = BytecodeHelper.getTypeDescription(controller.getClassNode());
+    }
+
+    /**
+     * Causes the state-stack to add an element and sets
+     * the given scope as new current variable scope. Creates
+     * a element for the state stack so pop has to be called later
+     */
+    public void pushVariableScope(VariableScope el) {
+        pushState();
+        scope = el;
+        superBlockNamedLabels = new HashMap(superBlockNamedLabels);
+        superBlockNamedLabels.putAll(currentBlockNamedLabels);
+        currentBlockNamedLabels = new HashMap();
+    }
+
+    /**
+     * Should be called when descending into a loop that defines
+     * also a scope. Calls pushVariableScope and prepares labels
+     * for a loop structure. Creates a element for the state stack
+     * so pop has to be called later, TODO: @Deprecate
+     */
+    public void pushLoop(VariableScope el, String labelName) {
+        pushVariableScope(el);
+        continueLabel = new Label();
+        breakLabel = new Label();
+        if (labelName != null) {
+            initLoopLabels(labelName);
+        }
+    }
+
+    /**
+     * Should be called when descending into a loop that defines
+     * also a scope. Calls pushVariableScope and prepares labels
+     * for a loop structure. Creates a element for the state stack
+     * so pop has to be called later
+     */
+    public void pushLoop(VariableScope el, List<String> labelNames) {
+        pushVariableScope(el);
+        continueLabel = new Label();
+        breakLabel = new Label();
+        if (labelNames != null) {
+            for (String labelName : labelNames) {
+                initLoopLabels(labelName);
+            }
+        }
+    }
+
+    private void initLoopLabels(String labelName) {
+        namedLoopBreakLabel.put(labelName,breakLabel);
+        namedLoopContinueLabel.put(labelName,continueLabel);
+    }
+
+    /**
+     * Should be called when descending into a loop that does
+     * not define a scope. Creates a element for the state stack
+     * so pop has to be called later, TODO: @Deprecate
+     */
+    public void pushLoop(String labelName) {
+        pushState();
+        continueLabel = new Label();
+        breakLabel = new Label();
+        initLoopLabels(labelName);
+    }
+
+    /**
+     * Should be called when descending into a loop that does
+     * not define a scope. Creates a element for the state stack
+     * so pop has to be called later
+     */
+    public void pushLoop(List<String> labelNames) {
+        pushState();
+        continueLabel = new Label();
+        breakLabel = new Label();
+        if (labelNames != null) {
+            for (String labelName : labelNames) {
+                initLoopLabels(labelName);
+            }
+        }
+    }
+
+    /**
+     * Used for <code>break foo</code> inside a loop to end the
+     * execution of the marked loop. This method will return the
+     * break label of the loop if there is one found for the name.
+     * If not, the current break label is returned.
+     */
+    public Label getNamedBreakLabel(String name) {
+        Label label = getBreakLabel();
+        Label endLabel = null;
+        if (name!=null) endLabel = (Label) namedLoopBreakLabel.get(name);
+        if (endLabel!=null) label = endLabel;
+        return label;
+    }
+
+    /**
+     * Used for <code>continue foo</code> inside a loop to continue
+     * the execution of the marked loop. This method will return
+     * the break label of the loop if there is one found for the
+     * name. If not, getLabel is used.
+     */
+    public Label getNamedContinueLabel(String name) {
+        Label label = getLabel(name);
+        Label endLabel = null;
+        if (name!=null) endLabel = (Label) namedLoopContinueLabel.get(name);
+        if (endLabel!=null) label = endLabel;
+        return label;
+    }
+
+    /**
+     * Creates a new break label and a element for the state stack
+     * so pop has to be called later
+     */
+    public Label pushSwitch(){
+        pushState();
+        breakLabel = new Label();
+        return breakLabel;
+    }
+
+    /**
+     * because a boolean Expression may not be evaluated completely
+     * it is important to keep the registers clean
+     */
+    public void pushBooleanExpression(){
+        pushState();
+    }
+
+    private BytecodeVariable defineVar(String name, ClassNode type, boolean holder, boolean useReferenceDirectly) {
+        int prevCurrent = currentVariableIndex;
+        makeNextVariableID(type,useReferenceDirectly);
+        int index = currentVariableIndex;
+        if (holder && !useReferenceDirectly) index = localVariableOffset++;
+        BytecodeVariable answer = new BytecodeVariable(index, type, name, prevCurrent);
+        usedVariables.add(answer);
+        answer.setHolder(holder);
+        return answer;
+    }
+
+    private void makeLocalVariablesOffset(Parameter[] paras, boolean isInStaticContext) {
+        resetVariableIndex(isInStaticContext);
+
+        for (Parameter para : paras) {
+            makeNextVariableID(para.getType(), false);
+        }
+        localVariableOffset = nextVariableIndex;
+
+        resetVariableIndex(isInStaticContext);
+    }
+
+    private void defineMethodVariables(Parameter[] paras, boolean isInStaticContext) {
+        Label startLabel  = new Label();
+        thisStartLabel = startLabel;
+        controller.getMethodVisitor().visitLabel(startLabel);
+
+        makeLocalVariablesOffset(paras,isInStaticContext);
+
+        for (Parameter para : paras) {
+            String name = para.getName();
+            BytecodeVariable answer;
+            ClassNode type = para.getType();
+            if (para.isClosureSharedVariable()) {
+                boolean useExistingReference = para.getNodeMetaData(ClosureWriter.UseExistingReference.class) != null;
+                answer = defineVar(name, para.getOriginType(), true, useExistingReference);
+                answer.setStartLabel(startLabel);
+                if (!useExistingReference) {
+                    controller.getOperandStack().load(type, currentVariableIndex);
+                    controller.getOperandStack().box();
+
+                    // GROOVY-4237, the original variable should always appear
+                    // in the variable index, otherwise some programs get into
+                    // trouble. So we define a dummy variable for the packaging
+                    // phase and let it end right away before the normal
+                    // reference will be used
+                    Label newStart = new Label();
+                    controller.getMethodVisitor().visitLabel(newStart);
+                    BytecodeVariable var = new BytecodeVariable(currentVariableIndex, para.getOriginType(), name, currentVariableIndex);
+                    var.setStartLabel(startLabel);
+                    var.setEndLabel(newStart);
+                    usedVariables.add(var);
+                    answer.setStartLabel(newStart);
+
+                    createReference(answer);
+                }
+            } else {
+                answer = defineVar(name, type, false, false);
+                answer.setStartLabel(startLabel);
+            }
+            stackVariables.put(name, answer);
+        }
+
+        nextVariableIndex = localVariableOffset;
+    }
+
+    private void createReference(BytecodeVariable reference) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitTypeInsn(NEW, "groovy/lang/Reference");
+        mv.visitInsn(DUP_X1);
+        mv.visitInsn(SWAP);
+        mv.visitMethodInsn(INVOKESPECIAL, "groovy/lang/Reference", "<init>", "(Ljava/lang/Object;)V", false);
+        mv.visitVarInsn(ASTORE, reference.getIndex());
+    }
+
+    private static void pushInitValue(ClassNode type, MethodVisitor mv) {
+        if (ClassHelper.isPrimitiveType(type)) {
+            if (type== ClassHelper.long_TYPE) {
+                mv.visitInsn(LCONST_0);
+            } else if (type== ClassHelper.double_TYPE) {
+                mv.visitInsn(DCONST_0);
+            } else if (type== ClassHelper.float_TYPE) {
+                mv.visitInsn(FCONST_0);
+            } else {
+                mv.visitLdcInsn(0);
+            }
+        } else {
+            mv.visitInsn(ACONST_NULL);
+        }
+    }
+
+    /**
+     * Defines a new Variable using an AST variable.
+     * @param initFromStack if true the last element of the
+     *                      stack will be used to initialize
+     *                      the new variable. If false null
+     *                      will be used.
+     */
+    public BytecodeVariable defineVariable(Variable v, boolean initFromStack) {
+        return defineVariable(v, v.getOriginType(), initFromStack);
+    }
+
+    public BytecodeVariable defineVariable(Variable v, ClassNode variableType, boolean initFromStack) {
+        String name = v.getName();
+        BytecodeVariable answer = defineVar(name, variableType, v.isClosureSharedVariable(), v.isClosureSharedVariable());
+        stackVariables.put(name, answer);
+
+        MethodVisitor mv = controller.getMethodVisitor();
+        Label startLabel  = new Label();
+        answer.setStartLabel(startLabel);
+        ClassNode type = answer.getType().redirect();
+        OperandStack operandStack = controller.getOperandStack();
+
+        if (!initFromStack) {
+            if (ClassHelper.isPrimitiveType(v.getOriginType()) && ClassHelper.getWrapper(v.getOriginType()) == variableType) {
+                pushInitValue(v.getOriginType(), mv);
+                operandStack.push(v.getOriginType());
+                operandStack.box();
+                operandStack.remove(1);
+            } else {
+                pushInitValue(type, mv);
+            }
+        }
+        operandStack.push(answer.getType());
+        if (answer.isHolder())  {
+            operandStack.box();
+            operandStack.remove(1);
+            createReference(answer);
+        } else {
+            operandStack.storeVar(answer);
+        }
+
+        mv.visitLabel(startLabel);
+        return answer;
+    }
+
+    /**
+     * @param name the name of the variable of interest
+     * @return true if a variable is already defined
+     */
+    public boolean containsVariable(String name) {
+        return stackVariables.containsKey(name);
+    }
+
+    /**
+     * Calculates the index of the next free register stores it
+     * and sets the current variable index to the old value
+     */
+    private void makeNextVariableID(ClassNode type, boolean useReferenceDirectly) {
+        currentVariableIndex = nextVariableIndex;
+        if ((type== ClassHelper.long_TYPE || type== ClassHelper.double_TYPE) && !useReferenceDirectly) {
+            nextVariableIndex++;
+        }
+        nextVariableIndex++;
+    }
+
+    /**
+     * Returns the label for the given name
+     */
+    public Label getLabel(String name) {
+        if (name==null) return null;
+        Label l = (Label) superBlockNamedLabels.get(name);
+        if (l==null) l = createLocalLabel(name);
+        return l;
+    }
+
+    /**
+     * creates a new named label
+     */
+    public Label createLocalLabel(String name) {
+        Label l = (Label) currentBlockNamedLabels.get(name);
+        if (l==null) {
+            l = new Label();
+            currentBlockNamedLabels.put(name,l);
+        }
+        return l;
+    }
+
+    public void applyFinallyBlocks(Label label, boolean isBreakLabel) {
+        // first find the state defining the label. That is the state
+        // directly after the state not knowing this label. If no state
+        // in the list knows that label, then the defining state is the
+        // current state.
+        StateStackElement result = null;
+        for (ListIterator iter = stateStack.listIterator(stateStack.size()); iter.hasPrevious();) {
+            StateStackElement element = (StateStackElement) iter.previous();
+            if (!element.currentBlockNamedLabels.values().contains(label)) {
+                if (isBreakLabel && element.breakLabel != label) {
+                    result = element;
+                    break;
+                }
+                if (!isBreakLabel && element.continueLabel != label) {
+                    result = element;
+                    break;
+                }
+            }
+        }
+
+        List<BlockRecorder> blocksToRemove;
+        if (result==null) {
+            // all Blocks do know the label, so use all finally blocks
+            blocksToRemove = (List<BlockRecorder>) Collections.EMPTY_LIST;
+        } else {
+            blocksToRemove = result.finallyBlocks;
+        }
+
+        List<BlockRecorder> blocks = new LinkedList<BlockRecorder>(finallyBlocks);
+        blocks.removeAll(blocksToRemove);
+        applyBlockRecorder(blocks);
+    }
+
+
+    private void applyBlockRecorder(List<BlockRecorder> blocks) {
+        if (blocks.isEmpty() || blocks.size() == visitedBlocks.size()) return;
+
+        MethodVisitor mv = controller.getMethodVisitor();
+        Label newStart = new Label();
+
+        for (BlockRecorder fb : blocks) {
+            if (visitedBlocks.contains(fb)) continue;
+
+            Label end = new Label();
+            mv.visitInsn(NOP);
+            mv.visitLabel(end);
+
+            fb.closeRange(end);
+
+            // we exclude the finally block from the exception table
+            // here to avoid double visiting of finally statements
+            fb.excludedStatement.run();
+
+            fb.startRange(newStart);
+        }
+
+        mv.visitInsn(NOP);
+        mv.visitLabel(newStart);
+    }
+
+    public void applyBlockRecorder() {
+        applyBlockRecorder(finallyBlocks);
+    }
+
+    public boolean hasBlockRecorder() {
+        return !finallyBlocks.isEmpty();
+    }
+
+    public void pushBlockRecorder(BlockRecorder recorder) {
+        pushState();
+        finallyBlocks.addFirst(recorder);
+    }
+
+    public void pushBlockRecorderVisit(BlockRecorder finallyBlock) {
+        visitedBlocks.add(finallyBlock);
+    }
+
+    public void popBlockRecorderVisit(BlockRecorder finallyBlock) {
+        visitedBlocks.remove(finallyBlock);
+    }
+
+    public void writeExceptionTable(BlockRecorder block, Label goal, String sig) {
+        if (block.isEmpty) return;
+        MethodVisitor mv = controller.getMethodVisitor();
+        for (LabelRange range : block.ranges) {
+            mv.visitTryCatchBlock(range.start, range.end, goal, sig);
+        }
+    }
+
+//    public MethodVisitor getMethodVisitor() {
+//        return mv;
+//    }
+
+    public boolean isLHS() {
+        return lhs;
+    }
+
+    public void pushLHS(boolean lhs) {
+        lhsStack.add(lhs);
+        this.lhs = lhs;
+    }
+
+    public void popLHS() {
+        lhsStack.removeLast();
+        this.lhs = lhsStack.getLast();
+    }
+
+    public void pushImplicitThis(boolean implicitThis) {
+        implicitThisStack.add(implicitThis);
+        this.implicitThis = implicitThis;
+    }
+
+    public boolean isImplicitThis() {
+        return implicitThis;
+    }
+
+    public void popImplicitThis() {
+        implicitThisStack.removeLast();
+        this.implicitThis = implicitThisStack.getLast();
+    }
+
+    public boolean isInSpecialConstructorCall() {
+        return inSpecialConstructorCall;
+    }
+
+    public void pushInSpecialConstructorCall() {
+        pushState();
+        inSpecialConstructorCall = true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java b/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java
new file mode 100644
index 0000000..22acbaa
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/DelegatingController.java
@@ -0,0 +1,276 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.InterfaceHelperClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * This class will delegate all calls to a WriterController given in the constructor. 
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class DelegatingController extends WriterController {
+    private final WriterController delegationController;
+    
+    public DelegatingController(WriterController normalController) {
+        this.delegationController = normalController;
+    }
+    
+    @Override
+    public void init(final AsmClassGenerator asmClassGenerator, final GeneratorContext gcon, final ClassVisitor cv, final ClassNode cn) {
+        delegationController.init(asmClassGenerator, gcon, cv, cn);
+    }
+
+    @Override
+    public void setMethodNode(final MethodNode mn) {
+        delegationController.setMethodNode(mn);
+    }
+
+    @Override
+    public void setConstructorNode(final ConstructorNode cn) {
+        delegationController.setConstructorNode(cn);
+    }
+    
+    @Override
+    public boolean isFastPath() {
+        return delegationController.isFastPath();
+    }
+    
+    @Override
+    public CallSiteWriter getCallSiteWriter() {
+        return delegationController.getCallSiteWriter();
+    }
+        
+    @Override
+    public StatementWriter getStatementWriter() {
+        return delegationController.getStatementWriter();            
+    }
+    
+    @Override
+    public TypeChooser getTypeChooser() {
+        return delegationController.getTypeChooser();
+    }
+    
+    @Override
+    public AsmClassGenerator getAcg() {
+        return delegationController.getAcg();
+    }
+    
+    @Override
+    public AssertionWriter getAssertionWriter() {
+        return delegationController.getAssertionWriter();
+    }
+    
+    @Override
+    public BinaryExpressionHelper getBinaryExpressionHelper() {
+        return delegationController.getBinaryExpressionHelper();
+    }
+
+    @Override
+    public UnaryExpressionHelper getUnaryExpressionHelper() {
+        return delegationController.getUnaryExpressionHelper();
+    }
+
+    @Override
+    public String getClassName() {
+        return delegationController.getClassName();
+    }
+    
+    @Override
+    public ClassNode getClassNode() {
+        return delegationController.getClassNode();
+    }
+    
+    @Override
+    public ClassVisitor getClassVisitor() {
+        return delegationController.getClassVisitor();
+    }
+    
+    @Override
+    public ClosureWriter getClosureWriter() {
+        return delegationController.getClosureWriter();
+    } 
+    
+    @Override
+    public CompileStack getCompileStack() {
+        return delegationController.getCompileStack();
+    }
+    
+    @Override
+    public ConstructorNode getConstructorNode() {
+        return delegationController.getConstructorNode();
+    }
+    
+    @Override
+    public GeneratorContext getContext() {
+        return delegationController.getContext();
+    }
+    
+    @Override
+    public ClassVisitor getCv() {
+        return delegationController.getCv();
+    }
+    
+    @Override
+    public InterfaceHelperClassNode getInterfaceClassLoadingClass() {
+        return delegationController.getInterfaceClassLoadingClass();
+    }
+    
+    @Override
+    public String getInternalBaseClassName() {
+        return delegationController.getInternalBaseClassName();
+    }
+    
+    @Override
+    public String getInternalClassName() {
+        return delegationController.getInternalClassName();
+    }
+    
+    @Override
+    public InvocationWriter getInvocationWriter() {
+        return delegationController.getInvocationWriter();
+    }
+    
+    @Override
+    public MethodNode getMethodNode() {
+        return delegationController.getMethodNode();
+    }
+    
+    @Override
+    public MethodVisitor getMethodVisitor() {
+        return delegationController.getMethodVisitor();
+    }
+    
+    @Override
+    public OperandStack getOperandStack() {
+        return delegationController.getOperandStack();
+    }
+    
+    @Override
+    public ClassNode getOutermostClass() {
+        return delegationController.getOutermostClass();
+    }
+    
+    @Override
+    public ClassNode getReturnType() {
+        return delegationController.getReturnType();
+    }
+    
+    @Override
+    public SourceUnit getSourceUnit() {
+        return delegationController.getSourceUnit();
+    }
+
+    @Override
+    public boolean isConstructor() {
+        return delegationController.isConstructor();
+    }
+    
+    @Override
+    public boolean isInClosure() {
+        return delegationController.isInClosure();
+    }
+    
+    @Override
+    public boolean isInClosureConstructor() {
+        return delegationController.isInClosureConstructor();
+    }
+    
+    @Override
+    public boolean isNotClinit() {
+        return delegationController.isNotClinit();
+    }
+    
+    @Override
+    public boolean isInScriptBody() {
+        return delegationController.isInScriptBody();
+    }
+    
+    @Override
+    public boolean isNotExplicitThisInClosure(boolean implicitThis) {
+        return delegationController.isNotExplicitThisInClosure(implicitThis);
+    }
+    
+    @Override
+    public boolean isStaticConstructor() {
+        return delegationController.isStaticConstructor();
+    }
+    
+    @Override
+    public boolean isStaticContext() {
+        return delegationController.isStaticContext();
+    }
+    
+    @Override
+    public boolean isStaticMethod() {
+        return delegationController.isStaticMethod();
+    }
+    
+    @Override
+    public void setInterfaceClassLoadingClass(InterfaceHelperClassNode ihc) {
+        delegationController.setInterfaceClassLoadingClass(ihc);
+    }
+    
+    @Override
+    public void setMethodVisitor(MethodVisitor methodVisitor) {
+        delegationController.setMethodVisitor(methodVisitor);
+    }
+    
+    @Override
+    public boolean shouldOptimizeForInt() {
+        return delegationController.shouldOptimizeForInt();
+    }
+    
+    @Override
+    public void switchToFastPath() {
+        delegationController.switchToFastPath();
+    }
+    
+    @Override
+    public void switchToSlowPath() {
+        delegationController.switchToSlowPath();
+    }
+    
+    @Override
+    public int getBytecodeVersion() {
+        return delegationController.getBytecodeVersion();
+    }
+    
+    @Override
+    public void setLineNumber(int n) {
+        delegationController.setLineNumber(n);
+    }
+    
+    @Override
+    public int getLineNumber() {
+        return delegationController.getLineNumber();
+    }
+    
+    @Override
+    public void resetLineNumber() {
+        delegationController.resetLineNumber();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/ExpressionAsVariableSlot.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/ExpressionAsVariableSlot.java b/src/main/java/org/codehaus/groovy/classgen/asm/ExpressionAsVariableSlot.java
new file mode 100644
index 0000000..a9e568b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/ExpressionAsVariableSlot.java
@@ -0,0 +1,81 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * Helper class that takes an Expression and if visited will load it normally, 
+ * storing the result in a helper variable, which then can be requested after
+ * the visit is completed. A copy of the variable will stay on the stack. 
+ * Subsequent visits will load the stored value instead of visiting the 
+ * expression again
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class ExpressionAsVariableSlot extends BytecodeExpression {
+    private int index = -1;
+    private final Expression exp;
+    private final WriterController controller;
+    private final String name;
+
+    public ExpressionAsVariableSlot(WriterController controller, Expression expression, String name) {
+        this.exp = expression;
+        this.controller = controller;
+        this.name = name;
+    }
+    
+    public ExpressionAsVariableSlot(WriterController controller, Expression expression) {
+        this(controller, expression, "ExpressionAsVariableSlot_TEMP");
+    }
+
+    @Override
+    public void visit(MethodVisitor mv) {
+        OperandStack os = controller.getOperandStack();
+        if (index == -1) { // first visit
+            // visit expression
+            exp.visit(controller.getAcg());
+            // make copy & set type
+            os.dup();
+            this.setType(os.getTopOperand());
+            // store copy in temporary variable
+            CompileStack compileStack = controller.getCompileStack();
+            index = compileStack.defineTemporaryVariable(name, getType(), true);
+        } else {
+            os.load(getType(), index);
+        }
+        // since the calling code will push the type again, we better remove it here
+        os.remove(1);
+    }
+
+    /**
+     * returns the index of the bytecode variable
+     */
+    public int getIndex() {
+        if (index == -1) throw new GroovyBugError("index requested before visit!");
+        return index;
+    }
+
+    @Override
+    public String getText() {
+        return exp.getText();
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/gradle/docs.gradle
----------------------------------------------------------------------
diff --git a/gradle/docs.gradle b/gradle/docs.gradle
index e80dcd4..d10b9d5 100644
--- a/gradle/docs.gradle
+++ b/gradle/docs.gradle
@@ -44,7 +44,7 @@ def javadocSpec = {
         encoding = 'UTF-8'
         author = true
         version = true
-        overview = rootProject.file('src/main/overviewj.html')
+        overview = rootProject.file('src/main/java/overviewj.html')
         footer = doc.footer
         source = '1.8'
         links('http://docs.oracle.com/javase/8/docs/api/', 'http://docs.oracle.com/javaee/7/api/',
@@ -55,13 +55,13 @@ def javadocSpec = {
 
 def groovydocSpec = {
     use = true
-    if (project != rootProject) source = project.sourceSets.main.allSource
+    source = project.sourceSets.main.allSource
     classpath = javadoc.classpath
     ext.windowtitle = doc.title
     ext.doctitle = doc.title
     header = doc.title
     footer = doc.footer
-    overviewText = rootProject.resources.text.fromFile('src/main/overview.html')
+    overviewText = rootProject.resources.text.fromFile('src/main/java/overview.html')
     includePrivate = false
     link 'http://docs.oracle.com/javaee/7/api/', 'javax.servlet.', 'javax.management.'
     link 'http://docs.oracle.com/javase/8/docs/api/', 'java.', 'org.xml.', 'javax.', 'org.w3c.'

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/gradle/test.gradle
----------------------------------------------------------------------
diff --git a/gradle/test.gradle b/gradle/test.gradle
index df0ff06..b138af1 100644
--- a/gradle/test.gradle
+++ b/gradle/test.gradle
@@ -77,7 +77,7 @@ tasks.withType(Test) {
     if (testdb) {
         systemProperties 'groovy.testdb.props': testdb
     }
-    systemProperties 'apple.awt.UIElement': 'true', 'javadocAssertion.src.dir': './src/main'
+    systemProperties 'apple.awt.UIElement': 'true', 'javadocAssertion.src.dir': './src/main/java'
     systemProperties 'gradle.home': gradle.gradleHomeDir // this is needed by the security.policy
 
     classpath = files('src/test') + classpath

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/ASTTestTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/ASTTestTransformation.groovy b/src/main/groovy/ASTTestTransformation.groovy
new file mode 100644
index 0000000..dcfe314
--- /dev/null
+++ b/src/main/groovy/ASTTestTransformation.groovy
@@ -0,0 +1,233 @@
+/*
+ *  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.transform
+
+import groovy.transform.CompilationUnitAware
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.PropertyExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.ErrorCollector
+import org.codehaus.groovy.control.Janitor
+import org.codehaus.groovy.control.ProcessingUnit
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.control.customizers.ImportCustomizer
+import org.codehaus.groovy.control.io.ReaderSource
+import org.codehaus.groovy.runtime.MethodClosure
+import org.codehaus.groovy.syntax.SyntaxException
+import org.codehaus.groovy.tools.Utilities
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
+
+@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
+class ASTTestTransformation extends AbstractASTTransformation implements CompilationUnitAware {
+    private CompilationUnit compilationUnit
+
+    void visit(final ASTNode[] nodes, final SourceUnit source) {
+        AnnotationNode annotationNode = nodes[0]
+        def member = annotationNode.getMember('phase')
+        def phase = null
+        if (member) {
+            if (member instanceof VariableExpression) {
+                phase = CompilePhase.valueOf(member.text)
+            } else if (member instanceof PropertyExpression) {
+                phase = CompilePhase.valueOf(member.propertyAsString)
+            }
+            annotationNode.setMember('phase', propX(classX(ClassHelper.make(CompilePhase)), phase.toString()))
+        }
+        member = annotationNode.getMember('value')
+        if (member && !(member instanceof ClosureExpression)) {
+            throw new SyntaxException("ASTTest value must be a closure", member.getLineNumber(), member.getColumnNumber())
+        }
+        if (!member && !annotationNode.getNodeMetaData(ASTTestTransformation)) {
+            throw new SyntaxException("Missing test expression", annotationNode.getLineNumber(), annotationNode.getColumnNumber())
+        }
+        // convert value into node metadata so that the expression doesn't mix up with other AST xforms like type checking
+        annotationNode.putNodeMetaData(ASTTestTransformation, member)
+        annotationNode.getMembers().remove('value')
+
+        def pcallback = compilationUnit.progressCallback
+        def callback = new CompilationUnit.ProgressCallback() {
+            Binding binding = new Binding([:].withDefault {null})
+
+            @Override
+            void call(final ProcessingUnit context, final int phaseRef) {
+                if (phase==null ||  phaseRef == phase.phaseNumber) {
+                    ClosureExpression testClosure = nodes[0].getNodeMetaData(ASTTestTransformation)
+                    StringBuilder sb = new StringBuilder()
+                    for (int i = testClosure.lineNumber; i <= testClosure.lastLineNumber; i++) {
+                        sb.append(source.source.getLine(i, new Janitor())).append('\n')
+                    }
+                    def testSource = sb.substring(testClosure.columnNumber + 1, sb.length())
+                    testSource = testSource.substring(0, testSource.lastIndexOf('}'))
+                    CompilerConfiguration config = new CompilerConfiguration()
+                    def customizer = new ImportCustomizer()
+                    config.addCompilationCustomizers(customizer)
+                    binding['sourceUnit'] = source
+                    binding['node'] = nodes[1]
+                    binding['lookup'] = new MethodClosure(LabelFinder, "lookup").curry(nodes[1])
+                    binding['compilationUnit'] = compilationUnit
+                    binding['compilePhase'] = CompilePhase.fromPhaseNumber(phaseRef)
+
+                    GroovyShell shell = new GroovyShell(binding, config)
+
+                    source.AST.imports.each {
+                        customizer.addImport(it.alias, it.type.name)
+                    }
+                    source.AST.starImports.each {
+                        customizer.addStarImports(it.packageName)
+                    }
+                    source.AST.staticImports.each {
+                        customizer.addStaticImport(it.value.alias, it.value.type.name, it.value.fieldName)
+                    }
+                    source.AST.staticStarImports.each {
+                        customizer.addStaticStars(it.value.className)
+                    }
+                    shell.evaluate(testSource)
+                }
+            }
+        }
+        
+        if (pcallback!=null) {
+            if (pcallback instanceof ProgressCallbackChain) {
+                pcallback.addCallback(callback)                
+            } else {
+                pcallback = new ProgressCallbackChain(pcallback, callback)
+            }
+            callback = pcallback
+        }
+        
+        compilationUnit.setProgressCallback(callback)
+
+    }
+
+    void setCompilationUnit(final CompilationUnit unit) {
+        this.compilationUnit = unit
+    }
+
+    private static class AssertionSourceDelegatingSourceUnit extends SourceUnit {
+        private final ReaderSource delegate
+
+        AssertionSourceDelegatingSourceUnit(final String name, final ReaderSource source, final CompilerConfiguration flags, final GroovyClassLoader loader, final ErrorCollector er) {
+            super(name, '', flags, loader, er)
+            delegate = source
+        }
+
+        @Override
+        String getSample(final int line, final int column, final Janitor janitor) {
+            String sample = null;
+            String text = delegate.getLine(line, janitor);
+
+            if (text != null) {
+                if (column > 0) {
+                    String marker = Utilities.repeatString(" ", column - 1) + "^";
+
+                    if (column > 40) {
+                        int start = column - 30 - 1;
+                        int end = (column + 10 > text.length() ? text.length() : column + 10 - 1);
+                        sample = "   " + text.substring(start, end) + Utilities.eol() + "   " +
+                                marker.substring(start, marker.length());
+                    } else {
+                        sample = "   " + text + Utilities.eol() + "   " + marker;
+                    }
+                } else {
+                    sample = text;
+                }
+            }
+
+            return sample;
+
+        }
+
+    }
+    
+    private static class ProgressCallbackChain extends CompilationUnit.ProgressCallback {
+
+        private final List<CompilationUnit.ProgressCallback> chain = new LinkedList<CompilationUnit.ProgressCallback>()
+
+        ProgressCallbackChain(CompilationUnit.ProgressCallback... callbacks) {
+            if (callbacks!=null) {
+                callbacks.each { addCallback(it) }
+            }
+        }
+
+        public void addCallback(CompilationUnit.ProgressCallback callback) {
+            chain << callback
+        }
+        
+        @Override
+        void call(final ProcessingUnit context, final int phase) {
+            chain*.call(context, phase)
+        }
+    }
+
+    public static class LabelFinder extends ClassCodeVisitorSupport {
+
+        public static List<Statement> lookup(MethodNode node, String label) {
+            LabelFinder finder = new LabelFinder(label, null)
+            node.code.visit(finder)
+
+            finder.targets
+        }
+
+        public static List<Statement> lookup(ClassNode node, String label) {
+            LabelFinder finder = new LabelFinder(label, null)
+            node.methods*.code*.visit(finder)
+            node.declaredConstructors*.code*.visit(finder)
+
+            finder.targets
+        }
+
+        private final String label
+        private final SourceUnit unit
+
+        private final List<Statement> targets = new LinkedList<Statement>();
+
+        LabelFinder(final String label, final SourceUnit unit) {
+            this.label = label
+            this.unit = unit;
+        }
+
+        @Override
+        protected SourceUnit getSourceUnit() {
+            unit
+        }
+
+        @Override
+        protected void visitStatement(final Statement statement) {
+            super.visitStatement(statement)
+            if (statement.statementLabel==label) targets << statement
+        }
+
+        List<Statement> getTargets() {
+            return Collections.unmodifiableList(targets)
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/ASTTransformationCustomizer.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/ASTTransformationCustomizer.groovy b/src/main/groovy/ASTTransformationCustomizer.groovy
new file mode 100644
index 0000000..7e84968
--- /dev/null
+++ b/src/main/groovy/ASTTransformationCustomizer.groovy
@@ -0,0 +1,301 @@
+/*
+ *  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.control.customizers
+
+import groovy.transform.CompilationUnitAware
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.expr.ClassExpression
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.ListExpression
+import org.codehaus.groovy.classgen.GeneratorContext
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformationClass
+
+import java.lang.annotation.Annotation
+
+/**
+ * This customizer allows applying an AST transformation to a source unit with
+ * several strategies.
+ *
+ * Creating a customizer with the {@link ASTTransformationCustomizer#ASTTransformationCustomizer(Class)
+ * class constructor} will trigger an AST transformation for
+ * each class node of a source unit. However, you cannot pass parameters to the annotation so the default values
+ * will be used. Writing :
+ * <pre>
+ *     def configuration = new CompilerConfiguration()
+ *     configuration.addCompilationCustomizers(new ASTTransformationCustomizer(Log))
+ *     def shell = new GroovyShell(configuration)
+ *     shell.evaluate("""
+ *        class MyClass {
+ *
+ *        }""")
+ * </pre>
+ *
+ * is equivalent to :
+ *
+ * <pre>
+ *     def shell = new GroovyShell()
+ *     shell.evaluate("""
+ *        &#64;Log
+ *        class MyClass {
+ *
+ *        }""")
+ * </pre>
+ *
+ * The class passed as a constructor parameter must be an AST transformation annotation.
+ *
+ * Alternatively, you can apply a global AST transformation by calling the
+ * {@link ASTTransformationCustomizer#ASTTransformationCustomizer(ASTTransformation) AST transformation
+ * constructor}. In that case, the transformation is applied once for the whole source unit.
+ *
+ * Unlike a global AST transformation declared in the META-INF/services/org.codehaus.groovy.transform.ASTTransformation
+ * file, which are applied if the file is in the classpath, using this customizer you'll have the choice to apply
+ * your transformation selectively. It can also be useful to debug global AST transformations without having to
+ * package your annotation in a jar file.
+ *
+ * @author Cedric Champeau
+ *
+ * @since 1.8.0
+ * 
+ */
+class ASTTransformationCustomizer extends CompilationCustomizer implements CompilationUnitAware {
+    private final AnnotationNode annotationNode;
+    final ASTTransformation transformation
+
+    protected CompilationUnit compilationUnit;
+    private boolean applied = false; // used for global AST transformations
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * It's assumed that the annotation is not annotated with {@code GroovyASTTransformationClass} and so the
+     * second argument supplies the link to the ASTTransformation class that should be used.
+     * @param transformationAnnotation
+     * @param astTransformationClassName
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, astTransformationClassName, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. It's assumed that the annotation
+     * is not annotated with {@code GroovyASTTransformationClass} and so the second argument supplies the link to
+     * the ASTTransformation class that should be used.
+     * @param transformationAnnotation
+     * @param astTransformationClassName
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
+        this(transformationAnnotation, astTransformationClassName, transformationAnnotation.classLoader)
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * Additionally, you can pass a map of parameters that will be used to parameterize the annotation.
+     * It's assumed that the annotation is not annotated with {@code GroovyASTTransformationClass} and so the
+     * second argument supplies the link to the ASTTransformation class that should be used.
+     * @param transformationAnnotation
+     * @param astTransformationClassName
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, astTransformationClassName, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, astTransformationClassName, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+        setAnnotationParameters(annotationParams)
+    }
+
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, String astTransformationClassName) {
+        this(annotationParams, transformationAnnotation, transformationAnnotation.classLoader)
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * @param transformationAnnotation
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation.
+     * @param transformationAnnotation
+     */
+    ASTTransformationCustomizer(final Class<? extends Annotation> transformationAnnotation) {
+        this(transformationAnnotation, transformationAnnotation.classLoader)
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified transformation.
+     */
+    ASTTransformationCustomizer(final ASTTransformation transformation) {
+        super(findPhase(transformation))
+        this.transformation = transformation
+        this.annotationNode = null
+    }
+
+    /**
+     * Creates an AST transformation customizer using the specified annotation. The transformation classloader can
+     * be used if the transformation class cannot be loaded from the same class loader as the annotation class.
+     * Additionally, you can pass a map of parameters that will be used to parameterize the annotation.
+     * @param transformationAnnotation
+     * @param transformationClassLoader
+     */
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation, ClassLoader transformationClassLoader) {
+        super(findPhase(transformationAnnotation, transformationClassLoader))
+        final Class<ASTTransformation> clazz = findASTTranformationClass(transformationAnnotation, transformationClassLoader)
+        this.transformation = clazz.newInstance()
+        this.annotationNode = new AnnotationNode(ClassHelper.make(transformationAnnotation))
+        setAnnotationParameters(annotationParams)
+    }
+
+    ASTTransformationCustomizer(final Map annotationParams, final Class<? extends Annotation> transformationAnnotation) {
+        this(annotationParams, transformationAnnotation, transformationAnnotation.classLoader)
+    }
+
+    ASTTransformationCustomizer(final Map annotationParams, final ASTTransformation transformation) {
+        this(transformation)
+        setAnnotationParameters(annotationParams)
+    }
+
+    void setCompilationUnit(CompilationUnit unit) {
+        compilationUnit = unit
+    }
+
+    private static Class<ASTTransformation> findASTTranformationClass(Class<? extends Annotation> anAnnotationClass, ClassLoader transformationClassLoader) {
+        final GroovyASTTransformationClass annotation = anAnnotationClass.getAnnotation(GroovyASTTransformationClass)
+        if (annotation==null) throw new IllegalArgumentException("Provided class doesn't look like an AST @interface")
+
+        Class[] classes = annotation.classes()
+        String[] classesAsStrings = annotation.value()
+        if (classes.length+classesAsStrings.length>1) {
+            throw new IllegalArgumentException("AST transformation customizer doesn't support AST transforms with multiple classes")
+        }
+        return classes?classes[0]:Class.forName(classesAsStrings[0], true, transformationClassLoader?:anAnnotationClass.classLoader)
+    }
+
+    private static Class<ASTTransformation> findASTTranformationClass(Class<? extends Annotation> anAnnotationClass, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        return Class.forName(astTransformationClassName, true, transformationClassLoader?:anAnnotationClass.classLoader) as Class<ASTTransformation>
+    }
+
+    private static CompilePhase findPhase(ASTTransformation transformation) {
+        if (transformation==null) throw new IllegalArgumentException("Provided transformation must not be null")
+        final Class<?> clazz = transformation.class
+        final GroovyASTTransformation annotation = clazz.getAnnotation(GroovyASTTransformation)
+        if (annotation==null) throw new IllegalArgumentException("Provided ast transformation is not annotated with "+GroovyASTTransformation.name)
+
+        annotation.phase()
+    }
+
+    private static CompilePhase findPhase(Class<? extends Annotation> annotationClass, ClassLoader transformationClassLoader) {
+        Class<ASTTransformation> clazz = findASTTranformationClass(annotationClass, transformationClassLoader);
+
+        findPhase(clazz.newInstance())
+    }
+
+    private static CompilePhase findPhase(Class<? extends Annotation> annotationClass, String astTransformationClassName, ClassLoader transformationClassLoader) {
+        Class<ASTTransformation> clazz = findASTTranformationClass(annotationClass, astTransformationClassName, transformationClassLoader);
+
+        findPhase(clazz.newInstance())
+    }
+
+    /**
+     * Specify annotation parameters. For example, if the annotation is :
+     * <pre>@Log(value='logger')</pre>
+     * You could create an AST transformation customizer and specify the "value" parameter thanks to this method:
+     * <pre>annotationParameters = [value: 'logger']
+     *
+     * Note that you cannot specify annotation closure values directly. If the annotation you want to add takes
+     * a closure as an argument, you will have to set a {@link ClosureExpression} instead. This can be done by either
+     * creating a custom {@link ClosureExpression} from code, or using the {@link org.codehaus.groovy.ast.builder.AstBuilder}.
+     *
+     * Here is an example :
+     * <pre>
+     *        // add @Contract({distance >= 0 })
+     *        customizer = new ASTTransformationCustomizer(Contract)
+     *        final expression = new AstBuilder().buildFromCode(CompilePhase.CONVERSION) {->
+     *            distance >= 0
+     *        }.expression[0]
+     *        customizer.annotationParameters = [value: expression]</pre>
+     *
+     * @param params the annotation parameters
+     *
+     * @since 1.8.1
+     */
+    public void setAnnotationParameters(Map<String,Object> params) {
+        if (params==null || annotationNode==null) return;
+        params.each { key, value ->
+            if (!annotationNode.classNode.getMethod(key)) {
+                throw new IllegalArgumentException("${annotationNode.classNode.name} does not accept any [$key] parameter")
+            }
+            if (value instanceof Closure) {
+                throw new IllegalArgumentException("Direct usage of closure is not supported by the AST " +
+                "compilation customizer. Please use ClosureExpression instead.")
+            } else if (value instanceof Expression) {
+                // avoid NPEs due to missing source code
+                value.setLineNumber(0)
+                value.setLastLineNumber(0)
+                annotationNode.addMember(key, value)
+            } else if (value instanceof Class) {
+                annotationNode.addMember(key, new ClassExpression(ClassHelper.make(value)))
+            } else if (value instanceof List) {
+                annotationNode.addMember(key, new ListExpression(value.collect {
+                    it instanceof Class ? new ClassExpression(ClassHelper.make(it)) : new ConstantExpression(it)
+                }))
+            } else {
+                annotationNode.addMember(key, new ConstantExpression(value))
+            }
+        }
+    }
+
+    @Override
+    void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+        if (transformation instanceof CompilationUnitAware) {
+            transformation.compilationUnit = compilationUnit
+        }
+        if (annotationNode!=null) {
+            // this is a local ast transformation which is applied on every class node
+            annotationNode.sourcePosition = classNode
+            transformation.visit([annotationNode, classNode] as ASTNode[], source)
+        } else {
+            // this is a global AST transformation
+            if (!applied) transformation.visit(null, source)
+        }
+        applied = true
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/ASTTransformationCustomizerFactory.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/ASTTransformationCustomizerFactory.groovy b/src/main/groovy/ASTTransformationCustomizerFactory.groovy
new file mode 100644
index 0000000..4e4f5be
--- /dev/null
+++ b/src/main/groovy/ASTTransformationCustomizerFactory.groovy
@@ -0,0 +1,60 @@
+/*
+ *  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.control.customizers.builder
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+
+/**
+ * This factory generates an {@link ASTTransformationCustomizer ast transformation customizer}.
+ * <p>
+ * Simple syntax:
+ * <pre>builder.ast(ToString)</pre>
+ * With AST transformation options:
+ * <pre>builder.ast(includeNames:true, ToString)</pre>
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+class ASTTransformationCustomizerFactory extends AbstractFactory {
+
+    @Override
+    @CompileStatic
+    public boolean isLeaf() {
+        true
+    }
+
+    @Override
+    @CompileStatic
+    public boolean onHandleNodeAttributes(final FactoryBuilderSupport builder, final Object node, final Map attributes) {
+        false
+    }
+
+    @Override
+    public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
+        ASTTransformationCustomizer customizer
+        if (attributes) {
+            customizer = new ASTTransformationCustomizer(attributes, value)
+        } else {
+            customizer = new ASTTransformationCustomizer(value)
+        }
+        customizer
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/AstBuilder.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/AstBuilder.groovy b/src/main/groovy/AstBuilder.groovy
new file mode 100644
index 0000000..06d027b
--- /dev/null
+++ b/src/main/groovy/AstBuilder.groovy
@@ -0,0 +1,145 @@
+/*
+ *  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.stmt.BlockStatement
+import org.codehaus.groovy.control.CompilePhase
+
+/**
+ * The AstBuilder provides several ways to build an abstract syntax tree (AST) of Groovy code.
+ *
+ * You can convert a String into AST using the buildFromString method.
+ * You can convert code into AST using the buildFromCode method.
+ * You can use the AST DSL with the buildFromSpec method. 
+ * 
+ * For more information, see the resources on the Groovy wiki pages. 
+ *
+ * @author Hamlet D'Arcy
+ */
+
+public class AstBuilder {
+
+    /**
+     * Builds AST based on the code within the  {@link Closure}  parameter.
+     *
+     * This method <strong>must</strong> be invoked at compile time and never at runtime, because
+     * an ASTTransformation must be run to support it. If you receive an IllegalStateException then
+     * you most likely need to add stronger typing. For instance, this will not work:
+     * <code>
+     *      def builder = new AstBuilder()
+     *      builder.buildFromCode {
+     *             // some code
+     *      }
+     * </code>
+     * While this code will:
+     * <code>
+     *      new AstBuilder().buildFromCode {
+     *             // some code
+     *      }
+     * </code>
+     *
+     * The compiler rewrites buildFromCode invocations into  {@link AstBuilder#buildFromString(CompilePhase, boolean, String)}
+     * invocations. An exception raised during AST generation will show a stack trace from  {@link AstBuilder#buildFromString(CompilePhase, boolean, String)}
+     * and not from  {@link AstBuilder#buildFromCode(CompilePhase, boolean, Closure)} .
+     *
+     * The compiler saves the source code of the closure as a String within the Java class file. The String source
+     * of the closure will be visible and un-obfuscated within the class file. If your Closure parameter contains
+     * sensitive data such as a hard-coded password then that data is free to be seen by anyone with the class file.
+     * Do not store sensitive data within the closure parameter.
+     *
+     * @param phase
+     *      the  {@link CompilePhase}  the AST will be targeted towards. Default is  {@link CompilePhase#CLASS_GENERATION}
+     * @param statementsOnly
+     *      when true, only the script statements are returned. WHen false, you will
+     *      receive back a Script class node also. Default is true.
+     * @param block
+     *      the code that will be converted
+     * @returns a List of  {@link ASTNode} .
+     * @throws IllegalStateException
+     *      this method may not be invoked at runtime. It works via a compile-time transformation
+     *      of the closure source code into a String, which is sent to the  {@link AstBuilder#buildFromString(CompilePhase, boolean, String)}
+     *      method. The buildFromCode() method must be invoked against a strongly typed AstBuilder.
+     */
+    List<ASTNode> buildFromCode(CompilePhase phase = CompilePhase.CLASS_GENERATION, boolean statementsOnly = true, Closure block) {
+        throw new IllegalStateException("""AstBuilder.build(CompilePhase, boolean, Closure):List<ASTNode> should never be called at runtime.
+Are you sure you are using it correctly?
+""")
+    }
+
+
+    /**
+     * Builds AST based on the code within the String parameter.
+     *
+     * @param phase
+     *      the  {@link CompilePhase}  the AST will be targeted towards. Default is  {@link CompilePhase#CLASS_GENERATION}
+     * @param statementsOnly
+     *      when true, only the script statements are returned. WHen false, you will
+     *      receive back a Script class node also. Default is true.
+     * @param source
+     *      The source code String that will be compiled.
+     * @returns a List of  {@link ASTNode} .
+     * @throws IllegalArgumentException
+     *      if source is null or empty
+     */
+    List<ASTNode> buildFromString(CompilePhase phase = CompilePhase.CLASS_GENERATION, boolean statementsOnly = true, String source) {
+        if (!source || "" == source.trim()) throw new IllegalArgumentException("A source must be specified")
+        return new AstStringCompiler().compile(source, phase, statementsOnly);
+    }
+
+    /**
+     * Builds AST based on the code within the String parameter. The parameter is assumed to be 
+     * a code block which is not legal Groovy code. A goto label is affixed to the block, compiled, 
+     * and the resulting BlockStatement wrapper is removed before returning a result. 
+     * @param phase
+     *      the  {@link CompilePhase}  the AST will be targeted towards. Default is  {@link CompilePhase#CLASS_GENERATION}
+     * @param statementsOnly
+     *      when true, only the script statements are returned. WHen false, you will
+     *      receive back a Script class node also. Default is true.
+     * @param source
+     *      The source code String that will be compiled. The string must be a block wrapped in curly braces. 
+     * @returns a List of  {@link ASTNode} .
+     * @throws IllegalArgumentException
+     *      if source is null or empty
+     */
+    private List<ASTNode> buildFromBlock(CompilePhase phase = CompilePhase.CLASS_GENERATION, boolean statementsOnly = true, String source) {
+        if (!source || "" == source.trim()) throw new IllegalArgumentException("A source must be specified")
+        def labelledSource = "__synthesized__label__${System.currentTimeMillis()}__:" + source
+        List<ASTNode> result = new AstStringCompiler().compile(labelledSource, phase, statementsOnly)
+        // find the block statement from the result, and unwrap it from one level.
+        result.collect { node ->
+            if (node instanceof BlockStatement) {
+                ((BlockStatement)node).statements[0] //unwrap the artifact of pre-pending the goto label
+            } else {
+                node
+            }
+        }
+    }
+
+    /**
+     * Builds AST based on the DSL data within the Closure parameter.
+     * @param specification
+     *      the contents to create
+     */
+    List<ASTNode> buildFromSpec(@DelegatesTo(AstSpecificationCompiler) Closure specification) {
+        if (specification == null) throw new IllegalArgumentException('Null: specification')
+        def properties = new AstSpecificationCompiler(specification)
+        return properties.expression
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/AstHelper.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/AstHelper.groovy b/src/main/groovy/AstHelper.groovy
new file mode 100644
index 0000000..206b0df
--- /dev/null
+++ b/src/main/groovy/AstHelper.groovy
@@ -0,0 +1,76 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.ContinueStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.ast.stmt.ThrowStatement
+
+import java.lang.reflect.Modifier
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.declS
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX
+
+/**
+ * Helping to create a few standard AST constructs
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class AstHelper {
+	static ExpressionStatement createVariableDefinition(String variableName, ClassNode variableType, Expression value, boolean variableShouldBeFinal = false ) {
+        def newVariable = varX(variableName, variableType)
+        if (variableShouldBeFinal)
+            newVariable.setModifiers(Modifier.FINAL)
+        (ExpressionStatement) declS(newVariable, value)
+	}
+
+	static ExpressionStatement createVariableAlias(String aliasName, ClassNode variableType, String variableName ) {
+		createVariableDefinition(aliasName, variableType, varX(variableName, variableType))
+	}
+
+    static VariableExpression createVariableReference(Map variableSpec) {
+        varX((String) variableSpec.name, (ClassNode) variableSpec.type)
+    }
+
+    /**
+     * This statement should make the code jump to surrounding while loop's start label
+     * Does not work from within Closures
+     */
+    static Statement recurStatement() {
+        //continue _RECUR_HERE_
+        new ContinueStatement(InWhileLoopWrapper.LOOP_LABEL)
+    }
+
+    /**
+     * This statement will throw exception which will be caught and redirected to jump to surrounding while loop's start label
+     * Also works from within Closures but is a tiny bit slower
+     */
+    static Statement recurByThrowStatement() {
+        // throw InWhileLoopWrapper.LOOP_EXCEPTION
+        new ThrowStatement(propX(classX(InWhileLoopWrapper), 'LOOP_EXCEPTION'))
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/AstSpecificationCompiler.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/AstSpecificationCompiler.groovy b/src/main/groovy/AstSpecificationCompiler.groovy
new file mode 100644
index 0000000..5e607b6
--- /dev/null
+++ b/src/main/groovy/AstSpecificationCompiler.groovy
@@ -0,0 +1,1080 @@
+/*
+ *  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.AnnotationNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.ConstructorNode
+import org.codehaus.groovy.ast.DynamicVariable
+import org.codehaus.groovy.ast.FieldNode
+import org.codehaus.groovy.ast.GenericsType
+import org.codehaus.groovy.ast.ImportNode
+import org.codehaus.groovy.ast.InnerClassNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.MixinNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.PropertyNode
+import org.codehaus.groovy.ast.VariableScope
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression
+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.ConstructorCallExpression
+import org.codehaus.groovy.ast.expr.DeclarationExpression
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression
+import org.codehaus.groovy.ast.expr.Expression
+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.MethodCallExpression
+import org.codehaus.groovy.ast.expr.MethodPointerExpression
+import org.codehaus.groovy.ast.expr.NamedArgumentListExpression
+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.EmptyStatement
+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.Statement
+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.runtime.MethodClosure
+import org.codehaus.groovy.syntax.Token
+import org.codehaus.groovy.syntax.Types
+
+/**
+ * Handles parsing the properties from the closure into values that can be referenced.
+ * 
+ * This object is very stateful and not threadsafe. It accumulates expressions in the 
+ * 'expression' field as they are found and executed within the DSL. 
+ * 
+ * Note: this class consists of many one-line method calls. A better implementation
+ * might be to take a declarative approach and replace the one-liners with map entries. 
+ * 
+ * @author Hamlet D'Arcy
+ */
+class AstSpecificationCompiler implements GroovyInterceptable {
+
+    private final List<ASTNode> expression = []
+
+    /**
+     * Creates the DSL compiler.
+     */
+    AstSpecificationCompiler(@DelegatesTo(AstSpecificationCompiler) Closure spec) {
+        spec.delegate = this
+        spec()
+    }
+
+    /**
+     * Gets the current generated expression.
+     */
+    List<ASTNode> getExpression() {
+        return expression
+    }
+
+    /**
+    * This method takes a List of Classes (a "spec"), and makes sure that the expression field 
+    * contains those classes. It is a safety mechanism to enforce that the DSL is being called
+    * properly. 
+    * 
+    * @param methodName
+    *   the name of the method within the DSL that is being invoked. Used in creating error messages. 
+    * @param spec
+    *   the list of Class objects that the method expects to have in the expression field when invoked.
+    * @return 
+    *   the portions of the expression field that adhere to the spec. 
+    */ 
+    private List<ASTNode> enforceConstraints(String methodName, List<Class> spec) {
+
+        // enforce that the correct # arguments was passed
+        if (spec.size() != expression.size()) {
+            throw new IllegalArgumentException("$methodName could not be invoked. Expected to receive parameters $spec but found ${expression?.collect { it.class }}")
+        }
+
+        // enforce types and collect result
+        (0..(spec.size() - 1)).collect { int it ->
+            def actualClass = expression[it].class
+            def expectedClass = spec[it]
+            if (!expectedClass.isAssignableFrom(actualClass)) {
+                throw new IllegalArgumentException("$methodName could not be invoked. Expected to receive parameters $spec but found ${expression?.collect { it.class }}")
+            }
+            expression[it]
+        }
+    }
+
+    /**
+    * This method helps you take Closure parameters to a method and bundle them into 
+    * constructor calls to a specific ASTNode subtype. 
+    * @param name 
+    *       name of object being constructed, used to create helpful error message. 
+    * @param argBlock
+    *       the actual parameters being specified for the node
+    * @param constructorStatement
+    *       the type specific construction code that will be run
+    */ 
+    private void captureAndCreateNode(String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, Closure constructorStatement) {
+        if (!argBlock) throw new IllegalArgumentException("nodes of type $name require arguments to be specified")
+
+        def oldProps = new ArrayList(expression)
+        expression.clear()
+        new AstSpecificationCompiler(argBlock)
+        def result = constructorStatement(expression) // invoke custom constructor for node
+        expression.clear()
+        expression.addAll(oldProps)
+        expression.add(result)
+    }
+
+    /**
+    * Helper method to convert a DSL invocation into an ASTNode instance. 
+    * 
+    * @param target     
+    *       the class you are going to create
+    * @param typeAlias  
+    *       the DSL keyword that was used to invoke this type
+    * @param ctorArgs   
+    *       a specification of what arguments the constructor expects
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    */ 
+    private void makeNode(Class target, String typeAlias, List<Class<? super ASTNode>> ctorArgs, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            target.newInstance(*enforceConstraints(typeAlias, ctorArgs))
+        }
+    }
+
+    /**
+    * Helper method to convert a DSL invocation with a list of parameters specified 
+    * in a Closure into an ASTNode instance. 
+    * 
+    * @param target     
+    *       the class you are going to create
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    */ 
+    private void makeNodeFromList(Class target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        //todo: add better error handling?
+        captureAndCreateNode(target.simpleName, argBlock) {
+            target.newInstance(new ArrayList(expression))
+        }
+    }
+
+    /**
+    * Helper method to convert a DSL invocation with a String parameter into a List of ASTNode instances. 
+    * 
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    * @param input   
+    *       the single String argument used during invocation
+    */ 
+    private void makeListOfNodes(@DelegatesTo(AstSpecificationCompiler) Closure argBlock, String input) {
+        captureAndCreateNode(input, argBlock) {
+            new ArrayList(expression)
+        }
+    }
+
+    /**
+    * Helper method to convert a DSL invocation with a String parameter into an Array of ASTNode instances. 
+    * 
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    * @param target   
+    *       the target type
+    */ 
+    private void makeArrayOfNodes(Object target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            expression.toArray(target)
+        }
+    }
+    
+    /**
+    * Helper method to convert a DSL invocation into an ASTNode instance when a Class parameter is specified. 
+    * 
+    * @param target     
+    *       the class you are going to create
+    * @param alias  
+    *       the DSL keyword that was used to invoke this type
+    * @param spec
+    *       the list of Classes that you expect to be present as parameters
+    * @param argBlock   
+    *       the single closure argument used during invocation
+    * @param type 
+    *       a type parameter
+    */ 
+    private void makeNodeWithClassParameter(Class target, String alias, List<Class> spec, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, Class type) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            expression.add(0, ClassHelper.make(type))
+            target.newInstance(*enforceConstraints(alias, spec))
+        }
+    }
+
+    private void makeNodeWithStringParameter(Class target, String alias, List<Class> spec, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, String text) {
+        captureAndCreateNode(target.class.simpleName, argBlock) {
+            expression.add(0, text)
+            target.newInstance(*enforceConstraints(alias, spec))
+        }
+    }
+
+    /**
+     * Creates a CastExpression.
+     */
+    void cast(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeWithClassParameter(CastExpression, 'cast', [ClassNode, Expression], argBlock, type)
+    }
+
+    /**
+     * Creates an ConstructorCallExpression.
+     */
+    void constructorCall(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeWithClassParameter(ConstructorCallExpression, 'constructorCall', [ClassNode, Expression], argBlock, type)
+    }
+
+    /**
+     * Creates a MethodCallExpression.
+     */
+    void methodCall(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(MethodCallExpression, 'methodCall', [Expression, Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates an AnnotationConstantExpression.
+     */
+    void annotationConstant(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(AnnotationConstantExpression, 'annotationConstant', [AnnotationNode], argBlock)
+    }
+
+    /**
+     * Creates a PostfixExpression.
+     */
+    void postfix(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(PostfixExpression, 'postfix', [Expression, Token], argBlock)
+    }
+
+    /**
+     * Creates a FieldExpression.
+     */
+    void field(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(FieldExpression, 'field', [FieldNode], argBlock)
+    }
+
+    /**
+     * Creates a MapExpression.
+     */
+    void map(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(MapExpression, argBlock)
+    }
+
+    /**
+     * Creates a TupleExpression.
+     */
+    void tuple(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(TupleExpression, argBlock)
+    }
+
+    /**
+     * Creates a MapEntryExpression.
+     */
+    void mapEntry(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(MapEntryExpression, 'mapEntry', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a gString.
+     */
+    void gString(String verbatimText, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeWithStringParameter(GStringExpression, 'gString', [String, List, List], argBlock, verbatimText)
+    }
+
+
+    /**
+     * Creates a methodPointer.
+     */
+
+    void methodPointer(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(MethodPointerExpression, 'methodPointer', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a property.
+     */
+    void property(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(PropertyExpression, 'property', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a RangeExpression.
+     */
+    void range(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(RangeExpression, 'range', [Expression, Expression, Boolean], argBlock)
+    }
+
+    /**
+     * Creates EmptyStatement.
+     */
+    void empty() {
+        expression << EmptyStatement.INSTANCE
+    }
+
+    /**
+     * Creates a label.
+     */
+    void label(String label) {
+        expression << label
+    }
+
+    /**
+     * Creates an ImportNode.
+     */
+    void importNode(Class target, String alias = null) {
+        expression << new ImportNode(ClassHelper.make(target), alias)
+    }
+
+    /**
+     * Creates a CatchStatement.
+     */
+    void catchStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(CatchStatement, 'catchStatement', [Parameter, Statement], argBlock)
+    }
+
+    /**
+     * Creates a ThrowStatement.
+     */
+    void throwStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ThrowStatement, 'throwStatement', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a SynchronizedStatement.
+     */
+    void synchronizedStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(SynchronizedStatement, 'synchronizedStatement', [Expression, Statement], argBlock)
+    }
+
+    /**
+     * Creates a ReturnStatement.
+     */
+    void returnStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ReturnStatement, 'returnStatement', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a TernaryExpression.
+     */
+
+    private void ternary(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(TernaryExpression, 'ternary', [BooleanExpression, Expression, Expression], argBlock)
+    }
+
+
+    /**
+     * Creates an ElvisOperatorExpression.
+     */
+    void elvisOperator(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ElvisOperatorExpression, 'elvisOperator', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates a BreakStatement.
+     */
+    void breakStatement(String label = null) {
+        if (label) {
+            expression << new BreakStatement(label)
+        } else {
+            expression << new BreakStatement()
+        }
+    }
+
+    /**
+     * Creates a ContinueStatement.
+     */
+    void continueStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (!argBlock) {
+            expression << new ContinueStatement()
+        } else {
+            makeNode(ContinueStatement, 'continueStatement', [String], argBlock)
+        }
+    }
+
+    /**
+     * Create a CaseStatement.
+     */
+    void caseStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(CaseStatement, 'caseStatement', [Expression, Statement], argBlock)
+    }
+
+    /**
+     * Creates a BlockStatement.
+     */
+    void defaultCase(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        block(argBlock) // same as arg block
+    }
+
+    /**
+     * Creates a PrefixExpression.
+     */
+    void prefix(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(PrefixExpression, 'prefix', [Token, Expression], argBlock)
+    }
+
+    /**
+     * Creates a NotExpression.
+     */
+    void not(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(NotExpression, 'not', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a DynamicVariable.
+     */
+    void dynamicVariable(String variable, boolean isStatic = false) {
+        expression << new DynamicVariable(variable, isStatic)
+    }
+
+    /**
+     * Creates a ClassNode[].
+     */
+    void exceptions(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeArrayOfNodes([] as ClassNode[], argBlock)
+    }
+
+    /**
+     * Designates a list of AnnotationNodes.
+     */
+    void annotations(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<AnnotationNode>")
+    }
+
+
+    /**
+     * Designates a list of MethodNodes.
+     */
+    void methods(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<MethodNode>")
+    }
+
+    /**
+     * Designates a list of ConstructorNodes.
+     */
+    void constructors(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<ConstructorNode>")
+    }
+
+    /**
+     * Designates a list of {@code PropertyNode}s.
+     */
+    void properties(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<PropertyNode>")
+    }
+
+    /**
+     * Designates a list of {@code FieldNode}s.
+     */
+    void fields(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<FieldNode>")
+    }
+
+    /**
+     * Designates a list of ConstantExpressions.
+     */
+
+    void strings(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<ConstantExpression>")
+    }
+
+    /**
+     * Designates a list of Expressions.
+     */
+
+    void values(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<Expression>")
+    }
+
+    /**
+     * Creates a boolean value.
+     */
+    void inclusive(boolean value) {
+        expression << value
+    }
+
+    /**
+     * Creates a ConstantExpression.
+     */
+    void constant(Object value) {
+        expression << new ConstantExpression(value)
+    }
+
+    /**
+     * Creates an IfStatement.
+     */
+    void ifStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(IfStatement, 'ifStatement', [BooleanExpression, Statement, Statement], argBlock)
+    }
+
+    /**
+     * Creates a SpreadExpression.
+     */
+    void spread(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(SpreadExpression, 'spread', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a SpreadMapExpression.
+     */
+    void spreadMap(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(SpreadMapExpression, 'spreadMap', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a WhileStatement.
+     */
+    void whileStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(WhileStatement, 'whileStatement', [BooleanExpression, Statement], argBlock)
+    }
+
+    /**
+     * Create a ForStatement.
+     */
+    void forStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ForStatement, 'forStatement', [Parameter, Expression, Statement], argBlock)
+    }
+
+    /**
+     * Creates a ClosureListExpression.
+     */
+    void closureList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(ClosureListExpression, argBlock)
+    }
+
+    /**
+     * Creates a DeclarationExpression.
+     */
+    void declaration(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(DeclarationExpression, 'declaration', [Expression, Token, Expression], argBlock)
+    }
+
+    /**
+     * Creates a ListExpression.
+     */
+    void list(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(ListExpression, argBlock)
+    }
+
+    /**
+     * Creates a BitwiseNegationExpression.
+     */
+    void bitwiseNegation(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(BitwiseNegationExpression, 'bitwiseNegation', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a ClosureExpression.
+     */
+    void closure(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ClosureExpression, 'closure', [Parameter[], Statement], argBlock)
+    }
+
+    /**
+     * Creates a BooleanExpression.
+     */
+    void booleanExpression(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(BooleanExpression, 'booleanExpression', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a BinaryExpression.
+     */
+    void binary(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(BinaryExpression, 'binary', [Expression, Token, Expression], argBlock)
+    }
+
+    /**
+     * Creates a UnaryPlusExpression.
+     */
+    void unaryPlus(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(UnaryPlusExpression, 'unaryPlus', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a ClassExpression.
+     */
+    void classExpression(Class type) {
+        expression << new ClassExpression(ClassHelper.make(type))
+    }
+
+    /**
+     * Creates a UnaryMinusExpression
+     */
+    void unaryMinus(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(UnaryMinusExpression, 'unaryMinus', [Expression], argBlock)
+    }
+
+    /**
+     * Creates an AttributeExpression.
+     */
+    void attribute(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(AttributeExpression, 'attribute', [Expression, Expression], argBlock)
+    }
+
+    /**
+     * Creates an ExpressionStatement.
+     */
+    void expression(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNode(ExpressionStatement, 'expression', [Expression], argBlock)
+    }
+
+    /**
+     * Creates a NamedArgumentListExpression.
+     */
+    void namedArgumentList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeNodeFromList(NamedArgumentListExpression, argBlock)
+    }
+
+    /**
+     * Creates a ClassNode[].
+     */
+    void interfaces(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<ClassNode>")
+    }
+
+    /**
+     * Creates a MixinNode[].
+     */
+    void mixins(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<MixinNode>")
+    }
+
+    /**
+     * Creates a GenericsTypes[].
+     */
+    void genericsTypes(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<GenericsTypes>")
+    }
+
+    /**
+     * Creates a ClassNode.
+     */
+    void classNode(Class target) {
+        expression << ClassHelper.make(target, false)
+    }
+
+    /**
+     * Creates a Parameter[].
+     */
+    void parameters(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeArrayOfNodes([] as Parameter[], argBlock)
+    }
+
+    /**
+     * Creates a BlockStatement.
+     */
+    void block(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("BlockStatement", argBlock) {
+            return new BlockStatement(new ArrayList(expression), new VariableScope())
+        }
+    }
+
+    /**
+     * Creates a Parameter.
+     */
+    void parameter(Map<String, Class> args, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (!args) throw new IllegalArgumentException()
+        if (args.size() > 1) throw new IllegalArgumentException()
+
+        //todo: add better error handling?
+        if (argBlock) {
+            args.each {name, type ->
+                captureAndCreateNode("Parameter", argBlock) {
+                    new Parameter(ClassHelper.make(type), name, expression[0])
+                }
+            }
+        } else {
+            args.each {name, type ->
+                expression << (new Parameter(ClassHelper.make(type), name))
+            }
+        }
+    }
+
+    /**
+     * Creates an ArrayExpression.
+     */
+    void array(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("ArrayExpression", argBlock) {
+            new ArrayExpression(ClassHelper.make(type), new ArrayList(expression))
+        }
+    }
+
+    /**
+     * Creates a GenericsType.
+     */
+    void genericsType(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (argBlock) {
+            captureAndCreateNode("GenericsType", argBlock) {
+                new GenericsType(ClassHelper.make(type), expression[0] as ClassNode[], expression[1])
+            }
+        } else {
+            expression << new GenericsType(ClassHelper.make(type))
+        }
+    }
+
+    /**
+     * Creates a list of upperBound ClassNodes.
+     */
+    void upperBound(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, 'List<ClassNode>')
+    }
+
+    /**
+     * Create lowerBound ClassNode.
+     */
+    void lowerBound(Class target) {
+        expression << ClassHelper.make(target)
+    }
+
+    /**
+     * Creates a 2 element list of name and Annotation. Used with Annotation Members.
+     */
+    void member(String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("Annotation Member", argBlock) {
+            [name, expression[0]]
+        }
+    }
+
+    /**
+     * Creates an ArgumentListExpression.
+     */
+    void argumentList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        if (!argBlock) {
+            expression << new ArgumentListExpression()
+        } else {
+            makeNodeFromList(ArgumentListExpression, argBlock)
+        }
+    }
+
+    /**
+     * Creates an AnnotationNode.
+     */
+    void annotation(Class target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
+        if (argBlock) {
+            //todo: add better error handling
+            captureAndCreateNode("ArgumentListExpression", argBlock) {
+                def node = new AnnotationNode(ClassHelper.make(target))
+                expression?.each {
+                    node.addMember(it[0], it[1])
+                }
+                node
+            }
+        } else {
+            expression << new AnnotationNode(ClassHelper.make(target))
+        }
+    }
+
+    /**
+     * Creates a MixinNode.
+     */
+    void mixin(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("AttributeExpression", argBlock) {
+            if (expression.size() > 1) {
+                new MixinNode(name, modifiers, expression[0], new ArrayList(expression[1]) as ClassNode[])
+            } else {
+                new MixinNode(name, modifiers, expression[0])
+            }
+        }
+    }
+
+    /**
+     * Creates a ClassNode
+     */
+    void classNode(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("ClassNode", argBlock) {
+            def result = new ClassNode(name, modifiers,
+                    expression[0],
+                    new ArrayList(expression[1]) as ClassNode[],
+                    new ArrayList(expression[2]) as MixinNode[]
+            )
+            while (expression.size() > 3) {
+                if (!List.isAssignableFrom(expression[3].getClass())) {
+                    throw new IllegalArgumentException("Expecting to find list of additional items instead found: " + expression[3].getClass())
+                }
+                if (expression[3].size() > 0) {
+                    def clazz = expression[3][0].getClass()
+                    switch(clazz) {
+                        case GenericsType:
+                            result.setGenericsTypes(new ArrayList(expression[3]) as GenericsType[])
+                            break
+                        case MethodNode:
+                            expression[3].each{ result.addMethod(it) }
+                            break
+                        case ConstructorNode:
+                            expression[3].each{ result.addConstructor(it) }
+                            break
+                        case PropertyNode:
+                            expression[3].each{
+                                it.field.owner = result
+                                result.addProperty(it)
+                            }
+                            break
+                        case FieldNode:
+                            expression[3].each{
+                                it.owner = result
+                                result.addField(it)
+                            }
+                            break
+                        case AnnotationNode:
+                            result.addAnnotations(new ArrayList(expression[3]))
+                            break
+                        default:
+                            throw new IllegalArgumentException("Unexpected item found in ClassNode spec. Expecting [Field|Method|Property|Constructor|Annotation|GenericsType] but found: $clazz.name")
+                    }
+                }
+                expression.remove(3)
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates an AssertStatement.
+     */
+    void assertStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("AssertStatement", argBlock) {
+            if (expression.size() < 2) {
+                new AssertStatement(*enforceConstraints('assertStatement', [BooleanExpression]))
+            } else {
+                new AssertStatement(*enforceConstraints('assertStatement', [BooleanExpression, Expression]))
+            }
+        }
+    }
+
+    /**
+     * Creates a TryCatchStatement.
+     */
+    void tryCatch(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("TryCatchStatement", argBlock) {
+            def result = new TryCatchStatement(expression[0], expression[1])
+            def catchStatements = expression.tail().tail()
+            catchStatements.each {statement -> result.addCatch(statement) }
+            return result
+        }
+    }
+
+    /**
+     * Creates a VariableExpression.
+     */
+    void variable(String variable) {
+        expression << new VariableExpression(variable)
+    }
+
+    /**
+     * Creates a MethodNode.
+     */
+    void method(String name, int modifiers, Class returnType, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("MethodNode", argBlock) {
+            //todo: enforce contract
+            def result = new MethodNode(name, modifiers, ClassHelper.make(returnType), expression[0], expression[1], expression[2])
+            if (expression[3]) {
+                result.addAnnotations(new ArrayList(expression[3]))
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates a token.
+     */
+    void token(String value) {
+        if (value == null) throw new IllegalArgumentException("Null: value")
+
+        def tokenID = Types.lookupKeyword(value)
+        if (tokenID == Types.UNKNOWN) {
+            tokenID = Types.lookupSymbol(value)
+        }
+        if (tokenID == Types.UNKNOWN) throw new IllegalArgumentException("could not find token for $value")
+
+        expression << new Token(tokenID, value, -1, -1)
+    }
+
+    /**
+     * Creates a RangeExpression.
+     */
+    void range(Range range) {
+        if (range == null) throw new IllegalArgumentException('Null: range')
+        expression << new RangeExpression(new ConstantExpression(range.getFrom()), new ConstantExpression(range.getTo()), true) //default is inclusive
+    }
+
+    /**
+     * Creates a SwitchStatement.
+     */
+    void switchStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("SwitchStatement", argBlock) {
+            def switchExpression = expression.head()
+            def caseStatements = expression.tail().tail()
+            def defaultExpression = expression.tail().head()
+            new SwitchStatement(switchExpression, caseStatements, defaultExpression)
+        }
+    }
+
+    /**
+     * Creates a mapEntry.
+     */
+    void mapEntry(Map map) {
+        map.entrySet().each {
+            expression << new MapEntryExpression(
+                    new ConstantExpression(it.key),
+                    new ConstantExpression(it.value))
+        }
+    }
+
+    //
+    // todo: these methods can still be reduced smaller
+    //
+
+    /**
+     * Creates a FieldNode.
+     */
+    void fieldNode(String name, int modifiers, Class type, Class owner, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("FieldNode", argBlock) {
+            def annotations = null
+            if (expression.size() > 1) {
+                annotations = expression[1]
+                expression.remove(1)
+            }
+            expression.add(0, ClassHelper.make(owner))
+            expression.add(0, ClassHelper.make(type))
+            expression.add(0, modifiers)
+            expression.add(0, name)
+            def result = new FieldNode(*enforceConstraints('fieldNode', [String, Integer, ClassNode, ClassNode, Expression]))
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates an inner class.
+     */
+    void innerClass(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("InnerClassNode", argBlock) {
+            //todo: enforce contract
+            new InnerClassNode(
+                    expression[0],
+                    name,
+                    modifiers,
+                    expression[1],
+                    new ArrayList(expression[2]) as ClassNode[],
+                    new ArrayList(expression[3]) as MixinNode[])
+        }
+    }
+
+    /**
+     * Creates a PropertyNode.
+     */
+    void propertyNode(String name, int modifiers, Class type, Class owner, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        //todo: improve error handling?
+        captureAndCreateNode("PropertyNode", argBlock) {
+            def annotations = null
+            // check if the last expression looks like annotations
+            if (List.isAssignableFrom(expression[-1].getClass())) {
+                annotations = expression[-1]
+                expression.remove(expression.size() - 1)
+            }
+            def result = new PropertyNode(name, modifiers, ClassHelper.make(type), ClassHelper.make(owner),
+                    expression[0],  // initial value (possibly null)
+                    expression[1],  // getter block (possibly null)
+                    expression[2])  // setter block (possibly null)
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
+        }
+    }
+
+    /**
+     * Creates a StaticMethodCallExpression.
+     */
+    void staticMethodCall(Class target, String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("StaticMethodCallExpression", argBlock) {
+            expression.add(0, name)
+            expression.add(0, ClassHelper.make(target))
+            new StaticMethodCallExpression(*enforceConstraints('staticMethodCall', [ClassNode, String, Expression]))
+        }
+    }
+
+    /**
+     * Creates a StaticMethodCallExpression.
+     */
+    void staticMethodCall(MethodClosure target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("StaticMethodCallExpression", argBlock) {
+            expression.add(0, target.method)
+            expression.add(0, ClassHelper.makeWithoutCaching(target.owner.class, false))
+            new StaticMethodCallExpression(*enforceConstraints('staticMethodCall', [ClassNode, String, Expression]))
+        }
+    }
+
+    /**
+     * Creates a ConstructorNode.
+     */
+    void constructor(int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        captureAndCreateNode("ConstructorNode", argBlock) {
+            def annotations = null
+            if (expression.size() > 3) {
+                annotations = expression[3]
+                expression.remove(3)
+            }
+            expression.add(0, modifiers)
+            def result = new ConstructorNode(*enforceConstraints('constructor', [Integer, Parameter[], ClassNode[], Statement]))
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/AstStringCompiler.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/AstStringCompiler.groovy b/src/main/groovy/AstStringCompiler.groovy
new file mode 100644
index 0000000..497c125
--- /dev/null
+++ b/src/main/groovy/AstStringCompiler.groovy
@@ -0,0 +1,63 @@
+/*
+ *  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 groovy.transform.PackageScope
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.ModuleNode
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.CompilerConfiguration
+
+/**
+ * This class handles converting Strings to ASTNode lists.
+ *
+ * @author Hamlet D'Arcy
+ */
+@PackageScope class AstStringCompiler {
+    
+    /**
+     * Performs the String source to {@link List} of {@link ASTNode}.
+     *
+     * @param script
+     *      a Groovy script in String form
+     * @param compilePhase
+     *      the int based CompilePhase to compile it to.
+     * @param statementsOnly
+     */
+    List<ASTNode> compile(String script, CompilePhase compilePhase, boolean statementsOnly) {
+        def scriptClassName = "script" + System.currentTimeMillis()
+        GroovyClassLoader classLoader = new GroovyClassLoader()
+        GroovyCodeSource codeSource = new GroovyCodeSource(script, scriptClassName + ".groovy", "/groovy/script")
+        CompilationUnit cu = new CompilationUnit(CompilerConfiguration.DEFAULT, codeSource.codeSource, classLoader)
+        cu.addSource(codeSource.getName(), script);
+        cu.compile(compilePhase.getPhaseNumber())
+        // collect all the ASTNodes into the result, possibly ignoring the script body if desired
+        return cu.ast.modules.inject([]) {List acc, ModuleNode node ->
+            if (node.statementBlock) acc.add(node.statementBlock)
+            node.classes?.each {
+                if (!(it.name == scriptClassName && statementsOnly)) {
+                    acc << it
+                }
+            }
+            acc
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/CollectRecursiveCalls.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/CollectRecursiveCalls.groovy b/src/main/groovy/CollectRecursiveCalls.groovy
new file mode 100644
index 0000000..2c7e6de
--- /dev/null
+++ b/src/main/groovy/CollectRecursiveCalls.groovy
@@ -0,0 +1,62 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.CodeVisitorSupport
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+
+/**
+ * Collect all recursive calls within method
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class CollectRecursiveCalls extends CodeVisitorSupport {
+	MethodNode method
+	List<Expression> recursiveCalls = []
+
+	public void visitMethodCallExpression(MethodCallExpression call) {
+		if (isRecursive(call)) {
+			recursiveCalls << call
+		}
+        super.visitMethodCallExpression(call)
+    }
+
+	public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
+		if (isRecursive(call)) {
+            recursiveCalls << call
+        }
+		super.visitStaticMethodCallExpression(call)
+	}
+	
+	private boolean isRecursive(call) {
+		new RecursivenessTester().isRecursive(method: method, call: call)
+	}
+	
+	synchronized List<Expression> collect(MethodNode method) {
+		recursiveCalls.clear()
+		this.method = method
+		this.method.code.visit(this)
+		recursiveCalls
+	}
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java
new file mode 100644
index 0000000..37a105f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java
@@ -0,0 +1,3269 @@
+/*
+ *  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.antlr;
+
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.TokenStreamRecognitionException;
+import antlr.collections.AST;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.antlr.treewalker.CompositeVisitor;
+import org.codehaus.groovy.antlr.treewalker.MindMapPrinter;
+import org.codehaus.groovy.antlr.treewalker.NodeAsHTMLPrinter;
+import org.codehaus.groovy.antlr.treewalker.PreOrderTraversal;
+import org.codehaus.groovy.antlr.treewalker.SourceCodeTraversal;
+import org.codehaus.groovy.antlr.treewalker.SourcePrinter;
+import org.codehaus.groovy.antlr.treewalker.Visitor;
+import org.codehaus.groovy.antlr.treewalker.VisitorAdapter;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.EnumConstantClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.MixinNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+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.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+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.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.MethodPointerExpression;
+import org.codehaus.groovy.ast.expr.NamedArgumentListExpression;
+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.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.EmptyStatement;
+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.Statement;
+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.control.CompilationFailedException;
+import org.codehaus.groovy.control.ParserPlugin;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.XStreamUtils;
+import org.codehaus.groovy.syntax.ASTHelper;
+import org.codehaus.groovy.syntax.Numbers;
+import org.codehaus.groovy.syntax.ParserException;
+import org.codehaus.groovy.syntax.Reduction;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.objectweb.asm.Opcodes;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A parser plugin which adapts the JSR Antlr Parser to the Groovy runtime
+ *
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ */
+public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, GroovyTokenTypes {
+
+    private static class AnonymousInnerClassCarrier extends Expression {
+        ClassNode innerClass;
+
+        public Expression transformExpression(ExpressionTransformer transformer) {
+            return null;
+        }
+
+        @Override
+        public void setSourcePosition(final ASTNode node) {
+            super.setSourcePosition(node);
+            innerClass.setSourcePosition(node);
+        }
+
+        @Override
+        public void setColumnNumber(final int columnNumber) {
+            super.setColumnNumber(columnNumber);
+            innerClass.setColumnNumber(columnNumber);
+        }
+
+        @Override
+        public void setLineNumber(final int lineNumber) {
+            super.setLineNumber(lineNumber);
+            innerClass.setLineNumber(lineNumber);
+        }
+
+        @Override
+        public void setLastColumnNumber(final int columnNumber) {
+            super.setLastColumnNumber(columnNumber);
+            innerClass.setLastColumnNumber(columnNumber);
+        }
+
+        @Override
+        public void setLastLineNumber(final int lineNumber) {
+            super.setLastLineNumber(lineNumber);
+            innerClass.setLastLineNumber(lineNumber);
+        }
+    }
+
+    protected AST ast;
+    private ClassNode classNode;
+    private MethodNode methodNode;
+    private String[] tokenNames;
+    private int innerClassCounter = 1;
+    private boolean enumConstantBeingDef = false;
+    private boolean forStatementBeingDef = false;
+    private boolean annotationBeingDef = false;
+    private boolean firstParamIsVarArg = false;
+    private boolean firstParam = false;
+
+    public /*final*/ Reduction parseCST(final SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
+        final SourceBuffer sourceBuffer = new SourceBuffer();
+        transformCSTIntoAST(sourceUnit, reader, sourceBuffer);
+        processAST();
+        return outputAST(sourceUnit, sourceBuffer);
+    }
+
+    protected void transformCSTIntoAST(SourceUnit sourceUnit, Reader reader, SourceBuffer sourceBuffer) throws CompilationFailedException {
+        ast = null;
+
+        setController(sourceUnit);
+
+        // TODO find a way to inject any GroovyLexer/GroovyRecognizer
+
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(reader, sourceBuffer);
+        UnicodeLexerSharedInputState inputState = new UnicodeLexerSharedInputState(unicodeReader);
+        GroovyLexer lexer = new GroovyLexer(inputState);
+        unicodeReader.setLexer(lexer);
+        GroovyRecognizer parser = GroovyRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+        tokenNames = parser.getTokenNames();
+        parser.setFilename(sourceUnit.getName());
+
+        // start parsing at the compilationUnit rule
+        try {
+            parser.compilationUnit();
+        }
+        catch (TokenStreamRecognitionException tsre) {
+            RecognitionException e = tsre.recog;
+            SyntaxException se = new SyntaxException(e.getMessage(), e, e.getLine(), e.getColumn());
+            se.setFatal(true);
+            sourceUnit.addError(se);
+        }
+        catch (RecognitionException e) {
+            SyntaxException se = new SyntaxException(e.getMessage(), e, e.getLine(), e.getColumn());
+            se.setFatal(true);
+            sourceUnit.addError(se);
+        }
+        catch (TokenStreamException e) {
+            sourceUnit.addException(e);
+        }
+
+        ast = parser.getAST();
+    }
+
+    protected void processAST() {
+        AntlrASTProcessor snippets = new AntlrASTProcessSnippets();
+        ast = snippets.process(ast);
+    }
+
+    public Reduction outputAST(final SourceUnit sourceUnit, final SourceBuffer sourceBuffer) {
+        AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                outputASTInVariousFormsIfNeeded(sourceUnit, sourceBuffer);
+                return null;
+            }
+        });
+
+        return null; //new Reduction(Tpken.EOF);
+    }
+
+    private void outputASTInVariousFormsIfNeeded(SourceUnit sourceUnit, SourceBuffer sourceBuffer) {
+        // straight xstream output of AST
+        String formatProp = System.getProperty("ANTLR.AST".toLowerCase()); // uppercase to hide from jarjar
+
+        if ("xml".equals(formatProp)) {
+            saveAsXML(sourceUnit.getName(), ast);
+        }
+
+        // 'pretty printer' output of AST
+        if ("groovy".equals(formatProp)) {
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".pretty.groovy"));
+                Visitor visitor = new SourcePrinter(out, tokenNames);
+                AntlrASTProcessor treewalker = new SourceCodeTraversal(visitor);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + sourceUnit.getName() + ".pretty.groovy");
+            }
+        }
+
+        // output AST in format suitable for opening in http://freemind.sourceforge.net
+        // which is a really nice way of seeing the AST, folding nodes etc
+        if ("mindmap".equals(formatProp)) {
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".mm"));
+                Visitor visitor = new MindMapPrinter(out, tokenNames);
+                AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + sourceUnit.getName() + ".mm");
+            }
+        }
+
+        // include original line/col info and source code on the mindmap output
+        if ("extendedMindmap".equals(formatProp)) {
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".mm"));
+                Visitor visitor = new MindMapPrinter(out, tokenNames, sourceBuffer);
+                AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + sourceUnit.getName() + ".mm");
+            }
+        }
+
+        // html output of AST
+        if ("html".equals(formatProp)) {
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(sourceUnit.getName() + ".html"));
+                List<VisitorAdapter> v = new ArrayList<VisitorAdapter>();
+                v.add(new NodeAsHTMLPrinter(out, tokenNames));
+                v.add(new SourcePrinter(out, tokenNames));
+                Visitor visitors = new CompositeVisitor(v);
+                AntlrASTProcessor treewalker = new SourceCodeTraversal(visitors);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + sourceUnit.getName() + ".html");
+            }
+        }
+    }
+
+    private static void saveAsXML(String name, AST ast) {
+        XStreamUtils.serialize(name+".antlr", ast);
+    }
+
+    public ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException {
+        setClassLoader(classLoader);
+        makeModule();
+        try {
+            convertGroovy(ast);
+            if (output.getStatementBlock().isEmpty() && output.getMethods().isEmpty() && output.getClasses().isEmpty()) {
+                output.addStatement(ReturnStatement.RETURN_NULL_OR_VOID);
+            }
+
+            // set the script source position
+
+            ClassNode scriptClassNode = output.getScriptClassDummy();
+            if (scriptClassNode != null) {
+                List<Statement> statements = output.getStatementBlock().getStatements();
+                if (!statements.isEmpty()) {
+                    Statement firstStatement = statements.get(0);
+                    Statement lastStatement = statements.get(statements.size() - 1);
+
+                    scriptClassNode.setSourcePosition(firstStatement);
+                    scriptClassNode.setLastColumnNumber(lastStatement.getLastColumnNumber());
+                    scriptClassNode.setLastLineNumber(lastStatement.getLastLineNumber());
+                }
+            }
+        }
+        catch (ASTRuntimeException e) {
+            throw new ASTParserException(e.getMessage() + ". File: " + sourceUnit.getName(), e);
+        }
+        return output;
+    }
+
+    /**
+     * Converts the Antlr AST to the Groovy AST
+     */
+    protected void convertGroovy(AST node) {
+        while (node != null) {
+            int type = node.getType();
+            switch (type) {
+                case PACKAGE_DEF:
+                    packageDef(node);
+                    break;
+
+                case STATIC_IMPORT:
+                case IMPORT:
+                    importDef(node);
+                    break;
+
+                case TRAIT_DEF:
+                case CLASS_DEF:
+                    classDef(node);
+                    break;
+
+                case INTERFACE_DEF:
+                    interfaceDef(node);
+                    break;
+
+                case METHOD_DEF:
+                    methodDef(node);
+                    break;
+
+                case ENUM_DEF:
+                    enumDef(node);
+                    break;
+
+                case ANNOTATION_DEF:
+                    annotationDef(node);
+                    break;
+
+                default: {
+                    Statement statement = statement(node);
+                    output.addStatement(statement);
+                }
+            }
+            node = node.getNextSibling();
+        }
+    }
+
+    // Top level control structures
+    //-------------------------------------------------------------------------
+
+    protected void packageDef(AST packageDef) {
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        AST node = packageDef.getFirstChild();
+        if (isType(ANNOTATIONS, node)) {
+            processAnnotations(annotations, node);
+            node = node.getNextSibling();
+        }
+        String name = qualifiedName(node);
+        // TODO should we check package node doesn't already exist? conflict?
+        PackageNode packageNode = setPackage(name, annotations);
+        configureAST(packageNode, packageDef);
+    }
+
+    protected void importDef(AST importNode) {
+        try {
+            // GROOVY-6094
+            output.putNodeMetaData(ImportNode.class, ImportNode.class);
+
+            boolean isStatic = importNode.getType() == STATIC_IMPORT;
+            List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+
+            AST node = importNode.getFirstChild();
+            if (isType(ANNOTATIONS, node)) {
+                processAnnotations(annotations, node);
+                node = node.getNextSibling();
+            }
+
+            String alias = null;
+            if (isType(LITERAL_as, node)) {
+                //import is like "import Foo as Bar"
+                node = node.getFirstChild();
+                AST aliasNode = node.getNextSibling();
+                alias = identifier(aliasNode);
+            }
+
+            if (node.getNumberOfChildren() == 0) {
+                String name = identifier(node);
+                // import is like  "import Foo"
+                ClassNode type = ClassHelper.make(name);
+                configureAST(type, importNode);
+                addImport(type, name, alias, annotations);
+                return;
+            }
+
+            AST packageNode = node.getFirstChild();
+            String packageName = qualifiedName(packageNode);
+            AST nameNode = packageNode.getNextSibling();
+            if (isType(STAR, nameNode)) {
+                if (isStatic) {
+                    // import is like "import static foo.Bar.*"
+                    // packageName is actually a className in this case
+                    ClassNode type = ClassHelper.make(packageName);
+                    configureAST(type, importNode);
+                    addStaticStarImport(type, packageName, annotations);
+                } else {
+                    // import is like "import foo.*"
+                    addStarImport(packageName, annotations);
+                }
+
+                if (alias != null) throw new GroovyBugError(
+                        "imports like 'import foo.* as Bar' are not " +
+                                "supported and should be caught by the grammar");
+            } else {
+                String name = identifier(nameNode);
+                if (isStatic) {
+                    // import is like "import static foo.Bar.method"
+                    // packageName is really class name in this case
+                    ClassNode type = ClassHelper.make(packageName);
+                    configureAST(type, importNode);
+                    addStaticImport(type, name, alias, annotations);
+                } else {
+                    // import is like "import foo.Bar"
+                    ClassNode type = ClassHelper.make(packageName + "." + name);
+                    configureAST(type, importNode);
+                    addImport(type, name, alias, annotations);
+                }
+            }
+        } finally {
+            // we're using node metadata here in order to fix GROOVY-6094
+            // without breaking external APIs
+            Object node = output.getNodeMetaData(ImportNode.class);
+            if (node!=null && node!=ImportNode.class) {
+                configureAST((ImportNode)node, importNode);
+            }
+            output.removeNodeMetaData(ImportNode.class);
+        }
+    }
+
+    private void processAnnotations(List<AnnotationNode> annotations, AST node) {
+        AST child = node.getFirstChild();
+        while (child != null) {
+            if (isType(ANNOTATION, child))
+                annotations.add(annotation(child));
+            child = child.getNextSibling();
+        }
+    }
+
+    protected void annotationDef(AST classDef) {
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        AST node = classDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            checkNoInvalidModifier(classDef, "Annotation Definition", modifiers, Opcodes.ACC_SYNCHRONIZED, "synchronized");
+            node = node.getNextSibling();
+        }
+        modifiers |= Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_ANNOTATION;
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+        ClassNode superClass = ClassHelper.OBJECT_TYPE;
+
+        GenericsType[] genericsType = null;
+        if (isType(TYPE_PARAMETERS, node)) {
+            genericsType = makeGenericsType(node);
+            node = node.getNextSibling();
+        }
+
+        ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
+        if (isType(EXTENDS_CLAUSE, node)) {
+            interfaces = interfaces(node);
+            node = node.getNextSibling();
+        }
+
+        boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
+        modifiers &= ~Opcodes.ACC_SYNTHETIC;
+        classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, null);
+        classNode.setSyntheticPublic(syntheticPublic);
+        classNode.addAnnotations(annotations);
+        classNode.setGenericsTypes(genericsType);
+        classNode.addInterface(ClassHelper.Annotation_TYPE);
+        configureAST(classNode, classDef);
+
+        assertNodeType(OBJBLOCK, node);
+        objectBlock(node);
+        output.addClass(classNode);
+        classNode = null;
+    }
+
+    protected void interfaceDef(AST classDef) {
+        int oldInnerClassCounter = innerClassCounter;
+        innerInterfaceDef(classDef);
+        classNode = null;
+        innerClassCounter = oldInnerClassCounter;
+    }
+
+    protected void innerInterfaceDef(AST classDef) {
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        AST node = classDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            checkNoInvalidModifier(classDef, "Interface", modifiers, Opcodes.ACC_SYNCHRONIZED, "synchronized");
+            node = node.getNextSibling();
+        }
+        modifiers |= Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE;
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+        ClassNode superClass = ClassHelper.OBJECT_TYPE;
+
+        GenericsType[] genericsType = null;
+        if (isType(TYPE_PARAMETERS, node)) {
+            genericsType = makeGenericsType(node);
+            node = node.getNextSibling();
+        }
+
+        ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
+        if (isType(EXTENDS_CLAUSE, node)) {
+            interfaces = interfaces(node);
+            node = node.getNextSibling();
+        }
+
+        ClassNode outerClass = classNode;
+        boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
+        modifiers &= ~Opcodes.ACC_SYNTHETIC;
+        if (classNode != null) {
+            name = classNode.getNameWithoutPackage() + "$" + name;
+            String fullName = dot(classNode.getPackageName(), name);
+            classNode = new InnerClassNode(classNode, fullName, modifiers, superClass, interfaces, null);
+        } else {
+            classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, null);
+        }
+        classNode.setSyntheticPublic(syntheticPublic);
+        classNode.addAnnotations(annotations);
+        classNode.setGenericsTypes(genericsType);
+        configureAST(classNode, classDef);
+
+        int oldClassCount = innerClassCounter;
+
+        assertNodeType(OBJBLOCK, node);
+        objectBlock(node);
+        output.addClass(classNode);
+
+        classNode = outerClass;
+        innerClassCounter = oldClassCount;
+    }
+
+    protected void classDef(AST classDef) {
+        int oldInnerClassCounter = innerClassCounter;
+        innerClassDef(classDef);
+        classNode = null;
+        innerClassCounter = oldInnerClassCounter;
+    }
+
+    private ClassNode getClassOrScript(ClassNode node) {
+        if (node != null) return node;
+        return output.getScriptClassDummy();
+    }
+
+    protected Expression anonymousInnerClassDef(AST node) {
+        ClassNode oldNode = classNode;
+        ClassNode outerClass = getClassOrScript(oldNode);
+        String fullName = outerClass.getName() + '$' + innerClassCounter;
+        innerClassCounter++;
+        if (enumConstantBeingDef) {
+            classNode = new EnumConstantClassNode(outerClass, fullName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        } else {
+            classNode = new InnerClassNode(outerClass, fullName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        }
+        ((InnerClassNode) classNode).setAnonymous(true);
+        classNode.setEnclosingMethod(methodNode);
+
+        assertNodeType(OBJBLOCK, node);
+        objectBlock(node);
+        output.addClass(classNode);
+        AnonymousInnerClassCarrier ret = new AnonymousInnerClassCarrier();
+        ret.innerClass = classNode;
+        classNode = oldNode;
+
+        return ret;
+    }
+
+    protected void innerClassDef(AST classDef) {
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+
+        if (isType(TRAIT_DEF, classDef)) {
+            annotations.add(new AnnotationNode(ClassHelper.make("groovy.transform.Trait")));
+        }
+
+        AST node = classDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            checkNoInvalidModifier(classDef, "Class", modifiers, Opcodes.ACC_SYNCHRONIZED, "synchronized");
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+
+        GenericsType[] genericsType = null;
+        if (isType(TYPE_PARAMETERS, node)) {
+            genericsType = makeGenericsType(node);
+            node = node.getNextSibling();
+        }
+
+        ClassNode superClass = null;
+        if (isType(EXTENDS_CLAUSE, node)) {
+            superClass = makeTypeWithArguments(node);
+            node = node.getNextSibling();
+        }
+
+        ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
+        if (isType(IMPLEMENTS_CLAUSE, node)) {
+            interfaces = interfaces(node);
+            node = node.getNextSibling();
+        }
+
+        // TODO read mixins
+        MixinNode[] mixins = {};
+        ClassNode outerClass = classNode;
+        boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
+        modifiers &= ~Opcodes.ACC_SYNTHETIC;
+        if (classNode != null) {
+            name = classNode.getNameWithoutPackage() + "$" + name;
+            String fullName = dot(classNode.getPackageName(), name);
+            if (classNode.isInterface()) {
+                modifiers |= Opcodes.ACC_STATIC;
+            }
+            classNode = new InnerClassNode(classNode, fullName, modifiers, superClass, interfaces, mixins);
+        } else {
+            classNode = new ClassNode(dot(getPackageName(), name), modifiers, superClass, interfaces, mixins);
+        }
+        classNode.addAnnotations(annotations);
+        classNode.setGenericsTypes(genericsType);
+        classNode.setSyntheticPublic(syntheticPublic);
+        configureAST(classNode, classDef);
+
+        // we put the class already in output to avoid the most inner classes
+        // will be used as first class later in the loader. The first class
+        // there determines what GCL#parseClass for example will return, so we
+        // have here to ensure it won't be the inner class
+        output.addClass(classNode);
+
+        int oldClassCount = innerClassCounter;
+
+        assertNodeType(OBJBLOCK, node);
+        objectBlock(node);
+
+        classNode = outerClass;
+        innerClassCounter = oldClassCount;
+    }
+
+    protected void objectBlock(AST objectBlock) {
+        for (AST node = objectBlock.getFirstChild(); node != null; node = node.getNextSibling()) {
+            int type = node.getType();
+            switch (type) {
+                case OBJBLOCK:
+                    objectBlock(node);
+                    break;
+
+                case ANNOTATION_FIELD_DEF:
+                case METHOD_DEF:
+                    methodDef(node);
+                    break;
+
+                case CTOR_IDENT:
+                    constructorDef(node);
+                    break;
+
+                case VARIABLE_DEF:
+                    fieldDef(node);
+                    break;
+
+                case STATIC_INIT:
+                    staticInit(node);
+                    break;
+
+                case INSTANCE_INIT:
+                    objectInit(node);
+                    break;
+
+                case ENUM_DEF:
+                    enumDef(node);
+                    break;
+
+                case ENUM_CONSTANT_DEF:
+                    enumConstantDef(node);
+                    break;
+
+                case TRAIT_DEF:
+                case CLASS_DEF:
+                    innerClassDef(node);
+                    break;
+
+                case INTERFACE_DEF:
+                    innerInterfaceDef(node);
+                    break;
+
+                default:
+                    unknownAST(node);
+            }
+        }
+    }
+
+    protected void enumDef(AST enumNode) {
+        assertNodeType(ENUM_DEF, enumNode);
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+
+        AST node = enumNode.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+
+        ClassNode[] interfaces = interfaces(node);
+        node = node.getNextSibling();
+
+        boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
+        modifiers &= ~Opcodes.ACC_SYNTHETIC;
+        String enumName = (classNode != null ? name : dot(getPackageName(), name));
+        ClassNode enumClass = EnumHelper.makeEnumNode(enumName, modifiers, interfaces, classNode);
+        enumClass.setSyntheticPublic(syntheticPublic);
+        ClassNode oldNode = classNode;
+        enumClass.addAnnotations(annotations);
+        classNode = enumClass;
+        configureAST(classNode, enumNode);
+        assertNodeType(OBJBLOCK, node);
+        objectBlock(node);
+        classNode = oldNode;
+
+        output.addClass(enumClass);
+    }
+
+    protected void enumConstantDef(AST node) {
+        enumConstantBeingDef = true;
+        assertNodeType(ENUM_CONSTANT_DEF, node);
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        AST element = node.getFirstChild();
+        if (isType(ANNOTATIONS, element)) {
+            processAnnotations(annotations, element);
+            element = element.getNextSibling();
+        }
+        String identifier = identifier(element);
+        Expression init = null;
+        element = element.getNextSibling();
+
+        if (element != null) {
+            init = expression(element);
+            ClassNode innerClass;
+            if (element.getNextSibling() == null) {
+                innerClass = getAnonymousInnerClassNode(init);
+                if (innerClass != null) {
+                    init = null;
+                }
+            } else {
+                element = element.getNextSibling();
+                Expression next = expression(element);
+                innerClass = getAnonymousInnerClassNode(next);
+            }
+
+            if (innerClass != null) {
+                // we have to handle an enum constant with a class overriding
+                // a method in which case we need to configure the inner class
+                innerClass.setSuperClass(classNode.getPlainNodeReference());
+                innerClass.setModifiers(classNode.getModifiers() | Opcodes.ACC_FINAL);
+                // we use a ClassExpression for transportation to EnumVisitor
+                Expression inner = new ClassExpression(innerClass);
+                if (init == null) {
+                    ListExpression le = new ListExpression();
+                    le.addExpression(inner);
+                    init = le;
+                } else {
+                    if (init instanceof ListExpression) {
+                        ((ListExpression) init).addExpression(inner);
+                    } else {
+                        ListExpression le = new ListExpression();
+                        le.addExpression(init);
+                        le.addExpression(inner);
+                        init = le;
+                    }
+                }
+                // and remove the final modifier from classNode to allow the sub class
+                classNode.setModifiers(classNode.getModifiers() & ~Opcodes.ACC_FINAL);
+            } else if (isType(ELIST, element)) {
+                if (init instanceof ListExpression && !((ListExpression) init).isWrapped()) {
+                    ListExpression le = new ListExpression();
+                    le.addExpression(init);
+                    init = le;
+                }
+            }
+        }
+        FieldNode enumField = EnumHelper.addEnumConstant(classNode, identifier, init);
+        enumField.addAnnotations(annotations);
+        configureAST(enumField, node);
+        enumConstantBeingDef = false;
+    }
+
+    protected void throwsList(AST node, List<ClassNode> list) {
+        String name;
+        if (isType(DOT, node)) {
+            name = qualifiedName(node);
+        } else {
+            name = identifier(node);
+        }
+        ClassNode exception = ClassHelper.make(name);
+        configureAST(exception, node);
+        list.add(exception);
+        AST next = node.getNextSibling();
+        if (next != null) throwsList(next, list);
+    }
+
+    protected void methodDef(AST methodDef) {
+        MethodNode oldNode = methodNode;
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        AST node = methodDef.getFirstChild();
+
+        GenericsType[] generics = null;
+        if (isType(TYPE_PARAMETERS, node)) {
+            generics = makeGenericsType(node);
+            node = node.getNextSibling();
+        }
+
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            checkNoInvalidModifier(methodDef, "Method", modifiers, Opcodes.ACC_VOLATILE, "volatile");
+            node = node.getNextSibling();
+        }
+
+        if (isAnInterface()) {
+            modifiers |= Opcodes.ACC_ABSTRACT;
+        }
+
+        ClassNode returnType = null;
+        if (isType(TYPE, node)) {
+            returnType = makeTypeWithArguments(node);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        if (classNode != null && !classNode.isAnnotationDefinition()) {
+            if (classNode.getNameWithoutPackage().equals(name)) {
+                if (isAnInterface()) {
+                    throw new ASTRuntimeException(methodDef, "Constructor not permitted within an interface.");
+                }
+                throw new ASTRuntimeException(methodDef, "Invalid constructor format. Remove '" + returnType.getName() +
+                        "' as the return type if you want a constructor, or use a different name if you want a method.");
+            }
+        }
+        node = node.getNextSibling();
+
+        Parameter[] parameters = Parameter.EMPTY_ARRAY;
+        ClassNode[] exceptions = ClassNode.EMPTY_ARRAY;
+
+        if (classNode == null || !classNode.isAnnotationDefinition()) {
+
+            assertNodeType(PARAMETERS, node);
+            parameters = parameters(node);
+            if (parameters == null) parameters = Parameter.EMPTY_ARRAY;
+            node = node.getNextSibling();
+
+            if (isType(LITERAL_throws, node)) {
+                AST throwsNode = node.getFirstChild();
+                List<ClassNode> exceptionList = new ArrayList<ClassNode>();
+                throwsList(throwsNode, exceptionList);
+                exceptions = exceptionList.toArray(exceptions);
+                node = node.getNextSibling();
+            }
+        }
+
+        boolean hasAnnotationDefault = false;
+        Statement code = null;
+        boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
+        modifiers &= ~Opcodes.ACC_SYNTHETIC;
+        methodNode = new MethodNode(name, modifiers, returnType, parameters, exceptions, code);
+        if ((modifiers & Opcodes.ACC_ABSTRACT) == 0) {
+            if (node == null) {
+                throw new ASTRuntimeException(methodDef, "You defined a method without body. Try adding a body, or declare it abstract.");
+            }
+            assertNodeType(SLIST, node);
+            code = statementList(node);
+        } else if (node != null && classNode.isAnnotationDefinition()) {
+            code = statement(node);
+            hasAnnotationDefault = true;
+        } else if ((modifiers & Opcodes.ACC_ABSTRACT) > 0) {
+            if (node != null) {
+                throw new ASTRuntimeException(methodDef, "Abstract methods do not define a body.");
+            }
+        }
+        methodNode.setCode(code);
+        methodNode.addAnnotations(annotations);
+        methodNode.setGenericsTypes(generics);
+        methodNode.setAnnotationDefault(hasAnnotationDefault);
+        methodNode.setSyntheticPublic(syntheticPublic);
+        configureAST(methodNode, methodDef);
+
+        if (classNode != null) {
+            classNode.addMethod(methodNode);
+        } else {
+            output.addMethod(methodNode);
+        }
+        methodNode = oldNode;
+    }
+
+    private static void checkNoInvalidModifier(AST node, String nodeType, int modifiers, int modifier, String modifierText) {
+        if ((modifiers & modifier) != 0) {
+            throw new ASTRuntimeException(node, nodeType + " has an incorrect modifier '" + modifierText + "'.");
+        }
+    }
+
+    private boolean isAnInterface() {
+        return classNode != null && (classNode.getModifiers() & Opcodes.ACC_INTERFACE) > 0;
+    }
+
+    protected void staticInit(AST staticInit) {
+        BlockStatement code = (BlockStatement) statementList(staticInit);
+        classNode.addStaticInitializerStatements(code.getStatements(), false);
+    }
+
+    protected void objectInit(AST init) {
+        BlockStatement code = (BlockStatement) statementList(init);
+        classNode.addObjectInitializerStatements(code);
+    }
+
+    protected void constructorDef(AST constructorDef) {
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        AST node = constructorDef.getFirstChild();
+        int modifiers = Opcodes.ACC_PUBLIC;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            checkNoInvalidModifier(constructorDef, "Constructor", modifiers, Opcodes.ACC_STATIC, "static");
+            checkNoInvalidModifier(constructorDef, "Constructor", modifiers, Opcodes.ACC_FINAL, "final");
+            checkNoInvalidModifier(constructorDef, "Constructor", modifiers, Opcodes.ACC_ABSTRACT, "abstract");
+            checkNoInvalidModifier(constructorDef, "Constructor", modifiers, Opcodes.ACC_NATIVE, "native");
+            node = node.getNextSibling();
+        }
+
+        assertNodeType(PARAMETERS, node);
+        Parameter[] parameters = parameters(node);
+        if (parameters == null) parameters = Parameter.EMPTY_ARRAY;
+        node = node.getNextSibling();
+
+        ClassNode[] exceptions = ClassNode.EMPTY_ARRAY;
+        if (isType(LITERAL_throws, node)) {
+            AST throwsNode = node.getFirstChild();
+            List<ClassNode> exceptionList = new ArrayList<ClassNode>();
+            throwsList(throwsNode, exceptionList);
+            exceptions = exceptionList.toArray(exceptions);
+            node = node.getNextSibling();
+        }
+
+        assertNodeType(SLIST, node);
+        boolean syntheticPublic = ((modifiers & Opcodes.ACC_SYNTHETIC) != 0);
+        modifiers &= ~Opcodes.ACC_SYNTHETIC;
+        ConstructorNode constructorNode = classNode.addConstructor(modifiers, parameters, exceptions, null);
+        MethodNode oldMethod = methodNode;
+        methodNode = constructorNode;
+        Statement code = statementList(node);
+        methodNode = oldMethod;
+        constructorNode.setCode(code);
+        constructorNode.setSyntheticPublic(syntheticPublic);
+        constructorNode.addAnnotations(annotations);
+        configureAST(constructorNode, constructorDef);
+    }
+
+    protected void fieldDef(AST fieldDef) {
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        AST node = fieldDef.getFirstChild();
+
+        int modifiers = 0;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+
+        if (classNode.isInterface()) {
+            modifiers |= Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
+            if ((modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) == 0) {
+                modifiers |= Opcodes.ACC_PUBLIC;
+            }
+        }
+
+        ClassNode type = null;
+        if (isType(TYPE, node)) {
+            type = makeTypeWithArguments(node);
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+
+        Expression initialValue = null;
+        if (node != null) {
+            assertNodeType(ASSIGN, node);
+            initialValue = expression(node.getFirstChild());
+        }
+
+        if (classNode.isInterface() && initialValue == null && type != null) {
+            initialValue = getDefaultValueForPrimitive(type);
+        }
+
+
+        FieldNode fieldNode = new FieldNode(name, modifiers, type, classNode, initialValue);
+        fieldNode.addAnnotations(annotations);
+        configureAST(fieldNode, fieldDef);
+
+        if (!hasVisibility(modifiers)) {
+            // let's set the modifiers on the field
+            int fieldModifiers = 0;
+            int flags = Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT | Opcodes.ACC_VOLATILE | Opcodes.ACC_FINAL;
+
+            if (!hasVisibility(modifiers)) {
+                modifiers |= Opcodes.ACC_PUBLIC;
+                fieldModifiers |= Opcodes.ACC_PRIVATE;
+            }
+
+            // let's pass along any other modifiers we need
+            fieldModifiers |= (modifiers & flags);
+            fieldNode.setModifiers(fieldModifiers);
+            fieldNode.setSynthetic(true);
+
+            // in the case that there is already a field, we would
+            // like to use that field, instead of the default field
+            // for the property
+            FieldNode storedNode = classNode.getDeclaredField(fieldNode.getName());
+            if (storedNode != null && !classNode.hasProperty(name)) {
+                fieldNode = storedNode;
+                // we remove it here, because addProperty will add it
+                // again and we want to avoid it showing up multiple
+                // times in the fields list.
+                classNode.getFields().remove(storedNode);
+            }
+
+            PropertyNode propertyNode = new PropertyNode(fieldNode, modifiers, null, null);
+            configureAST(propertyNode, fieldDef);
+            classNode.addProperty(propertyNode);
+        } else {
+            fieldNode.setModifiers(modifiers);
+            // if there is a property of that name, then a field of that
+            // name already exists, which means this new field here should
+            // be used instead of the field the property originally has.
+            PropertyNode pn = classNode.getProperty(name);
+            if (pn != null && pn.getField().isSynthetic()) {
+                classNode.getFields().remove(pn.getField());
+                pn.setField(fieldNode);
+            }
+            classNode.addField(fieldNode);
+        }
+    }
+
+    public static Expression getDefaultValueForPrimitive(ClassNode type) {
+        if (type == ClassHelper.int_TYPE) {
+            return new ConstantExpression(0);
+        }
+        if (type == ClassHelper.long_TYPE) {
+            return new ConstantExpression(0L);
+        }
+        if (type == ClassHelper.double_TYPE) {
+            return new ConstantExpression(0.0);
+        }
+        if (type == ClassHelper.float_TYPE) {
+            return new ConstantExpression(0.0F);
+        }
+        if (type == ClassHelper.boolean_TYPE) {
+            return ConstantExpression.FALSE;
+        }
+        if (type == ClassHelper.short_TYPE) {
+            return new ConstantExpression((short) 0);
+        }
+        if (type == ClassHelper.byte_TYPE) {
+            return new ConstantExpression((byte) 0);
+        }
+        if (type == ClassHelper.char_TYPE) {
+            return new ConstantExpression((char) 0);
+        }
+        return null;
+    }
+
+    protected ClassNode[] interfaces(AST node) {
+        List<ClassNode> interfaceList = new ArrayList<ClassNode>();
+        for (AST implementNode = node.getFirstChild(); implementNode != null; implementNode = implementNode.getNextSibling()) {
+            interfaceList.add(makeTypeWithArguments(implementNode));
+        }
+        ClassNode[] interfaces = ClassNode.EMPTY_ARRAY;
+        if (!interfaceList.isEmpty()) {
+            interfaces = new ClassNode[interfaceList.size()];
+            interfaceList.toArray(interfaces);
+        }
+        return interfaces;
+    }
+
+    protected Parameter[] parameters(AST parametersNode) {
+        AST node = parametersNode.getFirstChild();
+        firstParam = false;
+        firstParamIsVarArg = false;
+        if (node == null) {
+            if (isType(IMPLICIT_PARAMETERS, parametersNode)) return Parameter.EMPTY_ARRAY;
+            return null;
+        } else {
+            List<Parameter> parameters = new ArrayList<Parameter>();
+            AST firstParameterNode = null;
+            do {
+                firstParam = (firstParameterNode == null);
+                if (firstParameterNode == null) firstParameterNode = node;
+                parameters.add(parameter(node));
+                node = node.getNextSibling();
+            }
+            while (node != null);
+
+            verifyParameters(parameters, firstParameterNode);
+
+            Parameter[] answer = new Parameter[parameters.size()];
+            parameters.toArray(answer);
+            return answer;
+        }
+    }
+
+    private void verifyParameters(List<Parameter> parameters, AST firstParameterNode) {
+        if (parameters.size() <= 1) return;
+
+        Parameter first = parameters.get(0);
+        if (firstParamIsVarArg) {
+            throw new ASTRuntimeException(firstParameterNode, "The var-arg parameter " + first.getName() + " must be the last parameter.");
+        }
+    }
+
+    protected Parameter parameter(AST paramNode) {
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        boolean variableParameterDef = isType(VARIABLE_PARAMETER_DEF, paramNode);
+        AST node = paramNode.getFirstChild();
+
+        int modifiers = 0;
+        if (isType(MODIFIERS, node)) {
+            modifiers = modifiers(node, annotations, modifiers);
+            node = node.getNextSibling();
+        }
+
+        ClassNode type = ClassHelper.DYNAMIC_TYPE;
+        if (isType(TYPE, node)) {
+            type = makeTypeWithArguments(node);
+            if (variableParameterDef) type = type.makeArray();
+            node = node.getNextSibling();
+        }
+
+        String name = identifier(node);
+        node = node.getNextSibling();
+
+        VariableExpression leftExpression = new VariableExpression(name, type);
+        leftExpression.setModifiers(modifiers);
+        configureAST(leftExpression, paramNode);
+
+        Parameter parameter = null;
+        if (node != null) {
+            assertNodeType(ASSIGN, node);
+            Expression rightExpression = expression(node.getFirstChild());
+            if (isAnInterface()) {
+                throw new ASTRuntimeException(node, "Cannot specify default value for method parameter '" + name + " = " + rightExpression.getText() + "' inside an interface");
+            }
+            parameter = new Parameter(type, name, rightExpression);
+        } else
+            parameter = new Parameter(type, name);
+
+        if (firstParam) firstParamIsVarArg = variableParameterDef;
+
+        configureAST(parameter, paramNode);
+        parameter.addAnnotations(annotations);
+        parameter.setModifiers(modifiers);
+        return parameter;
+    }
+
+    protected int modifiers(AST modifierNode, List<AnnotationNode> annotations, int defaultModifiers) {
+        assertNodeType(MODIFIERS, modifierNode);
+
+        boolean access = false;
+        int answer = 0;
+
+        for (AST node = modifierNode.getFirstChild(); node != null; node = node.getNextSibling()) {
+            int type = node.getType();
+            switch (type) {
+                case STATIC_IMPORT:
+                    // ignore
+                    break;
+
+                // annotations
+                case ANNOTATION:
+                    annotations.add(annotation(node));
+                    break;
+
+                // core access scope modifiers
+                case LITERAL_private:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_PRIVATE);
+                    access = setAccessTrue(node, access);
+                    break;
+
+                case LITERAL_protected:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_PROTECTED);
+                    access = setAccessTrue(node, access);
+                    break;
+
+                case LITERAL_public:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_PUBLIC);
+                    access = setAccessTrue(node, access);
+                    break;
+
+                // other modifiers
+                case ABSTRACT:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_ABSTRACT);
+                    break;
+
+                case FINAL:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_FINAL);
+                    break;
+
+                case LITERAL_native:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_NATIVE);
+                    break;
+
+                case LITERAL_static:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_STATIC);
+                    break;
+
+                case STRICTFP:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_STRICT);
+                    break;
+
+                case LITERAL_synchronized:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_SYNCHRONIZED);
+                    break;
+
+                case LITERAL_transient:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_TRANSIENT);
+                    break;
+
+                case LITERAL_volatile:
+                    answer = setModifierBit(node, answer, Opcodes.ACC_VOLATILE);
+                    break;
+
+                default:
+                    unknownAST(node);
+            }
+        }
+        if (!access) {
+            answer |= defaultModifiers;
+            // ACC_SYNTHETIC isn't used here, use it as a special flag
+            if (defaultModifiers == Opcodes.ACC_PUBLIC) answer |= Opcodes.ACC_SYNTHETIC;
+        }
+        return answer;
+    }
+
+    protected boolean setAccessTrue(AST node, boolean access) {
+        if (!access) {
+            return true;
+        } else {
+            throw new ASTRuntimeException(node, "Cannot specify modifier: " + node.getText() + " when access scope has already been defined");
+        }
+    }
+
+    protected int setModifierBit(AST node, int answer, int bit) {
+        if ((answer & bit) != 0) {
+            throw new ASTRuntimeException(node, "Cannot repeat modifier: " + node.getText());
+        }
+        return answer | bit;
+    }
+
+    protected AnnotationNode annotation(AST annotationNode) {
+        annotationBeingDef = true;
+        AST node = annotationNode.getFirstChild();
+        String name = qualifiedName(node);
+        AnnotationNode annotatedNode = new AnnotationNode(ClassHelper.make(name));
+        configureAST(annotatedNode, annotationNode);
+        while (true) {
+            node = node.getNextSibling();
+            if (isType(ANNOTATION_MEMBER_VALUE_PAIR, node)) {
+                AST memberNode = node.getFirstChild();
+                String param = identifier(memberNode);
+                Expression expression = expression(memberNode.getNextSibling());
+                if (annotatedNode.getMember(param) != null) {
+                    throw new ASTRuntimeException(memberNode, "Annotation member '" + param + "' has already been associated with a value");
+                }
+                annotatedNode.setMember(param, expression);
+            } else {
+                break;
+            }
+        }
+        annotationBeingDef = false;
+        return annotatedNode;
+    }
+
+
+    // Statements
+    //-------------------------------------------------------------------------
+
+    protected Statement statement(AST node) {
+        Statement statement = null;
+        int type = node.getType();
+        switch (type) {
+            case SLIST:
+            case LITERAL_finally:
+                statement = statementList(node);
+                break;
+
+            case METHOD_CALL:
+                statement = methodCall(node);
+                break;
+
+            case VARIABLE_DEF:
+                statement = variableDef(node);
+                break;
+
+            case LABELED_STAT:
+                return labelledStatement(node);
+
+            case LITERAL_assert:
+                statement = assertStatement(node);
+                break;
+
+            case LITERAL_break:
+                statement = breakStatement(node);
+                break;
+
+            case LITERAL_continue:
+                statement = continueStatement(node);
+                break;
+
+            case LITERAL_if:
+                statement = ifStatement(node);
+                break;
+
+            case LITERAL_for:
+                statement = forStatement(node);
+                break;
+
+            case LITERAL_return:
+                statement = returnStatement(node);
+                break;
+
+            case LITERAL_synchronized:
+                statement = synchronizedStatement(node);
+                break;
+
+            case LITERAL_switch:
+                statement = switchStatement(node);
+                break;
+
+            case LITERAL_try:
+                statement = tryStatement(node);
+                break;
+
+            case LITERAL_throw:
+                statement = throwStatement(node);
+                break;
+
+            case LITERAL_while:
+                statement = whileStatement(node);
+                break;
+
+            default:
+                statement = new ExpressionStatement(expression(node));
+        }
+        if (statement != null) {
+            configureAST(statement, node);
+        }
+        return statement;
+    }
+
+    protected Statement statementList(AST code) {
+        return statementListNoChild(code.getFirstChild(), code);
+    }
+
+    protected Statement statementListNoChild(AST node, AST alternativeConfigureNode) {
+        BlockStatement block = new BlockStatement();
+        // alternativeConfigureNode is used only to set the source position
+        if (node != null) {
+            configureAST(block, node);
+        } else {
+            configureAST(block, alternativeConfigureNode);
+        }
+        for (; node != null; node = node.getNextSibling()) {
+            block.addStatement(statement(node));
+        }
+        return block;
+    }
+
+    protected Statement assertStatement(AST assertNode) {
+        AST node = assertNode.getFirstChild();
+        BooleanExpression booleanExpression = booleanExpression(node);
+        Expression messageExpression = null;
+
+        node = node.getNextSibling();
+        if (node != null) {
+            messageExpression = expression(node);
+        } else {
+            messageExpression = ConstantExpression.NULL;
+        }
+        AssertStatement assertStatement = new AssertStatement(booleanExpression, messageExpression);
+        configureAST(assertStatement, assertNode);
+        return assertStatement;
+    }
+
+    protected Statement breakStatement(AST node) {
+        BreakStatement breakStatement = new BreakStatement(label(node));
+        configureAST(breakStatement, node);
+        return breakStatement;
+    }
+
+    protected Statement continueStatement(AST node) {
+        ContinueStatement continueStatement = new ContinueStatement(label(node));
+        configureAST(continueStatement, node);
+        return continueStatement;
+    }
+
+    protected Statement forStatement(AST forNode) {
+        AST inNode = forNode.getFirstChild();
+        Expression collectionExpression;
+        Parameter forParameter;
+        if (isType(CLOSURE_LIST, inNode)) {
+            forStatementBeingDef = true;
+            ClosureListExpression clist = closureListExpression(inNode);
+            forStatementBeingDef = false;
+            int size = clist.getExpressions().size();
+            if (size != 3) {
+                throw new ASTRuntimeException(inNode, "3 expressions are required for the classic for loop, you gave " + size);
+            }
+            collectionExpression = clist;
+            forParameter = ForStatement.FOR_LOOP_DUMMY;
+        } else {
+            AST variableNode = inNode.getFirstChild();
+            AST collectionNode = variableNode.getNextSibling();
+
+            ClassNode type = ClassHelper.OBJECT_TYPE;
+            if (isType(VARIABLE_DEF, variableNode)) {
+                AST node = variableNode.getFirstChild();
+                // skip the final modifier if it's present
+                if (isType(MODIFIERS, node)) {
+                    int modifiersMask = modifiers(node, new ArrayList<AnnotationNode>(), 0);
+                    // only final modifier allowed
+                    if ((modifiersMask & ~Opcodes.ACC_FINAL) != 0) {
+                        throw new ASTRuntimeException(node, "Only the 'final' modifier is allowed in front of the for loop variable.");
+                    }
+                    node = node.getNextSibling();
+                }
+                type = makeTypeWithArguments(node);
+
+                variableNode = node.getNextSibling();
+            }
+            String variable = identifier(variableNode);
+
+            collectionExpression = expression(collectionNode);
+            forParameter = new Parameter(type, variable);
+            configureAST(forParameter, variableNode);
+        }
+
+        final AST node = inNode.getNextSibling();
+        Statement block;
+        if (isType(SEMI, node)) {
+            block = EmptyStatement.INSTANCE;
+        } else {
+            block = statement(node);
+        }
+        ForStatement forStatement = new ForStatement(forParameter, collectionExpression, block);
+        configureAST(forStatement, forNode);
+        return forStatement;
+    }
+
+    protected Statement ifStatement(AST ifNode) {
+        AST node = ifNode.getFirstChild();
+        assertNodeType(EXPR, node);
+        BooleanExpression booleanExpression = booleanExpression(node);
+
+        node = node.getNextSibling();
+        Statement ifBlock = statement(node);
+
+        Statement elseBlock = EmptyStatement.INSTANCE;
+        node = node.getNextSibling();
+        if (node != null) {
+            elseBlock = statement(node);
+        }
+        IfStatement ifStatement = new IfStatement(booleanExpression, ifBlock, elseBlock);
+        configureAST(ifStatement, ifNode);
+        return ifStatement;
+    }
+
+    protected Statement labelledStatement(AST labelNode) {
+        AST node = labelNode.getFirstChild();
+        String label = identifier(node);
+        Statement statement = statement(node.getNextSibling());
+        statement.addStatementLabel(label);
+        return statement;
+    }
+
+    protected Statement methodCall(AST code) {
+        Expression expression = methodCallExpression(code);
+        ExpressionStatement expressionStatement = new ExpressionStatement(expression);
+        configureAST(expressionStatement, code);
+        return expressionStatement;
+    }
+
+    protected Expression declarationExpression(AST variableDef) {
+        AST node = variableDef.getFirstChild();
+        ClassNode type = null;
+        List<AnnotationNode> annotations = new ArrayList<AnnotationNode>();
+        int modifiers = 0;
+        if (isType(MODIFIERS, node)) {
+            // force check of modifier conflicts
+            modifiers = modifiers(node, annotations, 0);
+            node = node.getNextSibling();
+        }
+        if (isType(TYPE, node)) {
+            type = makeTypeWithArguments(node);
+            node = node.getNextSibling();
+        }
+
+        Expression leftExpression;
+        Expression rightExpression = EmptyExpression.INSTANCE;
+        AST right;
+
+        if (isType(ASSIGN, node)) {
+            node = node.getFirstChild();
+            AST left = node.getFirstChild();
+            ArgumentListExpression alist = new ArgumentListExpression();
+            for (AST varDef = left; varDef != null; varDef = varDef.getNextSibling()) {
+                assertNodeType(VARIABLE_DEF, varDef);
+                DeclarationExpression de = (DeclarationExpression) declarationExpression(varDef);
+                alist.addExpression(de.getVariableExpression());
+            }
+            leftExpression = alist;
+            right = node.getNextSibling();
+            if (right != null) rightExpression = expression(right);
+        } else {
+            String name = identifier(node);
+            VariableExpression ve = new VariableExpression(name, type);
+            ve.setModifiers(modifiers);
+            leftExpression = ve;
+
+            right = node.getNextSibling();
+            if (right != null) {
+                assertNodeType(ASSIGN, right);
+                rightExpression = expression(right.getFirstChild());
+            }
+        }
+
+        configureAST(leftExpression, node);
+
+        Token token = makeToken(Types.ASSIGN, variableDef);
+        DeclarationExpression expression = new DeclarationExpression(leftExpression, token, rightExpression);
+        expression.addAnnotations(annotations);
+        configureAST(expression, variableDef);
+        ExpressionStatement expressionStatement = new ExpressionStatement(expression);
+        configureAST(expressionStatement, variableDef);
+        return expression;
+    }
+
+    protected Statement variableDef(AST variableDef) {
+        ExpressionStatement expressionStatement = new ExpressionStatement(declarationExpression(variableDef));
+        configureAST(expressionStatement, variableDef);
+        return expressionStatement;
+    }
+
+    protected Statement returnStatement(AST node) {
+        AST exprNode = node.getFirstChild();
+
+        // This will pick up incorrect sibling node if 'node' is a plain 'return'
+        //
+        //if (exprNode == null) {
+        //    exprNode = node.getNextSibling();
+        //}
+        Expression expression = exprNode == null ? ConstantExpression.NULL : expression(exprNode);
+        ReturnStatement returnStatement = new ReturnStatement(expression);
+        configureAST(returnStatement, node);
+        return returnStatement;
+    }
+
+    protected Statement switchStatement(AST switchNode) {
+        AST node = switchNode.getFirstChild();
+        Expression expression = expression(node);
+        Statement defaultStatement = EmptyStatement.INSTANCE;
+
+        List list = new ArrayList();
+        for (node = node.getNextSibling(); isType(CASE_GROUP, node); node = node.getNextSibling()) {
+            Statement tmpDefaultStatement;
+            AST child = node.getFirstChild();
+            if (isType(LITERAL_case, child)) {
+                List cases = new LinkedList();
+                // default statement can be grouped with previous case
+                tmpDefaultStatement = caseStatements(child, cases);
+                list.addAll(cases);
+            } else {
+                tmpDefaultStatement = statement(child.getNextSibling());
+            }
+            if (tmpDefaultStatement != EmptyStatement.INSTANCE) {
+                if (defaultStatement == EmptyStatement.INSTANCE) {
+                    defaultStatement = tmpDefaultStatement;
+                } else {
+                    throw new ASTRuntimeException(switchNode, "The default case is already defined.");
+                }
+            }
+        }
+        if (node != null) {
+            unknownAST(node);
+        }
+        SwitchStatement switchStatement = new SwitchStatement(expression, list, defaultStatement);
+        configureAST(switchStatement, switchNode);
+        return switchStatement;
+    }
+
+    protected Statement caseStatements(AST node, List cases) {
+        List<Expression> expressions = new LinkedList<Expression>();
+        Statement statement = EmptyStatement.INSTANCE;
+        Statement defaultStatement = EmptyStatement.INSTANCE;
+        AST nextSibling = node;
+        do {
+            Expression expression = expression(nextSibling.getFirstChild());
+            expressions.add(expression);
+            nextSibling = nextSibling.getNextSibling();
+        } while (isType(LITERAL_case, nextSibling));
+        if (nextSibling != null) {
+            if (isType(LITERAL_default, nextSibling)) {
+                defaultStatement = statement(nextSibling.getNextSibling());
+                statement = EmptyStatement.INSTANCE;
+            } else {
+                statement = statement(nextSibling);
+            }
+        }
+        Iterator iterator = expressions.iterator();
+        while (iterator.hasNext()) {
+            Expression expr = (Expression) iterator.next();
+            Statement stmt;
+            if (iterator.hasNext()) {
+                stmt = new CaseStatement(expr, EmptyStatement.INSTANCE);
+            } else {
+                stmt = new CaseStatement(expr, statement);
+            }
+            configureAST(stmt, node);
+            cases.add(stmt);
+        }
+        return defaultStatement;
+    }
+
+    protected Statement synchronizedStatement(AST syncNode) {
+        AST node = syncNode.getFirstChild();
+        Expression expression = expression(node);
+        Statement code = statement(node.getNextSibling());
+        SynchronizedStatement synchronizedStatement = new SynchronizedStatement(expression, code);
+        configureAST(synchronizedStatement, syncNode);
+        return synchronizedStatement;
+    }
+
+    protected Statement throwStatement(AST node) {
+        AST expressionNode = node.getFirstChild();
+        if (expressionNode == null) {
+            expressionNode = node.getNextSibling();
+        }
+        if (expressionNode == null) {
+            throw new ASTRuntimeException(node, "No expression available");
+        }
+        ThrowStatement throwStatement = new ThrowStatement(expression(expressionNode));
+        configureAST(throwStatement, node);
+        return throwStatement;
+    }
+
+    protected Statement tryStatement(AST tryStatementNode) {
+        AST tryNode = tryStatementNode.getFirstChild();
+        Statement tryStatement = statement(tryNode);
+        Statement finallyStatement = EmptyStatement.INSTANCE;
+        AST node = tryNode.getNextSibling();
+
+        // let's do the catch nodes
+        List<CatchStatement> catches = new ArrayList<CatchStatement>();
+        for (; node != null && isType(LITERAL_catch, node); node = node.getNextSibling()) {
+            final List<CatchStatement> catchStatements = catchStatement(node);
+            catches.addAll(catchStatements);
+        }
+
+        if (isType(LITERAL_finally, node)) {
+            finallyStatement = statement(node);
+            node = node.getNextSibling();
+        }
+
+        if (finallyStatement instanceof EmptyStatement && catches.isEmpty()) {
+            throw new ASTRuntimeException(tryStatementNode, "A try statement must have at least one catch or finally block.");
+        }
+
+        TryCatchStatement tryCatchStatement = new TryCatchStatement(tryStatement, finallyStatement);
+        configureAST(tryCatchStatement, tryStatementNode);
+        for (CatchStatement statement : catches) {
+            tryCatchStatement.addCatch(statement);
+        }
+        return tryCatchStatement;
+    }
+
+    protected List<CatchStatement> catchStatement(AST catchNode) {
+        AST node = catchNode.getFirstChild();
+        List<CatchStatement> catches = new LinkedList<CatchStatement>();
+        Statement code = statement(node.getNextSibling());
+        if (MULTICATCH == node.getType()) {
+            AST variableNode = node.getNextSibling();
+            final AST multicatches = node.getFirstChild();
+            if (multicatches.getType() != MULTICATCH_TYPES) {
+                // catch (e)
+                // catch (def e)
+                String variable = identifier(multicatches);
+                Parameter catchParameter = new Parameter(ClassHelper.DYNAMIC_TYPE, variable);
+                CatchStatement answer = new CatchStatement(catchParameter, code);
+                configureAST(answer, catchNode);
+                catches.add(answer);
+            } else {
+                // catch (Exception e)
+                // catch (Exception1 | Exception2 e)
+                AST exceptionNodes = multicatches.getFirstChild();
+                String variable = identifier(multicatches.getNextSibling());
+                while (exceptionNodes != null) {
+                    ClassNode exceptionType = buildName(exceptionNodes);
+                    Parameter catchParameter = new Parameter(exceptionType, variable);
+                    CatchStatement answer = new CatchStatement(catchParameter, code);
+                    configureAST(answer, catchNode);
+                    catches.add(answer);
+                    exceptionNodes = exceptionNodes.getNextSibling();
+                }
+            }
+        }
+        return catches;
+    }
+
+    protected Statement whileStatement(AST whileNode) {
+        AST node = whileNode.getFirstChild();
+        assertNodeType(EXPR, node);
+        // TODO remove this once we support declarations in the while condition
+        if (isType(VARIABLE_DEF, node.getFirstChild())) {
+            throw new ASTRuntimeException(whileNode,
+                    "While loop condition contains a declaration; this is currently unsupported.");
+        }
+        BooleanExpression booleanExpression = booleanExpression(node);
+
+        node = node.getNextSibling();
+        Statement block;
+        if (isType(SEMI, node)) {
+            block = EmptyStatement.INSTANCE;
+        } else {
+            block = statement(node);
+        }
+        WhileStatement whileStatement = new WhileStatement(booleanExpression, block);
+        configureAST(whileStatement, whileNode);
+        return whileStatement;
+    }
+
+
+    // Expressions
+    //-------------------------------------------------------------------------
+
+    protected Expression expression(AST node) {
+        return expression(node, false);
+    }
+
+    protected Expression expression(AST node, boolean convertToConstant) {
+        Expression expression = expressionSwitch(node);
+        if (convertToConstant && expression instanceof VariableExpression) {
+            // a method name can never be a VariableExpression, so it must converted
+            // to a ConstantExpression then. This is needed as the expression
+            // method doesn't know we want a ConstantExpression instead of a
+            // VariableExpression
+            VariableExpression ve = (VariableExpression) expression;
+            if (!ve.isThisExpression() && !ve.isSuperExpression()) {
+                expression = new ConstantExpression(ve.getName());
+            }
+        }
+        configureAST(expression, node);
+        return expression;
+    }
+
+    protected Expression expressionSwitch(AST node) {
+        int type = node.getType();
+        switch (type) {
+            case EXPR:
+                return expression(node.getFirstChild());
+
+            case ELIST:
+                return expressionList(node);
+
+            case SLIST:
+                return blockExpression(node);
+
+            case CLOSABLE_BLOCK:
+                return closureExpression(node);
+
+            case SUPER_CTOR_CALL:
+                return specialConstructorCallExpression(node, ClassNode.SUPER);
+
+            case METHOD_CALL:
+                return methodCallExpression(node);
+
+            case LITERAL_new:
+                return constructorCallExpression(node);
+
+            case CTOR_CALL:
+                return specialConstructorCallExpression(node, ClassNode.THIS);
+
+            case QUESTION:
+            case ELVIS_OPERATOR:
+                return ternaryExpression(node);
+
+            case OPTIONAL_DOT:
+            case SPREAD_DOT:
+            case DOT:
+                return dotExpression(node);
+
+            case IDENT:
+            case LITERAL_boolean:
+            case LITERAL_byte:
+            case LITERAL_char:
+            case LITERAL_double:
+            case LITERAL_float:
+            case LITERAL_int:
+            case LITERAL_long:
+            case LITERAL_short:
+            case LITERAL_void:
+            case LITERAL_this:
+            case LITERAL_super:
+                return variableExpression(node);
+
+            case LIST_CONSTRUCTOR:
+                return listExpression(node);
+
+            case MAP_CONSTRUCTOR:
+                return mapExpression(node);
+
+            case LABELED_ARG:
+                return mapEntryExpression(node);
+
+            case SPREAD_ARG:
+                return spreadExpression(node);
+
+            case SPREAD_MAP_ARG:
+                return spreadMapExpression(node);
+
+            // commented out of groovy.g due to non determinisms
+            //case MEMBER_POINTER_DEFAULT:
+            //    return defaultMethodPointerExpression(node);
+
+            case MEMBER_POINTER:
+                return methodPointerExpression(node);
+
+            case INDEX_OP:
+                return indexExpression(node);
+
+            case LITERAL_instanceof:
+                return instanceofExpression(node);
+
+            case LITERAL_as:
+                return asExpression(node);
+
+            case TYPECAST:
+                return castExpression(node);
+
+            // literals
+
+            case LITERAL_true:
+                return literalExpression(node, Boolean.TRUE);
+            case LITERAL_false:
+                return literalExpression(node, Boolean.FALSE);
+            case LITERAL_null:
+                return literalExpression(node, null);
+            case STRING_LITERAL:
+                return literalExpression(node, node.getText());
+
+            case STRING_CONSTRUCTOR:
+                return gstring(node);
+
+            case NUM_DOUBLE:
+            case NUM_FLOAT:
+            case NUM_BIG_DECIMAL:
+                return decimalExpression(node);
+
+            case NUM_BIG_INT:
+            case NUM_INT:
+            case NUM_LONG:
+                return integerExpression(node);
+
+            // Unary expressions
+            case LNOT:
+                NotExpression notExpression = new NotExpression(expression(node.getFirstChild()));
+                configureAST(notExpression, node);
+                return notExpression;
+
+            case UNARY_MINUS:
+                return unaryMinusExpression(node);
+
+            case BNOT:
+                BitwiseNegationExpression bitwiseNegationExpression = new BitwiseNegationExpression(expression(node.getFirstChild()));
+                configureAST(bitwiseNegationExpression, node);
+                return bitwiseNegationExpression;
+
+            case UNARY_PLUS:
+                return unaryPlusExpression(node);
+
+            // Prefix expressions
+            case INC:
+                return prefixExpression(node, Types.PLUS_PLUS);
+
+            case DEC:
+                return prefixExpression(node, Types.MINUS_MINUS);
+
+            // Postfix expressions
+            case POST_INC:
+                return postfixExpression(node, Types.PLUS_PLUS);
+
+            case POST_DEC:
+                return postfixExpression(node, Types.MINUS_MINUS);
+
+
+            // Binary expressions
+
+            case ASSIGN:
+                return binaryExpression(Types.ASSIGN, node);
+
+            case EQUAL:
+                return binaryExpression(Types.COMPARE_EQUAL, node);
+
+            case IDENTICAL:
+                return binaryExpression(Types.COMPARE_IDENTICAL, node);
+
+            case NOT_EQUAL:
+                return binaryExpression(Types.COMPARE_NOT_EQUAL, node);
+
+            case NOT_IDENTICAL:
+                return binaryExpression(Types.COMPARE_NOT_IDENTICAL, node);
+
+            case COMPARE_TO:
+                return binaryExpression(Types.COMPARE_TO, node);
+
+            case LE:
+                return binaryExpression(Types.COMPARE_LESS_THAN_EQUAL, node);
+
+            case LT:
+                return binaryExpression(Types.COMPARE_LESS_THAN, node);
+
+            case GT:
+                return binaryExpression(Types.COMPARE_GREATER_THAN, node);
+
+            case GE:
+                return binaryExpression(Types.COMPARE_GREATER_THAN_EQUAL, node);
+
+            /**
+             * TODO treble equal?
+             return binaryExpression(Types.COMPARE_IDENTICAL, node);
+
+             case ???:
+             return binaryExpression(Types.LOGICAL_AND_EQUAL, node);
+
+             case ???:
+             return binaryExpression(Types.LOGICAL_OR_EQUAL, node);
+
+             */
+
+            case LAND:
+                return binaryExpression(Types.LOGICAL_AND, node);
+
+            case LOR:
+                return binaryExpression(Types.LOGICAL_OR, node);
+
+            case BAND:
+                return binaryExpression(Types.BITWISE_AND, node);
+
+            case BAND_ASSIGN:
+                return binaryExpression(Types.BITWISE_AND_EQUAL, node);
+
+            case BOR:
+                return binaryExpression(Types.BITWISE_OR, node);
+
+            case BOR_ASSIGN:
+                return binaryExpression(Types.BITWISE_OR_EQUAL, node);
+
+            case BXOR:
+                return binaryExpression(Types.BITWISE_XOR, node);
+
+            case BXOR_ASSIGN:
+                return binaryExpression(Types.BITWISE_XOR_EQUAL, node);
+
+
+            case PLUS:
+                return binaryExpression(Types.PLUS, node);
+
+            case PLUS_ASSIGN:
+                return binaryExpression(Types.PLUS_EQUAL, node);
+
+
+            case MINUS:
+                return binaryExpression(Types.MINUS, node);
+
+            case MINUS_ASSIGN:
+                return binaryExpression(Types.MINUS_EQUAL, node);
+
+
+            case STAR:
+                return binaryExpression(Types.MULTIPLY, node);
+
+            case STAR_ASSIGN:
+                return binaryExpression(Types.MULTIPLY_EQUAL, node);
+
+
+            case STAR_STAR:
+                return binaryExpression(Types.POWER, node);
+
+            case STAR_STAR_ASSIGN:
+                return binaryExpression(Types.POWER_EQUAL, node);
+
+
+            case DIV:
+                return binaryExpression(Types.DIVIDE, node);
+
+            case DIV_ASSIGN:
+                return binaryExpression(Types.DIVIDE_EQUAL, node);
+
+
+            case MOD:
+                return binaryExpression(Types.MOD, node);
+
+            case MOD_ASSIGN:
+                return binaryExpression(Types.MOD_EQUAL, node);
+
+            case SL:
+                return binaryExpression(Types.LEFT_SHIFT, node);
+
+            case SL_ASSIGN:
+                return binaryExpression(Types.LEFT_SHIFT_EQUAL, node);
+
+            case SR:
+                return binaryExpression(Types.RIGHT_SHIFT, node);
+
+            case SR_ASSIGN:
+                return binaryExpression(Types.RIGHT_SHIFT_EQUAL, node);
+
+            case BSR:
+                return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED, node);
+
+            case BSR_ASSIGN:
+                return binaryExpression(Types.RIGHT_SHIFT_UNSIGNED_EQUAL, node);
+
+            case VARIABLE_DEF:
+                return declarationExpression(node);
+
+            // Regex
+            case REGEX_FIND:
+                return binaryExpression(Types.FIND_REGEX, node);
+
+            case REGEX_MATCH:
+                return binaryExpression(Types.MATCH_REGEX, node);
+
+
+            // Ranges
+            case RANGE_INCLUSIVE:
+                return rangeExpression(node, true);
+
+            case RANGE_EXCLUSIVE:
+                return rangeExpression(node, false);
+
+            case DYNAMIC_MEMBER:
+                return dynamicMemberExpression(node);
+
+            case LITERAL_in:
+                return binaryExpression(Types.KEYWORD_IN, node);
+
+            case ANNOTATION:
+                return new AnnotationConstantExpression(annotation(node));
+
+            case CLOSURE_LIST:
+                return closureListExpression(node);
+
+            case LBRACK:
+            case LPAREN:
+                return tupleExpression(node);
+
+            case OBJBLOCK:
+                return anonymousInnerClassDef(node);
+
+            default:
+                unknownAST(node);
+        }
+        return null;
+    }
+
+    private TupleExpression tupleExpression(AST node) {
+        TupleExpression exp = new TupleExpression();
+        configureAST(exp, node);
+        node = node.getFirstChild();
+        while (node != null) {
+            assertNodeType(VARIABLE_DEF, node);
+            AST nameNode = node.getFirstChild().getNextSibling();
+            VariableExpression varExp = new VariableExpression(nameNode.getText());
+            configureAST(varExp, nameNode);
+            exp.addExpression(varExp);
+            node = node.getNextSibling();
+        }
+        return exp;
+    }
+
+    private ClosureListExpression closureListExpression(AST node) {
+        isClosureListExpressionAllowedHere(node);
+        AST exprNode = node.getFirstChild();
+        List<Expression> list = new LinkedList<Expression>();
+        while (exprNode != null) {
+            if (isType(EXPR, exprNode)) {
+                Expression expr = expression(exprNode);
+                configureAST(expr, exprNode);
+                list.add(expr);
+            } else {
+                assertNodeType(EMPTY_STAT, exprNode);
+                list.add(EmptyExpression.INSTANCE);
+            }
+
+            exprNode = exprNode.getNextSibling();
+        }
+        ClosureListExpression cle = new ClosureListExpression(list);
+        configureAST(cle, node);
+        return cle;
+    }
+
+    private void isClosureListExpressionAllowedHere(AST node) {
+        if (!forStatementBeingDef) {
+            throw new ASTRuntimeException(node,
+                    "Expression list of the form (a; b; c) is not supported in this context.");
+        }
+    }
+
+    protected Expression dynamicMemberExpression(AST dynamicMemberNode) {
+        AST node = dynamicMemberNode.getFirstChild();
+        return expression(node);
+    }
+
+    protected Expression ternaryExpression(AST ternaryNode) {
+        AST node = ternaryNode.getFirstChild();
+        Expression base = expression(node);
+        node = node.getNextSibling();
+        Expression left = expression(node);
+        node = node.getNextSibling();
+        Expression ret;
+        if (node == null) {
+            ret = new ElvisOperatorExpression(base, left);
+        } else {
+            Expression right = expression(node);
+            BooleanExpression booleanExpression = new BooleanExpression(base);
+            booleanExpression.setSourcePosition(base);
+            ret = new TernaryExpression(booleanExpression, left, right);
+        }
+        configureAST(ret, ternaryNode);
+        return ret;
+    }
+
+    protected Expression variableExpression(AST node) {
+        String text = node.getText();
+
+        // TODO we might wanna only try to resolve the name if we are
+        // on the left hand side of an expression or before a dot?
+        VariableExpression variableExpression = new VariableExpression(text);
+        configureAST(variableExpression, node);
+        return variableExpression;
+    }
+
+    protected Expression literalExpression(AST node, Object value) {
+        ConstantExpression constantExpression = new ConstantExpression(value, value instanceof Boolean);
+        configureAST(constantExpression, node);
+        return constantExpression;
+    }
+
+    protected Expression rangeExpression(AST rangeNode, boolean inclusive) {
+        AST node = rangeNode.getFirstChild();
+        Expression left = expression(node);
+        Expression right = expression(node.getNextSibling());
+        RangeExpression rangeExpression = new RangeExpression(left, right, inclusive);
+        configureAST(rangeExpression, rangeNode);
+        return rangeExpression;
+    }
+
+    protected Expression spreadExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        AST listNode = exprNode.getFirstChild();
+        Expression right = expression(listNode);
+        SpreadExpression spreadExpression = new SpreadExpression(right);
+        configureAST(spreadExpression, node);
+        return spreadExpression;
+    }
+
+    protected Expression spreadMapExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        Expression expr = expression(exprNode);
+        SpreadMapExpression spreadMapExpression = new SpreadMapExpression(expr);
+        configureAST(spreadMapExpression, node);
+        return spreadMapExpression;
+    }
+
+    protected Expression methodPointerExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        Expression objectExpression = expression(exprNode);
+        AST mNode = exprNode.getNextSibling();
+        Expression methodName;
+        if (isType(DYNAMIC_MEMBER, mNode)) {
+            methodName = expression(mNode);
+        } else {
+            methodName = new ConstantExpression(identifier(mNode));
+        }
+        configureAST(methodName, mNode);
+        MethodPointerExpression methodPointerExpression = new MethodPointerExpression(objectExpression, methodName);
+        configureAST(methodPointerExpression, node);
+        return methodPointerExpression;
+    }
+
+/*  commented out due to groovy.g non-determinisms
+  protected Expression defaultMethodPointerExpression(AST node) {
+        AST exprNode = node.getFirstChild();
+        String methodName = exprNode.toString();
+        MethodPointerExpression methodPointerExpression =

<TRUNCATED>

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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
new file mode 100644
index 0000000..eec02af
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -0,0 +1,18930 @@
+/*
+ *  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.runtime;
+
+import groovy.io.FileType;
+import groovy.io.GroovyPrintWriter;
+import groovy.lang.Closure;
+import groovy.lang.DelegatesTo;
+import groovy.lang.DelegatingMetaClass;
+import groovy.lang.EmptyRange;
+import groovy.lang.ExpandoMetaClass;
+import groovy.lang.GString;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+import groovy.lang.Groovydoc;
+import groovy.lang.IntRange;
+import groovy.lang.ListWithDefault;
+import groovy.lang.MapWithDefault;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaClassRegistry;
+import groovy.lang.MetaMethod;
+import groovy.lang.MetaProperty;
+import groovy.lang.MissingPropertyException;
+import groovy.lang.ObjectRange;
+import groovy.lang.PropertyValue;
+import groovy.lang.Range;
+import groovy.lang.SpreadMap;
+import groovy.lang.Tuple2;
+import groovy.lang.Writable;
+import groovy.transform.stc.ClosureParams;
+import groovy.transform.stc.FirstParam;
+import groovy.transform.stc.FromString;
+import groovy.transform.stc.MapEntryOrKeyValue;
+import groovy.transform.stc.SimpleType;
+import groovy.util.BufferedIterator;
+import groovy.util.ClosureComparator;
+import groovy.util.GroovyCollections;
+import groovy.util.MapEntry;
+import groovy.util.OrderBy;
+import groovy.util.PermutationGenerator;
+import groovy.util.ProxyGenerator;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.reflection.MixinInMetaClass;
+import org.codehaus.groovy.reflection.ReflectionCache;
+import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
+import org.codehaus.groovy.runtime.callsite.BooleanClosureWrapper;
+import org.codehaus.groovy.runtime.callsite.BooleanReturningMethodInvoker;
+import org.codehaus.groovy.runtime.dgmimpl.NumberNumberDiv;
+import org.codehaus.groovy.runtime.dgmimpl.NumberNumberMinus;
+import org.codehaus.groovy.runtime.dgmimpl.NumberNumberMultiply;
+import org.codehaus.groovy.runtime.dgmimpl.NumberNumberPlus;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.BooleanArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.BooleanArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.ByteArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.ByteArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.CharacterArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.CharacterArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.DoubleArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.DoubleArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.FloatArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.FloatArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.IntegerArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.IntegerArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.LongArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.LongArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.ObjectArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.ObjectArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.ShortArrayGetAtMetaMethod;
+import org.codehaus.groovy.runtime.dgmimpl.arrays.ShortArrayPutAtMetaMethod;
+import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
+import org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
+import org.codehaus.groovy.runtime.typehandling.NumberMath;
+import org.codehaus.groovy.tools.RootLoader;
+import org.codehaus.groovy.transform.trait.Traits;
+import org.codehaus.groovy.util.ArrayIterator;
+import org.codehaus.groovy.util.IteratorBufferedIterator;
+import org.codehaus.groovy.util.ListBufferedIterator;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.text.MessageFormat;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.Stack;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.BlockingQueue;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * This class defines new groovy methods which appear on normal JDK
+ * classes inside the Groovy environment. Static methods are used with the
+ * first parameter being the destination class,
+ * i.e. <code>public static String reverse(String self)</code>
+ * provides a <code>reverse()</code> method for <code>String</code>.
+ * <p>
+ * NOTE: While this class contains many 'public' static methods, it is
+ * primarily regarded as an internal class (its internal package name
+ * suggests this also). We value backwards compatibility of these
+ * methods when used within Groovy but value less backwards compatibility
+ * at the Java method call level. I.e. future versions of Groovy may
+ * remove or move a method call in this file but would normally
+ * aim to keep the method available from within Groovy.
+ */
+public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
+
+    private static final Logger LOG = Logger.getLogger(DefaultGroovyMethods.class.getName());
+    private static final Integer ONE = 1;
+    private static final BigInteger BI_INT_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
+    private static final BigInteger BI_INT_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
+    private static final BigInteger BI_LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
+    private static final BigInteger BI_LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);
+
+    public static final Class[] ADDITIONAL_CLASSES = {
+            NumberNumberPlus.class,
+            NumberNumberMultiply.class,
+            NumberNumberMinus.class,
+            NumberNumberDiv.class,
+            ObjectArrayGetAtMetaMethod.class,
+            ObjectArrayPutAtMetaMethod.class,
+            BooleanArrayGetAtMetaMethod.class,
+            BooleanArrayPutAtMetaMethod.class,
+            ByteArrayGetAtMetaMethod.class,
+            ByteArrayPutAtMetaMethod.class,
+            CharacterArrayGetAtMetaMethod.class,
+            CharacterArrayPutAtMetaMethod.class,
+            ShortArrayGetAtMetaMethod.class,
+            ShortArrayPutAtMetaMethod.class,
+            IntegerArrayGetAtMetaMethod.class,
+            IntegerArrayPutAtMetaMethod.class,
+            LongArrayGetAtMetaMethod.class,
+            LongArrayPutAtMetaMethod.class,
+            FloatArrayGetAtMetaMethod.class,
+            FloatArrayPutAtMetaMethod.class,
+            DoubleArrayGetAtMetaMethod.class,
+            DoubleArrayPutAtMetaMethod.class,
+    };
+
+    public static final Class[] DGM_LIKE_CLASSES = new Class[]{
+            DefaultGroovyMethods.class,
+            DateGroovyMethods.class,
+            EncodingGroovyMethods.class,
+            IOGroovyMethods.class,
+            ProcessGroovyMethods.class,
+            ResourceGroovyMethods.class,
+            SocketGroovyMethods.class,
+            StringGroovyMethods.class//,
+            // TODO provide alternative way for these to be registered
+//            SqlGroovyMethods.class,
+//            SwingGroovyMethods.class,
+//            XmlGroovyMethods.class,
+//            NioGroovyMethods.class
+    };
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+    private static final NumberAwareComparator<Comparable> COMPARABLE_NUMBER_AWARE_COMPARATOR = new NumberAwareComparator<Comparable>();
+
+    /**
+     * Identity check. Since == is overridden in Groovy with the meaning of equality
+     * we need some fallback to check for object identity.  Invoke using the
+     * 'is' method, like so: <code>def same = this.is(that)</code>
+     *
+     * @param self  an object
+     * @param other an object to compare identity with
+     * @return true if self and other are both references to the same
+     *         instance, false otherwise
+     * @since 1.0
+     */
+    public static boolean is(Object self, Object other) {
+        return self == other;
+    }
+
+    /**
+     * Allows the closure to be called for the object reference self.
+     * Synonym for 'with()'.
+     *
+     * @param self    the object to have a closure act upon
+     * @param closure the closure to call on the object
+     * @return result of calling the closure
+     * @see #with(Object, Closure)
+     * @since 1.0
+     */
+    public static <T,U> T identity(
+            @DelegatesTo.Target("self") U self,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+                    Closure<T> closure) {
+        return DefaultGroovyMethods.with(self, closure);
+    }
+
+    /**
+     * Allows the closure to be called for the object reference self.
+     * <p>
+     * Any method invoked inside the closure will first be invoked on the
+     * self reference. For instance, the following method calls to the append()
+     * method are invoked on the StringBuilder instance:
+     * <pre class="groovyTestCase">
+     * def b = new StringBuilder().with {
+     *   append('foo')
+     *   append('bar')
+     *   return it
+     * }
+     * assert b.toString() == 'foobar'
+     * </pre>
+     * This is commonly used to simplify object creation, such as this example:
+     * <pre>
+     * def p = new Person().with {
+     *   firstName = 'John'
+     *   lastName = 'Doe'
+     *   return it
+     * }
+     * </pre>
+     * The other typical usage, uses the self object while creating some value:
+     * <pre>
+     * def fullName = person.with{ "$firstName $lastName" }
+     * </pre>
+     *
+     * @param self    the object to have a closure act upon
+     * @param closure the closure to call on the object
+     * @return result of calling the closure
+     * @see #with(Object, boolean, Closure)
+     * @see #tap(Object, Closure)
+     * @since 1.5.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T,U> T with(
+            @DelegatesTo.Target("self") U self,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+            Closure<T> closure) {
+        return (T) with(self, false, (Closure<Object>)closure);
+    }
+
+    /**
+     * Allows the closure to be called for the object reference self.
+     * <p/>
+     * Any method invoked inside the closure will first be invoked on the
+     * self reference. For example, the following method calls to the append()
+     * method are invoked on the StringBuilder instance and then, because
+     * 'returning' is true, the self instance is returned:
+     * <pre class="groovyTestCase">
+     * def b = new StringBuilder().with(true) {
+     *   append('foo')
+     *   append('bar')
+     * }
+     * assert b.toString() == 'foobar'
+     * </pre>
+     * The returning parameter is commonly set to true when using with to simplify object
+     * creation, such as this example:
+     * <pre>
+     * def p = new Person().with(true) {
+     *   firstName = 'John'
+     *   lastName = 'Doe'
+     * }
+     * </pre>
+     * Alternatively, 'tap' is an alias for 'with(true)', so that method can be used instead.
+     *
+     * The other main use case for with is when returning a value calculated using self as shown here:
+     * <pre>
+     * def fullName = person.with(false){ "$firstName $lastName" }
+     * </pre>
+     * Alternatively, 'with' is an alias for 'with(false)', so the boolean parameter can be ommitted instead.
+     *
+     * @param self      the object to have a closure act upon
+     * @param returning if true, return the self object; otherwise, the result of calling the closure
+     * @param closure   the closure to call on the object
+     * @return the self object or the result of calling the closure depending on 'returning'
+     * @see #with(Object, Closure)
+     * @see #tap(Object, Closure)
+     * @since 2.5.0
+     */
+    public static <T,U extends T, V extends T> T with(
+            @DelegatesTo.Target("self") U self,
+            boolean returning,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+            Closure<T> closure) {
+        @SuppressWarnings("unchecked")
+        final Closure<V> clonedClosure = (Closure<V>) closure.clone();
+        clonedClosure.setResolveStrategy(Closure.DELEGATE_FIRST);
+        clonedClosure.setDelegate(self);
+        V result = clonedClosure.call(self);
+        return returning ? self : result;
+    }
+
+    /**
+     * Allows the closure to be called for the object reference self (similar
+     * to <code>with</code> and always returns self.
+     * <p>
+     * Any method invoked inside the closure will first be invoked on the
+     * self reference. For instance, the following method calls to the append()
+     * method are invoked on the StringBuilder instance:
+     * <pre>
+     * def b = new StringBuilder().tap {
+     *   append('foo')
+     *   append('bar')
+     * }
+     * assert b.toString() == 'foobar'
+     * </pre>
+     * This is commonly used to simplify object creation, such as this example:
+     * <pre>
+     * def p = new Person().tap {
+     *   firstName = 'John'
+     *   lastName = 'Doe'
+     * }
+     * </pre>
+     *
+     * @param self    the object to have a closure act upon
+     * @param closure the closure to call on the object
+     * @return self
+     * @see #with(Object, boolean, Closure)
+     * @see #with(Object, Closure)
+     * @since 2.5.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T,U> U tap(
+            @DelegatesTo.Target("self") U self,
+            @DelegatesTo(value=DelegatesTo.Target.class,
+                    target="self",
+                    strategy=Closure.DELEGATE_FIRST)
+            @ClosureParams(FirstParam.class)
+            Closure<T> closure) {
+        return (U) with(self, true, (Closure<Object>)closure);
+    }
+
+    /**
+     * Allows the subscript operator to be used to lookup dynamic property values.
+     * <code>bean[somePropertyNameExpression]</code>. The normal property notation
+     * of groovy is neater and more concise but only works with compile-time known
+     * property names.
+     *
+     * @param self     the object to act upon
+     * @param property the property name of interest
+     * @return the property value
+     * @since 1.0
+     */
+    public static Object getAt(Object self, String property) {
+        return InvokerHelper.getProperty(self, property);
+    }
+
+    /**
+     * Allows the subscript operator to be used to set dynamically named property values.
+     * <code>bean[somePropertyNameExpression] = foo</code>. The normal property notation
+     * of groovy is neater and more concise but only works with property names which
+     * are known at compile time.
+     *
+     * @param self     the object to act upon
+     * @param property the name of the property to set
+     * @param newValue the value to set
+     * @since 1.0
+     */
+    public static void putAt(Object self, String property, Object newValue) {
+        InvokerHelper.setProperty(self, property, newValue);
+    }
+
+    /**
+     * Generates a detailed dump string of an object showing its class,
+     * hashCode and fields.
+     *
+     * @param self an object
+     * @return the dump representation
+     * @since 1.0
+     */
+    public static String dump(Object self) {
+        if (self == null) {
+            return "null";
+        }
+        StringBuilder buffer = new StringBuilder("<");
+        Class klass = self.getClass();
+        buffer.append(klass.getName());
+        buffer.append("@");
+        buffer.append(Integer.toHexString(self.hashCode()));
+        boolean groovyObject = self instanceof GroovyObject;
+
+        /*jes this may be rewritten to use the new getProperties() stuff
+         * but the original pulls out private variables, whereas getProperties()
+         * does not. What's the real use of dump() here?
+         */
+        while (klass != null) {
+            for (final Field field : klass.getDeclaredFields()) {
+                if ((field.getModifiers() & Modifier.STATIC) == 0) {
+                    if (groovyObject && field.getName().equals("metaClass")) {
+                        continue;
+                    }
+                    AccessController.doPrivileged(new PrivilegedAction() {
+                        public Object run() {
+                            field.setAccessible(true);
+                            return null;
+                        }
+                    });
+                    buffer.append(" ");
+                    buffer.append(field.getName());
+                    buffer.append("=");
+                    try {
+                        buffer.append(InvokerHelper.toString(field.get(self)));
+                    } catch (Exception e) {
+                        buffer.append(e);
+                    }
+                }
+            }
+
+            klass = klass.getSuperclass();
+        }
+
+        /* here is a different implementation that uses getProperties(). I have left
+         * it commented out because it returns a slightly different list of properties;
+         * i.e. it does not return privates. I don't know what dump() really should be doing,
+         * although IMO showing private fields is a no-no
+         */
+        /*
+        List props = getProperties(self);
+            for(Iterator itr = props.keySet().iterator(); itr.hasNext(); ) {
+            String propName = itr.next().toString();
+
+            // the original skipped this, so I will too
+            if(pv.getName().equals("class")) continue;
+            if(pv.getName().equals("metaClass")) continue;
+
+            buffer.append(" ");
+            buffer.append(propName);
+            buffer.append("=");
+            try {
+                buffer.append(InvokerHelper.toString(props.get(propName)));
+            }
+            catch (Exception e) {
+                buffer.append(e);
+            }
+        }
+        */
+
+        buffer.append(">");
+        return buffer.toString();
+    }
+
+    /**
+     * Retrieves the list of {@link groovy.lang.MetaProperty} objects for 'self' and wraps it
+     * in a list of {@link groovy.lang.PropertyValue} objects that additionally provide
+     * the value for each property of 'self'.
+     *
+     * @param self the receiver object
+     * @return list of {@link groovy.lang.PropertyValue} objects
+     * @see groovy.util.Expando#getMetaPropertyValues()
+     * @since 1.0
+     */
+    public static List<PropertyValue> getMetaPropertyValues(Object self) {
+        MetaClass metaClass = InvokerHelper.getMetaClass(self);
+        List<MetaProperty> mps = metaClass.getProperties();
+        List<PropertyValue> props = new ArrayList<PropertyValue>(mps.size());
+        for (MetaProperty mp : mps) {
+            props.add(new PropertyValue(self, mp));
+        }
+        return props;
+    }
+
+    /**
+     * Convenience method that calls {@link #getMetaPropertyValues(java.lang.Object)}(self)
+     * and provides the data in form of simple key/value pairs, i.e. without
+     * type() information.
+     *
+     * @param self the receiver object
+     * @return meta properties as Map of key/value pairs
+     * @since 1.0
+     */
+    public static Map getProperties(Object self) {
+        List<PropertyValue> metaProps = getMetaPropertyValues(self);
+        Map<String, Object> props = new LinkedHashMap<String, Object>(metaProps.size());
+
+        for (PropertyValue mp : metaProps) {
+            try {
+                props.put(mp.getName(), mp.getValue());
+            } catch (Exception e) {
+                LOG.throwing(self.getClass().getName(), "getProperty(" + mp.getName() + ")", e);
+            }
+        }
+        return props;
+    }
+
+    /**
+     * Scoped use method
+     *
+     * @param self          any Object
+     * @param categoryClass a category class to use
+     * @param closure       the closure to invoke with the category in place
+     * @return the value returned from the closure
+     * @since 1.0
+     */
+    public static <T> T use(Object self, Class categoryClass, Closure<T> closure) {
+        return GroovyCategorySupport.use(categoryClass, closure);
+    }
+
+    /**
+     * Extend object with category methods.
+     * All methods for given class and all super classes will be added to the object.
+     *
+     * @param self          any Class
+     * @param categoryClasses a category classes to use
+     * @since 1.6.0
+     */
+    public static void mixin(MetaClass self, List<Class> categoryClasses) {
+        MixinInMetaClass.mixinClassesToMetaClass(self, categoryClasses);
+    }
+
+    /**
+     * Extend class globally with category methods.
+     * All methods for given class and all super classes will be added to the class.
+     *
+     * @param self          any Class
+     * @param categoryClasses a category classes to use
+     * @since 1.6.0
+     */
+    public static void mixin(Class self, List<Class> categoryClasses) {
+        mixin(getMetaClass(self), categoryClasses);
+    }
+
+    /**
+     * Extend class globally with category methods.
+     *
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
+     */
+    public static void mixin(Class self, Class categoryClass) {
+        mixin(getMetaClass(self), Collections.singletonList(categoryClass));
+    }
+
+    /**
+     * Extend class globally with category methods.
+     *
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
+     */
+    public static void mixin(Class self, Class[] categoryClass) {
+        mixin(getMetaClass(self), Arrays.asList(categoryClass));
+    }
+
+    /**
+     * Extend class globally with category methods.
+     *
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
+     */
+    public static void mixin(MetaClass self, Class categoryClass) {
+        mixin(self, Collections.singletonList(categoryClass));
+    }
+
+    /**
+     * Extend class globally with category methods.
+     *
+     * @param self          any Class
+     * @param categoryClass a category class to use
+     * @since 1.6.0
+     */
+    public static void mixin(MetaClass self, Class[] categoryClass) {
+        mixin(self, Arrays.asList(categoryClass));
+    }
+
+    /**
+     * Scoped use method with list of categories.
+     *
+     * @param self              any Object
+     * @param categoryClassList a list of category classes
+     * @param closure           the closure to invoke with the categories in place
+     * @return the value returned from the closure
+     * @since 1.0
+     */
+    public static <T> T use(Object self, List<Class> categoryClassList, Closure<T> closure) {
+        return GroovyCategorySupport.use(categoryClassList, closure);
+    }
+
+    /**
+     * Allows the usage of addShutdownHook without getting the runtime first.
+     *
+     * @param self    the object the method is called on (ignored)
+     * @param closure the shutdown hook action
+     * @since 1.5.0
+     */
+    public static void addShutdownHook(Object self, Closure closure) {
+        Runtime.getRuntime().addShutdownHook(new Thread(closure));
+    }
+
+    /**
+     * Allows you to use a list of categories, specifying the list as varargs.
+     * <code>use(CategoryClass1, CategoryClass2) { ... }</code>
+     * This method saves having to wrap the the category
+     * classes in a list.
+     *
+     * @param self  any Object
+     * @param array a list of category classes and a Closure
+     * @return the value returned from the closure
+     * @since 1.0
+     */
+    public static Object use(Object self, Object[] array) {
+        if (array.length < 2)
+            throw new IllegalArgumentException(
+                    "Expecting at least 2 arguments, a category class and a Closure");
+        Closure closure;
+        try {
+            closure = (Closure) array[array.length - 1];
+        } catch (ClassCastException e) {
+            throw new IllegalArgumentException("Expecting a Closure to be the last argument");
+        }
+        List<Class> list = new ArrayList<Class>(array.length - 1);
+        for (int i = 0; i < array.length - 1; ++i) {
+            Class categoryClass;
+            try {
+                categoryClass = (Class) array[i];
+            } catch (ClassCastException e) {
+                throw new IllegalArgumentException("Expecting a Category Class for argument " + i);
+            }
+            list.add(categoryClass);
+        }
+        return GroovyCategorySupport.use(list, closure);
+    }
+
+    /**
+     * Print a value formatted Groovy style to self if it
+     * is a Writer, otherwise to the standard output stream.
+     *
+     * @param self  any Object
+     * @param value the value to print
+     * @since 1.0
+     */
+    public static void print(Object self, Object value) {
+        // we won't get here if we are a PrintWriter
+        if (self instanceof Writer) {
+            try {
+                ((Writer) self).write(InvokerHelper.toString(value));
+            } catch (IOException e) {
+                // TODO: Should we have some unified function like PrintWriter.checkError()?
+            }
+        } else {
+            System.out.print(InvokerHelper.toString(value));
+        }
+    }
+
+    /**
+     * Print a value formatted Groovy style to the print writer.
+     *
+     * @param self  a PrintWriter
+     * @param value the value to print
+     * @since 1.0
+     */
+    public static void print(PrintWriter self, Object value) {
+        self.print(InvokerHelper.toString(value));
+    }
+
+    /**
+     * Print a value formatted Groovy style to the print stream.
+     *
+     * @param self  a PrintStream
+     * @param value the value to print
+     * @since 1.6.0
+     */
+    public static void print(PrintStream self, Object value) {
+        self.print(InvokerHelper.toString(value));
+    }
+
+    /**
+     * Print a value to the standard output stream.
+     * This method delegates to the owner to execute the method.
+     *
+     * @param self  a generated closure
+     * @param value the value to print
+     * @since 1.0
+     */
+    public static void print(Closure self, Object value) {
+        Object owner = getClosureOwner(self);
+        InvokerHelper.invokeMethod(owner, "print", new Object[]{value});
+    }
+
+    /**
+     * Print a linebreak to the standard output stream.
+     *
+     * @param self any Object
+     * @since 1.0
+     */
+    public static void println(Object self) {
+        // we won't get here if we are a PrintWriter
+        if (self instanceof Writer) {
+            PrintWriter pw = new GroovyPrintWriter((Writer) self);
+            pw.println();
+        } else {
+            System.out.println();
+        }
+    }
+
+    /**
+     * Print a linebreak to the standard output stream.
+     * This method delegates to the owner to execute the method.
+     *
+     * @param self  a closure
+     * @since 1.0
+     */
+    public static void println(Closure self) {
+        Object owner = getClosureOwner(self);
+        InvokerHelper.invokeMethod(owner, "println", EMPTY_OBJECT_ARRAY);
+    }
+
+    private static Object getClosureOwner(Closure cls) {
+        Object owner =  cls.getOwner();
+        while (owner instanceof GeneratedClosure) {
+            owner = ((Closure) owner).getOwner();
+        }
+        return owner;
+    }
+
+    /**
+     * Print a value formatted Groovy style (followed by a newline) to self
+     * if it is a Writer, otherwise to the standard output stream.
+     *
+     * @param self  any Object
+     * @param value the value to print
+     * @since 1.0
+     */
+    public static void println(Object self, Object value) {
+        // we won't get here if we are a PrintWriter
+        if (self instanceof Writer) {
+            final PrintWriter pw = new GroovyPrintWriter((Writer) self);
+            pw.println(value);
+        } else {
+            System.out.println(InvokerHelper.toString(value));
+        }
+    }
+
+    /**
+     * Print a value formatted Groovy style (followed by a newline) to the print writer.
+     *
+     * @param self  a PrintWriter
+     * @param value the value to print
+     * @since 1.0
+     */
+    public static void println(PrintWriter self, Object value) {
+        self.println(InvokerHelper.toString(value));
+    }
+
+    /**
+     * Print a value formatted Groovy style (followed by a newline) to the print stream.
+     *
+     * @param self  any Object
+     * @param value the value to print
+     * @since 1.6.0
+     */
+    public static void println(PrintStream self, Object value) {
+        self.println(InvokerHelper.toString(value));
+    }
+
+    /**
+     * Print a value (followed by a newline) to the standard output stream.
+     * This method delegates to the owner to execute the method.
+     *
+     * @param self  a closure
+     * @param value the value to print
+     * @since 1.0
+     */
+    public static void println(Closure self, Object value) {
+        Object owner = getClosureOwner(self);
+        InvokerHelper.invokeMethod(owner, "println", new Object[]{value});
+    }
+
+    /**
+     * Printf to a console.
+     *
+     * @param self   any Object
+     * @param format a format string
+     * @param values values referenced by the format specifiers in the format string.
+     * @since 1.0
+     */
+    public static void printf(Object self, String format, Object[] values) {
+        if (self instanceof PrintStream)
+            ((PrintStream)self).printf(format, values);
+        else
+            System.out.printf(format, values);
+    }
+
+    /**
+     * Sprintf to a string.
+     *
+     * @param self   any Object
+     * @param format a format string
+     * @param values values referenced by the format specifiers in the format string.
+     * @return the resulting formatted string
+     * @since 1.5.0
+     */
+    public static String sprintf(Object self, String format, Object[] values) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        PrintStream out = new PrintStream(outputStream);
+        out.printf(format, values);
+        return outputStream.toString();
+    }
+
+    /**
+     * Prints a formatted string using the specified format string and
+     * arguments.
+     * <p>
+     * Examples:
+     * <pre>
+     *     printf ( "Hello, %s!\n" , [ "world" ] as String[] )
+     *     printf ( "Hello, %s!\n" , [ "Groovy" ])
+     *     printf ( "%d + %d = %d\n" , [ 1 , 2 , 1+2 ] as Integer[] )
+     *     printf ( "%d + %d = %d\n" , [ 3 , 3 , 3+3 ])
+     *
+     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as Integer[] ) }
+     *     ( 1..5 ).each { printf ( "-- %d\n" , [ it ] as int[] ) }
+     *     ( 0x41..0x45 ).each { printf ( "-- %c\n" , [ it ] as char[] ) }
+     *     ( 07..011 ).each { printf ( "-- %d\n" , [ it ] as byte[] ) }
+     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as short[] ) }
+     *     ( 7..11 ).each { printf ( "-- %d\n" , [ it ] as long[] ) }
+     *     ( 7..11 ).each { printf ( "-- %5.2f\n" , [ it ] as float[] ) }
+     *     ( 7..11 ).each { printf ( "-- %5.2g\n" , [ it ] as double[] ) }
+     * </pre>
+     *
+     * @param self   any Object
+     * @param format A format string
+     * @param arg    Argument which is referenced by the format specifiers in the format
+     *               string.  The type of <code>arg</code> should be one of Object[], List,
+     *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
+     * @since 1.0
+     */
+    public static void printf(Object self, String format, Object arg) {
+        if (self instanceof PrintStream)
+            printf((PrintStream) self, format, arg);
+        else if (self instanceof Writer)
+            printf((Writer) self, format, arg);
+        else
+            printf(System.out, format, arg);
+    }
+
+    private static void printf(PrintStream self, String format, Object arg) {
+        self.print(sprintf(self, format, arg));
+    }
+
+    private static void printf(Writer self, String format, Object arg) {
+        try {
+            self.write(sprintf(self, format, arg));
+        } catch (IOException e) {
+            printf(System.out, format, arg);
+        }
+    }
+
+    /**
+     * Returns a formatted string using the specified format string and
+     * arguments.
+     *
+     * @param self   any Object
+     * @param format A format string
+     * @param arg    Argument which is referenced by the format specifiers in the format
+     *               string.  The type of <code>arg</code> should be one of Object[], List,
+     *               int[], short[], byte[], char[], boolean[], long[], float[], or double[].
+     * @return the resulting printf'd string
+     * @since 1.5.0
+     */
+    public static String sprintf(Object self, String format, Object arg) {
+        if (arg instanceof Object[]) {
+            return sprintf(self, format, (Object[]) arg);
+        }
+        if (arg instanceof List) {
+            return sprintf(self, format, ((List) arg).toArray());
+        }
+        if (!arg.getClass().isArray()) {
+            Object[] o = (Object[]) java.lang.reflect.Array.newInstance(arg.getClass(), 1);
+            o[0] = arg;
+            return sprintf(self, format, o);
+        }
+
+        Object[] ans;
+        String elemType = arg.getClass().getName();
+        if (elemType.equals("[I")) {
+            int[] ia = (int[]) arg;
+            ans = new Integer[ia.length];
+            for (int i = 0; i < ia.length; i++) {
+                ans[i] = ia[i];
+            }
+        } else if (elemType.equals("[C")) {
+            char[] ca = (char[]) arg;
+            ans = new Character[ca.length];
+            for (int i = 0; i < ca.length; i++) {
+                ans[i] = ca[i];
+            }
+        } else if (elemType.equals("[Z")) {
+            boolean[] ba = (boolean[]) arg;
+            ans = new Boolean[ba.length];
+            for (int i = 0; i < ba.length; i++) {
+                ans[i] = ba[i];
+            }
+        } else if (elemType.equals("[B")) {
+            byte[] ba = (byte[]) arg;
+            ans = new Byte[ba.length];
+            for (int i = 0; i < ba.length; i++) {
+                ans[i] = ba[i];
+            }
+        } else if (elemType.equals("[S")) {
+            short[] sa = (short[]) arg;
+            ans = new Short[sa.length];
+            for (int i = 0; i < sa.length; i++) {
+                ans[i] = sa[i];
+            }
+        } else if (elemType.equals("[F")) {
+            float[] fa = (float[]) arg;
+            ans = new Float[fa.length];
+            for (int i = 0; i < fa.length; i++) {
+                ans[i] = fa[i];
+            }
+        } else if (elemType.equals("[J")) {
+            long[] la = (long[]) arg;
+            ans = new Long[la.length];
+            for (int i = 0; i < la.length; i++) {
+                ans[i] = la[i];
+            }
+        } else if (elemType.equals("[D")) {
+            double[] da = (double[]) arg;
+            ans = new Double[da.length];
+            for (int i = 0; i < da.length; i++) {
+                ans[i] = da[i];
+            }
+        } else {
+            throw new RuntimeException("sprintf(String," + arg + ")");
+        }
+        return sprintf(self, format, ans);
+    }
+
+
+    /**
+     * Inspects returns the String that matches what would be typed into a
+     * terminal to create this object.
+     *
+     * @param self any Object
+     * @return a String that matches what would be typed into a terminal to
+     *         create this object. e.g. [1, 'hello'].inspect() -> [1, "hello"]
+     * @since 1.0
+     */
+    public static String inspect(Object self) {
+        return InvokerHelper.inspect(self);
+    }
+
+    /**
+     * Print to a console in interactive format.
+     *
+     * @param self any Object
+     * @param out  the PrintWriter used for printing
+     * @since 1.0
+     */
+    public static void print(Object self, PrintWriter out) {
+        if (out == null) {
+            out = new PrintWriter(System.out);
+        }
+        out.print(InvokerHelper.toString(self));
+    }
+
+    /**
+     * Print to a console in interactive format.
+     *
+     * @param self any Object
+     * @param out  the PrintWriter used for printing
+     * @since 1.0
+     */
+    public static void println(Object self, PrintWriter out) {
+        if (out == null) {
+            out = new PrintWriter(System.out);
+        }
+        out.println(InvokerHelper.toString(self));
+    }
+
+    /**
+     * Provide a dynamic method invocation method which can be overloaded in
+     * classes to implement dynamic proxies easily.
+     *
+     * @param object    any Object
+     * @param method    the name of the method to call
+     * @param arguments the arguments to use
+     * @return the result of the method call
+     * @since 1.0
+     */
+    public static Object invokeMethod(Object object, String method, Object arguments) {
+        return InvokerHelper.invokeMethod(object, method, arguments);
+    }
+
+    // isCase methods
+    //-------------------------------------------------------------------------
+
+    /**
+     * Method for overloading the behavior of the 'case' method in switch statements.
+     * The default implementation handles arrays types but otherwise simply delegates
+     * to Object#equals, but this may be overridden for other types. In this example:
+     * <pre> switch( a ) {
+     *   case b: //some code
+     * }</pre>
+     * "some code" is called when <code>b.isCase( a )</code> returns
+     * <code>true</code>.
+     *
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the switchValue is deemed to be equal to the caseValue
+     * @since 1.0
+     */
+    public static boolean isCase(Object caseValue, Object switchValue) {
+        if (caseValue.getClass().isArray()) {
+            return isCase(DefaultTypeTransformation.asCollection(caseValue), switchValue);
+        }
+        return caseValue.equals(switchValue);
+    }
+
+    /**
+     * Special 'Case' implementation for Class, which allows testing
+     * for a certain class in a switch statement.
+     * For example:
+     * <pre>switch( obj ) {
+     *   case List :
+     *     // obj is a list
+     *     break;
+     *   case Set :
+     *     // etc
+     * }</pre>
+     *
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the switchValue is deemed to be assignable from the given class
+     * @since 1.0
+     */
+    public static boolean isCase(Class caseValue, Object switchValue) {
+        if (switchValue instanceof Class) {
+            Class val = (Class) switchValue;
+            return caseValue.isAssignableFrom(val);
+        }
+        return caseValue.isInstance(switchValue);
+    }
+
+    /**
+     * 'Case' implementation for collections which tests if the 'switch'
+     * operand is contained in any of the 'case' values.
+     * For example:
+     * <pre class="groovyTestCase">switch( 3 ) {
+     *   case [1,3,5]:
+     *     assert true
+     *     break
+     *   default:
+     *     assert false
+     * }</pre>
+     *
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the caseValue is deemed to contain the switchValue
+     * @see java.util.Collection#contains(java.lang.Object)
+     * @since 1.0
+     */
+    public static boolean isCase(Collection caseValue, Object switchValue) {
+        return caseValue.contains(switchValue);
+    }
+
+    /**
+     * 'Case' implementation for maps which tests the groovy truth
+     * value obtained using the 'switch' operand as key.
+     * For example:
+     * <pre class="groovyTestCase">switch( 'foo' ) {
+     *   case [foo:true, bar:false]:
+     *     assert true
+     *     break
+     *   default:
+     *     assert false
+     * }</pre>
+     *
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return the groovy truth value from caseValue corresponding to the switchValue key
+     * @since 1.7.6
+     */
+    public static boolean isCase(Map caseValue, Object switchValue) {
+        return DefaultTypeTransformation.castToBoolean(caseValue.get(switchValue));
+    }
+
+    /**
+     * Special 'case' implementation for all numbers, which delegates to the
+     * <code>compareTo()</code> method for comparing numbers of different
+     * types.
+     *
+     * @param caseValue   the case value
+     * @param switchValue the switch value
+     * @return true if the numbers are deemed equal
+     * @since 1.5.0
+     */
+    public static boolean isCase(Number caseValue, Number switchValue) {
+        return NumberMath.compareTo(caseValue, switchValue) == 0;
+    }
+
+    /**
+     * Returns an iterator equivalent to this iterator with all duplicated items removed
+     * by using Groovy's default number-aware comparator. The original iterator will become
+     * exhausted of elements after determining the unique values. A new iterator
+     * for the unique values will be returned.
+     *
+     * @param self an Iterator
+     * @return a new Iterator of the unique items from the original iterator
+     * @since 1.5.5
+     */
+    public static <T> Iterator<T> unique(Iterator<T> self) {
+        return uniqueItems(new IteratorIterableAdapter<T>(self)).listIterator();
+    }
+
+    /**
+     * Modifies this collection to remove all duplicated items, using Groovy's
+     * default number-aware comparator.
+     * <pre class="groovyTestCase">assert [1,3] == [1,3,3].unique()</pre>
+     *
+     * @param self a collection
+     * @return the now modified collection
+     * @see #unique(Collection, boolean)
+     * @since 1.0
+     */
+    public static <T> Collection<T> unique(Collection<T> self) {
+        return unique(self, true);
+    }
+
+    /**
+     * Modifies this List to remove all duplicated items, using Groovy's
+     * default number-aware comparator.
+     * <pre class="groovyTestCase">assert [1,3] == [1,3,3].unique()</pre>
+     *
+     * @param self a List
+     * @return the now modified List
+     * @see #unique(Collection, boolean)
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self) {
+        return (List<T>) unique((Collection<T>) self, true);
+    }
+
+    /**
+     * Remove all duplicates from a given Collection using Groovy's default number-aware comparator.
+     * If mutate is true, it works by modifying the original object (and also returning it).
+     * If mutate is false, a new collection is returned leaving the original unchanged.
+     * <pre class="groovyTestCase">
+     * assert [1,3] == [1,3,3].unique()
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 2, 3]
+     * def uniq = orig.unique(false)
+     * assert orig == [1, 3, 2, 3]
+     * assert uniq == [1, 3, 2]
+     * </pre>
+     *
+     * @param self a collection
+     * @param mutate false will cause a new list containing unique items from the collection to be created, true will mutate collections in place
+     * @return the now modified collection
+     * @since 1.8.1
+     */
+    public static <T> Collection<T> unique(Collection<T> self, boolean mutate) {
+        List<T> answer = uniqueItems(self);
+        if (mutate) {
+            self.clear();
+            self.addAll(answer);
+        }
+        return mutate ? self : answer ;
+    }
+
+    private static <T> List<T> uniqueItems(Iterable<T> self) {
+        List<T> answer = new ArrayList<T>();
+        for (T t : self) {
+            boolean duplicated = false;
+            for (T t2 : answer) {
+                if (coercedEquals(t, t2)) {
+                    duplicated = true;
+                    break;
+                }
+            }
+            if (!duplicated)
+                answer.add(t);
+        }
+        return answer;
+    }
+
+    /**
+     * Remove all duplicates from a given List using Groovy's default number-aware comparator.
+     * If mutate is true, it works by modifying the original object (and also returning it).
+     * If mutate is false, a new collection is returned leaving the original unchanged.
+     * <pre class="groovyTestCase">
+     * assert [1,3] == [1,3,3].unique()
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 2, 3]
+     * def uniq = orig.unique(false)
+     * assert orig == [1, 3, 2, 3]
+     * assert uniq == [1, 3, 2]
+     * </pre>
+     *
+     * @param self a List
+     * @param mutate false will cause a new List containing unique items from the List to be created, true will mutate List in place
+     * @return the now modified List
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, boolean mutate) {
+        return (List<T>) unique((Collection<T>) self, mutate);
+    }
+
+    /**
+     * Provides a method that compares two comparables using Groovy's
+     * default number aware comparator.
+     *
+     * @param self a Comparable
+     * @param other another Comparable
+     * @return a -ve number, 0 or a +ve number according to Groovy's compareTo contract
+     * @since 1.6.0
+     */
+    public static int numberAwareCompareTo(Comparable self, Comparable other) {
+        return COMPARABLE_NUMBER_AWARE_COMPARATOR.compare(self, other);
+    }
+
+    /**
+     * Returns an iterator equivalent to this iterator but with all duplicated items
+     * removed by using a Closure to determine duplicate (equal) items.
+     * The original iterator will be fully processed after the call.
+     * <p>
+     * If the closure takes a single parameter, the argument passed will be each element,
+     * and the closure should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the Iterator
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     *
+     * @param self      an Iterator
+     * @param condition a Closure used to determine unique items
+     * @return the modified Iterator
+     * @since 1.5.5
+     */
+    public static <T> Iterator<T> unique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<T>(condition, true)
+                : new ClosureComparator<T>(condition);
+        return unique(self, comparator);
+    }
+
+    /**
+     * A convenience method for making a collection unique using a Closure
+     * to determine duplicate (equal) items.
+     * <p>
+     * If the closure takes a single parameter, the
+     * argument passed will be each element, and the closure
+     * should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].unique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].unique { a, b -> a <=> b }</pre>
+     *
+     * @param self    a Collection
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @see #unique(Collection, boolean, Closure)
+     * @since 1.0
+     */
+    public static <T> Collection<T> unique(Collection<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return unique(self, true, closure);
+    }
+
+    /**
+     * A convenience method for making a List unique using a Closure
+     * to determine duplicate (equal) items.
+     * <p>
+     * If the closure takes a single parameter, the
+     * argument passed will be each element, and the closure
+     * should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the List
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].unique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].unique { a, b -> a <=> b }</pre>
+     *
+     * @param self    a List
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @see #unique(Collection, boolean, Closure)
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return (List<T>) unique((Collection<T>) self, true, closure);
+    }
+
+    /**
+     * A convenience method for making a collection unique using a Closure to determine duplicate (equal) items.
+     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
+     * <p>
+     * If the closure takes a single parameter, each element from the Collection will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 4, 5]
+     * def uniq = orig.unique(false) { it % 2 }
+     * assert orig == [1, 3, 4, 5]
+     * assert uniq == [1, 4]
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [2, 3, 3, 4]
+     * def uniq = orig.unique(false) { a, b -> a <=> b }
+     * assert orig == [2, 3, 3, 4]
+     * assert uniq == [2, 3, 4]
+     * </pre>
+     *
+     * @param self    a Collection
+     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @since 1.8.1
+     */
+    public static <T> Collection<T> unique(Collection<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        // use a comparator of one item or two
+        int params = closure.getMaximumNumberOfParameters();
+        if (params == 1) {
+            self = unique(self, mutate, new OrderBy<T>(closure, true));
+        } else {
+            self = unique(self, mutate, new ClosureComparator<T>(closure));
+        }
+        return self;
+    }
+
+    /**
+     * A convenience method for making a List unique using a Closure to determine duplicate (equal) items.
+     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
+     * <p>
+     * If the closure takes a single parameter, each element from the List will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 4, 5]
+     * def uniq = orig.unique(false) { it % 2 }
+     * assert orig == [1, 3, 4, 5]
+     * assert uniq == [1, 4]
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [2, 3, 3, 4]
+     * def uniq = orig.unique(false) { a, b -> a <=> b }
+     * assert orig == [2, 3, 3, 4]
+     * assert uniq == [2, 3, 4]
+     * </pre>
+     *
+     * @param self    a List
+     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return (List<T>) unique((Collection<T>) self, mutate, closure);
+    }
+
+    /**
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the supplied comparator. The original iterator
+     * will be exhausted upon returning.
+     *
+     * @param self an Iterator
+     * @param comparator a Comparator
+     * @return the modified Iterator
+     * @since 1.5.5
+     */
+    public static <T> Iterator<T> unique(Iterator<T> self, Comparator<T> comparator) {
+        return uniqueItems(new IteratorIterableAdapter<T>(self), comparator).listIterator();
+    }
+
+    private static final class IteratorIterableAdapter<T> implements Iterable<T> {
+        private final Iterator<T> self;
+
+        private IteratorIterableAdapter(Iterator<T> self) {
+            this.self = self;
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            return self;
+        }
+    }
+
+    /**
+     * Remove all duplicates from a given Collection.
+     * Works on the original object (and also returns it).
+     * The order of members in the Collection are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given Collection's iterator is retained, but all other ones are removed.
+     * The given Collection's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(new PersonComparator())
+     * assert( list2 == list && list == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a Collection
+     * @param comparator a Comparator
+     * @return self      the now modified collection without duplicates
+     * @see #unique(java.util.Collection, boolean, java.util.Comparator)
+     * @since 1.0
+     */
+    public static <T> Collection<T> unique(Collection<T> self, Comparator<T> comparator) {
+        return unique(self, true, comparator) ;
+    }
+
+    /**
+     * Remove all duplicates from a given List.
+     * Works on the original object (and also returns it).
+     * The order of members in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given List's iterator is retained, but all other ones are removed.
+     * The given List's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(new PersonComparator())
+     * assert( list2 == list && list == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a List
+     * @param comparator a Comparator
+     * @return self      the now modified List without duplicates
+     * @see #unique(java.util.Collection, boolean, java.util.Comparator)
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, Comparator<T> comparator) {
+        return (List<T>) unique((Collection<T>) self, true, comparator);
+    }
+
+    /**
+     * Remove all duplicates from a given Collection.
+     * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new collection is returned.
+     * The order of members in the Collection are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given Collection's iterator is retained, but all other ones are removed.
+     * The given Collection's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(false, new PersonComparator())
+     * assert( list2 != list && list2 == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a Collection
+     * @param mutate     false will always cause a new collection to be created, true will mutate collections in place
+     * @param comparator a Comparator
+     * @return self      the collection without duplicates
+     * @since 1.8.1
+     */
+    public static <T> Collection<T> unique(Collection<T> self, boolean mutate, Comparator<T> comparator) {
+        List<T> answer = uniqueItems(self, comparator);
+        if (mutate) {
+            self.clear();
+            self.addAll(answer);
+        }
+        return mutate ? self : answer;
+    }
+
+    private static <T> List<T> uniqueItems(Iterable<T> self, Comparator<T> comparator) {
+        List<T> answer = new ArrayList<T>();
+        for (T t : self) {
+            boolean duplicated = false;
+            for (T t2 : answer) {
+                if (comparator.compare(t, t2) == 0) {
+                    duplicated = true;
+                    break;
+                }
+            }
+            if (!duplicated)
+                answer.add(t);
+        }
+        return answer;
+    }
+
+    /**
+     * Remove all duplicates from a given List.
+     * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new List is returned.
+     * The order of members in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given List's iterator is retained, but all other ones are removed.
+     * The given List's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(false, new PersonComparator())
+     * assert( list2 != list && list2 == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a List
+     * @param mutate     false will always cause a new List to be created, true will mutate List in place
+     * @param comparator a Comparator
+     * @return self      the List without duplicates
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, boolean mutate, Comparator<T> comparator) {
+        return (List<T>) unique((Collection<T>) self, mutate, comparator);
+    }
+
+    /**
+     * Returns an iterator equivalent to this iterator but with all duplicated items
+     * removed where duplicate (equal) items are deduced by calling the supplied Closure condition.
+     * <p>
+     * If the supplied Closure takes a single parameter, the argument passed will be each element,
+     * and the closure should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the Iterator
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def items = "Hello".toList() + [null, null] + "there".toList()
+     * def toLower = { it == null ? null : it.toLowerCase() }
+     * def noDups = items.iterator().toUnique(toLower).toList()
+     * assert noDups == ['H', 'e', 'l', 'o', null, 't', 'r']
+     * </pre>
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].toUnique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].toUnique { a, b -> a <=> b }</pre>
+     *
+     * @param self an Iterator
+     * @param condition a Closure used to determine unique items
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Iterator<T> toUnique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        return toUnique(self, condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<T>(condition, true)
+                : new ClosureComparator<T>(condition));
+    }
+
+    private static final class ToUniqueIterator<E> implements Iterator<E> {
+        private final Iterator<E> delegate;
+        private final Set<E> seen;
+        private boolean exhausted;
+        private E next;
+
+        private ToUniqueIterator(Iterator<E> delegate, Comparator<E> comparator) {
+            this.delegate = delegate;
+            seen = new TreeSet<E>(comparator);
+            advance();
+        }
+
+        public boolean hasNext() {
+            return !exhausted;
+        }
+
+        public E next() {
+            if (exhausted) throw new NoSuchElementException();
+            E result = next;
+            advance();
+            return result;
+        }
+
+        public void remove() {
+            if (exhausted) throw new NoSuchElementException();
+            delegate.remove();
+        }
+
+        private void advance() {
+            boolean foundNext = false;
+            while (!foundNext && !exhausted) {
+                exhausted = !delegate.hasNext();
+                if (!exhausted) {
+                    next = delegate.next();
+                    foundNext = seen.add(next);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the supplied comparator.
+     *
+     * @param self an Iterator
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Iterator<T> toUnique(Iterator<T> self, Comparator<T> comparator) {
+        return new ToUniqueIterator<T>(self, comparator);
+    }
+
+    /**
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the natural ordering of the items.
+     *
+     * @param self an Iterator
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Iterator<T> toUnique(Iterator<T> self) {
+        return toUnique(self, (Comparator<T>) null);
+    }
+
+    /**
+     * Returns a Collection containing the items from the Iterable but with duplicates removed.
+     * The items in the Iterable are compared by the given Comparator.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.toUnique(new PersonComparator())
+     * assert list2 == [a, b, c] && list == [a, b, c, d]
+     * </pre>
+     *
+     * @param self       an Iterable
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the Collection of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> toUnique(Iterable<T> self, Comparator<T> comparator) {
+        Collection<T> result = createSimilarCollection((Collection<T>) self);
+        addAll(result, toUnique(self.iterator(), comparator));
+        return result;
+    }
+
+    /**
+     * Returns a List containing the items from the List but with duplicates removed.
+     * The items in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned from the
+     * List is retained, but all other ones are removed.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.toUnique(new PersonComparator())
+     * assert list2 == [a, b, c] && list == [a, b, c, d]
+     * </pre>
+     *
+     * @param self       a List
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the List of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> List<T> toUnique(List<T> self, Comparator<T> comparator) {
+        return (List<T>) toUnique((Iterable<T>) self, comparator);
+    }
+
+    /**
+     * Returns a Collection containing the items from the Iterable but with duplicates removed
+     * using the natural ordering of the items to determine uniqueness.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * String[] expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique() == expected
+     * </pre>
+     *
+     * @param self       an Iterable
+     * @return the Collection of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> toUnique(Iterable<T> self) {
+        return toUnique(self, (Comparator<T>) null);
+    }
+
+    /**
+     * Returns a List containing the items from the List but with duplicates removed
+     * using the natural ordering of the items to determine uniqueness.
+     * <p>
+     * <pre class="groovyTestCase">
+     * def letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * def expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique() == expected
+     * </pre>
+     *
+     * @param self       a List
+     * @return the List of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> List<T> toUnique(List<T> self) {
+        return toUnique(self, (Comparator<T>) null);
+    }
+
+    /**
+     * Returns a Collection containing the items from the Iterable but with duplicates removed.
+     * The items in the Iterable are compared by the given Closure condition.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * def list2 = list.toUnique{ p1, p2 -> p1.lname != p2.lname ? p1.lname &lt;=&gt; p2.lname : p1.fname &lt;=&gt; p2.fname }
+     * assert( list2 == [a, b, c] && list == [a, b, c, d] )
+     * def list3 = list.toUnique{ it.toString() }
+     * assert( list3 == [a, b, c] && list == [a, b, c, d] )
+     * </pre>
+     *
+     * @param self      an Iterable
+     * @param condition a Closure used to determine unique items
+     * @return a new Collection
+     * @see #toUnique(Iterable, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> toUnique(Iterable<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
+        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<T>(condition, true)
+                : new ClosureComparator<T>(condition);
+        return toUnique(self, comparator);
+    }
+
+    /**
+     * Returns a List containing the items from the List but with duplicates removed.
+     * The items in the List are compared by the given Closure condition.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * def list2 = list.toUnique{ p1, p2 -> p1.lname != p2.lname ? p1.lname &lt;=&gt; p2.lname : p1.fname &lt;=&gt; p2.fname }
+     * assert( list2 == [a, b, c] && list == [a, b, c, d] )
+     * def list3 = list.toUnique{ it.toString() }
+     * assert( list3 == [a, b, c] && list == [a, b, c, d] )
+     * </pre>
+     *
+     * @param self      a List
+     * @param condition a Closure used to determine unique items
+     * @return a new List
+     * @see #toUnique(Iterable, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> List<T> toUnique(List<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
+        return (List<T>) toUnique((Iterable<T>) self, condition);
+    }
+
+    /**
+     * Returns a new Array containing the items from the original Array but with duplicates removed with the supplied
+     * comparator determining which items are unique.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'A', 't', 'h', 'a', 'T']
+     * String[] lower = ['c', 'a', 't', 's', 'h']
+     * class LowerComparator implements Comparator {
+     *     int compare(let1, let2) { let1.toLowerCase() <=> let2.toLowerCase() }
+     * }
+     * assert letters.toUnique(new LowerComparator()) == lower
+     * </pre>
+     *
+     * @param self an array
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the unique items from the array
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] toUnique(T[] self, Comparator<T> comparator) {
+        Collection<T> items = toUnique(toList(self), comparator);
+        T[] result = createSimilarArray(self, items.size());
+        return items.toArray(result);
+    }
+
+    /**
+     * Returns a new Array containing the items from the original Array but with duplicates removed using the
+     * natural ordering of the items in the array.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * String[] expected = ['c', 'a', 't', 's', 'h']
+     * def result = letters.toUnique()
+     * assert result == expected
+     * assert result.class.componentType == String
+     * </pre>
+     *
+     * @param self an array
+     * @return the unique items from the array
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] toUnique(T[] self) {
+        return (T[]) toUnique(self, (Comparator) null);
+    }
+
+    /**
+     * Returns a new Array containing the items from the original Array but with duplicates removed with the supplied
+     * comparator determining which items are unique.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'A', 't', 'h', 'a', 'T']
+     * String[] expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique{ p1, p2 -> p1.toLowerCase() <=> p2.toLowerCase() } == expected
+     * assert letters.toUnique{ it.toLowerCase() } == expected
+     * </pre>
+     *
+     * @param self an array
+     * @param condition a Closure used to determine unique items
+     * @return the unique items from the array
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] toUnique(T[] self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<T>(condition, true)
+                : new ClosureComparator<T>(condition);
+        return toUnique(self, comparator);
+    }
+
+    /**
+     * Iterates through an array passing each array entry to the given closure.
+     * <pre class="groovyTestCase">
+     * String[] letters = ['a', 'b', 'c']
+     * String result = ''
+     * letters.each{ result += it }
+     * assert result == 'abc'
+     * </pre>
+     *
+     * @param self    the array over which we iterate
+     * @param closure the closure applied on each array entry
+     * @return the self array
+     * @since 2.5.0
+     */
+    public static <T> T[] each(T[] self, @ClosureParams(FirstParam.Component.class) Closure closure) {
+        for(T item : self){
+            closure.call(item);
+        }
+        return self;
+    }
+
+    /**
+     * Iterates through an aggregate type or data structure,
+     * passing each item to the given closure.  Custom types may utilize this
+     * method by simply providing an "iterator()" method.  The items returned
+     * from the resulting iterator will be passed to the closure.
+     * <pre class="groovyTestCase">
+     * String result = ''
+     * ['a', 'b', 'c'].each{ result += it }
+     * assert result == 'abc'
+     * </pre>
+     *
+     * @param self    the object over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self Object
+     * @since 1.0
+     */
+    public static <T> T each(T self, Closure closure) {
+        each(InvokerHelper.asIterator(self), closure);
+        return self;
+    }
+
+    /**
+     * Iterates through an array,
+     * passing each array element and the element's index (a counter starting at
+     * zero) to the given closure.
+     * <pre class="groovyTestCase">
+     * String[] letters = ['a', 'b', 'c']
+     * String result = ''
+     * letters.eachWithIndex{ letter, index -> result += "$index:$letter" }
+     * assert result == '0:a1:b2:c'
+     * </pre>
+     *
+     * @param self    an array
+     * @param closure a Closure to operate on each array entry
+     * @return the self array
+     * @since 2.5.0
+     */
+    public static <T> T[] eachWithIndex(T[] self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
+        final Object[] args = new Object[2];
+        int counter = 0;
+        for(T item : self) {
+            args[0] = item;
+            args[1] = counter++;
+            closure.call(args);
+        }
+        return self;
+    }
+
+    /**
+     * Iterates through an aggregate type or data structure,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     * <pre class="groovyTestCase">
+     * String result = ''
+     * ['a', 'b', 'c'].eachWithIndex{ letter, index -> result += "$index:$letter" }
+     * assert result == '0:a1:b2:c'
+     * </pre>
+     *
+     * @param self    an Object
+     * @param closure a Closure to operate on each item
+     * @return the self Object
+     * @since 1.0
+     */
+    public static <T> T eachWithIndex(T self, /*@ClosureParams(value=FromString.class, options="?,Integer")*/ Closure closure) {
+        final Object[] args = new Object[2];
+        int counter = 0;
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            args[0] = iter.next();
+            args[1] = counter++;
+            closure.call(args);
+        }
+        return self;
+    }
+
+    /**
+     * Iterates through an iterable type,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an Iterable
+     * @param closure a Closure to operate on each item
+     * @return the self Iterable
+     * @since 2.3.0
+     */
+    public static <T> Iterable<T> eachWithIndex(Iterable<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+        eachWithIndex(self.iterator(), closure);
+        return self;
+    }
+
+    /**
+     * Iterates through an iterator type,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an Iterator
+     * @param closure a Closure to operate on each item
+     * @return the self Iterator (now exhausted)
+     * @since 2.3.0
+     */
+    public static <T> Iterator<T> eachWithIndex(Iterator<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+        final Object[] args = new Object[2];
+        int counter = 0;
+        while (self.hasNext()) {
+            args[0] = self.next();
+            args[1] = counter++;
+            closure.call(args);
+        }
+        return self;
+    }
+
+    /**
+     * Iterates through a Collection,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    a Collection
+     * @param closure a Closure to operate on each item
+     * @return the self Collection
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> eachWithIndex(Collection<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+        return (Collection<T>) eachWithIndex((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through a List,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    a List
+     * @param closure a Closure to operate on each item
+     * @return the self List
+     * @since 2.4.0
+     */
+    public static <T> List<T> eachWithIndex(List<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+        return (List<T>) eachWithIndex((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through a Set,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    a Set
+     * @param closure a Closure to operate on each item
+     * @return the self Set
+     * @since 2.4.0
+     */
+    public static <T> Set<T> eachWithIndex(Set<T> self, @ClosureParams(value=FromString.class, options="T,java.lang.Integer") Closure closure) {
+        return (Set<T>) eachWithIndex((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through a SortedSet,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    a SortedSet
+     * @param closure a Closure to operate on each item
+     * @return the self SortedSet
+     * @since 2.4.0
+     */
+    public static <T> Sort

<TRUNCATED>

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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/SystemUtil.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/SystemUtil.java b/src/main/java/org/apache/groovy/util/SystemUtil.java
new file mode 100644
index 0000000..967b37b
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/SystemUtil.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.apache.groovy.util;
+
+public class SystemUtil {
+    /**
+     * Sets a system property from a name=value String
+     *
+     * @param nameValue the non-null name=value String
+     * @return the found name
+     */
+    public static String setSystemPropertyFrom(final String nameValue) {
+        if (nameValue == null) throw new IllegalArgumentException("argument should not be null");
+
+        String name, value;
+        int i = nameValue.indexOf("=");
+
+        if (i == -1) {
+            name = nameValue;
+            value = Boolean.TRUE.toString();
+        } else {
+            name = nameValue.substring(0, i);
+            value = nameValue.substring(i + 1, nameValue.length());
+        }
+        name = name.trim();
+
+        System.setProperty(name, value);
+        return name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java
new file mode 100644
index 0000000..938ef63
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.java
@@ -0,0 +1,1600 @@
+/*
+ * Copyright 2010 Google Inc. All Rights Reserved.
+ *
+ * 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.apache.groovy.util.concurrentlinkedhashmap;
+
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.Immutable;
+import javax.annotation.concurrent.ThreadSafe;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractQueue;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.unmodifiableMap;
+import static java.util.Collections.unmodifiableSet;
+import static org.apache.groovy.util.concurrentlinkedhashmap.ConcurrentLinkedHashMap.DrainStatus.IDLE;
+import static org.apache.groovy.util.concurrentlinkedhashmap.ConcurrentLinkedHashMap.DrainStatus.PROCESSING;
+import static org.apache.groovy.util.concurrentlinkedhashmap.ConcurrentLinkedHashMap.DrainStatus.REQUIRED;
+
+/**
+ * A hash table supporting full concurrency of retrievals, adjustable expected
+ * concurrency for updates, and a maximum capacity to bound the map by. This
+ * implementation differs from {@link ConcurrentHashMap} in that it maintains a
+ * page replacement algorithm that is used to evict an entry when the map has
+ * exceeded its capacity. Unlike the <tt>Java Collections Framework</tt>, this
+ * map does not have a publicly visible constructor and instances are created
+ * through a {@link Builder}.
+ * <p>
+ * An entry is evicted from the map when the <tt>weighted capacity</tt> exceeds
+ * its <tt>maximum weighted capacity</tt> threshold. A {@link EntryWeigher}
+ * determines how many units of capacity that an entry consumes. The default
+ * weigher assigns each value a weight of <tt>1</tt> to bound the map by the
+ * total number of key-value pairs. A map that holds collections may choose to
+ * weigh values by the number of elements in the collection and bound the map
+ * by the total number of elements that it contains. A change to a value that
+ * modifies its weight requires that an update operation is performed on the
+ * map.
+ * <p>
+ * An {@link EvictionListener} may be supplied for notification when an entry
+ * is evicted from the map. This listener is invoked on a caller's thread and
+ * will not block other threads from operating on the map. An implementation
+ * should be aware that the caller's thread will not expect long execution
+ * times or failures as a side effect of the listener being notified. Execution
+ * safety and a fast turn around time can be achieved by performing the
+ * operation asynchronously, such as by submitting a task to an
+ * {@link java.util.concurrent.ExecutorService}.
+ * <p>
+ * The <tt>concurrency level</tt> determines the number of threads that can
+ * concurrently modify the table. Using a significantly higher or lower value
+ * than needed can waste space or lead to thread contention, but an estimate
+ * within an order of magnitude of the ideal value does not usually have a
+ * noticeable impact. Because placement in hash tables is essentially random,
+ * the actual concurrency will vary.
+ * <p>
+ * This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces.
+ * <p>
+ * Like {@link java.util.Hashtable} but unlike {@link HashMap}, this class
+ * does <em>not</em> allow <tt>null</tt> to be used as a key or value. Unlike
+ * {@link LinkedHashMap}, this class does <em>not</em> provide
+ * predictable iteration order. A snapshot of the keys and entries may be
+ * obtained in ascending and descending order of retention.
+ *
+ * @author ben.manes@gmail.com (Ben Manes)
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
+ *      http://code.google.com/p/concurrentlinkedhashmap/</a>
+ */
+@ThreadSafe
+public final class ConcurrentLinkedHashMap<K, V> extends AbstractMap<K, V>
+    implements ConcurrentMap<K, V>, Serializable {
+
+  /*
+   * This class performs a best-effort bounding of a ConcurrentHashMap using a
+   * page-replacement algorithm to determine which entries to evict when the
+   * capacity is exceeded.
+   *
+   * The page replacement algorithm's data structures are kept eventually
+   * consistent with the map. An update to the map and recording of reads may
+   * not be immediately reflected on the algorithm's data structures. These
+   * structures are guarded by a lock and operations are applied in batches to
+   * avoid lock contention. The penalty of applying the batches is spread across
+   * threads so that the amortized cost is slightly higher than performing just
+   * the ConcurrentHashMap operation.
+   *
+   * A memento of the reads and writes that were performed on the map are
+   * recorded in buffers. These buffers are drained at the first opportunity
+   * after a write or when the read buffer exceeds a threshold size. The reads
+   * are recorded in a lossy buffer, allowing the reordering operations to be
+   * discarded if the draining process cannot keep up. Due to the concurrent
+   * nature of the read and write operations a strict policy ordering is not
+   * possible, but is observably strict when single threaded.
+   *
+   * Due to a lack of a strict ordering guarantee, a task can be executed
+   * out-of-order, such as a removal followed by its addition. The state of the
+   * entry is encoded within the value's weight.
+   *
+   * Alive: The entry is in both the hash-table and the page replacement policy.
+   * This is represented by a positive weight.
+   *
+   * Retired: The entry is not in the hash-table and is pending removal from the
+   * page replacement policy. This is represented by a negative weight.
+   *
+   * Dead: The entry is not in the hash-table and is not in the page replacement
+   * policy. This is represented by a weight of zero.
+   *
+   * The Least Recently Used page replacement algorithm was chosen due to its
+   * simplicity, high hit rate, and ability to be implemented with O(1) time
+   * complexity.
+   */
+
+  /** The number of CPUs */
+  static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+  /** The maximum weighted capacity of the map. */
+  static final long MAXIMUM_CAPACITY = Long.MAX_VALUE - Integer.MAX_VALUE;
+
+  /** The number of read buffers to use. */
+  static final int NUMBER_OF_READ_BUFFERS = ceilingNextPowerOfTwo(NCPU);
+
+  /** Mask value for indexing into the read buffers. */
+  static final int READ_BUFFERS_MASK = NUMBER_OF_READ_BUFFERS - 1;
+
+  /** The number of pending read operations before attempting to drain. */
+  static final int READ_BUFFER_THRESHOLD = 32;
+
+  /** The maximum number of read operations to perform per amortized drain. */
+  static final int READ_BUFFER_DRAIN_THRESHOLD = 2 * READ_BUFFER_THRESHOLD;
+
+  /** The maximum number of pending reads per buffer. */
+  static final int READ_BUFFER_SIZE = 2 * READ_BUFFER_DRAIN_THRESHOLD;
+
+  /** Mask value for indexing into the read buffer. */
+  static final int READ_BUFFER_INDEX_MASK = READ_BUFFER_SIZE - 1;
+
+  /** The maximum number of write operations to perform per amortized drain. */
+  static final int WRITE_BUFFER_DRAIN_THRESHOLD = 16;
+
+  /** A queue that discards all entries. */
+  static final Queue<?> DISCARDING_QUEUE = new DiscardingQueue();
+
+  static int ceilingNextPowerOfTwo(int x) {
+    // From Hacker's Delight, Chapter 3, Harry S. Warren Jr.
+    return 1 << (Integer.SIZE - Integer.numberOfLeadingZeros(x - 1));
+  }
+
+  // The backing data store holding the key-value associations
+  final ConcurrentMap<K, Node<K, V>> data;
+  final int concurrencyLevel;
+
+  // These fields provide support to bound the map by a maximum capacity
+  @GuardedBy("evictionLock")
+  final long[] readBufferReadCount;
+  @GuardedBy("evictionLock")
+  final LinkedDeque<Node<K, V>> evictionDeque;
+
+  @GuardedBy("evictionLock") // must write under lock
+  final AtomicLong weightedSize;
+  @GuardedBy("evictionLock") // must write under lock
+  final AtomicLong capacity;
+
+  final Lock evictionLock;
+  final Queue<Runnable> writeBuffer;
+  final AtomicLong[] readBufferWriteCount;
+  final AtomicLong[] readBufferDrainAtWriteCount;
+  final AtomicReference<Node<K, V>>[][] readBuffers;
+
+  final AtomicReference<DrainStatus> drainStatus;
+  final EntryWeigher<? super K, ? super V> weigher;
+
+  // These fields provide support for notifying a listener.
+  final Queue<Node<K, V>> pendingNotifications;
+  final EvictionListener<K, V> listener;
+
+  transient Set<K> keySet;
+  transient Collection<V> values;
+  transient Set<Entry<K, V>> entrySet;
+
+  /**
+   * Creates an instance based on the builder's configuration.
+   */
+  @SuppressWarnings({"unchecked", "cast"})
+  private ConcurrentLinkedHashMap(Builder<K, V> builder) {
+    // The data store and its maximum capacity
+    concurrencyLevel = builder.concurrencyLevel;
+    capacity = new AtomicLong(Math.min(builder.capacity, MAXIMUM_CAPACITY));
+    data = new ConcurrentHashMap<K, Node<K, V>>(builder.initialCapacity, 0.75f, concurrencyLevel);
+
+    // The eviction support
+    weigher = builder.weigher;
+    evictionLock = new ReentrantLock();
+    weightedSize = new AtomicLong();
+    evictionDeque = new LinkedDeque<Node<K, V>>();
+    writeBuffer = new ConcurrentLinkedQueue<Runnable>();
+    drainStatus = new AtomicReference<DrainStatus>(IDLE);
+
+    readBufferReadCount = new long[NUMBER_OF_READ_BUFFERS];
+    readBufferWriteCount = new AtomicLong[NUMBER_OF_READ_BUFFERS];
+    readBufferDrainAtWriteCount = new AtomicLong[NUMBER_OF_READ_BUFFERS];
+    readBuffers = new AtomicReference[NUMBER_OF_READ_BUFFERS][READ_BUFFER_SIZE];
+    for (int i = 0; i < NUMBER_OF_READ_BUFFERS; i++) {
+      readBufferWriteCount[i] = new AtomicLong();
+      readBufferDrainAtWriteCount[i] = new AtomicLong();
+      readBuffers[i] = new AtomicReference[READ_BUFFER_SIZE];
+      for (int j = 0; j < READ_BUFFER_SIZE; j++) {
+        readBuffers[i][j] = new AtomicReference<Node<K, V>>();
+      }
+    }
+
+    // The notification queue and listener
+    listener = builder.listener;
+    pendingNotifications = (listener == DiscardingListener.INSTANCE)
+        ? (Queue<Node<K, V>>) DISCARDING_QUEUE
+        : new ConcurrentLinkedQueue<Node<K, V>>();
+  }
+
+  /** Ensures that the object is not null. */
+  static void checkNotNull(Object o) {
+    if (o == null) {
+      throw new NullPointerException();
+    }
+  }
+
+  /** Ensures that the argument expression is true. */
+  static void checkArgument(boolean expression) {
+    if (!expression) {
+      throw new IllegalArgumentException();
+    }
+  }
+
+  /** Ensures that the state expression is true. */
+  static void checkState(boolean expression) {
+    if (!expression) {
+      throw new IllegalStateException();
+    }
+  }
+
+  /* ---------------- Eviction Support -------------- */
+
+  /**
+   * Retrieves the maximum weighted capacity of the map.
+   *
+   * @return the maximum weighted capacity
+   */
+  public long capacity() {
+    return capacity.get();
+  }
+
+  /**
+   * Sets the maximum weighted capacity of the map and eagerly evicts entries
+   * until it shrinks to the appropriate size.
+   *
+   * @param capacity the maximum weighted capacity of the map
+   * @throws IllegalArgumentException if the capacity is negative
+   */
+  public void setCapacity(long capacity) {
+    checkArgument(capacity >= 0);
+    evictionLock.lock();
+    try {
+      this.capacity.lazySet(Math.min(capacity, MAXIMUM_CAPACITY));
+      drainBuffers();
+      evict();
+    } finally {
+      evictionLock.unlock();
+    }
+    notifyListener();
+  }
+
+  /** Determines whether the map has exceeded its capacity. */
+  @GuardedBy("evictionLock")
+  boolean hasOverflowed() {
+    return weightedSize.get() > capacity.get();
+  }
+
+  /**
+   * Evicts entries from the map while it exceeds the capacity and appends
+   * evicted entries to the notification queue for processing.
+   */
+  @GuardedBy("evictionLock")
+  void evict() {
+    // Attempts to evict entries from the map if it exceeds the maximum
+    // capacity. If the eviction fails due to a concurrent removal of the
+    // victim, that removal may cancel out the addition that triggered this
+    // eviction. The victim is eagerly unlinked before the removal task so
+    // that if an eviction is still required then a new victim will be chosen
+    // for removal.
+    while (hasOverflowed()) {
+      final Node<K, V> node = evictionDeque.poll();
+
+      // If weighted values are used, then the pending operations will adjust
+      // the size to reflect the correct weight
+      if (node == null) {
+        return;
+      }
+
+      // Notify the listener only if the entry was evicted
+      if (data.remove(node.key, node)) {
+        pendingNotifications.add(node);
+      }
+
+      makeDead(node);
+    }
+  }
+
+  /**
+   * Performs the post-processing work required after a read.
+   *
+   * @param node the entry in the page replacement policy
+   */
+  void afterRead(Node<K, V> node) {
+    final int bufferIndex = readBufferIndex();
+    final long writeCount = recordRead(bufferIndex, node);
+    drainOnReadIfNeeded(bufferIndex, writeCount);
+    notifyListener();
+  }
+
+  /** Returns the index to the read buffer to record into. */
+  static int readBufferIndex() {
+    // A buffer is chosen by the thread's id so that tasks are distributed in a
+    // pseudo evenly manner. This helps avoid hot entries causing contention
+    // due to other threads trying to append to the same buffer.
+    return ((int) Thread.currentThread().getId()) & READ_BUFFERS_MASK;
+  }
+
+  /**
+   * Records a read in the buffer and return its write count.
+   *
+   * @param bufferIndex the index to the chosen read buffer
+   * @param node the entry in the page replacement policy
+   * @return the number of writes on the chosen read buffer
+   */
+  long recordRead(int bufferIndex, Node<K, V> node) {
+    // The location in the buffer is chosen in a racy fashion as the increment
+    // is not atomic with the insertion. This means that concurrent reads can
+    // overlap and overwrite one another, resulting in a lossy buffer.
+    final AtomicLong counter = readBufferWriteCount[bufferIndex];
+    final long writeCount = counter.get();
+    counter.lazySet(writeCount + 1);
+
+    final int index = (int) (writeCount & READ_BUFFER_INDEX_MASK);
+    readBuffers[bufferIndex][index].lazySet(node);
+
+    return writeCount;
+  }
+
+  /**
+   * Attempts to drain the buffers if it is determined to be needed when
+   * post-processing a read.
+   *
+   * @param bufferIndex the index to the chosen read buffer
+   * @param writeCount the number of writes on the chosen read buffer
+   */
+  void drainOnReadIfNeeded(int bufferIndex, long writeCount) {
+    final long pending = (writeCount - readBufferDrainAtWriteCount[bufferIndex].get());
+    final boolean delayable = (pending < READ_BUFFER_THRESHOLD);
+    final DrainStatus status = drainStatus.get();
+    if (status.shouldDrainBuffers(delayable)) {
+      tryToDrainBuffers();
+    }
+  }
+
+  /**
+   * Performs the post-processing work required after a write.
+   *
+   * @param task the pending operation to be applied
+   */
+  void afterWrite(Runnable task) {
+    writeBuffer.add(task);
+    drainStatus.lazySet(REQUIRED);
+    tryToDrainBuffers();
+    notifyListener();
+  }
+
+  /**
+   * Attempts to acquire the eviction lock and apply the pending operations, up
+   * to the amortized threshold, to the page replacement policy.
+   */
+  void tryToDrainBuffers() {
+    if (evictionLock.tryLock()) {
+      try {
+        drainStatus.lazySet(PROCESSING);
+        drainBuffers();
+      } finally {
+        drainStatus.compareAndSet(PROCESSING, IDLE);
+        evictionLock.unlock();
+      }
+    }
+  }
+
+  /** Drains the read and write buffers up to an amortized threshold. */
+  @GuardedBy("evictionLock")
+  void drainBuffers() {
+    drainReadBuffers();
+    drainWriteBuffer();
+  }
+
+  /** Drains the read buffers, each up to an amortized threshold. */
+  @GuardedBy("evictionLock")
+  void drainReadBuffers() {
+    final int start = (int) Thread.currentThread().getId();
+    final int end = start + NUMBER_OF_READ_BUFFERS;
+    for (int i = start; i < end; i++) {
+      drainReadBuffer(i & READ_BUFFERS_MASK);
+    }
+  }
+
+  /** Drains the read buffer up to an amortized threshold. */
+  @GuardedBy("evictionLock")
+  void drainReadBuffer(int bufferIndex) {
+    final long writeCount = readBufferWriteCount[bufferIndex].get();
+    for (int i = 0; i < READ_BUFFER_DRAIN_THRESHOLD; i++) {
+      final int index = (int) (readBufferReadCount[bufferIndex] & READ_BUFFER_INDEX_MASK);
+      final AtomicReference<Node<K, V>> slot = readBuffers[bufferIndex][index];
+      final Node<K, V> node = slot.get();
+      if (node == null) {
+        break;
+      }
+
+      slot.lazySet(null);
+      applyRead(node);
+      readBufferReadCount[bufferIndex]++;
+    }
+    readBufferDrainAtWriteCount[bufferIndex].lazySet(writeCount);
+  }
+
+  /** Updates the node's location in the page replacement policy. */
+  @GuardedBy("evictionLock")
+  void applyRead(Node<K, V> node) {
+    // An entry may be scheduled for reordering despite having been removed.
+    // This can occur when the entry was concurrently read while a writer was
+    // removing it. If the entry is no longer linked then it does not need to
+    // be processed.
+    if (evictionDeque.contains(node)) {
+      evictionDeque.moveToBack(node);
+    }
+  }
+
+  /** Drains the read buffer up to an amortized threshold. */
+  @GuardedBy("evictionLock")
+  void drainWriteBuffer() {
+    for (int i = 0; i < WRITE_BUFFER_DRAIN_THRESHOLD; i++) {
+      final Runnable task = writeBuffer.poll();
+      if (task == null) {
+        break;
+      }
+      task.run();
+    }
+  }
+
+  /**
+   * Attempts to transition the node from the <tt>alive</tt> state to the
+   * <tt>retired</tt> state.
+   *
+   * @param node the entry in the page replacement policy
+   * @param expect the expected weighted value
+   * @return if successful
+   */
+  boolean tryToRetire(Node<K, V> node, WeightedValue<V> expect) {
+    if (expect.isAlive()) {
+      final WeightedValue<V> retired = new WeightedValue<V>(expect.value, -expect.weight);
+      return node.compareAndSet(expect, retired);
+    }
+    return false;
+  }
+
+  /**
+   * Atomically transitions the node from the <tt>alive</tt> state to the
+   * <tt>retired</tt> state, if a valid transition.
+   *
+   * @param node the entry in the page replacement policy
+   */
+  void makeRetired(Node<K, V> node) {
+    for (;;) {
+      final WeightedValue<V> current = node.get();
+      if (!current.isAlive()) {
+        return;
+      }
+      final WeightedValue<V> retired = new WeightedValue<V>(current.value, -current.weight);
+      if (node.compareAndSet(current, retired)) {
+        return;
+      }
+    }
+  }
+
+  /**
+   * Atomically transitions the node to the <tt>dead</tt> state and decrements
+   * the <tt>weightedSize</tt>.
+   *
+   * @param node the entry in the page replacement policy
+   */
+  @GuardedBy("evictionLock")
+  void makeDead(Node<K, V> node) {
+    for (;;) {
+      WeightedValue<V> current = node.get();
+      WeightedValue<V> dead = new WeightedValue<V>(current.value, 0);
+      if (node.compareAndSet(current, dead)) {
+        weightedSize.lazySet(weightedSize.get() - Math.abs(current.weight));
+        return;
+      }
+    }
+  }
+
+  /** Notifies the listener of entries that were evicted. */
+  void notifyListener() {
+    Node<K, V> node;
+    while ((node = pendingNotifications.poll()) != null) {
+      listener.onEviction(node.key, node.getValue());
+    }
+  }
+
+  /** Adds the node to the page replacement policy. */
+  final class AddTask implements Runnable {
+    final Node<K, V> node;
+    final int weight;
+
+    AddTask(Node<K, V> node, int weight) {
+      this.weight = weight;
+      this.node = node;
+    }
+
+    @Override
+    @GuardedBy("evictionLock")
+    public void run() {
+      weightedSize.lazySet(weightedSize.get() + weight);
+
+      // ignore out-of-order write operations
+      if (node.get().isAlive()) {
+        evictionDeque.add(node);
+        evict();
+      }
+    }
+  }
+
+  /** Removes a node from the page replacement policy. */
+  final class RemovalTask implements Runnable {
+    final Node<K, V> node;
+
+    RemovalTask(Node<K, V> node) {
+      this.node = node;
+    }
+
+    @Override
+    @GuardedBy("evictionLock")
+    public void run() {
+      // add may not have been processed yet
+      evictionDeque.remove(node);
+      makeDead(node);
+    }
+  }
+
+  /** Updates the weighted size and evicts an entry on overflow. */
+  final class UpdateTask implements Runnable {
+    final int weightDifference;
+    final Node<K, V> node;
+
+    public UpdateTask(Node<K, V> node, int weightDifference) {
+      this.weightDifference = weightDifference;
+      this.node = node;
+    }
+
+    @Override
+    @GuardedBy("evictionLock")
+    public void run() {
+      weightedSize.lazySet(weightedSize.get() + weightDifference);
+      applyRead(node);
+      evict();
+    }
+  }
+
+  /* ---------------- Concurrent Map Support -------------- */
+
+  @Override
+  public boolean isEmpty() {
+    return data.isEmpty();
+  }
+
+  @Override
+  public int size() {
+    return data.size();
+  }
+
+  /**
+   * Returns the weighted size of this map.
+   *
+   * @return the combined weight of the values in this map
+   */
+  public long weightedSize() {
+    return Math.max(0, weightedSize.get());
+  }
+
+  @Override
+  public void clear() {
+    evictionLock.lock();
+    try {
+      // Discard all entries
+      Node<K, V> node;
+      while ((node = evictionDeque.poll()) != null) {
+        data.remove(node.key, node);
+        makeDead(node);
+      }
+
+      // Discard all pending reads
+      for (AtomicReference<Node<K, V>>[] buffer : readBuffers) {
+        for (AtomicReference<Node<K, V>> slot : buffer) {
+          slot.lazySet(null);
+        }
+      }
+
+      // Apply all pending writes
+      Runnable task;
+      while ((task = writeBuffer.poll()) != null) {
+        task.run();
+      }
+    } finally {
+      evictionLock.unlock();
+    }
+  }
+
+  @Override
+  public boolean containsKey(Object key) {
+    return data.containsKey(key);
+  }
+
+  @Override
+  public boolean containsValue(Object value) {
+    checkNotNull(value);
+
+    for (Node<K, V> node : data.values()) {
+      if (node.getValue().equals(value)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public V get(Object key) {
+    final Node<K, V> node = data.get(key);
+    if (node == null) {
+      return null;
+    }
+    afterRead(node);
+    return node.getValue();
+  }
+
+  /**
+   * Returns the value to which the specified key is mapped, or {@code null}
+   * if this map contains no mapping for the key. This method differs from
+   * {@link #get(Object)} in that it does not record the operation with the
+   * page replacement policy.
+   *
+   * @param key the key whose associated value is to be returned
+   * @return the value to which the specified key is mapped, or
+   *     {@code null} if this map contains no mapping for the key
+   * @throws NullPointerException if the specified key is null
+   */
+  public V getQuietly(Object key) {
+    final Node<K, V> node = data.get(key);
+    return (node == null) ? null : node.getValue();
+  }
+
+  @Override
+  public V put(K key, V value) {
+    return put(key, value, false);
+  }
+
+  @Override
+  public V putIfAbsent(K key, V value) {
+    return put(key, value, true);
+  }
+
+  /**
+   * Adds a node to the list and the data store. If an existing node is found,
+   * then its value is updated if allowed.
+   *
+   * @param key key with which the specified value is to be associated
+   * @param value value to be associated with the specified key
+   * @param onlyIfAbsent a write is performed only if the key is not already
+   *     associated with a value
+   * @return the prior value in the data store or null if no mapping was found
+   */
+  V put(K key, V value, boolean onlyIfAbsent) {
+    checkNotNull(key);
+    checkNotNull(value);
+
+    final int weight = weigher.weightOf(key, value);
+    final WeightedValue<V> weightedValue = new WeightedValue<V>(value, weight);
+    final Node<K, V> node = new Node<K, V>(key, weightedValue);
+
+    for (;;) {
+      final Node<K, V> prior = data.putIfAbsent(node.key, node);
+      if (prior == null) {
+        afterWrite(new AddTask(node, weight));
+        return null;
+      } else if (onlyIfAbsent) {
+        afterRead(prior);
+        return prior.getValue();
+      }
+      for (;;) {
+        final WeightedValue<V> oldWeightedValue = prior.get();
+        if (!oldWeightedValue.isAlive()) {
+          break;
+        }
+
+        if (prior.compareAndSet(oldWeightedValue, weightedValue)) {
+          final int weightedDifference = weight - oldWeightedValue.weight;
+          if (weightedDifference == 0) {
+            afterRead(prior);
+          } else {
+            afterWrite(new UpdateTask(prior, weightedDifference));
+          }
+          return oldWeightedValue.value;
+        }
+      }
+    }
+  }
+
+  @Override
+  public V remove(Object key) {
+    final Node<K, V> node = data.remove(key);
+    if (node == null) {
+      return null;
+    }
+
+    makeRetired(node);
+    afterWrite(new RemovalTask(node));
+    return node.getValue();
+  }
+
+  @Override
+  public boolean remove(Object key, Object value) {
+    final Node<K, V> node = data.get(key);
+    if ((node == null) || (value == null)) {
+      return false;
+    }
+
+    WeightedValue<V> weightedValue = node.get();
+    for (;;) {
+      if (weightedValue.contains(value)) {
+        if (tryToRetire(node, weightedValue)) {
+          if (data.remove(key, node)) {
+            afterWrite(new RemovalTask(node));
+            return true;
+          }
+        } else {
+          weightedValue = node.get();
+          if (weightedValue.isAlive()) {
+            // retry as an intermediate update may have replaced the value with
+            // an equal instance that has a different reference identity
+            continue;
+          }
+        }
+      }
+      return false;
+    }
+  }
+
+  @Override
+  public V replace(K key, V value) {
+    checkNotNull(key);
+    checkNotNull(value);
+
+    final int weight = weigher.weightOf(key, value);
+    final WeightedValue<V> weightedValue = new WeightedValue<V>(value, weight);
+
+    final Node<K, V> node = data.get(key);
+    if (node == null) {
+      return null;
+    }
+    for (;;) {
+      final WeightedValue<V> oldWeightedValue = node.get();
+      if (!oldWeightedValue.isAlive()) {
+        return null;
+      }
+      if (node.compareAndSet(oldWeightedValue, weightedValue)) {
+        final int weightedDifference = weight - oldWeightedValue.weight;
+        if (weightedDifference == 0) {
+          afterRead(node);
+        } else {
+          afterWrite(new UpdateTask(node, weightedDifference));
+        }
+        return oldWeightedValue.value;
+      }
+    }
+  }
+
+  @Override
+  public boolean replace(K key, V oldValue, V newValue) {
+    checkNotNull(key);
+    checkNotNull(oldValue);
+    checkNotNull(newValue);
+
+    final int weight = weigher.weightOf(key, newValue);
+    final WeightedValue<V> newWeightedValue = new WeightedValue<V>(newValue, weight);
+
+    final Node<K, V> node = data.get(key);
+    if (node == null) {
+      return false;
+    }
+    for (;;) {
+      final WeightedValue<V> weightedValue = node.get();
+      if (!weightedValue.isAlive() || !weightedValue.contains(oldValue)) {
+        return false;
+      }
+      if (node.compareAndSet(weightedValue, newWeightedValue)) {
+        final int weightedDifference = weight - weightedValue.weight;
+        if (weightedDifference == 0) {
+          afterRead(node);
+        } else {
+          afterWrite(new UpdateTask(node, weightedDifference));
+        }
+        return true;
+      }
+    }
+  }
+
+  @Override
+  public Set<K> keySet() {
+    final Set<K> ks = keySet;
+    return (ks == null) ? (keySet = new KeySet()) : ks;
+  }
+
+  /**
+   * Returns a unmodifiable snapshot {@link Set} view of the keys contained in
+   * this map. The set's iterator returns the keys whose order of iteration is
+   * the ascending order in which its entries are considered eligible for
+   * retention, from the least-likely to be retained to the most-likely.
+   * <p>
+   * Beware that, unlike in {@link #keySet()}, obtaining the set is <em>NOT</em>
+   * a constant-time operation. Because of the asynchronous nature of the page
+   * replacement policy, determining the retention ordering requires a traversal
+   * of the keys.
+   *
+   * @return an ascending snapshot view of the keys in this map
+   */
+  public Set<K> ascendingKeySet() {
+    return ascendingKeySetWithLimit(Integer.MAX_VALUE);
+  }
+
+  /**
+   * Returns an unmodifiable snapshot {@link Set} view of the keys contained in
+   * this map. The set's iterator returns the keys whose order of iteration is
+   * the ascending order in which its entries are considered eligible for
+   * retention, from the least-likely to be retained to the most-likely.
+   * <p>
+   * Beware that, unlike in {@link #keySet()}, obtaining the set is <em>NOT</em>
+   * a constant-time operation. Because of the asynchronous nature of the page
+   * replacement policy, determining the retention ordering requires a traversal
+   * of the keys.
+   *
+   * @param limit the maximum size of the returned set
+   * @return a ascending snapshot view of the keys in this map
+   * @throws IllegalArgumentException if the limit is negative
+   */
+  public Set<K> ascendingKeySetWithLimit(int limit) {
+    return orderedKeySet(true, limit);
+  }
+
+  /**
+   * Returns an unmodifiable snapshot {@link Set} view of the keys contained in
+   * this map. The set's iterator returns the keys whose order of iteration is
+   * the descending order in which its entries are considered eligible for
+   * retention, from the most-likely to be retained to the least-likely.
+   * <p>
+   * Beware that, unlike in {@link #keySet()}, obtaining the set is <em>NOT</em>
+   * a constant-time operation. Because of the asynchronous nature of the page
+   * replacement policy, determining the retention ordering requires a traversal
+   * of the keys.
+   *
+   * @return a descending snapshot view of the keys in this map
+   */
+  public Set<K> descendingKeySet() {
+    return descendingKeySetWithLimit(Integer.MAX_VALUE);
+  }
+
+  /**
+   * Returns an unmodifiable snapshot {@link Set} view of the keys contained in
+   * this map. The set's iterator returns the keys whose order of iteration is
+   * the descending order in which its entries are considered eligible for
+   * retention, from the most-likely to be retained to the least-likely.
+   * <p>
+   * Beware that, unlike in {@link #keySet()}, obtaining the set is <em>NOT</em>
+   * a constant-time operation. Because of the asynchronous nature of the page
+   * replacement policy, determining the retention ordering requires a traversal
+   * of the keys.
+   *
+   * @param limit the maximum size of the returned set
+   * @return a descending snapshot view of the keys in this map
+   * @throws IllegalArgumentException if the limit is negative
+   */
+  public Set<K> descendingKeySetWithLimit(int limit) {
+    return orderedKeySet(false, limit);
+  }
+
+  Set<K> orderedKeySet(boolean ascending, int limit) {
+    checkArgument(limit >= 0);
+    evictionLock.lock();
+    try {
+      drainBuffers();
+
+      final int initialCapacity = (weigher == Weighers.entrySingleton())
+          ? Math.min(limit, (int) weightedSize())
+          : 16;
+      final Set<K> keys = new LinkedHashSet<K>(initialCapacity);
+      final Iterator<Node<K, V>> iterator = ascending
+          ? evictionDeque.iterator()
+          : evictionDeque.descendingIterator();
+      while (iterator.hasNext() && (limit > keys.size())) {
+        keys.add(iterator.next().key);
+      }
+      return unmodifiableSet(keys);
+    } finally {
+      evictionLock.unlock();
+    }
+  }
+
+  @Override
+  public Collection<V> values() {
+    final Collection<V> vs = values;
+    return (vs == null) ? (values = new Values()) : vs;
+  }
+
+  @Override
+  public Set<Entry<K, V>> entrySet() {
+    final Set<Entry<K, V>> es = entrySet;
+    return (es == null) ? (entrySet = new EntrySet()) : es;
+  }
+
+  /**
+   * Returns an unmodifiable snapshot {@link Map} view of the mappings contained
+   * in this map. The map's collections return the mappings whose order of
+   * iteration is the ascending order in which its entries are considered
+   * eligible for retention, from the least-likely to be retained to the
+   * most-likely.
+   * <p>
+   * Beware that obtaining the mappings is <em>NOT</em> a constant-time
+   * operation. Because of the asynchronous nature of the page replacement
+   * policy, determining the retention ordering requires a traversal of the
+   * entries.
+   *
+   * @return a ascending snapshot view of this map
+   */
+  public Map<K, V> ascendingMap() {
+    return ascendingMapWithLimit(Integer.MAX_VALUE);
+  }
+
+  /**
+   * Returns an unmodifiable snapshot {@link Map} view of the mappings contained
+   * in this map. The map's collections return the mappings whose order of
+   * iteration is the ascending order in which its entries are considered
+   * eligible for retention, from the least-likely to be retained to the
+   * most-likely.
+   * <p>
+   * Beware that obtaining the mappings is <em>NOT</em> a constant-time
+   * operation. Because of the asynchronous nature of the page replacement
+   * policy, determining the retention ordering requires a traversal of the
+   * entries.
+   *
+   * @param limit the maximum size of the returned map
+   * @return a ascending snapshot view of this map
+   * @throws IllegalArgumentException if the limit is negative
+   */
+  public Map<K, V> ascendingMapWithLimit(int limit) {
+    return orderedMap(true, limit);
+  }
+
+  /**
+   * Returns an unmodifiable snapshot {@link Map} view of the mappings contained
+   * in this map. The map's collections return the mappings whose order of
+   * iteration is the descending order in which its entries are considered
+   * eligible for retention, from the most-likely to be retained to the
+   * least-likely.
+   * <p>
+   * Beware that obtaining the mappings is <em>NOT</em> a constant-time
+   * operation. Because of the asynchronous nature of the page replacement
+   * policy, determining the retention ordering requires a traversal of the
+   * entries.
+   *
+   * @return a descending snapshot view of this map
+   */
+  public Map<K, V> descendingMap() {
+    return descendingMapWithLimit(Integer.MAX_VALUE);
+  }
+
+  /**
+   * Returns an unmodifiable snapshot {@link Map} view of the mappings contained
+   * in this map. The map's collections return the mappings whose order of
+   * iteration is the descending order in which its entries are considered
+   * eligible for retention, from the most-likely to be retained to the
+   * least-likely.
+   * <p>
+   * Beware that obtaining the mappings is <em>NOT</em> a constant-time
+   * operation. Because of the asynchronous nature of the page replacement
+   * policy, determining the retention ordering requires a traversal of the
+   * entries.
+   *
+   * @param limit the maximum size of the returned map
+   * @return a descending snapshot view of this map
+   * @throws IllegalArgumentException if the limit is negative
+   */
+  public Map<K, V> descendingMapWithLimit(int limit) {
+    return orderedMap(false, limit);
+  }
+
+  Map<K, V> orderedMap(boolean ascending, int limit) {
+    checkArgument(limit >= 0);
+    evictionLock.lock();
+    try {
+      drainBuffers();
+
+      final int initialCapacity = (weigher == Weighers.entrySingleton())
+          ? Math.min(limit, (int) weightedSize())
+          : 16;
+      final Map<K, V> map = new LinkedHashMap<K, V>(initialCapacity);
+      final Iterator<Node<K, V>> iterator = ascending
+          ? evictionDeque.iterator()
+          : evictionDeque.descendingIterator();
+      while (iterator.hasNext() && (limit > map.size())) {
+        Node<K, V> node = iterator.next();
+        map.put(node.key, node.getValue());
+      }
+      return unmodifiableMap(map);
+    } finally {
+      evictionLock.unlock();
+    }
+  }
+
+  /** The draining status of the buffers. */
+  enum DrainStatus {
+
+    /** A drain is not taking place. */
+    IDLE {
+      @Override boolean shouldDrainBuffers(boolean delayable) {
+        return !delayable;
+      }
+    },
+
+    /** A drain is required due to a pending write modification. */
+    REQUIRED {
+      @Override boolean shouldDrainBuffers(boolean delayable) {
+        return true;
+      }
+    },
+
+    /** A drain is in progress. */
+    PROCESSING {
+      @Override boolean shouldDrainBuffers(boolean delayable) {
+        return false;
+      }
+    };
+
+    /**
+     * Determines whether the buffers should be drained.
+     *
+     * @param delayable if a drain should be delayed until required
+     * @return if a drain should be attempted
+     */
+    abstract boolean shouldDrainBuffers(boolean delayable);
+  }
+
+  /** A value, its weight, and the entry's status. */
+  @Immutable
+  static final class WeightedValue<V> {
+    final int weight;
+    final V value;
+
+    WeightedValue(V value, int weight) {
+      this.weight = weight;
+      this.value = value;
+    }
+
+    boolean contains(Object o) {
+      return (o == value) || value.equals(o);
+    }
+
+    /**
+     * If the entry is available in the hash-table and page replacement policy.
+     */
+    boolean isAlive() {
+      return weight > 0;
+    }
+
+    /**
+     * If the entry was removed from the hash-table and is awaiting removal from
+     * the page replacement policy.
+     */
+    boolean isRetired() {
+      return weight < 0;
+    }
+
+    /**
+     * If the entry was removed from the hash-table and the page replacement
+     * policy.
+     */
+    boolean isDead() {
+      return weight == 0;
+    }
+  }
+
+  /**
+   * A node contains the key, the weighted value, and the linkage pointers on
+   * the page-replacement algorithm's data structures.
+   */
+  @SuppressWarnings("serial")
+  static final class Node<K, V> extends AtomicReference<WeightedValue<V>>
+      implements Linked<Node<K, V>> {
+    final K key;
+    @GuardedBy("evictionLock")
+    Node<K, V> prev;
+    @GuardedBy("evictionLock")
+    Node<K, V> next;
+
+    /** Creates a new, unlinked node. */
+    Node(K key, WeightedValue<V> weightedValue) {
+      super(weightedValue);
+      this.key = key;
+    }
+
+    @Override
+    @GuardedBy("evictionLock")
+    public Node<K, V> getPrevious() {
+      return prev;
+    }
+
+    @Override
+    @GuardedBy("evictionLock")
+    public void setPrevious(Node<K, V> prev) {
+      this.prev = prev;
+    }
+
+    @Override
+    @GuardedBy("evictionLock")
+    public Node<K, V> getNext() {
+      return next;
+    }
+
+    @Override
+    @GuardedBy("evictionLock")
+    public void setNext(Node<K, V> next) {
+      this.next = next;
+    }
+
+    /** Retrieves the value held by the current <tt>WeightedValue</tt>. */
+    V getValue() {
+      return get().value;
+    }
+  }
+
+  /** An adapter to safely externalize the keys. */
+  final class KeySet extends AbstractSet<K> {
+    final ConcurrentLinkedHashMap<K, V> map = ConcurrentLinkedHashMap.this;
+
+    @Override
+    public int size() {
+      return map.size();
+    }
+
+    @Override
+    public void clear() {
+      map.clear();
+    }
+
+    @Override
+    public Iterator<K> iterator() {
+      return new KeyIterator();
+    }
+
+    @Override
+    public boolean contains(Object obj) {
+      return containsKey(obj);
+    }
+
+    @Override
+    public boolean remove(Object obj) {
+      return (map.remove(obj) != null);
+    }
+
+    @Override
+    public Object[] toArray() {
+      return map.data.keySet().toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] array) {
+      return map.data.keySet().toArray(array);
+    }
+  }
+
+  /** An adapter to safely externalize the key iterator. */
+  final class KeyIterator implements Iterator<K> {
+    final Iterator<K> iterator = data.keySet().iterator();
+    K current;
+
+    @Override
+    public boolean hasNext() {
+      return iterator.hasNext();
+    }
+
+    @Override
+    public K next() {
+      current = iterator.next();
+      return current;
+    }
+
+    @Override
+    public void remove() {
+      checkState(current != null);
+      ConcurrentLinkedHashMap.this.remove(current);
+      current = null;
+    }
+  }
+
+  /** An adapter to safely externalize the values. */
+  final class Values extends AbstractCollection<V> {
+
+    @Override
+    public int size() {
+      return ConcurrentLinkedHashMap.this.size();
+    }
+
+    @Override
+    public void clear() {
+      ConcurrentLinkedHashMap.this.clear();
+    }
+
+    @Override
+    public Iterator<V> iterator() {
+      return new ValueIterator();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+      return containsValue(o);
+    }
+  }
+
+  /** An adapter to safely externalize the value iterator. */
+  final class ValueIterator implements Iterator<V> {
+    final Iterator<Node<K, V>> iterator = data.values().iterator();
+    Node<K, V> current;
+
+    @Override
+    public boolean hasNext() {
+      return iterator.hasNext();
+    }
+
+    @Override
+    public V next() {
+      current = iterator.next();
+      return current.getValue();
+    }
+
+    @Override
+    public void remove() {
+      checkState(current != null);
+      ConcurrentLinkedHashMap.this.remove(current.key);
+      current = null;
+    }
+  }
+
+  /** An adapter to safely externalize the entries. */
+  final class EntrySet extends AbstractSet<Entry<K, V>> {
+    final ConcurrentLinkedHashMap<K, V> map = ConcurrentLinkedHashMap.this;
+
+    @Override
+    public int size() {
+      return map.size();
+    }
+
+    @Override
+    public void clear() {
+      map.clear();
+    }
+
+    @Override
+    public Iterator<Entry<K, V>> iterator() {
+      return new EntryIterator();
+    }
+
+    @Override
+    public boolean contains(Object obj) {
+      if (!(obj instanceof Entry<?, ?>)) {
+        return false;
+      }
+      Entry<?, ?> entry = (Entry<?, ?>) obj;
+      Node<K, V> node = map.data.get(entry.getKey());
+      return (node != null) && (node.getValue().equals(entry.getValue()));
+    }
+
+    @Override
+    public boolean add(Entry<K, V> entry) {
+      return (map.putIfAbsent(entry.getKey(), entry.getValue()) == null);
+    }
+
+    @Override
+    public boolean remove(Object obj) {
+      if (!(obj instanceof Entry<?, ?>)) {
+        return false;
+      }
+      Entry<?, ?> entry = (Entry<?, ?>) obj;
+      return map.remove(entry.getKey(), entry.getValue());
+    }
+  }
+
+  /** An adapter to safely externalize the entry iterator. */
+  final class EntryIterator implements Iterator<Entry<K, V>> {
+    final Iterator<Node<K, V>> iterator = data.values().iterator();
+    Node<K, V> current;
+
+    @Override
+    public boolean hasNext() {
+      return iterator.hasNext();
+    }
+
+    @Override
+    public Entry<K, V> next() {
+      current = iterator.next();
+      return new WriteThroughEntry(current);
+    }
+
+    @Override
+    public void remove() {
+      checkState(current != null);
+      ConcurrentLinkedHashMap.this.remove(current.key);
+      current = null;
+    }
+  }
+
+  /** An entry that allows updates to write through to the map. */
+  final class WriteThroughEntry extends SimpleEntry<K, V> {
+    static final long serialVersionUID = 1;
+
+    WriteThroughEntry(Node<K, V> node) {
+      super(node.key, node.getValue());
+    }
+
+    @Override
+    public V setValue(V value) {
+      put(getKey(), value);
+      return super.setValue(value);
+    }
+
+    Object writeReplace() {
+      return new SimpleEntry<K, V>(this);
+    }
+  }
+
+  /** A weigher that enforces that the weight falls within a valid range. */
+  static final class BoundedEntryWeigher<K, V> implements EntryWeigher<K, V>, Serializable {
+    static final long serialVersionUID = 1;
+    final EntryWeigher<? super K, ? super V> weigher;
+
+    BoundedEntryWeigher(EntryWeigher<? super K, ? super V> weigher) {
+      checkNotNull(weigher);
+      this.weigher = weigher;
+    }
+
+    @Override
+    public int weightOf(K key, V value) {
+      int weight = weigher.weightOf(key, value);
+      checkArgument(weight >= 1);
+      return weight;
+    }
+
+    Object writeReplace() {
+      return weigher;
+    }
+  }
+
+  /** A queue that discards all additions and is always empty. */
+  static final class DiscardingQueue extends AbstractQueue<Object> {
+    @Override public boolean add(Object e) { return true; }
+    @Override public boolean offer(Object e) { return true; }
+    @Override public Object poll() { return null; }
+    @Override public Object peek() { return null; }
+    @Override public int size() { return 0; }
+    @Override public Iterator<Object> iterator() { return emptyList().iterator(); }
+  }
+
+  /** A listener that ignores all notifications. */
+  enum DiscardingListener implements EvictionListener<Object, Object> {
+    INSTANCE;
+
+    @Override public void onEviction(Object key, Object value) {}
+  }
+
+  /* ---------------- Serialization Support -------------- */
+
+  static final long serialVersionUID = 1;
+
+  Object writeReplace() {
+    return new SerializationProxy<K, V>(this);
+  }
+
+  private void readObject(ObjectInputStream stream) throws InvalidObjectException {
+    throw new InvalidObjectException("Proxy required");
+  }
+
+  /**
+   * A proxy that is serialized instead of the map. The page-replacement
+   * algorithm's data structures are not serialized so the deserialized
+   * instance contains only the entries. This is acceptable as caches hold
+   * transient data that is recomputable and serialization would tend to be
+   * used as a fast warm-up process.
+   */
+  static final class SerializationProxy<K, V> implements Serializable {
+    final EntryWeigher<? super K, ? super V> weigher;
+    final EvictionListener<K, V> listener;
+    final int concurrencyLevel;
+    final Map<K, V> data;
+    final long capacity;
+
+    SerializationProxy(ConcurrentLinkedHashMap<K, V> map) {
+      concurrencyLevel = map.concurrencyLevel;
+      data = new HashMap<K, V>(map);
+      capacity = map.capacity.get();
+      listener = map.listener;
+      weigher = map.weigher;
+    }
+
+    Object readResolve() {
+      ConcurrentLinkedHashMap<K, V> map = new Builder<K, V>()
+          .concurrencyLevel(concurrencyLevel)
+          .maximumWeightedCapacity(capacity)
+          .listener(listener)
+          .weigher(weigher)
+          .build();
+      map.putAll(data);
+      return map;
+    }
+
+    static final long serialVersionUID = 1;
+  }
+
+  /* ---------------- Builder -------------- */
+
+  /**
+   * A builder that creates {@link ConcurrentLinkedHashMap} instances. It
+   * provides a flexible approach for constructing customized instances with
+   * a named parameter syntax. It can be used in the following manner:
+   * <pre>{@code
+   * ConcurrentMap<Vertex, Set<Edge>> graph = new Builder<Vertex, Set<Edge>>()
+   *     .maximumWeightedCapacity(5000)
+   *     .weigher(Weighers.<Edge>set())
+   *     .build();
+   * }</pre>
+   */
+  public static final class Builder<K, V> {
+    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+    static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    EvictionListener<K, V> listener;
+    EntryWeigher<? super K, ? super V> weigher;
+
+    int concurrencyLevel;
+    int initialCapacity;
+    long capacity;
+
+    @SuppressWarnings("unchecked")
+    public Builder() {
+      capacity = -1;
+      weigher = Weighers.entrySingleton();
+      initialCapacity = DEFAULT_INITIAL_CAPACITY;
+      concurrencyLevel = DEFAULT_CONCURRENCY_LEVEL;
+      listener = (EvictionListener<K, V>) DiscardingListener.INSTANCE;
+    }
+
+    /**
+     * Specifies the initial capacity of the hash table (default <tt>16</tt>).
+     * This is the number of key-value pairs that the hash table can hold
+     * before a resize operation is required.
+     *
+     * @param initialCapacity the initial capacity used to size the hash table
+     *     to accommodate this many entries.
+     * @throws IllegalArgumentException if the initialCapacity is negative
+     */
+    public Builder<K, V> initialCapacity(int initialCapacity) {
+      checkArgument(initialCapacity >= 0);
+      this.initialCapacity = initialCapacity;
+      return this;
+    }
+
+    /**
+     * Specifies the maximum weighted capacity to coerce the map to and may
+     * exceed it temporarily.
+     *
+     * @param capacity the weighted threshold to bound the map by
+     * @throws IllegalArgumentException if the maximumWeightedCapacity is
+     *     negative
+     */
+    public Builder<K, V> maximumWeightedCapacity(long capacity) {
+      checkArgument(capacity >= 0);
+      this.capacity = capacity;
+      return this;
+    }
+
+    /**
+     * Specifies the estimated number of concurrently updating threads. The
+     * implementation performs internal sizing to try to accommodate this many
+     * threads (default <tt>16</tt>).
+     *
+     * @param concurrencyLevel the estimated number of concurrently updating
+     *     threads
+     * @throws IllegalArgumentException if the concurrencyLevel is less than or
+     *     equal to zero
+     */
+    public Builder<K, V> concurrencyLevel(int concurrencyLevel) {
+      checkArgument(concurrencyLevel > 0);
+      this.concurrencyLevel = concurrencyLevel;
+      return this;
+    }
+
+    /**
+     * Specifies an optional listener that is registered for notification when
+     * an entry is evicted.
+     *
+     * @param listener the object to forward evicted entries to
+     * @throws NullPointerException if the listener is null
+     */
+    public Builder<K, V> listener(EvictionListener<K, V> listener) {
+      checkNotNull(listener);
+      this.listener = listener;
+      return this;
+    }
+
+    /**
+     * Specifies an algorithm to determine how many the units of capacity a
+     * value consumes. The default algorithm bounds the map by the number of
+     * key-value pairs by giving each entry a weight of <tt>1</tt>.
+     *
+     * @param weigher the algorithm to determine a value's weight
+     * @throws NullPointerException if the weigher is null
+     */
+    public Builder<K, V> weigher(Weigher<? super V> weigher) {
+      this.weigher = (weigher == Weighers.singleton())
+          ? Weighers.<K, V>entrySingleton()
+          : new BoundedEntryWeigher<K, V>(Weighers.asEntryWeigher(weigher));
+      return this;
+    }
+
+    /**
+     * Specifies an algorithm to determine how many the units of capacity an
+     * entry consumes. The default algorithm bounds the map by the number of
+     * key-value pairs by giving each entry a weight of <tt>1</tt>.
+     *
+     * @param weigher the algorithm to determine a entry's weight
+     * @throws NullPointerException if the weigher is null
+     */
+    public Builder<K, V> weigher(EntryWeigher<? super K, ? super V> weigher) {
+      this.weigher = (weigher == Weighers.entrySingleton())
+          ? Weighers.<K, V>entrySingleton()
+          : new BoundedEntryWeigher<K, V>(weigher);
+      return this;
+    }
+
+    /**
+     * Creates a new {@link ConcurrentLinkedHashMap} instance.
+     *
+     * @throws IllegalStateException if the maximum weighted capacity was
+     *     not set
+     */
+    public ConcurrentLinkedHashMap<K, V> build() {
+      checkState(capacity >= 0);
+      return new ConcurrentLinkedHashMap<K, V>(this);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EntryWeigher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EntryWeigher.java b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EntryWeigher.java
new file mode 100644
index 0000000..1075c10
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EntryWeigher.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Google Inc. All Rights Reserved.
+ *
+ * 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.apache.groovy.util.concurrentlinkedhashmap;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * A class that can determine the weight of an entry. The total weight threshold
+ * is used to determine when an eviction is required.
+ *
+ * @author ben.manes@gmail.com (Ben Manes)
+ * @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
+ *      http://code.google.com/p/concurrentlinkedhashmap/</a>
+ */
+@ThreadSafe
+public interface EntryWeigher<K, V> {
+
+  /**
+   * Measures an entry's weight to determine how many units of capacity that
+   * the key and value consumes. An entry must consume a minimum of one unit.
+   *
+   * @param key the key to weigh
+   * @param value the value to weigh
+   * @return the entry's weight
+   */
+  int weightOf(K key, V value);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EvictionListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EvictionListener.java b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EvictionListener.java
new file mode 100644
index 0000000..4b608a0
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/EvictionListener.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 Google Inc. All Rights Reserved.
+ *
+ * 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.apache.groovy.util.concurrentlinkedhashmap;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * A listener registered for notification when an entry is evicted. An instance
+ * may be called concurrently by multiple threads to process entries. An
+ * implementation should avoid performing blocking calls or synchronizing on
+ * shared resources.
+ * <p>
+ * The listener is invoked by {@link ConcurrentLinkedHashMap} on a caller's
+ * thread and will not block other threads from operating on the map. An
+ * implementation should be aware that the caller's thread will not expect
+ * long execution times or failures as a side effect of the listener being
+ * notified. Execution safety and a fast turn around time can be achieved by
+ * performing the operation asynchronously, such as by submitting a task to an
+ * {@link java.util.concurrent.ExecutorService}.
+ *
+ * @author ben.manes@gmail.com (Ben Manes)
+ * @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
+ *      http://code.google.com/p/concurrentlinkedhashmap/</a>
+ */
+@ThreadSafe
+public interface EvictionListener<K, V> {
+
+  /**
+   * A call-back notification that the entry was evicted.
+   *
+   * @param key the entry's key
+   * @param value the entry's value
+   */
+  void onEviction(K key, V value);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/LinkedDeque.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/LinkedDeque.java b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/LinkedDeque.java
new file mode 100644
index 0000000..447b769
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/LinkedDeque.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.apache.groovy.util.concurrentlinkedhashmap;
+
+import javax.annotation.concurrent.NotThreadSafe;
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Linked list implementation of the {@link Deque} interface where the link
+ * pointers are tightly integrated with the element. Linked deques have no
+ * capacity restrictions; they grow as necessary to support usage. They are not
+ * thread-safe; in the absence of external synchronization, they do not support
+ * concurrent access by multiple threads. Null elements are prohibited.
+ * <p>
+ * Most <tt>LinkedDeque</tt> operations run in constant time by assuming that
+ * the {@link Linked} parameter is associated with the deque instance. Any usage
+ * that violates this assumption will result in non-deterministic behavior.
+ * <p>
+ * The iterators returned by this class are <em>not</em> <i>fail-fast</i>: If
+ * the deque is modified at any time after the iterator is created, the iterator
+ * will be in an unknown state. Thus, in the face of concurrent modification,
+ * the iterator risks arbitrary, non-deterministic behavior at an undetermined
+ * time in the future.
+ *
+ * @author ben.manes@gmail.com (Ben Manes)
+ * @param <E> the type of elements held in this collection
+ * @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
+ *      http://code.google.com/p/concurrentlinkedhashmap/</a>
+ */
+@NotThreadSafe
+final class LinkedDeque<E extends Linked<E>> extends AbstractCollection<E> implements Deque<E> {
+
+  // This class provides a doubly-linked list that is optimized for the virtual
+  // machine. The first and last elements are manipulated instead of a slightly
+  // more convenient sentinel element to avoid the insertion of null checks with
+  // NullPointerException throws in the byte code. The links to a removed
+  // element are cleared to help a generational garbage collector if the
+  // discarded elements inhabit more than one generation.
+
+  /**
+   * Pointer to first node.
+   * Invariant: (first == null && last == null) ||
+   *            (first.prev == null)
+   */
+  E first;
+
+  /**
+   * Pointer to last node.
+   * Invariant: (first == null && last == null) ||
+   *            (last.next == null)
+   */
+  E last;
+
+  /**
+   * Links the element to the front of the deque so that it becomes the first
+   * element.
+   *
+   * @param e the unlinked element
+   */
+  void linkFirst(final E e) {
+    final E f = first;
+    first = e;
+
+    if (f == null) {
+      last = e;
+    } else {
+      f.setPrevious(e);
+      e.setNext(f);
+    }
+  }
+
+  /**
+   * Links the element to the back of the deque so that it becomes the last
+   * element.
+   *
+   * @param e the unlinked element
+   */
+  void linkLast(final E e) {
+    final E l = last;
+    last = e;
+
+    if (l == null) {
+      first = e;
+    } else {
+      l.setNext(e);
+      e.setPrevious(l);
+    }
+  }
+
+  /** Unlinks the non-null first element. */
+  E unlinkFirst() {
+    final E f = first;
+    final E next = f.getNext();
+    f.setNext(null);
+
+    first = next;
+    if (next == null) {
+      last = null;
+    } else {
+      next.setPrevious(null);
+    }
+    return f;
+  }
+
+  /** Unlinks the non-null last element. */
+  E unlinkLast() {
+    final E l = last;
+    final E prev = l.getPrevious();
+    l.setPrevious(null);
+    last = prev;
+    if (prev == null) {
+      first = null;
+    } else {
+      prev.setNext(null);
+    }
+    return l;
+  }
+
+  /** Unlinks the non-null element. */
+  void unlink(E e) {
+    final E prev = e.getPrevious();
+    final E next = e.getNext();
+
+    if (prev == null) {
+      first = next;
+    } else {
+      prev.setNext(next);
+      e.setPrevious(null);
+    }
+
+    if (next == null) {
+      last = prev;
+    } else {
+      next.setPrevious(prev);
+      e.setNext(null);
+    }
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return (first == null);
+  }
+
+  void checkNotEmpty() {
+    if (isEmpty()) {
+      throw new NoSuchElementException();
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * Beware that, unlike in most collections, this method is <em>NOT</em> a
+   * constant-time operation.
+   */
+  @Override
+  public int size() {
+    int size = 0;
+    for (E e = first; e != null; e = e.getNext()) {
+      size++;
+    }
+    return size;
+  }
+
+  @Override
+  public void clear() {
+    for (E e = first; e != null;) {
+      E next = e.getNext();
+      e.setPrevious(null);
+      e.setNext(null);
+      e = next;
+    }
+    first = last = null;
+  }
+
+  @Override
+  public boolean contains(Object o) {
+    return (o instanceof Linked<?>) && contains((Linked<?>) o);
+  }
+
+  // A fast-path containment check
+  boolean contains(Linked<?> e) {
+    return (e.getPrevious() != null)
+        || (e.getNext() != null)
+        || (e == first);
+  }
+
+  /**
+   * Moves the element to the front of the deque so that it becomes the first
+   * element.
+   *
+   * @param e the linked element
+   */
+  public void moveToFront(E e) {
+    if (e != first) {
+      unlink(e);
+      linkFirst(e);
+    }
+  }
+
+  /**
+   * Moves the element to the back of the deque so that it becomes the last
+   * element.
+   *
+   * @param e the linked element
+   */
+  public void moveToBack(E e) {
+    if (e != last) {
+      unlink(e);
+      linkLast(e);
+    }
+  }
+
+  @Override
+  public E peek() {
+    return peekFirst();
+  }
+
+  @Override
+  public E peekFirst() {
+    return first;
+  }
+
+  @Override
+  public E peekLast() {
+    return last;
+  }
+
+  @Override
+  public E getFirst() {
+    checkNotEmpty();
+    return peekFirst();
+  }
+
+  @Override
+  public E getLast() {
+    checkNotEmpty();
+    return peekLast();
+  }
+
+  @Override
+  public E element() {
+    return getFirst();
+  }
+
+  @Override
+  public boolean offer(E e) {
+    return offerLast(e);
+  }
+
+  @Override
+  public boolean offerFirst(E e) {
+    if (contains(e)) {
+      return false;
+    }
+    linkFirst(e);
+    return true;
+  }
+
+  @Override
+  public boolean offerLast(E e) {
+    if (contains(e)) {
+      return false;
+    }
+    linkLast(e);
+    return true;
+  }
+
+  @Override
+  public boolean add(E e) {
+    return offerLast(e);
+  }
+
+
+  @Override
+  public void addFirst(E e) {
+    if (!offerFirst(e)) {
+      throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public void addLast(E e) {
+    if (!offerLast(e)) {
+      throw new IllegalArgumentException();
+    }
+  }
+
+  @Override
+  public E poll() {
+    return pollFirst();
+  }
+
+  @Override
+  public E pollFirst() {
+    return isEmpty() ? null : unlinkFirst();
+  }
+
+  @Override
+  public E pollLast() {
+    return isEmpty() ? null : unlinkLast();
+  }
+
+  @Override
+  public E remove() {
+    return removeFirst();
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  public boolean remove(Object o) {
+    return (o instanceof Linked<?>) && remove((E) o);
+  }
+
+  // A fast-path removal
+  boolean remove(E e) {
+    if (contains(e)) {
+      unlink(e);
+      return true;
+    }
+    return false;
+  }
+
+  @Override
+  public E removeFirst() {
+    checkNotEmpty();
+    return pollFirst();
+  }
+
+  @Override
+  public boolean removeFirstOccurrence(Object o) {
+    return remove(o);
+  }
+
+  @Override
+  public E removeLast() {
+    checkNotEmpty();
+    return pollLast();
+  }
+
+  @Override
+  public boolean removeLastOccurrence(Object o) {
+    return remove(o);
+  }
+
+  @Override
+  public boolean removeAll(Collection<?> c) {
+    boolean modified = false;
+    for (Object o : c) {
+      modified |= remove(o);
+    }
+    return modified;
+  }
+
+  @Override
+  public void push(E e) {
+    addFirst(e);
+  }
+
+  @Override
+  public E pop() {
+    return removeFirst();
+  }
+
+  @Override
+  public Iterator<E> iterator() {
+    return new AbstractLinkedIterator(first) {
+      @Override E computeNext() {
+        return cursor.getNext();
+      }
+    };
+  }
+
+  @Override
+  public Iterator<E> descendingIterator() {
+    return new AbstractLinkedIterator(last) {
+      @Override E computeNext() {
+        return cursor.getPrevious();
+      }
+    };
+  }
+
+  abstract class AbstractLinkedIterator implements Iterator<E> {
+    E cursor;
+
+    /**
+     * Creates an iterator that can can traverse the deque.
+     *
+     * @param start the initial element to begin traversal from
+     */
+    AbstractLinkedIterator(E start) {
+      cursor = start;
+    }
+
+    @Override
+    public boolean hasNext() {
+      return (cursor != null);
+    }
+
+    @Override
+    public E next() {
+      if (!hasNext()) {
+        throw new NoSuchElementException();
+      }
+      E e = cursor;
+      cursor = computeNext();
+      return e;
+    }
+
+    @Override
+    public void remove() {
+      throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the next element to traverse to or <tt>null</tt> if there are
+     * no more elements.
+     */
+    abstract E computeNext();
+  }
+}
+
+/**
+ * An element that is linked on the {@link Deque}.
+ */
+interface Linked<T extends Linked<T>> {
+
+  /**
+   * Retrieves the previous element or <tt>null</tt> if either the element is
+   * unlinked or the first element on the deque.
+   */
+  T getPrevious();
+
+  /** Sets the previous element or <tt>null</tt> if there is no link. */
+  void setPrevious(T prev);
+
+  /**
+   * Retrieves the next element or <tt>null</tt> if either the element is
+   * unlinked or the last element on the deque.
+   */
+  T getNext();
+
+  /** Sets the next element or <tt>null</tt> if there is no link. */
+  void setNext(T next);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weigher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weigher.java b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weigher.java
new file mode 100644
index 0000000..c7eac09
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weigher.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010 Google Inc. All Rights Reserved.
+ *
+ * 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.apache.groovy.util.concurrentlinkedhashmap;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * A class that can determine the weight of a value. The total weight threshold
+ * is used to determine when an eviction is required.
+ *
+ * @author ben.manes@gmail.com (Ben Manes)
+ * @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
+ *      http://code.google.com/p/concurrentlinkedhashmap/</a>
+ */
+@ThreadSafe
+public interface Weigher<V> {
+
+  /**
+   * Measures an object's weight to determine how many units of capacity that
+   * the value consumes. A value must consume a minimum of one unit.
+   *
+   * @param value the object to weigh
+   * @return the object's weight
+   */
+  int weightOf(V value);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weighers.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weighers.java b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weighers.java
new file mode 100644
index 0000000..6fd9b25
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/Weighers.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2010 Google Inc. All Rights Reserved.
+ *
+ * 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.apache.groovy.util.concurrentlinkedhashmap;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.groovy.util.concurrentlinkedhashmap.ConcurrentLinkedHashMap.checkNotNull;
+
+/**
+ * A common set of {@link Weigher} and {@link EntryWeigher} implementations.
+ *
+ * @author ben.manes@gmail.com (Ben Manes)
+ * @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
+ *      http://code.google.com/p/concurrentlinkedhashmap/</a>
+ */
+public final class Weighers {
+
+  private Weighers() {
+    throw new AssertionError();
+  }
+
+  /**
+   * A entry weigher backed by the specified weigher. The weight of the value
+   * determines the weight of the entry.
+   *
+   * @param weigher the weigher to be "wrapped" in a entry weigher.
+   * @return A entry weigher view of the specified weigher.
+   */
+  public static <K, V> EntryWeigher<K, V> asEntryWeigher(
+      final Weigher<? super V> weigher) {
+    return (weigher == singleton())
+        ? Weighers.<K, V>entrySingleton()
+        : new EntryWeigherView<K, V>(weigher);
+  }
+
+  /**
+   * A weigher where an entry has a weight of <tt>1</tt>. A map bounded with
+   * this weigher will evict when the number of key-value pairs exceeds the
+   * capacity.
+   *
+   * @return A weigher where a value takes one unit of capacity.
+   */
+  @SuppressWarnings({"cast", "unchecked"})
+  public static <K, V> EntryWeigher<K, V> entrySingleton() {
+    return (EntryWeigher<K, V>) SingletonEntryWeigher.INSTANCE;
+  }
+
+  /**
+   * A weigher where a value has a weight of <tt>1</tt>. A map bounded with
+   * this weigher will evict when the number of key-value pairs exceeds the
+   * capacity.
+   *
+   * @return A weigher where a value takes one unit of capacity.
+   */
+  @SuppressWarnings({"cast", "unchecked"})
+  public static <V> Weigher<V> singleton() {
+    return (Weigher<V>) SingletonWeigher.INSTANCE;
+  }
+
+  /**
+   * A weigher where the value is a byte array and its weight is the number of
+   * bytes. A map bounded with this weigher will evict when the number of bytes
+   * exceeds the capacity rather than the number of key-value pairs in the map.
+   * This allows for restricting the capacity based on the memory-consumption
+   * and is primarily for usage by dedicated caching servers that hold the
+   * serialized data.
+   * <p>
+   * A value with a weight of <tt>0</tt> will be rejected by the map. If a value
+   * with this weight can occur then the caller should eagerly evaluate the
+   * value and treat it as a removal operation. Alternatively, a custom weigher
+   * may be specified on the map to assign an empty value a positive weight.
+   *
+   * @return A weigher where each byte takes one unit of capacity.
+   */
+  public static Weigher<byte[]> byteArray() {
+    return ByteArrayWeigher.INSTANCE;
+  }
+
+  /**
+   * A weigher where the value is a {@link Iterable} and its weight is the
+   * number of elements. This weigher only should be used when the alternative
+   * {@link #collection()} weigher cannot be, as evaluation takes O(n) time. A
+   * map bounded with this weigher will evict when the total number of elements
+   * exceeds the capacity rather than the number of key-value pairs in the map.
+   * <p>
+   * A value with a weight of <tt>0</tt> will be rejected by the map. If a value
+   * with this weight can occur then the caller should eagerly evaluate the
+   * value and treat it as a removal operation. Alternatively, a custom weigher
+   * may be specified on the map to assign an empty value a positive weight.
+   *
+   * @return A weigher where each element takes one unit of capacity.
+   */
+  @SuppressWarnings({"cast", "unchecked"})
+  public static <E> Weigher<? super Iterable<E>> iterable() {
+    return (Weigher<Iterable<E>>) (Weigher<?>) IterableWeigher.INSTANCE;
+  }
+
+  /**
+   * A weigher where the value is a {@link Collection} and its weight is the
+   * number of elements. A map bounded with this weigher will evict when the
+   * total number of elements exceeds the capacity rather than the number of
+   * key-value pairs in the map.
+   * <p>
+   * A value with a weight of <tt>0</tt> will be rejected by the map. If a value
+   * with this weight can occur then the caller should eagerly evaluate the
+   * value and treat it as a removal operation. Alternatively, a custom weigher
+   * may be specified on the map to assign an empty value a positive weight.
+   *
+   * @return A weigher where each element takes one unit of capacity.
+   */
+  @SuppressWarnings({"cast", "unchecked"})
+  public static <E> Weigher<? super Collection<E>> collection() {
+    return (Weigher<Collection<E>>) (Weigher<?>) CollectionWeigher.INSTANCE;
+  }
+
+  /**
+   * A weigher where the value is a {@link List} and its weight is the number
+   * of elements. A map bounded with this weigher will evict when the total
+   * number of elements exceeds the capacity rather than the number of
+   * key-value pairs in the map.
+   * <p>
+   * A value with a weight of <tt>0</tt> will be rejected by the map. If a value
+   * with this weight can occur then the caller should eagerly evaluate the
+   * value and treat it as a removal operation. Alternatively, a custom weigher
+   * may be specified on the map to assign an empty value a positive weight.
+   *
+   * @return A weigher where each element takes one unit of capacity.
+   */
+  @SuppressWarnings({"cast", "unchecked"})
+  public static <E> Weigher<? super List<E>> list() {
+    return (Weigher<List<E>>) (Weigher<?>) ListWeigher.INSTANCE;
+  }
+
+  /**
+   * A weigher where the value is a {@link Set} and its weight is the number
+   * of elements. A map bounded with this weigher will evict when the total
+   * number of elements exceeds the capacity rather than the number of
+   * key-value pairs in the map.
+   * <p>
+   * A value with a weight of <tt>0</tt> will be rejected by the map. If a value
+   * with this weight can occur then the caller should eagerly evaluate the
+   * value and treat it as a removal operation. Alternatively, a custom weigher
+   * may be specified on the map to assign an empty value a positive weight.
+   *
+   * @return A weigher where each element takes one unit of capacity.
+   */
+  @SuppressWarnings({"cast", "unchecked"})
+  public static <E> Weigher<? super Set<E>> set() {
+    return (Weigher<Set<E>>) (Weigher<?>) SetWeigher.INSTANCE;
+  }
+
+  /**
+   * A weigher where the value is a {@link Map} and its weight is the number of
+   * entries. A map bounded with this weigher will evict when the total number of
+   * entries across all values exceeds the capacity rather than the number of
+   * key-value pairs in the map.
+   * <p>
+   * A value with a weight of <tt>0</tt> will be rejected by the map. If a value
+   * with this weight can occur then the caller should eagerly evaluate the
+   * value and treat it as a removal operation. Alternatively, a custom weigher
+   * may be specified on the map to assign an empty value a positive weight.
+   *
+   * @return A weigher where each entry takes one unit of capacity.
+   */
+  @SuppressWarnings({"cast", "unchecked"})
+  public static <A, B> Weigher<? super Map<A, B>> map() {
+    return (Weigher<Map<A, B>>) (Weigher<?>) MapWeigher.INSTANCE;
+  }
+
+  static final class EntryWeigherView<K, V> implements EntryWeigher<K, V>, Serializable {
+    static final long serialVersionUID = 1;
+    final Weigher<? super V> weigher;
+
+    EntryWeigherView(Weigher<? super V> weigher) {
+      checkNotNull(weigher);
+      this.weigher = weigher;
+    }
+
+    @Override
+    public int weightOf(K key, V value) {
+      return weigher.weightOf(value);
+    }
+  }
+
+  enum SingletonEntryWeigher implements EntryWeigher<Object, Object> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(Object key, Object value) {
+      return 1;
+    }
+  }
+
+  enum SingletonWeigher implements Weigher<Object> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(Object value) {
+      return 1;
+    }
+  }
+
+  enum ByteArrayWeigher implements Weigher<byte[]> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(byte[] value) {
+      return value.length;
+    }
+  }
+
+  enum IterableWeigher implements Weigher<Iterable<?>> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(Iterable<?> values) {
+      if (values instanceof Collection<?>) {
+        return ((Collection<?>) values).size();
+      }
+      int size = 0;
+      for (Iterator<?> i = values.iterator(); i.hasNext();) {
+        i.next();
+        size++;
+      }
+      return size;
+    }
+  }
+
+  enum CollectionWeigher implements Weigher<Collection<?>> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(Collection<?> values) {
+      return values.size();
+    }
+  }
+
+  enum ListWeigher implements Weigher<List<?>> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(List<?> values) {
+      return values.size();
+    }
+  }
+
+  enum SetWeigher implements Weigher<Set<?>> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(Set<?> values) {
+      return values.size();
+    }
+  }
+
+  enum MapWeigher implements Weigher<Map<?, ?>> {
+    INSTANCE;
+
+    @Override
+    public int weightOf(Map<?, ?> values) {
+      return values.size();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/package-info.java b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/package-info.java
new file mode 100644
index 0000000..665de2e
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/concurrentlinkedhashmap/package-info.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+/**
+ * This package contains an implementation of a bounded
+ * {@link java.util.concurrent.ConcurrentMap} data structure.
+ * <p>
+ * {@link org.apache.groovy.util.concurrentlinkedhashmap.Weigher} is a simple interface
+ * for determining how many units of capacity an entry consumes. Depending on
+ * which concrete Weigher class is used, an entry may consume a different amount
+ * of space within the cache. The
+ * {@link org.apache.groovy.util.concurrentlinkedhashmap.Weighers} class provides
+ * utility methods for obtaining the most common kinds of implementations.
+ * <p>
+ * {@link org.apache.groovy.util.concurrentlinkedhashmap.EvictionListener} provides the
+ * ability to be notified when an entry is evicted from the map. An eviction
+ * occurs when the entry was automatically removed due to the map exceeding a
+ * capacity threshold. It is not called when an entry was explicitly removed.
+ * <p>
+ * The {@link org.apache.groovy.util.concurrentlinkedhashmap.ConcurrentLinkedHashMap}
+ * class supplies an efficient, scalable, thread-safe, bounded map. As with the
+ * <tt>Java Collections Framework</tt> the "Concurrent" prefix is used to
+ * indicate that the map is not governed by a single exclusion lock.
+ *
+ * @see <a href="http://code.google.com/p/concurrentlinkedhashmap/">
+ *      http://code.google.com/p/concurrentlinkedhashmap/</a>
+ */
+package org.apache.groovy.util.concurrentlinkedhashmap;


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java b/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
new file mode 100644
index 0000000..1bb302b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
@@ -0,0 +1,1189 @@
+/*
+ *  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.control.customizers;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.ImportNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
+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.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+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.MethodCallExpression;
+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.EmptyStatement;
+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.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.Token;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This customizer allows securing source code by controlling what code constructs are allowed. For example, if you only
+ * want to allow arithmetic operations in a groovy shell, you can configure this customizer to restrict package imports,
+ * method calls and so on.
+ * <p>
+ * Most of the security customization options found in this class work with either blacklist or whitelist. This means that, for a
+ * single option, you can set a whitelist OR a blacklist, but not both. You can mix whitelist/blacklist strategies for
+ * different options. For example, you can have import whitelist and tokens blacklist.
+ * <p>
+ * The recommended way of securing shells is to use whitelists because it is guaranteed that future features of the
+ * Groovy language won't be allowed by defaut. Using blacklists, you can limit the features of the languages by opting
+ * out, but new language features would require you to update your configuration.
+ * <p>
+ * If you set neither a whitelist nor a blacklist, then everything is authorized.
+ * <p>
+ * Combinations of import and star imports constraints are authorized as long as you use the same type of list for both.
+ * For example, you may use an import whitelist and a star import whitelist together, but you cannot use an import white
+ * list with a star import blacklist. static imports are handled separately, meaning that blacklisting an import <b>
+ * does not</b> prevent from using a static import.
+ * <p>
+ * Eventually, if the features provided here are not sufficient, you may implement custom AST filtering handlers, either
+ * implementing the {@link StatementChecker} interface or {@link ExpressionChecker} interface then register your
+ * handlers thanks to the {@link #addExpressionCheckers(org.codehaus.groovy.control.customizers.SecureASTCustomizer.ExpressionChecker...)}
+ * and {@link #addStatementCheckers(org.codehaus.groovy.control.customizers.SecureASTCustomizer.StatementChecker...)}
+ * methods.
+ * <p>
+ * Here is an example of usage. We will create a groovy classloader which only supports arithmetic operations and imports
+ * the java.lang.Math classes by default.
+ *
+ * <pre>
+ * final ImportCustomizer imports = new ImportCustomizer().addStaticStars('java.lang.Math') // add static import of java.lang.Math
+ *             final SecureASTCustomizer secure = new SecureASTCustomizer()
+ *             secure.with {
+ *                 closuresAllowed = false
+ *                 methodDefinitionAllowed = false
+ *
+ *                 importsWhitelist = []
+ *                 staticImportsWhitelist = []
+ *                 staticStarImportsWhitelist = ['java.lang.Math'] // only java.lang.Math is allowed
+ *
+ *                 tokensWhitelist = [
+ *                         PLUS,
+ *                         MINUS,
+ *                         MULTIPLY,
+ *                         DIVIDE,
+ *                         MOD,
+ *                         POWER,
+ *                         PLUS_PLUS,
+ *                         MINUS_MINUS,
+ *                         COMPARE_EQUAL,
+ *                         COMPARE_NOT_EQUAL,
+ *                         COMPARE_LESS_THAN,
+ *                         COMPARE_LESS_THAN_EQUAL,
+ *                         COMPARE_GREATER_THAN,
+ *                         COMPARE_GREATER_THAN_EQUAL,
+ *                 ].asImmutable()
+ *
+ *                 constantTypesClassesWhiteList = [
+ *                         Integer,
+ *                         Float,
+ *                         Long,
+ *                         Double,
+ *                         BigDecimal,
+ *                         Integer.TYPE,
+ *                         Long.TYPE,
+ *                         Float.TYPE,
+ *                         Double.TYPE
+ *                 ].asImmutable()
+ *
+ *                 receiversClassesWhiteList = [
+ *                         Math,
+ *                         Integer,
+ *                         Float,
+ *                         Double,
+ *                         Long,
+ *                         BigDecimal
+ *                 ].asImmutable()
+ *             }
+ *             CompilerConfiguration config = new CompilerConfiguration()
+ *             config.addCompilationCustomizers(imports, secure)
+ *             GroovyClassLoader loader = new GroovyClassLoader(this.class.classLoader, config)
+ *  </pre>
+ *  
+ * @author Cedric Champeau
+ * @author Guillaume Laforge
+ * @author Hamlet D'Arcy
+ * @since 1.8.0
+ */
+public class SecureASTCustomizer extends CompilationCustomizer {
+
+    private boolean isPackageAllowed = true;
+    private boolean isMethodDefinitionAllowed = true;
+    private boolean isClosuresAllowed = true;
+
+    // imports
+    private List<String> importsWhitelist;
+    private List<String> importsBlacklist;
+
+    // static imports
+    private List<String> staticImportsWhitelist;
+    private List<String> staticImportsBlacklist;
+
+    // star imports
+    private List<String> starImportsWhitelist;
+    private List<String> starImportsBlacklist;
+
+    // static star imports
+    private List<String> staticStarImportsWhitelist;
+    private List<String> staticStarImportsBlacklist;
+
+
+    // indirect import checks
+    // if set to true, then security rules on imports will also be applied on classnodes.
+    // Direct instantiation of classes without imports will therefore also fail if this option is enabled
+    private boolean isIndirectImportCheckEnabled;
+
+    // statements
+    private List<Class<? extends Statement>> statementsWhitelist;
+    private List<Class<? extends Statement>> statementsBlacklist;
+    private final List<StatementChecker> statementCheckers = new LinkedList<StatementChecker>();
+
+    // expressions
+    private List<Class<? extends Expression>> expressionsWhitelist;
+    private List<Class<? extends Expression>> expressionsBlacklist;
+    private final List<ExpressionChecker> expressionCheckers = new LinkedList<ExpressionChecker>();
+
+    // tokens from Types
+    private List<Integer> tokensWhitelist;
+    private List<Integer> tokensBlacklist;
+
+    // constant types
+    private List<String> constantTypesWhiteList;
+    private List<String> constantTypesBlackList;
+
+    // receivers
+    private List<String> receiversWhiteList;
+    private List<String> receiversBlackList;
+
+    public SecureASTCustomizer() {
+        super(CompilePhase.CANONICALIZATION);
+    }
+
+    public boolean isMethodDefinitionAllowed() {
+        return isMethodDefinitionAllowed;
+    }
+
+    public void setMethodDefinitionAllowed(final boolean methodDefinitionAllowed) {
+        isMethodDefinitionAllowed = methodDefinitionAllowed;
+    }
+
+    public boolean isPackageAllowed() {
+        return isPackageAllowed;
+    }
+
+    public boolean isClosuresAllowed() {
+        return isClosuresAllowed;
+    }
+
+    public void setClosuresAllowed(final boolean closuresAllowed) {
+        isClosuresAllowed = closuresAllowed;
+    }
+
+    public void setPackageAllowed(final boolean packageAllowed) {
+        isPackageAllowed = packageAllowed;
+    }
+
+    public List<String> getImportsBlacklist() {
+        return importsBlacklist;
+    }
+
+    public void setImportsBlacklist(final List<String> importsBlacklist) {
+        if (importsWhitelist != null || starImportsWhitelist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.importsBlacklist = importsBlacklist;
+    }
+
+    public List<String> getImportsWhitelist() {
+        return importsWhitelist;
+    }
+
+    public void setImportsWhitelist(final List<String> importsWhitelist) {
+        if (importsBlacklist != null || starImportsBlacklist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.importsWhitelist = importsWhitelist;
+    }
+
+    public List<String> getStarImportsBlacklist() {
+        return starImportsBlacklist;
+    }
+
+    public void setStarImportsBlacklist(final List<String> starImportsBlacklist) {
+        if (importsWhitelist != null || starImportsWhitelist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.starImportsBlacklist = normalizeStarImports(starImportsBlacklist);
+        if (this.importsBlacklist == null) importsBlacklist = Collections.emptyList();
+    }
+
+    public List<String> getStarImportsWhitelist() {
+        return starImportsWhitelist;
+    }
+
+    public void setStarImportsWhitelist(final List<String> starImportsWhitelist) {
+        if (importsBlacklist != null || starImportsBlacklist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.starImportsWhitelist = normalizeStarImports(starImportsWhitelist);
+        if (this.importsWhitelist == null) importsWhitelist = Collections.emptyList();
+    }
+
+    /**
+     * Ensures that every star import ends with .* as this is the expected syntax in import checks.
+     */
+    private static List<String> normalizeStarImports(List<String> starImports) {
+        List<String> result = new ArrayList<String>(starImports.size());
+        for (String starImport : starImports) {
+            if (starImport.endsWith(".*")) {
+                result.add(starImport);
+            } else if (starImport.endsWith(".")) {
+                result.add(starImport + "*");
+            } else {
+                result.add(starImport + ".*");
+            }
+        }
+        return Collections.unmodifiableList(result);
+    }
+
+    public List<String> getStaticImportsBlacklist() {
+        return staticImportsBlacklist;
+    }
+
+    public void setStaticImportsBlacklist(final List<String> staticImportsBlacklist) {
+        if (staticImportsWhitelist != null || staticStarImportsWhitelist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.staticImportsBlacklist = staticImportsBlacklist;
+    }
+
+    public List<String> getStaticImportsWhitelist() {
+        return staticImportsWhitelist;
+    }
+
+    public void setStaticImportsWhitelist(final List<String> staticImportsWhitelist) {
+        if (staticImportsBlacklist != null || staticStarImportsBlacklist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.staticImportsWhitelist = staticImportsWhitelist;
+    }
+
+    public List<String> getStaticStarImportsBlacklist() {
+        return staticStarImportsBlacklist;
+    }
+
+    public void setStaticStarImportsBlacklist(final List<String> staticStarImportsBlacklist) {
+        if (staticImportsWhitelist != null || staticStarImportsWhitelist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.staticStarImportsBlacklist = normalizeStarImports(staticStarImportsBlacklist);
+        if (this.staticImportsBlacklist == null) this.staticImportsBlacklist = Collections.emptyList();
+    }
+
+    public List<String> getStaticStarImportsWhitelist() {
+        return staticStarImportsWhitelist;
+    }
+
+    public void setStaticStarImportsWhitelist(final List<String> staticStarImportsWhitelist) {
+        if (staticImportsBlacklist != null || staticStarImportsBlacklist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.staticStarImportsWhitelist = normalizeStarImports(staticStarImportsWhitelist);
+        if (this.staticImportsWhitelist == null) this.staticImportsWhitelist = Collections.emptyList();
+    }
+
+    public List<Class<? extends Expression>> getExpressionsBlacklist() {
+        return expressionsBlacklist;
+    }
+
+    public void setExpressionsBlacklist(final List<Class<? extends Expression>> expressionsBlacklist) {
+        if (expressionsWhitelist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.expressionsBlacklist = expressionsBlacklist;
+    }
+
+    public List<Class<? extends Expression>> getExpressionsWhitelist() {
+        return expressionsWhitelist;
+    }
+
+    public void setExpressionsWhitelist(final List<Class<? extends Expression>> expressionsWhitelist) {
+        if (expressionsBlacklist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.expressionsWhitelist = expressionsWhitelist;
+    }
+
+    public List<Class<? extends Statement>> getStatementsBlacklist() {
+        return statementsBlacklist;
+    }
+
+    public void setStatementsBlacklist(final List<Class<? extends Statement>> statementsBlacklist) {
+        if (statementsWhitelist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.statementsBlacklist = statementsBlacklist;
+    }
+
+    public List<Class<? extends Statement>> getStatementsWhitelist() {
+        return statementsWhitelist;
+    }
+
+    public void setStatementsWhitelist(final List<Class<? extends Statement>> statementsWhitelist) {
+        if (statementsBlacklist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.statementsWhitelist = statementsWhitelist;
+    }
+
+    public List<Integer> getTokensBlacklist() {
+        return tokensBlacklist;
+    }
+
+    public boolean isIndirectImportCheckEnabled() {
+        return isIndirectImportCheckEnabled;
+    }
+
+    /**
+     * Set this option to true if you want your import rules to be checked against every class node. This means that if
+     * someone uses a fully qualified class name, then it will also be checked against the import rules, preventing, for
+     * example, instantiation of classes without imports thanks to FQCN.
+     *
+     * @param indirectImportCheckEnabled set to true to enable indirect checks
+     */
+    public void setIndirectImportCheckEnabled(final boolean indirectImportCheckEnabled) {
+        isIndirectImportCheckEnabled = indirectImportCheckEnabled;
+    }
+
+    /**
+     * Sets the list of tokens which are blacklisted.
+     *
+     * @param tokensBlacklist the tokens. The values of the tokens must be those of {@link org.codehaus.groovy.syntax.Types}
+     */
+    public void setTokensBlacklist(final List<Integer> tokensBlacklist) {
+        if (tokensWhitelist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.tokensBlacklist = tokensBlacklist;
+    }
+
+    public List<Integer> getTokensWhitelist() {
+        return tokensWhitelist;
+    }
+
+    /**
+     * Sets the list of tokens which are whitelisted.
+     *
+     * @param tokensWhitelist the tokens. The values of the tokens must be those of {@link org.codehaus.groovy.syntax.Types}
+     */
+    public void setTokensWhitelist(final List<Integer> tokensWhitelist) {
+        if (tokensBlacklist != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.tokensWhitelist = tokensWhitelist;
+    }
+
+    public void addStatementCheckers(StatementChecker... checkers) {
+        statementCheckers.addAll(Arrays.asList(checkers));
+    }
+
+    public void addExpressionCheckers(ExpressionChecker... checkers) {
+        expressionCheckers.addAll(Arrays.asList(checkers));
+    }
+
+    public List<String> getConstantTypesBlackList() {
+        return constantTypesBlackList;
+    }
+
+    public void setConstantTypesBlackList(final List<String> constantTypesBlackList) {
+        if (constantTypesWhiteList != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.constantTypesBlackList = constantTypesBlackList;
+    }
+
+    public List<String> getConstantTypesWhiteList() {
+        return constantTypesWhiteList;
+    }
+
+    public void setConstantTypesWhiteList(final List<String> constantTypesWhiteList) {
+        if (constantTypesBlackList != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.constantTypesWhiteList = constantTypesWhiteList;
+    }
+
+    /**
+     * An alternative way of setting constant types.
+     *
+     * @param constantTypesWhiteList a list of classes.
+     */
+    public void setConstantTypesClassesWhiteList(final List<Class> constantTypesWhiteList) {
+        List<String> values = new LinkedList<String>();
+        for (Class aClass : constantTypesWhiteList) {
+            values.add(aClass.getName());
+        }
+        setConstantTypesWhiteList(values);
+    }
+
+    /**
+     * An alternative way of setting constant types.
+     *
+     * @param constantTypesBlackList a list of classes.
+     */
+    public void setConstantTypesClassesBlackList(final List<Class> constantTypesBlackList) {
+        List<String> values = new LinkedList<String>();
+        for (Class aClass : constantTypesBlackList) {
+            values.add(aClass.getName());
+        }
+        setConstantTypesBlackList(values);
+    }
+
+    public List<String> getReceiversBlackList() {
+        return receiversBlackList;
+    }
+
+    /**
+     * Sets the list of classes which deny method calls.
+     * 
+     * Please note that since Groovy is a dynamic language, and 
+     * this class performs a static type check, it will be reletively
+     * simple to bypass any blacklist unless the receivers blacklist contains, at
+     * a minimum, Object, Script, GroovyShell, and Eval. Additionally,
+     * it is necessary to also blacklist MethodPointerExpression in the
+     * expressions blacklist for the receivers blacklist to function
+     * as a security check.
+     *
+     * @param receiversBlackList the list of refused classes, as fully qualified names
+     */
+    public void setReceiversBlackList(final List<String> receiversBlackList) {
+        if (receiversWhiteList != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.receiversBlackList = receiversBlackList;
+    }
+
+    /**
+     * An alternative way of setting {@link #setReceiversBlackList(java.util.List) receiver classes}.
+     *
+     * @param receiversBlacklist a list of classes.
+     */
+    public void setReceiversClassesBlackList(final List<Class> receiversBlacklist) {
+        List<String> values = new LinkedList<String>();
+        for (Class aClass : receiversBlacklist) {
+            values.add(aClass.getName());
+        }
+        setReceiversBlackList(values);
+    }
+
+    public List<String> getReceiversWhiteList() {
+        return receiversWhiteList;
+    }
+
+    /**
+     * Sets the list of classes which may accept method calls.
+     *
+     * @param receiversWhiteList the list of accepted classes, as fully qualified names
+     */
+    public void setReceiversWhiteList(final List<String> receiversWhiteList) {
+        if (receiversBlackList != null) {
+            throw new IllegalArgumentException("You are not allowed to set both whitelist and blacklist");
+        }
+        this.receiversWhiteList = receiversWhiteList;
+    }
+
+    /**
+     * An alternative way of setting {@link #setReceiversWhiteList(java.util.List) receiver classes}.
+     *
+     * @param receiversWhitelist a list of classes.
+     */
+    public void setReceiversClassesWhiteList(final List<Class> receiversWhitelist) {
+        List<String> values = new LinkedList<String>();
+        for (Class aClass : receiversWhitelist) {
+            values.add(aClass.getName());
+        }
+        setReceiversWhiteList(values);
+    }
+
+    @Override
+    public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+        final ModuleNode ast = source.getAST();
+        if (!isPackageAllowed && ast.getPackage() != null) {
+            throw new SecurityException("Package definitions are not allowed");
+        }
+        checkMethodDefinitionAllowed(classNode);
+
+        // verify imports
+        if (importsBlacklist != null || importsWhitelist != null || starImportsBlacklist != null || starImportsWhitelist != null) {
+            for (ImportNode importNode : ast.getImports()) {
+                final String className = importNode.getClassName();
+                assertImportIsAllowed(className);
+            }
+            for (ImportNode importNode : ast.getStarImports()) {
+                final String className = importNode.getPackageName();
+                assertStarImportIsAllowed(className + "*");
+            }
+        }
+
+        // verify static imports
+        if (staticImportsBlacklist != null || staticImportsWhitelist != null || staticStarImportsBlacklist != null || staticStarImportsWhitelist != null) {
+            for (Map.Entry<String, ImportNode> entry : ast.getStaticImports().entrySet()) {
+                final String className = entry.getValue().getClassName();
+                assertStaticImportIsAllowed(entry.getKey(), className);
+            }
+            for (Map.Entry<String, ImportNode> entry : ast.getStaticStarImports().entrySet()) {
+                final String className = entry.getValue().getClassName();
+                assertStaticImportIsAllowed(entry.getKey(), className);
+            }
+        }
+
+        final SecuringCodeVisitor visitor = new SecuringCodeVisitor();
+        ast.getStatementBlock().visit(visitor);
+        for (ClassNode clNode : ast.getClasses()) {
+            if (clNode!=classNode) {
+                checkMethodDefinitionAllowed(clNode);
+                for (MethodNode methodNode : clNode.getMethods()) {
+                    if (!methodNode.isSynthetic() && methodNode.getCode() != null) {
+                        methodNode.getCode().visit(visitor);
+                    }
+                }
+            }
+        }
+
+        List<MethodNode> methods = filterMethods(classNode);
+        if (isMethodDefinitionAllowed) {
+            for (MethodNode method : methods) {
+                if (method.getDeclaringClass()==classNode && method.getCode() != null) method.getCode().visit(visitor);
+            }
+        }
+    }
+    
+    private void checkMethodDefinitionAllowed(ClassNode owner) {
+        if (isMethodDefinitionAllowed) return;
+        List<MethodNode> methods = filterMethods(owner);
+        if (!methods.isEmpty()) throw new SecurityException("Method definitions are not allowed");
+    }
+    
+    private static List<MethodNode> filterMethods(ClassNode owner) {
+        List<MethodNode> result = new LinkedList<MethodNode>();
+        List<MethodNode> methods = owner.getMethods();
+        for (MethodNode method : methods) {
+            if (method.getDeclaringClass() == owner && !method.isSynthetic()) {
+                if ("main".equals(method.getName()) || "run".equals(method.getName()) && owner.isScriptBody()) continue;
+                result.add(method);
+            }
+        }
+        return result;
+    }
+
+    private void assertStarImportIsAllowed(final String packageName) {
+        if (starImportsWhitelist != null && !starImportsWhitelist.contains(packageName)) {
+            throw new SecurityException("Importing [" + packageName + "] is not allowed");
+        }
+        if (starImportsBlacklist != null && starImportsBlacklist.contains(packageName)) {
+            throw new SecurityException("Importing [" + packageName + "] is not allowed");
+        }
+    }
+
+    private void assertImportIsAllowed(final String className) {
+        if (importsWhitelist != null && !importsWhitelist.contains(className)) {
+            if (starImportsWhitelist != null) {
+                // we should now check if the import is in the star imports
+                ClassNode node = ClassHelper.make(className);
+                final String packageName = node.getPackageName();
+                if (!starImportsWhitelist.contains(packageName + ".*")) {
+                    throw new SecurityException("Importing [" + className + "] is not allowed");
+                }
+            } else {
+                throw new SecurityException("Importing [" + className + "] is not allowed");
+            }
+        }
+        if (importsBlacklist != null && importsBlacklist.contains(className)) {
+            throw new SecurityException("Importing [" + className + "] is not allowed");
+        }
+        // check that there's no star import blacklist
+        if (starImportsBlacklist != null) {
+            ClassNode node = ClassHelper.make(className);
+            final String packageName = node.getPackageName();
+            if (starImportsBlacklist.contains(packageName + ".*")) {
+                throw new SecurityException("Importing [" + className + "] is not allowed");
+            }
+        }
+    }
+
+    private void assertStaticImportIsAllowed(final String member, final String className) {
+        final String fqn = member.equals(className) ? member : className + "." + member;
+        if (staticImportsWhitelist != null && !staticImportsWhitelist.contains(fqn)) {
+            if (staticStarImportsWhitelist != null) {
+                // we should now check if the import is in the star imports
+                if (!staticStarImportsWhitelist.contains(className + ".*")) {
+                    throw new SecurityException("Importing [" + fqn + "] is not allowed");
+                }
+            } else {
+                throw new SecurityException("Importing [" + fqn + "] is not allowed");
+            }
+        }
+        if (staticImportsBlacklist != null && staticImportsBlacklist.contains(fqn)) {
+            throw new SecurityException("Importing [" + fqn + "] is not allowed");
+        }
+        // check that there's no star import blacklist
+        if (staticStarImportsBlacklist != null) {
+            if (staticStarImportsBlacklist.contains(className + ".*")) {
+                throw new SecurityException("Importing [" + fqn + "] is not allowed");
+            }
+        }
+    }
+
+    /**
+     * This visitor directly implements the {@link GroovyCodeVisitor} interface instead of using the {@link
+     * CodeVisitorSupport} class to make sure that future features of the language gets managed by this visitor. Thus,
+     * adding a new feature would result in a compilation error if this visitor is not updated.
+     */
+    private class SecuringCodeVisitor implements GroovyCodeVisitor {
+
+        /**
+         * Checks that a given statement is either in the whitelist or not in the blacklist.
+         *
+         * @param statement the statement to be checked
+         * @throws SecurityException if usage of this statement class is forbidden
+         */
+        private void assertStatementAuthorized(final Statement statement) throws SecurityException {
+            final Class<? extends Statement> clazz = statement.getClass();
+            if (statementsBlacklist != null && statementsBlacklist.contains(clazz)) {
+                throw new SecurityException(clazz.getSimpleName() + "s are not allowed");
+            } else if (statementsWhitelist != null && !statementsWhitelist.contains(clazz)) {
+                throw new SecurityException(clazz.getSimpleName() + "s are not allowed");
+            }
+            for (StatementChecker statementChecker : statementCheckers) {
+                if (!statementChecker.isAuthorized(statement)) {
+                    throw new SecurityException("Statement [" + clazz.getSimpleName() + "] is not allowed");
+                }
+            }
+        }
+
+        /**
+         * Checks that a given expression is either in the whitelist or not in the blacklist.
+         *
+         * @param expression the expression to be checked
+         * @throws SecurityException if usage of this expression class is forbidden
+         */
+        private void assertExpressionAuthorized(final Expression expression) throws SecurityException {
+            final Class<? extends Expression> clazz = expression.getClass();
+            if (expressionsBlacklist != null && expressionsBlacklist.contains(clazz)) {
+                throw new SecurityException(clazz.getSimpleName() + "s are not allowed: " + expression.getText());
+            } else if (expressionsWhitelist != null && !expressionsWhitelist.contains(clazz)) {
+                throw new SecurityException(clazz.getSimpleName() + "s are not allowed: " + expression.getText());
+            }
+            for (ExpressionChecker expressionChecker : expressionCheckers) {
+                if (!expressionChecker.isAuthorized(expression)) {
+                    throw new SecurityException("Expression [" + clazz.getSimpleName() + "] is not allowed: " + expression.getText());
+                }
+            }
+            if (isIndirectImportCheckEnabled) {
+                try {
+                    if (expression instanceof ConstructorCallExpression) {
+                        assertImportIsAllowed(expression.getType().getName());
+                    } else if (expression instanceof MethodCallExpression) {
+                        MethodCallExpression expr = (MethodCallExpression) expression;
+                        ClassNode objectExpressionType = expr.getObjectExpression().getType();
+                        final String typename = getExpressionType(objectExpressionType).getName();
+                        assertImportIsAllowed(typename);
+                        assertStaticImportIsAllowed(expr.getMethodAsString(), typename);
+                    } else if (expression instanceof StaticMethodCallExpression) {
+                        StaticMethodCallExpression expr = (StaticMethodCallExpression) expression;
+                        final String typename = expr.getOwnerType().getName();
+                        assertImportIsAllowed(typename);
+                        assertStaticImportIsAllowed(expr.getMethod(), typename);
+                    } else if (expression instanceof MethodPointerExpression) {
+                        MethodPointerExpression expr = (MethodPointerExpression) expression;
+                        final String typename = expr.getType().getName();
+                        assertImportIsAllowed(typename);
+                        assertStaticImportIsAllowed(expr.getText(), typename);
+                    }
+                } catch (SecurityException e) {
+                    throw new SecurityException("Indirect import checks prevents usage of expression", e);
+                }
+            }
+        }
+
+        private ClassNode getExpressionType(ClassNode objectExpressionType) {
+            return objectExpressionType.isArray() ? getExpressionType(objectExpressionType.getComponentType()) : objectExpressionType;
+        }
+
+        /**
+         * Checks that a given token is either in the whitelist or not in the blacklist.
+         *
+         * @param token the token to be checked
+         * @throws SecurityException if usage of this token is forbidden
+         */
+        private void assertTokenAuthorized(final Token token) throws SecurityException {
+            final int value = token.getType();
+            if (tokensBlacklist != null && tokensBlacklist.contains(value)) {
+                throw new SecurityException("Token " + token + " is not allowed");
+            } else if (tokensWhitelist != null && !tokensWhitelist.contains(value)) {
+                throw new SecurityException("Token " + token + " is not allowed");
+            }
+        }
+
+        public void visitBlockStatement(final BlockStatement block) {
+            assertStatementAuthorized(block);
+            for (Statement statement : block.getStatements()) {
+                statement.visit(this);
+            }
+        }
+
+
+        public void visitForLoop(final ForStatement forLoop) {
+            assertStatementAuthorized(forLoop);
+            forLoop.getCollectionExpression().visit(this);
+            forLoop.getLoopBlock().visit(this);
+        }
+
+        public void visitWhileLoop(final WhileStatement loop) {
+            assertStatementAuthorized(loop);
+            loop.getBooleanExpression().visit(this);
+            loop.getLoopBlock().visit(this);
+        }
+
+        public void visitDoWhileLoop(final DoWhileStatement loop) {
+            assertStatementAuthorized(loop);
+            loop.getBooleanExpression().visit(this);
+            loop.getLoopBlock().visit(this);
+        }
+
+        public void visitIfElse(final IfStatement ifElse) {
+            assertStatementAuthorized(ifElse);
+            ifElse.getBooleanExpression().visit(this);
+            ifElse.getIfBlock().visit(this);
+
+            Statement elseBlock = ifElse.getElseBlock();
+            if (elseBlock instanceof EmptyStatement) {
+                // dispatching to EmptyStatement will not call back visitor,
+                // must call our visitEmptyStatement explicitly
+                visitEmptyStatement((EmptyStatement) elseBlock);
+            } else {
+                elseBlock.visit(this);
+            }
+        }
+
+        public void visitExpressionStatement(final ExpressionStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getExpression().visit(this);
+        }
+
+        public void visitReturnStatement(final ReturnStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getExpression().visit(this);
+        }
+
+        public void visitAssertStatement(final AssertStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getBooleanExpression().visit(this);
+            statement.getMessageExpression().visit(this);
+        }
+
+        public void visitTryCatchFinally(final TryCatchStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getTryStatement().visit(this);
+            for (CatchStatement catchStatement : statement.getCatchStatements()) {
+                catchStatement.visit(this);
+            }
+            Statement finallyStatement = statement.getFinallyStatement();
+            if (finallyStatement instanceof EmptyStatement) {
+                // dispatching to EmptyStatement will not call back visitor,
+                // must call our visitEmptyStatement explicitly
+                visitEmptyStatement((EmptyStatement) finallyStatement);
+            } else {
+                finallyStatement.visit(this);
+            }
+        }
+
+        protected void visitEmptyStatement(EmptyStatement statement) {
+            // noop
+        }
+
+        public void visitSwitch(final SwitchStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getExpression().visit(this);
+            for (CaseStatement caseStatement : statement.getCaseStatements()) {
+                caseStatement.visit(this);
+            }
+            statement.getDefaultStatement().visit(this);
+        }
+
+        public void visitCaseStatement(final CaseStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getExpression().visit(this);
+            statement.getCode().visit(this);
+        }
+
+        public void visitBreakStatement(final BreakStatement statement) {
+            assertStatementAuthorized(statement);
+        }
+
+        public void visitContinueStatement(final ContinueStatement statement) {
+            assertStatementAuthorized(statement);
+        }
+
+        public void visitThrowStatement(final ThrowStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getExpression().visit(this);
+        }
+
+        public void visitSynchronizedStatement(final SynchronizedStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getExpression().visit(this);
+            statement.getCode().visit(this);
+        }
+
+        public void visitCatchStatement(final CatchStatement statement) {
+            assertStatementAuthorized(statement);
+            statement.getCode().visit(this);
+        }
+
+        public void visitMethodCallExpression(final MethodCallExpression call) {
+            assertExpressionAuthorized(call);
+            Expression receiver = call.getObjectExpression();
+            final String typeName = receiver.getType().getName();
+            if (receiversWhiteList != null && !receiversWhiteList.contains(typeName)) {
+                throw new SecurityException("Method calls not allowed on [" + typeName + "]");
+            } else if (receiversBlackList != null && receiversBlackList.contains(typeName)) {
+                throw new SecurityException("Method calls not allowed on [" + typeName + "]");
+            }
+            receiver.visit(this);
+            final Expression method = call.getMethod();
+            checkConstantTypeIfNotMethodNameOrProperty(method);
+            call.getArguments().visit(this);
+        }
+
+        public void visitStaticMethodCallExpression(final StaticMethodCallExpression call) {
+            assertExpressionAuthorized(call);
+            final String typeName = call.getOwnerType().getName();
+            if (receiversWhiteList != null && !receiversWhiteList.contains(typeName)) {
+                throw new SecurityException("Method calls not allowed on [" + typeName + "]");
+            } else if (receiversBlackList != null && receiversBlackList.contains(typeName)) {
+                throw new SecurityException("Method calls not allowed on [" + typeName + "]");
+            }
+            call.getArguments().visit(this);
+        }
+
+        public void visitConstructorCallExpression(final ConstructorCallExpression call) {
+            assertExpressionAuthorized(call);
+            call.getArguments().visit(this);
+        }
+
+        public void visitTernaryExpression(final TernaryExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getBooleanExpression().visit(this);
+            expression.getTrueExpression().visit(this);
+            expression.getFalseExpression().visit(this);
+        }
+
+        public void visitShortTernaryExpression(final ElvisOperatorExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitTernaryExpression(expression);
+        }
+
+        public void visitBinaryExpression(final BinaryExpression expression) {
+            assertExpressionAuthorized(expression);
+            assertTokenAuthorized(expression.getOperation());
+            expression.getLeftExpression().visit(this);
+            expression.getRightExpression().visit(this);
+        }
+
+        public void visitPrefixExpression(final PrefixExpression expression) {
+            assertExpressionAuthorized(expression);
+            assertTokenAuthorized(expression.getOperation());
+            expression.getExpression().visit(this);
+        }
+
+        public void visitPostfixExpression(final PostfixExpression expression) {
+            assertExpressionAuthorized(expression);
+            assertTokenAuthorized(expression.getOperation());
+            expression.getExpression().visit(this);
+        }
+
+        public void visitBooleanExpression(final BooleanExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitClosureExpression(final ClosureExpression expression) {
+            assertExpressionAuthorized(expression);
+            if (!isClosuresAllowed) throw new SecurityException("Closures are not allowed");
+            expression.getCode().visit(this);
+        }
+
+        public void visitTupleExpression(final TupleExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitListOfExpressions(expression.getExpressions());
+        }
+
+        public void visitMapExpression(final MapExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitListOfExpressions(expression.getMapEntryExpressions());
+        }
+
+        public void visitMapEntryExpression(final MapEntryExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getKeyExpression().visit(this);
+            expression.getValueExpression().visit(this);
+        }
+
+        public void visitListExpression(final ListExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitListOfExpressions(expression.getExpressions());
+        }
+
+        public void visitRangeExpression(final RangeExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getFrom().visit(this);
+            expression.getTo().visit(this);
+        }
+
+        public void visitPropertyExpression(final PropertyExpression expression) {
+            assertExpressionAuthorized(expression);
+            Expression receiver = expression.getObjectExpression();
+            final String typeName = receiver.getType().getName();
+            if (receiversWhiteList != null && !receiversWhiteList.contains(typeName)) {
+                throw new SecurityException("Property access not allowed on [" + typeName + "]");
+            } else if (receiversBlackList != null && receiversBlackList.contains(typeName)) {
+                throw new SecurityException("Property access not allowed on [" + typeName + "]");
+            }
+            receiver.visit(this);
+            final Expression property = expression.getProperty();
+            checkConstantTypeIfNotMethodNameOrProperty(property);
+        }
+
+        private void checkConstantTypeIfNotMethodNameOrProperty(final Expression expr) {
+            if (expr instanceof ConstantExpression) {
+                if (!"java.lang.String".equals(expr.getType().getName())) {
+                    expr.visit(this);
+                }
+            } else {
+                expr.visit(this);
+            }
+        }
+
+        public void visitAttributeExpression(final AttributeExpression expression) {
+            assertExpressionAuthorized(expression);
+            Expression receiver = expression.getObjectExpression();
+            final String typeName = receiver.getType().getName();
+            if (receiversWhiteList != null && !receiversWhiteList.contains(typeName)) {
+                throw new SecurityException("Attribute access not allowed on [" + typeName + "]");
+            } else if (receiversBlackList != null && receiversBlackList.contains(typeName)) {
+                throw new SecurityException("Attribute access not allowed on [" + typeName + "]");
+            }
+            receiver.visit(this);
+            final Expression property = expression.getProperty();
+            checkConstantTypeIfNotMethodNameOrProperty(property);
+        }
+
+        public void visitFieldExpression(final FieldExpression expression) {
+            assertExpressionAuthorized(expression);
+        }
+
+        public void visitMethodPointerExpression(final MethodPointerExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+            expression.getMethodName().visit(this);
+        }
+
+        public void visitConstantExpression(final ConstantExpression expression) {
+            assertExpressionAuthorized(expression);
+            final String type = expression.getType().getName();
+            if (constantTypesWhiteList != null && !constantTypesWhiteList.contains(type)) {
+                throw new SecurityException("Constant expression type [" + type + "] is not allowed");
+            }
+            if (constantTypesBlackList != null && constantTypesBlackList.contains(type)) {
+                throw new SecurityException("Constant expression type [" + type + "] is not allowed");
+            }
+        }
+
+        public void visitClassExpression(final ClassExpression expression) {
+            assertExpressionAuthorized(expression);
+        }
+
+        public void visitVariableExpression(final VariableExpression expression) {
+            assertExpressionAuthorized(expression);
+            final String type = expression.getType().getName();
+            if (constantTypesWhiteList != null && !constantTypesWhiteList.contains(type)) {
+                throw new SecurityException("Usage of variables of type [" + type + "] is not allowed");
+            }
+            if (constantTypesBlackList != null && constantTypesBlackList.contains(type)) {
+                throw new SecurityException("Usage of variables of type [" + type + "] is not allowed");
+            }
+        }
+
+        public void visitDeclarationExpression(final DeclarationExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitBinaryExpression(expression);
+        }
+
+        protected void visitListOfExpressions(List<? extends Expression> list) {
+            if (list == null) return;
+            for (Expression expression : list) {
+                if (expression instanceof SpreadExpression) {
+                    Expression spread = ((SpreadExpression) expression).getExpression();
+                    spread.visit(this);
+                } else {
+                    expression.visit(this);
+                }
+            }
+        }
+
+        public void visitGStringExpression(final GStringExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitListOfExpressions(expression.getStrings());
+            visitListOfExpressions(expression.getValues());
+        }
+
+        public void visitArrayExpression(final ArrayExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitListOfExpressions(expression.getExpressions());
+            visitListOfExpressions(expression.getSizeExpression());
+        }
+
+        public void visitSpreadExpression(final SpreadExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitSpreadMapExpression(final SpreadMapExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitNotExpression(final NotExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitUnaryMinusExpression(final UnaryMinusExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitUnaryPlusExpression(final UnaryPlusExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitBitwiseNegationExpression(final BitwiseNegationExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitCastExpression(final CastExpression expression) {
+            assertExpressionAuthorized(expression);
+            expression.getExpression().visit(this);
+        }
+
+        public void visitArgumentlistExpression(final ArgumentListExpression expression) {
+            assertExpressionAuthorized(expression);
+            visitTupleExpression(expression);
+        }
+
+        public void visitClosureListExpression(final ClosureListExpression closureListExpression) {
+            assertExpressionAuthorized(closureListExpression);
+            if (!isClosuresAllowed) throw new SecurityException("Closures are not allowed");
+            visitListOfExpressions(closureListExpression.getExpressions());
+        }
+
+        public void visitBytecodeExpression(final BytecodeExpression expression) {
+            assertExpressionAuthorized(expression);
+        }
+    }
+
+    /**
+     * This interface allows the user to plugin custom expression checkers if expression blacklist or whitelist are not
+     * sufficient
+     */
+    public interface ExpressionChecker {
+        boolean isAuthorized(Expression expression);
+    }
+
+    /**
+     * This interface allows the user to plugin custom statement checkers if statement blacklist or whitelist are not
+     * sufficient
+     */
+    public interface StatementChecker {
+        boolean isAuthorized(Statement expression);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/SourceAwareCustomizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/SourceAwareCustomizer.java b/src/main/java/org/codehaus/groovy/control/customizers/SourceAwareCustomizer.java
new file mode 100644
index 0000000..3bb5183
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/SourceAwareCustomizer.java
@@ -0,0 +1,105 @@
+/*
+ *  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.control.customizers;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.io.FileReaderSource;
+import org.codehaus.groovy.control.io.ReaderSource;
+
+/**
+ * A base class for customizers which only have to be applied on specific source units.
+ * This is for example useful if you want a customizer to be applied only for files
+ * matching some extensions.
+ * <p>
+ * For convenience, this class implements several methods that you may extend to customize
+ * the behaviour of this utility. For example, if you want to apply a customizer only
+ * for classes matching the '.foo' file extension, then you only have to override the
+ * {@link #acceptExtension(String)} method:
+ * <pre><code>return "foo".equals(extension)</code></pre>
+ *
+ * @since 2.1.0
+ * @author Cedric Champeau
+ */
+public class SourceAwareCustomizer extends DelegatingCustomizer {
+
+    private Closure<Boolean> extensionValidator;
+    private Closure<Boolean> baseNameValidator;
+    private Closure<Boolean> sourceUnitValidator;
+    private Closure<Boolean> classValidator;
+
+    public SourceAwareCustomizer(CompilationCustomizer delegate) {
+        super(delegate);
+    }
+
+    @Override
+    public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+        String fileName = source.getName();
+        ReaderSource reader = source.getSource();
+        if (reader instanceof FileReaderSource) {
+            FileReaderSource file = (FileReaderSource) reader;
+            fileName = file.getFile().getName();
+        }
+        if (acceptSource(source) && acceptClass(classNode) && accept(fileName)) {
+            delegate.call(source, context, classNode);
+        }
+    }
+
+    public void setBaseNameValidator(final Closure<Boolean> baseNameValidator) {
+        this.baseNameValidator = baseNameValidator;
+    }
+
+    public void setExtensionValidator(final Closure<Boolean> extensionValidator) {
+        this.extensionValidator = extensionValidator;
+    }
+
+    public void setSourceUnitValidator(final Closure<Boolean> sourceUnitValidator) {
+        this.sourceUnitValidator = sourceUnitValidator;
+    }
+
+    public void setClassValidator(final Closure<Boolean> classValidator) {
+        this.classValidator = classValidator;
+    }
+
+    public boolean accept(String fileName) {
+        int ext = fileName.lastIndexOf(".");
+        String baseName = ext<0?fileName:fileName.substring(0, ext);
+        String extension = ext<0?"":fileName.substring(ext+1);
+        return acceptExtension(extension) && acceptBaseName(baseName);
+    }
+
+    public boolean acceptClass(ClassNode cnode) {
+        return classValidator == null || classValidator.call(cnode);
+    }
+
+    public boolean acceptSource(SourceUnit unit) {
+        return sourceUnitValidator==null || sourceUnitValidator.call(unit);
+    }
+
+    public boolean acceptExtension(String extension) {
+        return extensionValidator==null || extensionValidator.call(extension);
+    }
+
+    public boolean acceptBaseName(String baseName) {
+        return baseNameValidator==null || baseNameValidator.call(baseName);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java b/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java
new file mode 100644
index 0000000..40ce7e7
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/builder/CustomizersFactory.java
@@ -0,0 +1,59 @@
+/*
+ *  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.control.customizers.builder;
+
+import groovy.util.AbstractFactory;
+import groovy.util.FactoryBuilderSupport;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This factory generates an array of compilation customizers.
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+public class CustomizersFactory extends AbstractFactory implements PostCompletionFactory {
+
+    public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
+        return new LinkedList();
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void setChild(final FactoryBuilderSupport builder, final Object parent, final Object child) {
+        if (parent instanceof Collection && child instanceof CompilationCustomizer) {
+            ((Collection) parent).add(child);
+        }
+    }
+
+
+    @SuppressWarnings("unchecked")
+    public Object postCompleteNode(final FactoryBuilderSupport factory, final Object parent, final Object node) {
+        if (node instanceof List) {
+            List col = (List) node;
+            return col.toArray(new CompilationCustomizer[col.size()]);
+        }
+        return node;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/builder/ImportCustomizerFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/builder/ImportCustomizerFactory.java b/src/main/java/org/codehaus/groovy/control/customizers/builder/ImportCustomizerFactory.java
new file mode 100644
index 0000000..e9e8b7e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/builder/ImportCustomizerFactory.java
@@ -0,0 +1,134 @@
+/*
+ *  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.control.customizers.builder;
+
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.util.AbstractFactory;
+import groovy.util.FactoryBuilderSupport;
+import org.codehaus.groovy.control.customizers.ImportCustomizer;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * This factory allows the generation of an {@link ImportCustomizer import customizer}. You may embed several
+ * elements:
+ * <ul>
+ *     <li><i>normal</i> for "regular" imports</li>
+ *     <li><i>star</i> for "star" imports</li>
+ *     <li><i>staticStar</i> for "static star" imports</li>
+ *     <li><i>alias</i> for imports with alias</li>
+ *     <li><i>staticMember</i> for static imports of individual members</li>
+ * </ul>
+ *
+ * For example:
+ * <pre><code>builder.imports {
+ * alias 'AI', 'java.util.concurrent.atomic.AtomicInteger'
+ * alias 'AL', 'java.util.concurrent.atomic.AtomicLong'
+ *}</code></pre>
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+public class ImportCustomizerFactory extends AbstractFactory {
+    @Override
+    public boolean isHandlesNodeChildren() {
+        return true;
+    }
+
+    public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
+        ImportCustomizer customizer = new ImportCustomizer();
+        addImport(customizer, value);
+        return customizer;
+    }
+
+    private void addImport(final ImportCustomizer customizer, final Object value) {
+        if (value==null) return;
+        if (value instanceof Collection) {
+            for (Object e : (Collection)value) {
+                addImport(customizer, e);
+            }
+        } else if (value instanceof String) {
+            customizer.addImports((String)value);
+        } else if (value instanceof Class) {
+            customizer.addImports(((Class) value).getName());
+        } else if (value instanceof GString) {
+            customizer.addImports(value.toString());
+        } else {
+            throw new RuntimeException("Unsupported import value type ["+value+"]");
+        }
+    }
+
+    @Override
+    public boolean onNodeChildren(final FactoryBuilderSupport builder, final Object node, final Closure childContent) {
+        if (node instanceof ImportCustomizer) {
+            Closure clone = (Closure) childContent.clone();
+            clone.setDelegate(new ImportHelper((ImportCustomizer) node));
+            clone.call();
+        }
+        return false;
+    }
+
+    private static final class ImportHelper {
+        private final ImportCustomizer customizer;
+
+        private ImportHelper(final ImportCustomizer customizer) {
+            this.customizer = customizer;
+        }
+
+        protected void normal(String... names) {
+            customizer.addImports(names);
+        }
+        protected void normal(Class... classes) {
+            for (Class aClass : classes) {
+                customizer.addImports(aClass.getName());
+            }
+        }
+
+        protected void alias(String alias, String name) {
+            customizer.addImport(alias, name);
+        }
+        protected void alias(String alias, Class clazz) {
+            customizer.addImport(alias, clazz.getName());
+        }
+
+        protected void star(String... packages) {
+            customizer.addStarImports(packages);
+        }
+
+        protected void staticStar(String... classNames) {
+            customizer.addStaticStars(classNames);
+        }
+        protected void staticStar(Class... classes) {
+            for (Class aClass : classes) {
+                customizer.addStaticStars(aClass.getName());
+            }
+        }
+
+        protected void staticMember(String name, String field) {
+            customizer.addStaticImport(name, field);
+        }
+        protected void staticMember(String alias, String name, String field) {
+            customizer.addStaticImport(alias, name, field);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/builder/InlinedASTCustomizerFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/builder/InlinedASTCustomizerFactory.java b/src/main/java/org/codehaus/groovy/control/customizers/builder/InlinedASTCustomizerFactory.java
new file mode 100644
index 0000000..c7b599c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/builder/InlinedASTCustomizerFactory.java
@@ -0,0 +1,89 @@
+/*
+ *  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.control.customizers.builder;
+
+import groovy.lang.Closure;
+import groovy.util.AbstractFactory;
+import groovy.util.FactoryBuilderSupport;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+import org.codehaus.groovy.runtime.ProxyGeneratorAdapter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This factory lets a user define a compilation customizer without having to define
+ * an anonymous inner class.
+ * <p>
+ * Here is an example, which only logs the class name during compilation:
+ * <pre>
+ * inline(phase:'CONVERSION') { source, context, classNode ->
+ *     println "visiting $classNode"
+ * }
+ * </pre>
+ *
+ * @author Cedric Champeau
+ * @since 2.1.0
+ */
+@SuppressWarnings("unchecked")
+public class InlinedASTCustomizerFactory extends AbstractFactory implements PostCompletionFactory {
+
+    @Override
+    public boolean isHandlesNodeChildren() {
+        return true;
+    }
+
+    public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
+        if (attributes.isEmpty() || !attributes.containsKey("phase")) {
+            throw new RuntimeException("You must specify a CompilePhase to run at, using the [phase] attribute");
+        }
+        Map result = new HashMap(1+attributes.size());
+        result.putAll(attributes);
+        return result;
+    }
+
+    @Override
+    public boolean onNodeChildren(final FactoryBuilderSupport builder, final Object node, final Closure childContent) {
+        if (node instanceof Map) {
+            ((Map)node).put("call", childContent.clone());
+        }
+        return false;
+    }
+
+    public Object postCompleteNode(final FactoryBuilderSupport factory, final Object parent, final Object node) {
+        if (node instanceof Map) {
+            Map map = (Map) node;
+            ProxyGeneratorAdapter adapter = new ProxyGeneratorAdapter(
+                    map,
+                    map.containsKey("superClass")?(Class)map.get("superClass"):CompilationCustomizer.class,
+                    map.containsKey("interfaces")?(Class[])map.get("interfaces"):null,
+                    this.getClass().getClassLoader(),
+                    false,
+                    null
+            );
+            Object phase = map.get("phase");
+            if (!(phase instanceof CompilePhase)) {
+                phase = CompilePhase.valueOf(phase.toString());
+            }
+            return adapter.proxy(map, phase);
+        }
+        return node;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/builder/PostCompletionFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/builder/PostCompletionFactory.java b/src/main/java/org/codehaus/groovy/control/customizers/builder/PostCompletionFactory.java
new file mode 100644
index 0000000..8855dbf
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/builder/PostCompletionFactory.java
@@ -0,0 +1,31 @@
+/*
+ *  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.control.customizers.builder;
+
+import groovy.util.FactoryBuilderSupport;
+
+/**
+ * A helper interface for factories which require post processing of generated nodes.
+ *
+ * @since 2.1.0
+ * @author Cedric Champeau
+ */
+public interface PostCompletionFactory {
+    Object postCompleteNode(FactoryBuilderSupport factory, Object parent, Object node);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/builder/SecureASTCustomizerFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/builder/SecureASTCustomizerFactory.java b/src/main/java/org/codehaus/groovy/control/customizers/builder/SecureASTCustomizerFactory.java
new file mode 100644
index 0000000..3c81dee
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/builder/SecureASTCustomizerFactory.java
@@ -0,0 +1,55 @@
+/*
+ *  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.control.customizers.builder;
+
+import groovy.lang.Closure;
+import groovy.util.AbstractFactory;
+import groovy.util.FactoryBuilderSupport;
+import org.codehaus.groovy.control.customizers.SecureASTCustomizer;
+
+import java.util.Map;
+
+/**
+ * This factory allows the generation of a {@link SecureASTCustomizer}. Embedded elements are delegated
+ * to a {@link SecureASTCustomizer} instance.
+ *
+ * @since 2.1.0
+ * @author Cedric Champeau
+ */
+public class SecureASTCustomizerFactory extends AbstractFactory {
+    @Override
+    public boolean isHandlesNodeChildren() {
+        return true;
+    }
+
+    public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
+        return new SecureASTCustomizer();
+    }
+
+    @Override
+    public boolean onNodeChildren(final FactoryBuilderSupport builder, final Object node, final Closure childContent) {
+        if (node instanceof SecureASTCustomizer) {
+            Closure clone = (Closure) childContent.clone();
+            clone.setDelegate(node);
+            clone.setResolveStrategy(Closure.DELEGATE_FIRST);
+            clone.call();
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/customizers/builder/SourceAwareCustomizerFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/customizers/builder/SourceAwareCustomizerFactory.java b/src/main/java/org/codehaus/groovy/control/customizers/builder/SourceAwareCustomizerFactory.java
new file mode 100644
index 0000000..d0fc541
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/customizers/builder/SourceAwareCustomizerFactory.java
@@ -0,0 +1,160 @@
+/*
+ *  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.control.customizers.builder;
+
+import groovy.lang.Closure;
+import groovy.util.AbstractFactory;
+import groovy.util.FactoryBuilderSupport;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+import org.codehaus.groovy.control.customizers.SourceAwareCustomizer;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Factory for use with {@link CompilerCustomizationBuilder}. Allows the construction of {@link SourceAwareCustomizer
+ * source aware customizers}. Syntax:
+ * <pre><code>
+ *     // apply CompileStatic AST annotation on .sgroovy files
+ *     builder.source(extension: 'sgroovy') {
+ *         ast(CompileStatic)
+ *     }
+ *
+ *     // apply CompileStatic AST annotation on .sgroovy or .sg files
+ *     builder.source(extensions: ['sgroovy','sg']) {
+ *         ast(CompileStatic)
+ *     }
+ *
+ *     // apply CompileStatic AST annotation on .sgroovy or .sg files
+ *     builder.source(extensionValidator: { it.name in ['sgroovy','sg']}) {
+ *         ast(CompileStatic)
+ *     }
+ *
+ *     // apply CompileStatic AST annotation on files whose name is 'foo'
+ *     builder.source(basename: 'foo') {
+ *         ast(CompileStatic)
+ *     }
+ *
+ *     // apply CompileStatic AST annotation on files whose name is 'foo' or 'bar'
+ *     builder.source(basenames: ['foo', 'bar']) {
+ *         ast(CompileStatic)
+ *     }
+ *
+ *     // apply CompileStatic AST annotation on files whose name is 'foo' or 'bar'
+ *     builder.source(basenameValidator: { it in ['foo', 'bar'] }) {
+ *         ast(CompileStatic)
+ *     }
+ *
+ *     // apply CompileStatic AST annotation on files that do not contain a class named 'Baz'
+ *     builder.source(unitValidator: { unit -> !unit.AST.classes.any { it.name == 'Baz' } }) {
+ *         ast(CompileStatic)
+ *     }
+ *
+ *     // apply CompileStatic AST annotation on class nodes that end with 'CS'
+ *     builder.source(classValidator: { cn -> cn.name.endsWith('CS') }) {
+ *         ast(CompileStatic)
+ *     }
+ * </code></pre>
+ *
+ * @author Cedric Champeau
+ */
+public class SourceAwareCustomizerFactory extends AbstractFactory implements PostCompletionFactory {
+
+    public Object newInstance(final FactoryBuilderSupport builder, final Object name, final Object value, final Map attributes) throws InstantiationException, IllegalAccessException {
+        SourceOptions data = new SourceOptions();
+        if (value instanceof CompilationCustomizer) {
+            data.delegate = (CompilationCustomizer) value;
+        }
+        return data;
+    }
+
+    @Override
+    public void setChild(final FactoryBuilderSupport builder, final Object parent, final Object child) {
+        if (child instanceof CompilationCustomizer && parent instanceof SourceOptions) {
+            ((SourceOptions) parent).delegate = (CompilationCustomizer) child;
+        }
+    }
+
+    public Object postCompleteNode(final FactoryBuilderSupport factory, final Object parent, final Object node) {
+        SourceOptions data = (SourceOptions) node;
+        SourceAwareCustomizer sourceAwareCustomizer = new SourceAwareCustomizer(data.delegate);
+        if (data.extensionValidator !=null && (data.extension!=null || data.extensions!=null)) {
+            throw new RuntimeException("You must choose between an extension name validator or an explicit extension name");
+        }
+        if (data.basenameValidator!=null && (data.basename!=null || data.basenames!=null)) {
+            throw new RuntimeException("You must choose between an base name validator or an explicit base name");
+        }
+
+        addExtensionValidator(sourceAwareCustomizer, data);
+        addBasenameValidator(sourceAwareCustomizer, data);
+        if (data.unitValidator!=null) sourceAwareCustomizer.setSourceUnitValidator(data.unitValidator);
+        if (data.classValidator!=null) sourceAwareCustomizer.setClassValidator(data.classValidator);
+        return sourceAwareCustomizer;
+    }
+
+    private static void addExtensionValidator(final SourceAwareCustomizer sourceAwareCustomizer, final SourceOptions data) {
+        final List<String> extensions = data.extensions!=null?data.extensions : new LinkedList<String>();
+        if (data.extension!=null) extensions.add(data.extension);
+        Closure<Boolean> extensionValidator = data.extensionValidator;
+        if (extensionValidator==null && !extensions.isEmpty()) {
+            extensionValidator = new Closure<Boolean>(sourceAwareCustomizer) {
+                @Override
+                @SuppressWarnings("unchecked")
+                public Boolean call(final Object arguments) {
+                    return extensions.contains(arguments);
+                }
+            };
+        }
+        sourceAwareCustomizer.setExtensionValidator(extensionValidator);
+    }
+
+    private static void addBasenameValidator(final SourceAwareCustomizer sourceAwareCustomizer, final SourceOptions data) {
+        final List<String> basenames = data.basenames!=null?data.basenames : new LinkedList<String>();
+        if (data.basename!=null) basenames.add(data.basename);
+        Closure<Boolean> basenameValidator = data.basenameValidator;
+        if (basenameValidator==null && !basenames.isEmpty()) {
+            basenameValidator = new Closure<Boolean>(sourceAwareCustomizer) {
+                @Override
+                @SuppressWarnings("unchecked")
+                public Boolean call(final Object arguments) {
+                    return basenames.contains(arguments);
+                }
+            };
+        }
+        sourceAwareCustomizer.setBaseNameValidator(basenameValidator);
+    }
+
+    public static class SourceOptions {
+        public CompilationCustomizer delegate;
+        // validate with closures
+        public Closure<Boolean> extensionValidator;
+        public Closure<Boolean> unitValidator;
+        public Closure<Boolean> basenameValidator;
+        public Closure<Boolean> classValidator;
+
+        // validate with one string
+        public String extension;
+        public String basename;
+
+        // validate with list of strings
+        public List<String> extensions;
+        public List<String> basenames;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java b/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java
new file mode 100644
index 0000000..1c1084c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java
@@ -0,0 +1,120 @@
+/*
+ *  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.control.io;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.Janitor;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+
+/**
+ * For ReaderSources that can choose a parent class, a base that
+ * provides common functionality.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public abstract class AbstractReaderSource implements ReaderSource {
+    protected CompilerConfiguration configuration;   // Configuration data
+
+    public AbstractReaderSource(CompilerConfiguration configuration) {
+        if (configuration == null) {
+            throw new IllegalArgumentException("Compiler configuration must not be null!");
+            // ... or more relaxed?
+            // configuration = CompilerConfiguration.DEFAULT;
+        }
+        this.configuration = configuration;
+    }
+
+    /**
+     * Returns true if the source can be restarted (ie. if getReader()
+     * will return non-null on subsequent calls.
+     */
+    public boolean canReopenSource() {
+        return true;
+    }
+
+    private BufferedReader lineSource = null;    // If set, a reader on the current source file
+    private String line = null;    // The last line read from the current source file
+    private int number = 0;       // The last line number read
+
+    /**
+     * Returns a line from the source, or null, if unavailable.  If
+     * you supply a Janitor, resources will be cached.
+     */
+    public String getLine(int lineNumber, Janitor janitor) {
+        // If the source is already open and is passed the line we
+        // want, close it.
+        if (lineSource != null && number > lineNumber) {
+            cleanup();
+        }
+
+        // If the line source is closed, try to open it.
+        if (lineSource == null) {
+            try {
+                lineSource = new BufferedReader(getReader());
+            } catch (Exception e) {
+                // Ignore
+            }
+            number = 0;
+        }
+
+        // Read until the appropriate line number.
+        if (lineSource != null) {
+            while (number < lineNumber) {
+                try {
+                    line = lineSource.readLine();
+                    number++;
+                }
+                catch (IOException e) {
+                    cleanup();
+                }
+            }
+
+            if (janitor == null) {
+                final String result = line;   // otherwise cleanup() will wipe out value
+                cleanup();
+                return result;
+            } else {
+                janitor.register(this);
+            }
+        }
+
+        return line;
+    }
+
+    /**
+     * Cleans up any cached resources used by getLine().
+     */
+    public void cleanup() {
+        if (lineSource != null) {
+            try {
+                lineSource.close();
+            } catch (Exception e) {
+                // Ignore
+            }
+        }
+
+        lineSource = null;
+        line = null;
+        number = 0;
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassNode.java b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
new file mode 100644
index 0000000..083d5b4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ClassNode.java
@@ -0,0 +1,1503 @@
+/*
+ *  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.groovydoc.Groovydoc;
+import groovy.lang.groovydoc.GroovydocHolder;
+import org.apache.groovy.ast.tools.ClassNodeUtils;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+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.ast.tools.ParameterUtils;
+import org.codehaus.groovy.control.CompilePhase;
+import org.codehaus.groovy.transform.ASTTransformation;
+import org.codehaus.groovy.transform.GroovyASTTransformation;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents a class in the AST.
+ * <p>
+ * A ClassNode should be created using the methods in ClassHelper.
+ * This ClassNode may be used to represent a class declaration or
+ * any other type. This class uses a proxy mechanism allowing to
+ * create a class for a plain name at AST creation time. In another
+ * phase of the compiler the real ClassNode for the plain name may be
+ * found. To avoid the need of exchanging this ClassNode with an
+ * instance of the correct ClassNode the correct ClassNode is set as
+ * redirect. Most method calls are then redirected to that ClassNode.
+ * <p>
+ * There are three types of ClassNodes:
+ * <ol>
+ * <li> Primary ClassNodes:<br>
+ * A primary ClassNode is one where we have a source representation
+ * which is to be compiled by Groovy and which we have an AST for. 
+ * The groovy compiler will output one class for each such ClassNode
+ * that passes through AsmBytecodeGenerator... not more, not less.
+ * That means for example Closures become such ClassNodes too at
+ * some point. 
+ * <li> ClassNodes create through different sources (typically created
+ * from a java.lang.reflect.Class object):<br>
+ * The compiler will not output classes from these, the methods
+ * usually do not contain bodies. These kind of ClassNodes will be
+ * used in different checks, but not checks that work on the method 
+ * bodies. For example if such a ClassNode is a super class to a primary
+ * ClassNode, then the abstract method test and others will be done 
+ * with data based on these. Theoretically it is also possible to mix both 
+ * (1 and 2) kind of classes in a hierarchy, but this probably works only
+ *  in the newest Groovy versions. Such ClassNodes normally have to
+ *  isResolved() returning true without having a redirect.In the Groovy 
+ *  compiler the only version of this, that exists, is a ClassNode created 
+ *  through a Class instance
+ * <li> Labels:<br>
+ * ClassNodes created through ClassHelper.makeWithoutCaching. They 
+ * are place holders, its redirect points to the real structure, which can
+ * be a label too, but following all redirects it should end with a ClassNode
+ * from one of the other two categories. If ResolveVisitor finds such a 
+ * node, it tries to set the redirects. Any such label created after 
+ * ResolveVisitor has done its work needs to have a redirect pointing to 
+ * case 1 or 2. If not the compiler may react strange... this can be considered 
+ * as a kind of dangling pointer. 
+ * </ol>
+ * <b>Note:</b> the redirect mechanism is only allowed for classes 
+ * that are not primary ClassNodes. Typically this is done for classes
+ * created by name only.  The redirect itself can be any type of ClassNode.
+ * <p>
+ * To describe generic type signature see {@link #getGenericsTypes()} and
+ * {@link #setGenericsTypes(GenericsType[])}. These methods are not proxied,
+ * they describe the type signature used at the point of declaration or the
+ * type signatures provided by the class. If the type signatures provided
+ * by the class are needed, then a call to {@link #redirect()} will help.
+ *
+ * @see org.codehaus.groovy.ast.ClassHelper
+ */
+public class ClassNode extends AnnotatedNode implements Opcodes, GroovydocHolder<ClassNode> {
+
+    private static class MapOfLists {
+        private Map<Object, List<MethodNode>> map;
+        public List<MethodNode> get(Object key) {
+            return map == null ? null : map.get(key);
+        }
+
+        public List<MethodNode> getNotNull(Object key) {
+            List<MethodNode> ret = get(key);
+            if (ret==null) ret = Collections.emptyList();
+            return ret;
+        }
+
+        public void put(Object key, MethodNode value) {
+            if (map == null) {
+                 map = new HashMap<Object, List<MethodNode>>();
+            }
+            if (map.containsKey(key)) {
+                get(key).add(value);
+            } else {
+                List<MethodNode> list = new ArrayList<MethodNode>(2);
+                list.add(value);
+                map.put(key, list);
+            }
+        }
+
+        public void remove(Object key, MethodNode value) {
+            get(key).remove(value);
+        }
+    }
+
+    public static final ClassNode[] EMPTY_ARRAY = new ClassNode[0];
+    public static final ClassNode THIS = new ClassNode(Object.class);
+    public static final ClassNode SUPER = new ClassNode(Object.class);
+
+    private String name;
+    private int modifiers;
+    private boolean syntheticPublic;
+    private ClassNode[] interfaces;
+    private MixinNode[] mixins;
+    private List<ConstructorNode> constructors;
+    private List<Statement> objectInitializers;
+    private MapOfLists methods;
+    private List<MethodNode> methodsList;
+    private LinkedList<FieldNode> fields;
+    private List<PropertyNode> properties;
+    private Map<String, FieldNode> fieldIndex;
+    private ModuleNode module;
+    private CompileUnit compileUnit;
+    private boolean staticClass = false;
+    private boolean scriptBody = false;
+    private boolean script;
+    private ClassNode superClass;
+    protected boolean isPrimaryNode;
+    protected List<InnerClassNode> innerClasses;
+
+    /**
+     * The ASTTransformations to be applied to the Class
+     */
+    private Map<CompilePhase, Map<Class<? extends ASTTransformation>, Set<ASTNode>>> transformInstances;
+
+    // use this to synchronize access for the lazy init
+    protected final Object lazyInitLock = new Object();
+
+    // clazz!=null when resolved
+    protected Class clazz;
+    // only false when this classNode is constructed from a class
+    private volatile boolean lazyInitDone=true;
+    // not null if if the ClassNode is an array
+    private ClassNode componentType = null;
+    // if not null this instance is handled as proxy
+    // for the redirect
+    private ClassNode redirect=null;
+    // flag if the classes or its members are annotated
+    private boolean annotated;
+
+    // type spec for generics
+    private GenericsType[] genericsTypes=null;
+    private boolean usesGenerics=false;
+
+    // if set to true the name getGenericsTypes consists
+    // of 1 element describing the name of the placeholder
+    private boolean placeholder;
+
+    /**
+     * Returns the ClassNode this ClassNode is redirecting to.
+     */
+    public ClassNode redirect(){
+        if (redirect==null) return this;
+        return redirect.redirect();
+    }
+
+    /**
+     * Sets this instance as proxy for the given ClassNode.
+     * @param cn the class to redirect to. If set to null the redirect will be removed
+     */
+    public void setRedirect(ClassNode cn) {
+        if (isPrimaryNode) throw new GroovyBugError("tried to set a redirect for a primary ClassNode ("+getName()+"->"+cn.getName()+").");
+        if (cn!=null) cn = cn.redirect();
+        if (cn==this) return;
+        redirect = cn;
+    }
+
+    /**
+     * Returns a ClassNode representing an array of the class
+     * represented by this ClassNode
+     */
+    public ClassNode makeArray() {
+        if (redirect!=null) {
+            ClassNode res = redirect().makeArray();
+            res.componentType = this;
+            return res;
+        }
+        ClassNode cn;
+        if (clazz!=null) {
+            Class ret = Array.newInstance(clazz,0).getClass();
+            // don't use the ClassHelper here!
+            cn = new ClassNode(ret,this);
+        } else {
+            cn = new ClassNode(this);
+        }
+        return cn;
+    }
+
+    /**
+     * @return true if this instance is a primary ClassNode
+     */
+    public boolean isPrimaryClassNode() {
+        return redirect().isPrimaryNode || (componentType != null && componentType.isPrimaryClassNode());
+    }
+
+    /*
+     * Constructor used by makeArray() if no real class is available
+     */
+    private ClassNode(ClassNode componentType) {
+        this(componentType.getName()+"[]", ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
+        this.componentType = componentType.redirect();
+        isPrimaryNode=false;
+    }
+
+    /*
+     * Constructor used by makeArray() if a real class is available
+     */
+    private ClassNode(Class c, ClassNode componentType) {
+        this(c);
+        this.componentType = componentType;
+        isPrimaryNode=false;
+    }
+
+    /**
+     * Creates a ClassNode from a real class. The resulting
+     * ClassNode will not be a primary ClassNode.
+     */
+    public ClassNode(Class c) {
+        this(c.getName(), c.getModifiers(), null, null ,MixinNode.EMPTY_ARRAY);
+        clazz=c;
+        lazyInitDone=false;
+        CompileUnit cu = getCompileUnit();
+        if (cu!=null) cu.addClass(this);
+        isPrimaryNode=false;
+    }
+
+    /**
+     * The complete class structure will be initialized only when really
+     * needed to avoid having too many objects during compilation
+     */
+    private void lazyClassInit() {
+        if (lazyInitDone) return;
+        synchronized (lazyInitLock) {
+            if (redirect!=null) {
+                throw new GroovyBugError("lazyClassInit called on a proxy ClassNode, that must not happen."+
+                                         "A redirect() call is missing somewhere!");
+            }   
+            if (lazyInitDone) return;
+            VMPluginFactory.getPlugin().configureClassNode(compileUnit,this);
+            lazyInitDone = true;
+        }
+    }
+
+    // added to track the enclosing method for local inner classes
+    private MethodNode enclosingMethod = null;
+
+    public MethodNode getEnclosingMethod() {
+        return redirect().enclosingMethod;
+    }
+
+    public void setEnclosingMethod(MethodNode enclosingMethod) {
+        redirect().enclosingMethod = enclosingMethod;
+    }
+
+    /**
+     * Indicates that this class has been "promoted" to public by
+     * Groovy when in fact there was no public modifier explicitly
+     * in the source code. I.e. it remembers that it has applied
+     * Groovy's "public classes by default" rule.This property is
+     * typically only of interest to AST transform writers.
+     *
+     * @return true if this class is public but had no explicit public modifier
+     */
+    public boolean isSyntheticPublic() {
+        return syntheticPublic;
+    }
+
+    public void setSyntheticPublic(boolean syntheticPublic) {
+        this.syntheticPublic = syntheticPublic;
+    }
+
+    /**
+     * @param name       is the full name of the class
+     * @param modifiers  the modifiers,
+     * @param superClass the base class name - use "java.lang.Object" if no direct
+     *                   base class
+     * @see org.objectweb.asm.Opcodes
+     */
+    public ClassNode(String name, int modifiers, ClassNode superClass) {
+        this(name, modifiers, superClass, EMPTY_ARRAY, MixinNode.EMPTY_ARRAY);
+    }
+
+    /**
+     * @param name       is the full name of the class
+     * @param modifiers  the modifiers,
+     * @param superClass the base class name - use "java.lang.Object" if no direct
+     *                   base class
+     * @param interfaces the interfaces for this class
+     * @param mixins     the mixins for this class
+     * @see org.objectweb.asm.Opcodes
+     */
+    public ClassNode(String name, int modifiers, ClassNode superClass, ClassNode[] interfaces, MixinNode[] mixins) {
+        this.name = name;
+        this.modifiers = modifiers;
+        this.superClass = superClass;
+        this.interfaces = interfaces;
+        this.mixins = mixins;
+        isPrimaryNode = true;
+        if (superClass!=null) {
+            usesGenerics = superClass.isUsingGenerics();
+        }
+        if (!usesGenerics && interfaces!=null) {
+            for (ClassNode anInterface : interfaces) {
+                usesGenerics = usesGenerics || anInterface.isUsingGenerics();
+                if (usesGenerics) break;
+            }
+        }
+        this.methods = new MapOfLists();
+        this.methodsList = Collections.emptyList();
+    }
+
+    /**
+     * Sets the superclass of this ClassNode
+     */
+    public void setSuperClass(ClassNode superClass) {
+        redirect().superClass = superClass;
+    }
+
+    /**
+     * @return the list of FieldNode's associated with this ClassNode
+     */
+    public List<FieldNode> getFields() {
+        if (redirect!=null) return redirect().getFields();
+        lazyClassInit();
+        if (fields == null)
+            fields = new LinkedList<FieldNode> ();
+        return fields;
+    }
+
+    /**
+     * @return the array of interfaces which this ClassNode implements
+     */
+    public ClassNode[] getInterfaces() {
+        if (redirect!=null) return redirect().getInterfaces();
+        lazyClassInit();
+        return interfaces;
+    }
+
+    public void setInterfaces(ClassNode[] interfaces) {
+        if (redirect!=null) {
+            redirect().setInterfaces(interfaces);
+        } else {
+            this.interfaces = interfaces;
+        }
+    }
+
+    /**
+     * @return the array of mixins associated with this ClassNode
+     */
+    public MixinNode[] getMixins() {
+        return redirect().mixins;
+    }
+
+
+    public void setMixins(MixinNode[] mixins) {
+        redirect().mixins = mixins;
+    }
+
+    /**
+     * @return the list of methods associated with this ClassNode
+     */
+    public List<MethodNode> getMethods() {
+        if (redirect!=null) return redirect().getMethods();
+        lazyClassInit();
+        return methodsList;
+    }
+
+    /**
+     * @return the list of abstract methods associated with this
+     * ClassNode or null if there are no such methods
+     */
+    public List<MethodNode> getAbstractMethods() {
+        List<MethodNode> result = new ArrayList<MethodNode>(3);
+        for (MethodNode method : getDeclaredMethodsMap().values()) {
+            if (method.isAbstract()) {
+                result.add(method);
+            }
+        }
+        
+        if (result.isEmpty()) {
+            return null;
+        } else {
+            return result;
+        }
+
+    }
+
+    public List<MethodNode> getAllDeclaredMethods() {
+        return new ArrayList<MethodNode>(getDeclaredMethodsMap().values());
+    }
+
+    public Set<ClassNode> getAllInterfaces () {
+        Set<ClassNode> res = new LinkedHashSet<ClassNode>();
+        getAllInterfaces(res);
+        return res;
+    }
+
+    private void getAllInterfaces(Set<ClassNode> res) {
+        if (isInterface())
+          res.add(this);
+
+        for (ClassNode anInterface : getInterfaces()) {
+            res.add(anInterface);
+            anInterface.getAllInterfaces(res);
+        }
+    }
+
+    public Map<String, MethodNode> getDeclaredMethodsMap() {
+        Map<String, MethodNode> result = ClassNodeUtils.getDeclaredMethodsFromSuper(this);
+        ClassNodeUtils.addDeclaredMethodsFromInterfaces(this, result);
+
+        // And add in the methods implemented in this class.
+        for (MethodNode method : getMethods()) {
+            String sig = method.getTypeDescriptor();
+            result.put(sig, method);
+        }
+        return result;
+    }
+
+    public String getName() {
+        return redirect().name;
+    }
+
+    public String getUnresolvedName() {
+        return name;
+    }
+
+    public String setName(String name) {
+        return redirect().name=name;
+    }
+
+    public int getModifiers() {
+        return redirect().modifiers;
+    }
+
+    public void setModifiers(int modifiers) {
+        redirect().modifiers = modifiers;
+    }
+
+    public List<PropertyNode> getProperties() {
+        final ClassNode r = redirect();
+        if (r.properties == null)
+            r.properties = new ArrayList<PropertyNode> ();
+        return r.properties;
+    }
+
+    public List<ConstructorNode> getDeclaredConstructors() {
+        if (redirect != null) return redirect().getDeclaredConstructors();
+        lazyClassInit();
+        if (constructors == null)
+            constructors = new ArrayList<ConstructorNode> ();
+        return constructors;
+    }
+
+    /**
+     * Finds a constructor matching the given parameters in this class.
+     *
+     * @return the constructor matching the given parameters or null
+     */
+    public ConstructorNode getDeclaredConstructor(Parameter[] parameters) {
+        for (ConstructorNode method : getDeclaredConstructors()) {
+            if (parametersEqual(method.getParameters(), parameters)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    public void removeConstructor(ConstructorNode node) {
+        redirect().constructors.remove(node);
+    }
+
+    public ModuleNode getModule() {
+        return redirect().module;
+    }
+
+    public PackageNode getPackage() {
+        return getModule() == null ? null : getModule().getPackage();
+    }
+
+    public void setModule(ModuleNode module) {
+        redirect().module = module;
+        if (module != null) {
+            redirect().compileUnit = module.getUnit();
+        }
+    }
+
+    public void addField(FieldNode node) {
+        addField(node, false);
+    }
+
+    public void addFieldFirst(FieldNode node) {
+        addField(node, true);
+    }
+
+    private void addField(FieldNode node, boolean isFirst) {
+        final ClassNode r = redirect();
+        node.setDeclaringClass(r);
+        node.setOwner(r);
+        if (r.fields == null)
+            r.fields = new LinkedList<>();
+        if (r.fieldIndex == null)
+            r.fieldIndex = new HashMap<>();
+
+        if (isFirst)
+            r.fields.addFirst(node);
+        else
+            r.fields.add(node);
+
+        r.fieldIndex.put(node.getName(), node);
+    }
+
+    public Map<String, FieldNode> getFieldIndex() {
+        return fieldIndex;
+    }
+
+    public void addProperty(PropertyNode node) {
+        node.setDeclaringClass(redirect());
+        FieldNode field = node.getField();
+        addField(field);
+        final ClassNode r = redirect();
+        if (r.properties == null)
+            r.properties = new ArrayList<PropertyNode> ();
+        r.properties.add(node);
+    }
+
+    public PropertyNode addProperty(String name,
+                                    int modifiers,
+                                    ClassNode type,
+                                    Expression initialValueExpression,
+                                    Statement getterBlock,
+                                    Statement setterBlock) {
+        for (PropertyNode pn : getProperties()) {
+            if (pn.getName().equals(name)) {
+                if (pn.getInitialExpression() == null && initialValueExpression != null)
+                    pn.getField().setInitialValueExpression(initialValueExpression);
+
+                if (pn.getGetterBlock() == null && getterBlock != null)
+                    pn.setGetterBlock(getterBlock);
+
+                if (pn.getSetterBlock() == null && setterBlock != null)
+                    pn.setSetterBlock(setterBlock);
+
+                return pn;
+            }
+        }
+        PropertyNode node =
+                new PropertyNode(name, modifiers, type, redirect(), initialValueExpression, getterBlock, setterBlock);
+        addProperty(node);
+        return node;
+    }
+
+    public boolean hasProperty(String name) {
+        return getProperty(name) != null;
+    }
+
+    public PropertyNode getProperty(String name) {
+        for (PropertyNode pn : getProperties()) {
+            if (pn.getName().equals(name)) return pn;
+        }
+        return null;
+    }
+
+    public void addConstructor(ConstructorNode node) {
+        node.setDeclaringClass(this);
+        final ClassNode r = redirect();
+        if (r.constructors == null)
+            r.constructors = new ArrayList<ConstructorNode> ();
+        r.constructors.add(node);
+    }
+
+    public ConstructorNode addConstructor(int modifiers, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
+        ConstructorNode node = new ConstructorNode(modifiers, parameters, exceptions, code);
+        addConstructor(node);
+        return node;
+    }
+
+    public void addMethod(MethodNode node) {
+        node.setDeclaringClass(this);
+        ClassNode base = redirect();
+        if (base.methodsList.isEmpty()) {
+            base.methodsList = new ArrayList<MethodNode>();
+        }
+        base.methodsList.add(node);
+        base.methods.put(node.getName(), node);
+    }
+
+    public void removeMethod(MethodNode node) {
+        ClassNode base = redirect();
+        if (!base.methodsList.isEmpty()) {
+            base.methodsList.remove(node);
+        }
+        base.methods.remove(node.getName(), node);
+    }
+
+    /**
+     * If a method with the given name and parameters is already defined then it is returned
+     * otherwise the given method is added to this node. This method is useful for
+     * default method adding like getProperty() or invokeMethod() where there may already
+     * be a method defined in a class and so the default implementations should not be added
+     * if already present.
+     */
+    public MethodNode addMethod(String name,
+                                int modifiers,
+                                ClassNode returnType,
+                                Parameter[] parameters,
+                                ClassNode[] exceptions,
+                                Statement code) {
+        MethodNode other = getDeclaredMethod(name, parameters);
+        // let's not add duplicate methods
+        if (other != null) {
+            return other;
+        }
+        MethodNode node = new MethodNode(name, modifiers, returnType, parameters, exceptions, code);
+        addMethod(node);
+        return node;
+    }
+
+    /**
+     * @see #getDeclaredMethod(String, Parameter[])
+     */
+    public boolean hasDeclaredMethod(String name, Parameter[] parameters) {
+        MethodNode other = getDeclaredMethod(name, parameters);
+        return other != null;
+    }
+
+    /**
+     * @see #getMethod(String, Parameter[])
+     */
+    public boolean hasMethod(String name, Parameter[] parameters) {
+        MethodNode other = getMethod(name, parameters);
+        return other != null;
+    }
+
+    /**
+     * Adds a synthetic method as part of the compilation process
+     */
+    public MethodNode addSyntheticMethod(String name,
+                                         int modifiers,
+                                         ClassNode returnType,
+                                         Parameter[] parameters,
+                                         ClassNode[] exceptions,
+                                         Statement code) {
+        MethodNode answer = addMethod(name, modifiers|ACC_SYNTHETIC, returnType, parameters, exceptions, code);
+        answer.setSynthetic(true);
+        return answer;
+    }
+
+    public FieldNode addField(String name, int modifiers, ClassNode type, Expression initialValue) {
+        FieldNode node = new FieldNode(name, modifiers, type, redirect(), initialValue);
+        addField(node);
+        return node;
+    }
+
+    public FieldNode addFieldFirst(String name, int modifiers, ClassNode type, Expression initialValue) {
+        FieldNode node = new FieldNode(name, modifiers, type, redirect(), initialValue);
+        addFieldFirst(node);
+        return node;
+    }
+
+    public void addInterface(ClassNode type) {
+        // let's check if it already implements an interface
+        boolean skip = false;
+        ClassNode[] interfaces = redirect().interfaces;
+        for (ClassNode existing : interfaces) {
+            if (type.equals(existing)) {
+                skip = true;
+                break;
+            }
+        }
+        if (!skip) {
+            ClassNode[] newInterfaces = new ClassNode[interfaces.length + 1];
+            System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
+            newInterfaces[interfaces.length] = type;
+            redirect().interfaces = newInterfaces;
+        }
+    }
+
+    public boolean equals(Object o) {
+        if (redirect!=null) return redirect().equals(o);
+        if (!(o instanceof ClassNode)) return false;
+        ClassNode cn = (ClassNode) o;
+        return (cn.getText().equals(getText()));
+    }
+
+    public int hashCode() {
+        if (redirect!=null) return redirect().hashCode();
+        return getName().hashCode();
+    }
+
+    public void addMixin(MixinNode mixin) {
+        // let's check if it already uses a mixin
+        MixinNode[] mixins = redirect().mixins;
+        boolean skip = false;
+        for (MixinNode existing : mixins) {
+            if (mixin.equals(existing)) {
+                skip = true;
+                break;
+            }
+        }
+        if (!skip) {
+            MixinNode[] newMixins = new MixinNode[mixins.length + 1];
+            System.arraycopy(mixins, 0, newMixins, 0, mixins.length);
+            newMixins[mixins.length] = mixin;
+            redirect().mixins = newMixins;
+        }
+    }
+
+    /**
+     * Finds a field matching the given name in this class.
+     *
+     * @param name the name of the field of interest
+     * @return the method matching the given name and parameters or null
+     */
+    public FieldNode getDeclaredField(String name) {
+        if (redirect != null) return redirect().getDeclaredField(name);
+
+        lazyClassInit();
+        return fieldIndex == null ? null : fieldIndex.get(name);
+    }
+
+    /**
+     * Finds a field matching the given name in this class or a parent class.
+     *
+     * @param name the name of the field of interest
+     * @return the method matching the given name and parameters or null
+     */
+    public FieldNode getField(String name) {
+        ClassNode node = this;
+        while (node != null) {
+            FieldNode fn = node.getDeclaredField(name);
+            if (fn != null) return fn;
+            node = node.getSuperClass();
+        }
+        return null;
+    }
+
+    /**
+     * @return the field node on the outer class or null if this is not an
+     *         inner class
+     */
+    public FieldNode getOuterField(String name) {
+        return null;
+    }
+
+    /**
+     * Helper method to avoid casting to inner class
+     */
+    public ClassNode getOuterClass() {
+        return null;
+    }
+
+    /**
+     * Adds a statement to the object initializer.
+     *
+     * @param statements the statement to be added
+     */
+    public void addObjectInitializerStatements(Statement statements) {
+        getObjectInitializerStatements().add(statements);
+    }
+
+    public List<Statement> getObjectInitializerStatements() {
+        if (objectInitializers == null)
+            objectInitializers = new LinkedList<Statement> ();
+        return objectInitializers;
+    }
+
+    private MethodNode getOrAddStaticConstructorNode() {
+        MethodNode method = null;
+        List declaredMethods = getDeclaredMethods("<clinit>");
+        if (declaredMethods.isEmpty()) {
+            method =
+                    addMethod("<clinit>", ACC_STATIC, ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement());
+            method.setSynthetic(true);
+        }
+        else {
+            method = (MethodNode) declaredMethods.get(0);
+        }
+        return method;
+    }
+    
+    public void addStaticInitializerStatements(List<Statement> staticStatements, boolean fieldInit) {
+        MethodNode method = getOrAddStaticConstructorNode();
+        BlockStatement block = null;
+        Statement statement = method.getCode();
+        if (statement == null) {
+            block = new BlockStatement();
+        }
+        else if (statement instanceof BlockStatement) {
+            block = (BlockStatement) statement;
+        }
+        else {
+            block = new BlockStatement();
+            block.addStatement(statement);
+        }
+
+        // while anything inside a static initializer block is appended
+        // we don't want to append in the case we have a initialization
+        // expression of a static field. In that case we want to add
+        // before the other statements
+        if (!fieldInit) {
+            block.addStatements(staticStatements);
+        } else {
+            List<Statement> blockStatements = block.getStatements();
+            staticStatements.addAll(blockStatements);
+            blockStatements.clear();
+            blockStatements.addAll(staticStatements);
+        }
+    }
+
+    public void positionStmtsAfterEnumInitStmts(List<Statement> staticFieldStatements) {
+        MethodNode method = getOrAddStaticConstructorNode();
+        Statement statement = method.getCode();
+        if (statement instanceof BlockStatement) {
+            BlockStatement block = (BlockStatement) statement;
+            // add given statements for explicitly declared static fields just after enum-special fields
+            // are found - the $VALUES binary expression marks the end of such fields.
+            List<Statement> blockStatements = block.getStatements();
+            ListIterator<Statement> litr = blockStatements.listIterator();
+            while (litr.hasNext()) {
+                Statement stmt = litr.next();
+                if (stmt instanceof ExpressionStatement &&
+                        ((ExpressionStatement) stmt).getExpression() instanceof BinaryExpression) {
+                    BinaryExpression bExp = (BinaryExpression) ((ExpressionStatement) stmt).getExpression();
+                    if (bExp.getLeftExpression() instanceof FieldExpression) {
+                        FieldExpression fExp = (FieldExpression) bExp.getLeftExpression();
+                        if (fExp.getFieldName().equals("$VALUES")) {
+                            for (Statement tmpStmt : staticFieldStatements) {
+                                litr.add(tmpStmt);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * This methods returns a list of all methods of the given name
+     * defined in the current class
+     * @return the method list
+     * @see #getMethods(String)
+     */
+    public List<MethodNode> getDeclaredMethods(String name) {
+        if (redirect!=null) return redirect().getDeclaredMethods(name);
+        lazyClassInit();
+        return methods.getNotNull(name);
+    }
+
+    /**
+     * This methods creates a list of all methods with this name of the
+     * current class and of all super classes
+     * @return the methods list
+     * @see #getDeclaredMethods(String)
+     */
+    public List<MethodNode> getMethods(String name) {
+        List<MethodNode> answer = new ArrayList<MethodNode>();
+        ClassNode node = this;
+        while (node != null) {
+            answer.addAll(node.getDeclaredMethods(name));
+            node = node.getSuperClass();
+        }
+        return answer;
+    }
+
+    /**
+     * Finds a method matching the given name and parameters in this class.
+     *
+     * @return the method matching the given name and parameters or null
+     */
+    public MethodNode getDeclaredMethod(String name, Parameter[] parameters) {
+        for (MethodNode method :  getDeclaredMethods(name)) {
+            if (parametersEqual(method.getParameters(), parameters)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Finds a method matching the given name and parameters in this class
+     * or any parent class.
+     *
+     * @return the method matching the given name and parameters or null
+     */
+    public MethodNode getMethod(String name, Parameter[] parameters) {
+        for (MethodNode method : getMethods(name)) {
+            if (parametersEqual(method.getParameters(), parameters)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param type the ClassNode of interest
+     * @return true if this node is derived from the given ClassNode
+     */
+    public boolean isDerivedFrom(ClassNode type) {
+        if (this.equals(ClassHelper.VOID_TYPE)) {
+            return type.equals(ClassHelper.VOID_TYPE);
+        }
+        if (type.equals(ClassHelper.OBJECT_TYPE)) return true;
+        ClassNode node = this;
+        while (node != null) {
+            if (type.equals(node)) {
+                return true;
+            }
+            node = node.getSuperClass();
+        }
+        return false;
+    }
+
+    /**
+     * @return true if this class is derived from a groovy object
+     *         i.e. it implements GroovyObject
+     */
+    public boolean isDerivedFromGroovyObject() {
+        return implementsInterface(ClassHelper.GROOVY_OBJECT_TYPE);
+    }
+
+    /**
+     * @param classNode the class node for the interface
+     * @return true if this class or any base class implements the given interface
+     */
+    public boolean implementsInterface(ClassNode classNode) {
+        ClassNode node = redirect();
+        do {
+            if (node.declaresInterface(classNode)) {
+                return true;
+            }
+            node = node.getSuperClass();
+        }
+        while (node != null);
+        return false;
+    }
+
+    /**
+     * @param classNode the class node for the interface
+     * @return true if this class declares that it implements the given interface
+     * or if one of its interfaces extends directly or indirectly the interface
+     *
+     * NOTE: Doesn't consider an interface to implement itself.
+     * I think this is intended to be called on ClassNodes representing
+     * classes, not interfaces.
+     * 
+     */
+    public boolean declaresInterface(ClassNode classNode) {
+        ClassNode[] interfaces = redirect().getInterfaces();
+        for (ClassNode cn : interfaces) {
+            if (cn.equals(classNode)) return true;
+        }
+        for (ClassNode cn : interfaces) {
+            if (cn.declaresInterface(classNode)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return the ClassNode of the super class of this type
+     */
+    public ClassNode getSuperClass() {
+        if (!lazyInitDone && !isResolved()) {
+            throw new GroovyBugError("ClassNode#getSuperClass for "+getName()+" called before class resolving");
+        }
+        ClassNode sn = redirect().getUnresolvedSuperClass();
+        if (sn!=null) sn=sn.redirect();
+        return sn;
+    }
+
+    public ClassNode getUnresolvedSuperClass() {
+        return getUnresolvedSuperClass(true);
+    }
+
+    public ClassNode getUnresolvedSuperClass(boolean useRedirect) {
+        if (!useRedirect) return superClass;
+        if (redirect != null) return redirect().getUnresolvedSuperClass(true);
+        lazyClassInit();
+        return superClass;
+    }
+
+    public void setUnresolvedSuperClass(ClassNode sn) {
+        superClass = sn;
+    }
+
+    public ClassNode [] getUnresolvedInterfaces() {
+        return getUnresolvedInterfaces(true);
+    }
+
+    public ClassNode [] getUnresolvedInterfaces(boolean useRedirect) {
+        if (!useRedirect) return interfaces;
+        if (redirect != null) return redirect().getUnresolvedInterfaces(true);
+        lazyClassInit();
+        return interfaces;
+    }
+
+    public CompileUnit getCompileUnit() {
+        if (redirect!=null) return redirect().getCompileUnit();
+        if (compileUnit == null && module != null) {
+            compileUnit = module.getUnit();
+        }
+        return compileUnit;
+    }
+
+    protected void setCompileUnit(CompileUnit cu) {
+        if (redirect!=null) redirect().setCompileUnit(cu);
+        if (compileUnit!= null) compileUnit = cu;
+    }
+
+    /**
+     * @return true if the two arrays are of the same size and have the same contents
+     */
+    protected boolean parametersEqual(Parameter[] a, Parameter[] b) {
+        return ParameterUtils.parametersEqual(a, b);
+    }
+
+    /**
+     * @return the package name of this class
+     */
+    public String getPackageName() {
+        int idx = getName().lastIndexOf('.');
+        if (idx > 0) {
+            return getName().substring(0, idx);
+        }
+        return null;
+    }
+
+    public String getNameWithoutPackage() {
+        int idx = getName().lastIndexOf('.');
+        if (idx > 0) {
+            return getName().substring(idx + 1);
+        }
+        return getName();
+    }
+
+    public void visitContents(GroovyClassVisitor visitor) {
+        // now let's visit the contents of the class
+        for (PropertyNode pn : getProperties()) {
+            visitor.visitProperty(pn);
+        }
+
+        for (FieldNode fn : getFields()) {
+            visitor.visitField(fn);
+        }
+
+        for (ConstructorNode cn : getDeclaredConstructors()) {
+            visitor.visitConstructor(cn);
+        }
+
+        for (MethodNode mn : getMethods()) {
+            visitor.visitMethod(mn);
+        }
+    }
+
+    public MethodNode getGetterMethod(String getterName) {
+        return getGetterMethod(getterName, true);
+    }
+
+    public MethodNode getGetterMethod(String getterName, boolean searchSuperClasses) {
+        MethodNode getterMethod = null;
+        boolean booleanReturnOnly = getterName.startsWith("is");
+        for (MethodNode method : getDeclaredMethods(getterName)) {
+            if (getterName.equals(method.getName())
+                    && ClassHelper.VOID_TYPE!=method.getReturnType()
+                    && method.getParameters().length == 0
+                    && (!booleanReturnOnly || ClassHelper.Boolean_TYPE.equals(ClassHelper.getWrapper(method.getReturnType())))) {
+                // GROOVY-7363: There can be multiple matches for a getter returning a generic parameter type, due to
+                // the generation of a bridge method. The real getter is really the non-bridge, non-synthetic one as it
+                // has the most specific and exact return type of the two. Picking the bridge method results in loss of
+                // type information, as it down-casts the return type to the lower bound of the generic parameter.
+                if (getterMethod == null || getterMethod.isSynthetic()) {
+                    getterMethod = method;
+                }
+            }
+        }
+        if (getterMethod != null) return getterMethod;
+        if (searchSuperClasses) {
+            ClassNode parent = getSuperClass();
+            if (parent != null) return parent.getGetterMethod(getterName);
+        }
+        return null;
+    }
+
+    public MethodNode getSetterMethod(String setterName) {
+        return getSetterMethod(setterName, true);
+    }
+
+    public MethodNode getSetterMethod(String setterName, boolean voidOnly) {
+        for (MethodNode method : getDeclaredMethods(setterName)) {
+            if (setterName.equals(method.getName())
+                    && (!voidOnly || ClassHelper.VOID_TYPE==method.getReturnType())
+                    && method.getParameters().length == 1) {
+                return method;
+            }
+        }
+        ClassNode parent = getSuperClass();
+        if (parent!=null) return parent.getSetterMethod(setterName, voidOnly);
+        return null;
+    }
+
+    /**
+     * Is this class declared in a static method (such as a closure / inner class declared in a static method)
+     */
+    public boolean isStaticClass() {
+        return redirect().staticClass;
+    }
+
+    public void setStaticClass(boolean staticClass) {
+        redirect().staticClass = staticClass;
+    }
+
+    /**
+     * @return Returns true if this inner class or closure was declared inside a script body
+     */
+    public boolean isScriptBody() {
+        return redirect().scriptBody;
+    }
+
+    public void setScriptBody(boolean scriptBody) {
+        redirect().scriptBody = scriptBody;
+    }
+
+    public boolean isScript() {
+        return redirect().script || isDerivedFrom(ClassHelper.SCRIPT_TYPE);
+    }
+
+    public void setScript(boolean script) {
+        redirect().script = script;
+    }
+
+    public String toString() {
+        return toString(true);
+    }
+
+    public String toString(boolean showRedirect) {
+        if (isArray()) {
+            return componentType.toString(showRedirect)+"[]";
+        }
+        StringBuilder ret = new StringBuilder(getName());
+        if (placeholder) ret = new StringBuilder(getUnresolvedName());
+        if (!placeholder && genericsTypes != null) {
+            ret.append(" <");
+            for (int i = 0; i < genericsTypes.length; i++) {
+                if (i != 0) ret.append(", ");
+                GenericsType genericsType = genericsTypes[i];
+                ret.append(genericTypeAsString(genericsType));
+            }
+            ret.append(">");
+        }
+        if (redirect != null && showRedirect) {
+            ret.append(" -> ").append(redirect().toString());
+        }
+        return ret.toString();
+    }
+
+    /**
+     * This exists to avoid a recursive definition of toString. The default toString
+     * in GenericsType calls ClassNode.toString(), which calls GenericsType.toString(), etc. 
+     * @param genericsType
+     * @return the string representing the generic type
+     */
+    private String genericTypeAsString(GenericsType genericsType) {
+        StringBuilder ret = new StringBuilder(genericsType.getName());
+        if (genericsType.getUpperBounds() != null) {
+            ret.append(" extends ");
+            for (int i = 0; i < genericsType.getUpperBounds().length; i++) {
+                ClassNode classNode = genericsType.getUpperBounds()[i];
+                if (classNode.equals(this)) {
+                    ret.append(classNode.getName());
+                } else {
+                    ret.append(classNode.toString(false));
+                }
+                if (i + 1 < genericsType.getUpperBounds().length) ret.append(" & ");
+            }
+        } else if (genericsType.getLowerBound() !=null) {
+            ClassNode classNode = genericsType.getLowerBound();
+            if (classNode.equals(this)) {
+                ret.append(" super ").append(classNode.getName());
+            } else {
+                ret.append(" super ").append(classNode);
+            }
+        }
+        return ret.toString();
+    }
+
+    /**
+     * Returns true if the given method has a possibly matching instance method with the given name and arguments.
+     *
+     * @param name      the name of the method of interest
+     * @param arguments the arguments to match against
+     * @return true if a matching method was found
+     */
+    public boolean hasPossibleMethod(String name, Expression arguments) {
+        int count = 0;
+
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) arguments;
+            // TODO this won't strictly be true when using list expansion in argument calls
+            count = tuple.getExpressions().size();
+        }
+        ClassNode node = this;
+        do {
+            for (MethodNode method : getMethods(name)) {
+                if (method.getParameters().length == count && !method.isStatic()) {
+                    return true;
+                }
+            }
+            node = node.getSuperClass();
+        }
+        while (node != null);
+        return false;
+    }
+
+    public MethodNode tryFindPossibleMethod(String name, Expression arguments) {
+        int count = 0;
+
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tuple = (TupleExpression) arguments;
+            // TODO this won't strictly be true when using list expansion in argument calls
+            count = tuple.getExpressions().size();
+        } else
+            return null;
+
+        MethodNode res = null;
+        ClassNode node = this;
+        TupleExpression args = (TupleExpression) arguments;
+        do {
+            for (MethodNode method : node.getMethods(name)) {
+                if (method.getParameters().length == count) {
+                    boolean match = true;
+                    for (int i = 0; i != count; ++i)
+                        if (!args.getType().isDerivedFrom(method.getParameters()[i].getType())) {
+                            match = false;
+                            break;
+                        }
+
+                    if (match) {
+                        if (res == null)
+                            res = method;
+                        else {
+                            if (res.getParameters().length != count)
+                                return null;
+                            if (node.equals(this))
+                                return null;
+
+                            match = true;
+                            for (int i = 0; i != count; ++i)
+                                if (!res.getParameters()[i].getType().equals(method.getParameters()[i].getType())) {
+                                    match = false;
+                                    break;
+                                }
+                            if (!match)
+                                return null;
+                        }
+                    }
+                }
+            }
+            node = node.getSuperClass();
+        }
+        while (node != null);
+
+        return res;
+    }
+
+    /**
+     * Returns true if the given method has a possibly matching static method with the given name and arguments.
+     *
+     * @param name      the name of the method of interest
+     * @param arguments the arguments to match against
+     * @return true if a matching method was found
+     */
+    public boolean hasPossibleStaticMethod(String name, Expression arguments) {
+        return ClassNodeUtils.hasPossibleStaticMethod(this, name, arguments, false);
+    }
+
+    public boolean isInterface(){
+        return (getModifiers() & Opcodes.ACC_INTERFACE) > 0;
+    }
+
+    public boolean isAbstract(){
+        return (getModifiers() & Opcodes.ACC_ABSTRACT) > 0;
+    }
+
+    public boolean isResolved() {
+        if (clazz != null) return true;
+        if (redirect != null) return redirect.isResolved();
+        return componentType != null && componentType.isResolved();
+    }
+
+    public boolean isArray(){
+        return componentType!=null;
+    }
+
+    public ClassNode getComponentType() {
+        return componentType;
+    }
+
+    /**
+     * Returns the concrete class this classnode relates to. However, this method
+     * is inherently unsafe as it may return null depending on the compile phase you are
+     * using. AST transformations should never use this method directly, but rather obtain
+     * a new class node using {@link #getPlainNodeReference()}.
+     * @return the class this classnode relates to. May return null.
+     */
+    public Class getTypeClass(){
+        if (clazz != null) return clazz;
+        if (redirect != null) return redirect.getTypeClass();
+
+        ClassNode component = redirect().componentType;
+        if (component!=null && component.isResolved()){
+            return Array.newInstance(component.getTypeClass(), 0).getClass();
+        }
+        throw new GroovyBugError("ClassNode#getTypeClass for "+getName()+" is called before the type class is set ");
+    }
+
+    public boolean hasPackageName(){
+        return redirect().name.indexOf('.')>0;
+    }
+
+    /**
+     * Marks if the current class uses annotations or not
+     * @param flag
+     */
+    public void setAnnotated(boolean flag) {
+        this.annotated = flag;
+    }
+
+    public boolean isAnnotated() {
+        return this.annotated;
+    }
+
+    public GenericsType[] getGenericsTypes() {
+        return genericsTypes;
+    }
+
+    public void setGenericsTypes(GenericsType[] genericsTypes) {
+        usesGenerics = usesGenerics || genericsTypes!=null;
+        this.genericsTypes = genericsTypes;
+    }
+
+    public void setGenericsPlaceHolder(boolean b) {
+        usesGenerics = usesGenerics || b;
+        placeholder = b;
+    }
+
+    public boolean isGenericsPlaceHolder() {
+        return placeholder;
+    }
+
+    public boolean isUsingGenerics() {
+        return usesGenerics;
+    }
+
+    public void setUsingGenerics(boolean b) {
+        usesGenerics = b;
+    }
+
+    public ClassNode getPlainNodeReference() {
+        if (ClassHelper.isPrimitiveType(this)) return this;
+        ClassNode n = new ClassNode(name, modifiers, superClass,null,null);
+        n.isPrimaryNode = false;
+        n.setRedirect(redirect());
+        if (isArray()) {
+            n.componentType = redirect().getComponentType();
+        } 
+        return n;
+    }
+
+    public boolean isAnnotationDefinition() {
+        return redirect().isPrimaryNode &&
+               isInterface() &&
+               (getModifiers() & Opcodes.ACC_ANNOTATION)!=0;
+    }
+
+    public List<AnnotationNode> getAnnotations() {
+        if (redirect!=null) return redirect.getAnnotations();
+        lazyClassInit();
+        return super.getAnnotations();
+    }
+
+    public List<AnnotationNode> getAnnotations(ClassNode type) {
+        if (redirect!=null) return redirect.getAnnotations(type);
+        lazyClassInit();
+        return super.getAnnotations(type);
+    }
+
+    public void addTransform(Class<? extends ASTTransformation> transform, ASTNode node) {
+        GroovyASTTransformation annotation = transform.getAnnotation(GroovyASTTransformation.class);
+        if (annotation == null) return;
+
+        Set<ASTNode> nodes = getTransformInstances().get(annotation.phase()).get(transform);
+        if (nodes == null) {
+            nodes = new LinkedHashSet<ASTNode>();
+            getTransformInstances().get(annotation.phase()).put(transform, nodes);
+        }
+        nodes.add(node);
+    }
+
+    public Map<Class <? extends ASTTransformation>, Set<ASTNode>> getTransforms(CompilePhase phase) {
+        return getTransformInstances().get(phase);
+    }
+
+    public void renameField(String oldName, String newName) {
+        ClassNode r = redirect ();
+        if (r.fieldIndex == null)
+            r.fieldIndex = new HashMap<String,FieldNode> ();
+        final Map<String,FieldNode> index = r.fieldIndex;
+        index.put(newName, index.remove(oldName));
+    }
+    
+    public void removeField(String oldName) {
+        ClassNode r = redirect ();
+        if (r.fieldIndex == null)
+            r.fieldIndex = new HashMap<String,FieldNode> ();
+        final Map<String,FieldNode> index = r.fieldIndex;
+        r.fields.remove(index.get(oldName));
+        index.remove(oldName);
+    }
+
+    public boolean isEnum() {
+        return (getModifiers()&Opcodes.ACC_ENUM) != 0;
+     }
+
+    /**
+     * @return iterator of inner classes defined inside this one
+     */
+    public Iterator<InnerClassNode> getInnerClasses() {
+        return (innerClasses == null ? Collections.<InnerClassNode>emptyList() : innerClasses).iterator();
+    }
+
+    private Map<CompilePhase, Map<Class<? extends ASTTransformation>, Set<ASTNode>>> getTransformInstances() {
+        if(transformInstances == null){
+            transformInstances = new EnumMap<CompilePhase, Map<Class <? extends ASTTransformation>, Set<ASTNode>>>(CompilePhase.class);
+            for (CompilePhase phase : CompilePhase.values()) {
+                transformInstances.put(phase, new HashMap<Class <? extends ASTTransformation>, Set<ASTNode>>());
+            }
+        }
+        return transformInstances;
+    }
+    
+    public boolean isRedirectNode() {
+        return redirect!=null;
+    }
+
+    @Override
+    public String getText() {
+        return getName();
+    }
+
+    @Override
+    public Groovydoc getGroovydoc() {
+        return this.<Groovydoc>getNodeMetaData(DOC_COMMENT);
+    }
+
+    @Override
+    public ClassNode getInstance() {
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
new file mode 100644
index 0000000..523475e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
@@ -0,0 +1,345 @@
+/*
+ *  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.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+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.MethodCallExpression;
+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.EmptyStatement;
+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.Statement;
+import org.codehaus.groovy.ast.stmt.SwitchStatement;
+import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
+import org.codehaus.groovy.ast.stmt.ThrowStatement;
+import org.codehaus.groovy.ast.stmt.TryCatchStatement;
+import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+
+import java.util.List;
+
+/**
+ * Abstract base class for any GroovyCodeVisitor which by default
+ * just walks the code and expression tree
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public abstract class CodeVisitorSupport implements GroovyCodeVisitor {
+
+    public void visitBlockStatement(BlockStatement block) {
+        for (Statement statement : block.getStatements()) {
+            statement.visit(this);
+        }
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        forLoop.getCollectionExpression().visit(this);
+        forLoop.getLoopBlock().visit(this);
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        loop.getBooleanExpression().visit(this);
+        loop.getLoopBlock().visit(this);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        loop.getLoopBlock().visit(this);
+        loop.getBooleanExpression().visit(this);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        ifElse.getBooleanExpression().visit(this);
+        ifElse.getIfBlock().visit(this);
+
+        Statement elseBlock = ifElse.getElseBlock();
+        if (elseBlock instanceof EmptyStatement) {
+            // dispatching to EmptyStatement will not call back visitor, 
+            // must call our visitEmptyStatement explicitly
+            visitEmptyStatement((EmptyStatement) elseBlock);
+        } else {
+            elseBlock.visit(this);
+        }
+    }
+
+    public void visitExpressionStatement(ExpressionStatement statement) {
+        statement.getExpression().visit(this);
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        statement.getExpression().visit(this);
+    }
+
+    public void visitAssertStatement(AssertStatement statement) {
+        statement.getBooleanExpression().visit(this);
+        statement.getMessageExpression().visit(this);
+    }
+
+    public void visitTryCatchFinally(TryCatchStatement statement) {
+        statement.getTryStatement().visit(this);
+        for (CatchStatement catchStatement : statement.getCatchStatements()) {
+            catchStatement.visit(this);
+        }
+        Statement finallyStatement = statement.getFinallyStatement();
+        if (finallyStatement instanceof EmptyStatement) {
+            // dispatching to EmptyStatement will not call back visitor, 
+            // must call our visitEmptyStatement explicitly
+            visitEmptyStatement((EmptyStatement) finallyStatement);
+        } else {
+            finallyStatement.visit(this);
+        }
+    }
+
+    protected void visitEmptyStatement(EmptyStatement statement) {
+        // noop
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        statement.getExpression().visit(this);
+        for (CaseStatement caseStatement : statement.getCaseStatements()) {
+            caseStatement.visit(this);
+        }
+        statement.getDefaultStatement().visit(this);
+    }
+
+    public void visitCaseStatement(CaseStatement statement) {
+        statement.getExpression().visit(this);
+        statement.getCode().visit(this);
+    }
+
+    public void visitBreakStatement(BreakStatement statement) {
+    }
+
+    public void visitContinueStatement(ContinueStatement statement) {
+    }
+
+    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+        statement.getExpression().visit(this);
+        statement.getCode().visit(this);
+    }
+
+    public void visitThrowStatement(ThrowStatement statement) {
+        statement.getExpression().visit(this);
+    }
+
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        call.getObjectExpression().visit(this);
+        call.getMethod().visit(this);
+        call.getArguments().visit(this);
+    }
+
+    public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
+        call.getArguments().visit(this);
+    }
+
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        call.getArguments().visit(this);
+    }
+
+    public void visitBinaryExpression(BinaryExpression expression) {
+        expression.getLeftExpression().visit(this);
+        expression.getRightExpression().visit(this);
+    }
+
+    public void visitTernaryExpression(TernaryExpression expression) {
+        expression.getBooleanExpression().visit(this);
+        expression.getTrueExpression().visit(this);
+        expression.getFalseExpression().visit(this);
+    }
+
+    public void visitShortTernaryExpression(ElvisOperatorExpression expression) {
+        visitTernaryExpression(expression);
+    }
+
+    public void visitPostfixExpression(PostfixExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitPrefixExpression(PrefixExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitBooleanExpression(BooleanExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitNotExpression(NotExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        expression.getCode().visit(this);
+    }
+
+    public void visitTupleExpression(TupleExpression expression) {
+        visitListOfExpressions(expression.getExpressions());
+    }
+
+    public void visitListExpression(ListExpression expression) {
+        visitListOfExpressions(expression.getExpressions());
+    }
+
+    public void visitArrayExpression(ArrayExpression expression) {
+        visitListOfExpressions(expression.getExpressions());
+        visitListOfExpressions(expression.getSizeExpression());
+    }
+
+    public void visitMapExpression(MapExpression expression) {
+        visitListOfExpressions(expression.getMapEntryExpressions());
+
+    }
+
+    public void visitMapEntryExpression(MapEntryExpression expression) {
+        expression.getKeyExpression().visit(this);
+        expression.getValueExpression().visit(this);
+
+    }
+
+    public void visitRangeExpression(RangeExpression expression) {
+        expression.getFrom().visit(this);
+        expression.getTo().visit(this);
+    }
+
+    public void visitSpreadExpression(SpreadExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitSpreadMapExpression(SpreadMapExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitMethodPointerExpression(MethodPointerExpression expression) {
+        expression.getExpression().visit(this);
+        expression.getMethodName().visit(this);
+    }
+
+    public void visitUnaryMinusExpression(UnaryMinusExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitUnaryPlusExpression(UnaryPlusExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitCastExpression(CastExpression expression) {
+        expression.getExpression().visit(this);
+    }
+
+    public void visitConstantExpression(ConstantExpression expression) {
+    }
+
+    public void visitClassExpression(ClassExpression expression) {
+    }
+
+    public void visitVariableExpression(VariableExpression expression) {
+    }
+
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        visitBinaryExpression(expression);
+    }
+
+    public void visitPropertyExpression(PropertyExpression expression) {
+        expression.getObjectExpression().visit(this);
+        expression.getProperty().visit(this);
+    }
+
+    public void visitAttributeExpression(AttributeExpression expression) {
+        expression.getObjectExpression().visit(this);
+        expression.getProperty().visit(this);
+    }
+
+    public void visitFieldExpression(FieldExpression expression) {
+    }
+
+    public void visitGStringExpression(GStringExpression expression) {
+        visitListOfExpressions(expression.getStrings());
+        visitListOfExpressions(expression.getValues());
+    }
+
+    protected void visitListOfExpressions(List<? extends Expression> list) {
+        if (list == null) return;
+        for (Expression expression : list) {
+            if (expression instanceof SpreadExpression) {
+                Expression spread = ((SpreadExpression) expression).getExpression();
+                spread.visit(this);
+            } else {
+                expression.visit(this);
+            }
+        }
+    }
+
+    public void visitCatchStatement(CatchStatement statement) {
+        statement.getCode().visit(this);
+    }
+
+    public void visitArgumentlistExpression(ArgumentListExpression ale) {
+        visitTupleExpression(ale);
+    }
+
+    public void visitClosureListExpression(ClosureListExpression cle) {
+        visitListOfExpressions(cle.getExpressions());
+    }
+
+    public void visitBytecodeExpression(BytecodeExpression cle) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/CompileUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/CompileUnit.java b/src/main/java/org/codehaus/groovy/ast/CompileUnit.java
new file mode 100644
index 0000000..ea0722c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/CompileUnit.java
@@ -0,0 +1,193 @@
+/*
+ *  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.GroovyClassLoader;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+import java.security.CodeSource;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents the entire contents of a compilation step which consists of one or more
+ * {@link ModuleNode} instances. There's one instance of this that's shared by all modules and
+ * classes compiled during a single invocation of the compiler.
+ * <p>
+ * It's attached to MethodNodes and ClassNodes and is used to find fully qualified names of classes,
+ * resolve imports, and that sort of thing.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan </a>
+ */
+public class CompileUnit {
+
+    private final List<ModuleNode> modules = new ArrayList<ModuleNode>();
+    private final Map<String, ClassNode> classes = new HashMap<String, ClassNode>();
+    private final CompilerConfiguration config;
+    private final GroovyClassLoader classLoader;
+    private final CodeSource codeSource;
+    private final Map<String, ClassNode> classesToCompile = new HashMap<String, ClassNode>();
+    private final Map<String, SourceUnit> classNameToSource = new HashMap<String, SourceUnit>();
+    private final Map<String, InnerClassNode> generatedInnerClasses = new HashMap();
+
+    public CompileUnit(GroovyClassLoader classLoader, CompilerConfiguration config) {
+        this(classLoader, null, config);
+    }
+
+    public CompileUnit(GroovyClassLoader classLoader, CodeSource codeSource, CompilerConfiguration config) {
+        this.classLoader = classLoader;
+        this.config = config;
+        this.codeSource = codeSource;
+    }
+
+    public List<ModuleNode> getModules() {
+        return modules;
+    }
+
+    public void addModule(ModuleNode node) {
+        // node==null means a compilation error prevented
+        // groovy from building an ast
+        if (node == null) return;
+        modules.add(node);
+        node.setUnit(this);
+        addClasses(node.getClasses());
+    }
+
+    /**
+     * @return the ClassNode for the given qualified name or returns null if
+     *         the name does not exist in the current compilation unit
+     *         (ignoring the .class files on the classpath)
+     */
+    public ClassNode getClass(String name) {
+        ClassNode cn = classes.get(name);
+        if (cn != null) return cn;
+        return classesToCompile.get(name);
+    }
+
+    /**
+     * @return a list of all the classes in each module in the compilation unit
+     */
+    public List getClasses() {
+        List<ClassNode> answer = new ArrayList<ClassNode>();
+        for (ModuleNode module : modules) {
+            answer.addAll(module.getClasses());
+        }
+        return answer;
+    }
+
+    public CompilerConfiguration getConfig() {
+        return config;
+    }
+
+    public GroovyClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    public CodeSource getCodeSource() {
+        return codeSource;
+    }
+
+    /**
+     * Appends all of the fully qualified class names in this
+     * module into the given map
+     */
+    void addClasses(List<ClassNode> classList) {
+        for (ClassNode node : classList) {
+            addClass(node);
+        }
+    }
+
+    /**
+     * Adds a class to the unit.
+     */
+    public void addClass(ClassNode node) {
+        node = node.redirect();
+        String name = node.getName();
+        ClassNode stored = classes.get(name);
+        if (stored != null && stored != node) {
+            // we have a duplicate class!
+            // One possibility for this is, that we declared a script and a
+            // class in the same file and named the class like the file
+            SourceUnit nodeSource = node.getModule().getContext();
+            SourceUnit storedSource = stored.getModule().getContext();
+            String txt = "Invalid duplicate class definition of class " + node.getName() + " : ";
+            if (nodeSource == storedSource) {
+                // same class in same source
+                txt += "The source " + nodeSource.getName() + " contains at least two definitions of the class " + node.getName() + ".\n";
+                if (node.isScriptBody() || stored.isScriptBody()) {
+                    txt += "One of the classes is an explicit generated class using the class statement, the other is a class generated from" +
+                            " the script body based on the file name. Solutions are to change the file name or to change the class name.\n";
+                }
+            } else {
+                txt += "The sources " + nodeSource.getName() + " and " + storedSource.getName() + " each contain a class with the name " + node.getName() + ".\n";
+            }
+            nodeSource.getErrorCollector().addErrorAndContinue(
+                    new SyntaxErrorMessage(new SyntaxException(txt, node.getLineNumber(), node.getColumnNumber(), node.getLastLineNumber(), node.getLastColumnNumber()), nodeSource)
+            );
+        }
+        classes.put(name, node);
+
+        if (classesToCompile.containsKey(name)) {
+            ClassNode cn = classesToCompile.get(name);
+            cn.setRedirect(node);
+            classesToCompile.remove(name);
+        }
+    }
+
+    /**
+     * this method actually does not compile a class. It's only
+     * a marker that this type has to be compiled by the CompilationUnit
+     * at the end of a parse step no node should be be left.
+     */
+    public void addClassNodeToCompile(ClassNode node, SourceUnit location) {
+        classesToCompile.put(node.getName(), node);
+        classNameToSource.put(node.getName(), location);
+    }
+
+    public SourceUnit getScriptSourceLocation(String className) {
+        return classNameToSource.get(className);
+    }
+
+    public boolean hasClassNodeToCompile() {
+        return !classesToCompile.isEmpty();
+    }
+
+    public Iterator<String> iterateClassNodeToCompile() {
+        return classesToCompile.keySet().iterator();
+    }
+
+    public InnerClassNode getGeneratedInnerClass(String name) {
+        return generatedInnerClasses.get(name);
+    }
+    
+    public void addGeneratedInnerClass(InnerClassNode icn) {
+        generatedInnerClasses.put(icn.getName(), icn);
+    }
+
+    public Map<String, InnerClassNode> getGeneratedInnerClasses() {
+        return Collections.unmodifiableMap(generatedInnerClasses);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java b/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java
new file mode 100644
index 0000000..fe7a7da
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/ConstructorNode.java
@@ -0,0 +1,59 @@
+/*
+ *  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.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+
+/**
+ * Represents a constructor declaration
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ConstructorNode extends MethodNode {
+    
+    public ConstructorNode(int modifiers, Statement code) {
+        this(modifiers, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
+    }
+    
+    public ConstructorNode(int modifiers, Parameter[] parameters, ClassNode[] exceptions, Statement code) {
+        super("<init>",modifiers,ClassHelper.VOID_TYPE,parameters,exceptions,code);
+        
+        // This variable scope is thrown out and replaced with a different one during semantic analysis.
+        VariableScope scope = new VariableScope();
+        for (int i = 0; i < parameters.length; i++) {
+            scope.putDeclaredVariable(parameters[i]);
+        }
+        this.setVariableScope(scope);
+    }
+    
+    public boolean firstStatementIsSpecialConstructorCall() {
+        Statement code = getFirstStatement();
+        if (code == null || !(code instanceof ExpressionStatement)) return false;
+
+        Expression expression = ((ExpressionStatement) code).getExpression();
+        if (!(expression instanceof ConstructorCallExpression)) return false;
+        ConstructorCallExpression cce = (ConstructorCallExpression) expression;
+        return cce.isSpecialCall();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/DynamicVariable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/DynamicVariable.java b/src/main/java/org/codehaus/groovy/ast/DynamicVariable.java
new file mode 100644
index 0000000..f2d4550
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/DynamicVariable.java
@@ -0,0 +1,76 @@
+/*
+ *  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;
+
+// An implicitly created variable, such as a variable in a script that's doesn't have an explicit
+// declaration, or the "it" argument to a closure.
+public class DynamicVariable implements Variable {
+
+    private final String name;
+    private boolean closureShare = false;
+    private boolean staticContext = false;
+
+    public DynamicVariable(String name, boolean context) {
+        this.name = name;
+        staticContext = context;
+    }
+
+    public ClassNode getType() {
+        return ClassHelper.DYNAMIC_TYPE;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Expression getInitialExpression() {
+        return null;
+    }
+
+    public boolean hasInitialExpression() {
+        return false;
+    }
+
+    public boolean isInStaticContext() {
+        return staticContext;
+    }
+
+    public boolean isDynamicTyped() {
+        return true;
+    }
+
+    public boolean isClosureSharedVariable() {
+        return closureShare;
+    }
+
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;
+    }
+
+    public int getModifiers() {
+        return 0;
+    }
+
+    public ClassNode getOriginType() {
+        return getType();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/EnumConstantClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/EnumConstantClassNode.java b/src/main/java/org/codehaus/groovy/ast/EnumConstantClassNode.java
new file mode 100644
index 0000000..4dae4d0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/EnumConstantClassNode.java
@@ -0,0 +1,39 @@
+/*
+ *  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 the anonymous inner class for an enum constant
+ * This subtype is needed so that EnumVisitor can differentiate between the scenarios when a InnerClassNode
+ * represents anonymous inner class for an enu constant and when it represents an enum class defined inside
+ * another class
+ * 
+ * @author Roshan Dawrani
+ */
+public class EnumConstantClassNode extends InnerClassNode {
+
+    /**
+     * @param name is the full name of the class
+     * @param modifiers the modifiers, @see org.objectweb.asm.Opcodes
+     * @param superClass the base class name - use "java.lang.Object" if no direct base class
+     */
+    public EnumConstantClassNode(ClassNode outerClass, String name, int modifiers, ClassNode superClass) {
+        super(outerClass, name, modifiers, superClass);
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
new file mode 100644
index 0000000..45d1908
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java
@@ -0,0 +1,638 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ClosureListExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+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.EmptyStatement;
+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.Statement;
+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.asm.CompileStack.BlockRecorder;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.Iterator;
+import java.util.List;
+
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ATHROW;
+import static org.objectweb.asm.Opcodes.CHECKCAST;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IFEQ;
+import static org.objectweb.asm.Opcodes.MONITORENTER;
+import static org.objectweb.asm.Opcodes.MONITOREXIT;
+import static org.objectweb.asm.Opcodes.NOP;
+import static org.objectweb.asm.Opcodes.RETURN;
+
+public class StatementWriter {
+    // iterator
+    private static final MethodCaller iteratorNextMethod = MethodCaller.newInterface(Iterator.class, "next");
+    private static final MethodCaller iteratorHasNextMethod = MethodCaller.newInterface(Iterator.class, "hasNext");
+    
+    private final WriterController controller;
+    public StatementWriter(WriterController controller) {
+        this.controller = controller;
+    }
+
+    protected void writeStatementLabel(Statement statement) {
+        String name = statement.getStatementLabel();
+        if (name != null) {
+            Label label = controller.getCompileStack().createLocalLabel(name);
+            controller.getMethodVisitor().visitLabel(label);
+        }
+    }
+    
+    public void writeBlockStatement(BlockStatement block) {
+        CompileStack compileStack = controller.getCompileStack();
+
+        //GROOVY-4505 use no line number information for the block
+        writeStatementLabel(block);
+        
+        int mark = controller.getOperandStack().getStackLength();
+        compileStack.pushVariableScope(block.getVariableScope());
+        for (Statement statement : block.getStatements()) {
+            statement.visit(controller.getAcg());
+        }
+        compileStack.pop();
+
+        controller.getOperandStack().popDownTo(mark);
+    }
+
+    public void writeForStatement(ForStatement loop) {
+        Parameter loopVar = loop.getVariable();
+        if (loopVar == ForStatement.FOR_LOOP_DUMMY) {
+            writeForLoopWithClosureList(loop);
+        } else {
+            writeForInLoop(loop);
+        }
+    }
+    
+    protected void writeIteratorHasNext(MethodVisitor mv) {
+        iteratorHasNextMethod.call(mv);
+    }
+    
+    protected void writeIteratorNext(MethodVisitor mv) {
+        iteratorNextMethod.call(mv);
+    }
+    
+    protected void writeForInLoop(ForStatement loop) {
+        controller.getAcg().onLineNumber(loop,"visitForLoop");
+        writeStatementLabel(loop);
+        
+        CompileStack compileStack = controller.getCompileStack();
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+
+        compileStack.pushLoop(loop.getVariableScope(), loop.getStatementLabels());
+
+        // Declare the loop counter.
+        BytecodeVariable variable = compileStack.defineVariable(loop.getVariable(), false);
+
+        // Then get the iterator and generate the loop control
+        MethodCallExpression iterator = new MethodCallExpression(loop.getCollectionExpression(), "iterator", new ArgumentListExpression());
+        iterator.visit(controller.getAcg());
+        operandStack.doGroovyCast(ClassHelper.Iterator_TYPE);
+
+        final int iteratorIdx = compileStack.defineTemporaryVariable("iterator", ClassHelper.Iterator_TYPE, true);
+
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+
+        mv.visitLabel(continueLabel);
+        mv.visitVarInsn(ALOAD, iteratorIdx);
+        writeIteratorHasNext(mv);
+        // note: ifeq tests for ==0, a boolean is 0 if it is false
+        mv.visitJumpInsn(IFEQ, breakLabel);
+
+        mv.visitVarInsn(ALOAD, iteratorIdx);
+        writeIteratorNext(mv);
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        operandStack.storeVar(variable);
+
+        // Generate the loop body
+        loop.getLoopBlock().visit(controller.getAcg());
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+        mv.visitLabel(breakLabel);
+
+        compileStack.removeVar(iteratorIdx);
+        compileStack.pop();
+    }
+
+    private void visitExpressionOfLoopStatement(Expression expression) {
+        if (expression instanceof ClosureListExpression) {
+            for (Expression e : ((ClosureListExpression) expression).getExpressions()) {
+                visitExpressionOrStatement(e);
+            }
+        } else {
+            visitExpressionOrStatement(expression);
+        }
+    }
+
+    protected void writeForLoopWithClosureList(ForStatement loop) {
+        controller.getAcg().onLineNumber(loop,"visitForLoop");
+        writeStatementLabel(loop);
+
+        MethodVisitor mv = controller.getMethodVisitor();
+        controller.getCompileStack().pushLoop(loop.getVariableScope(), loop.getStatementLabels());
+
+        ClosureListExpression clExpr = (ClosureListExpression) loop.getCollectionExpression();
+        controller.getCompileStack().pushVariableScope(clExpr.getVariableScope());
+
+        List<Expression> expressions = clExpr.getExpressions();
+        int size = expressions.size();
+
+        // middle element is condition, lower half is init, higher half is increment
+        int condIndex = (size - 1) / 2;
+
+        // visit init
+        for (int i = 0; i < condIndex; i++) {
+            visitExpressionOfLoopStatement(expressions.get(i));
+        }
+
+        Label continueLabel = controller.getCompileStack().getContinueLabel();
+        Label breakLabel = controller.getCompileStack().getBreakLabel();
+
+        Label cond = new Label();
+        mv.visitLabel(cond);
+        // visit condition leave boolean on stack
+        {
+            Expression condExpr = expressions.get(condIndex);
+            int mark = controller.getOperandStack().getStackLength();
+            condExpr.visit(controller.getAcg());
+            controller.getOperandStack().castToBool(mark,true);
+        }
+        // jump if we don't want to continue
+        // note: ifeq tests for ==0, a boolean is 0 if it is false
+        controller.getOperandStack().jump(IFEQ, breakLabel);
+
+        // Generate the loop body
+        loop.getLoopBlock().visit(controller.getAcg());
+
+        // visit increment
+        mv.visitLabel(continueLabel);
+        for (int i = condIndex + 1; i < size; i++) {
+            visitExpressionOfLoopStatement(expressions.get(i));
+        }
+
+        // jump to test the condition again
+        mv.visitJumpInsn(GOTO, cond);
+
+        // loop end
+        mv.visitLabel(breakLabel);
+
+        controller.getCompileStack().pop();
+        controller.getCompileStack().pop();
+    }
+    
+    private void visitExpressionOrStatement(Object o) {
+        if (o == EmptyExpression.INSTANCE) return;
+        if (o instanceof Expression) {
+            Expression expr = (Expression) o;
+            int mark = controller.getOperandStack().getStackLength();
+            expr.visit(controller.getAcg());
+            controller.getOperandStack().popDownTo(mark);
+        } else {
+            ((Statement) o).visit(controller.getAcg());
+        }
+    }
+
+    private void visitConditionOfLoopingStatement(BooleanExpression bool, Label breakLabel, MethodVisitor mv) {
+        boolean boolHandled = false;
+        if (bool.getExpression() instanceof ConstantExpression) {
+            ConstantExpression constant = (ConstantExpression) bool.getExpression();
+            if (constant.getValue()==Boolean.TRUE) {
+                boolHandled = true;
+                // do nothing
+            } else if (constant.getValue()==Boolean.FALSE) {
+                boolHandled = true;
+                mv.visitJumpInsn(GOTO, breakLabel);
+            }
+        }
+
+        if(!boolHandled) {
+            bool.visit(controller.getAcg());
+            controller.getOperandStack().jump(IFEQ, breakLabel);
+        }
+    }
+
+    public void writeWhileLoop(WhileStatement loop) {
+        controller.getAcg().onLineNumber(loop,"visitWhileLoop");
+        writeStatementLabel(loop);
+
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        controller.getCompileStack().pushLoop(loop.getStatementLabels());
+        Label continueLabel = controller.getCompileStack().getContinueLabel();
+        Label breakLabel = controller.getCompileStack().getBreakLabel();
+
+        mv.visitLabel(continueLabel);
+
+        this.visitConditionOfLoopingStatement(loop.getBooleanExpression(), breakLabel, mv);
+        loop.getLoopBlock().visit(controller.getAcg());
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+        mv.visitLabel(breakLabel);
+
+        controller.getCompileStack().pop();            
+    }
+
+    public void writeDoWhileLoop(DoWhileStatement loop) {
+        controller.getAcg().onLineNumber(loop,"visitDoWhileLoop");
+        writeStatementLabel(loop);
+
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        controller.getCompileStack().pushLoop(loop.getStatementLabels());
+        Label continueLabel = controller.getCompileStack().getContinueLabel();
+        Label breakLabel = controller.getCompileStack().getBreakLabel();
+
+        mv.visitLabel(continueLabel);
+
+        loop.getLoopBlock().visit(controller.getAcg());
+        this.visitConditionOfLoopingStatement(loop.getBooleanExpression(), breakLabel, mv);
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+        mv.visitLabel(breakLabel);
+
+        controller.getCompileStack().pop();
+    }
+
+    public void writeIfElse(IfStatement ifElse) {
+        controller.getAcg().onLineNumber(ifElse,"visitIfElse");
+        writeStatementLabel(ifElse);
+
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        ifElse.getBooleanExpression().visit(controller.getAcg());
+        Label l0 = controller.getOperandStack().jump(IFEQ);
+
+        // if-else is here handled as a special version
+        // of a boolean expression
+        controller.getCompileStack().pushBooleanExpression();
+        ifElse.getIfBlock().visit(controller.getAcg());
+        controller.getCompileStack().pop();
+
+        if (ifElse.getElseBlock()==EmptyStatement.INSTANCE) {
+            mv.visitLabel(l0);
+        } else {
+            Label l1 = new Label();
+            mv.visitJumpInsn(GOTO, l1);
+            mv.visitLabel(l0);
+    
+            controller.getCompileStack().pushBooleanExpression();
+            ifElse.getElseBlock().visit(controller.getAcg());
+            controller.getCompileStack().pop();
+    
+            mv.visitLabel(l1);
+        } 
+    }
+
+    public void writeTryCatchFinally(TryCatchStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitTryCatchFinally");
+        writeStatementLabel(statement);
+        
+        MethodVisitor mv = controller.getMethodVisitor();
+        CompileStack compileStack = controller.getCompileStack();
+        OperandStack operandStack = controller.getOperandStack();
+
+        Statement tryStatement = statement.getTryStatement();
+        final Statement finallyStatement = statement.getFinallyStatement();
+
+        // start try block, label needed for exception table
+        Label tryStart = new Label();
+        mv.visitLabel(tryStart);
+        BlockRecorder tryBlock = makeBlockRecorder(finallyStatement);
+        tryBlock.startRange(tryStart);
+
+        tryStatement.visit(controller.getAcg());
+
+        // goto finally part
+        Label finallyStart = new Label();
+        mv.visitJumpInsn(GOTO, finallyStart);
+
+        Label tryEnd = new Label();
+        mv.visitLabel(tryEnd);
+        tryBlock.closeRange(tryEnd);
+        // pop for "makeBlockRecorder(finallyStatement)"
+        controller.getCompileStack().pop();
+
+        BlockRecorder catches = makeBlockRecorder(finallyStatement);
+        for (CatchStatement catchStatement : statement.getCatchStatements()) {
+            ClassNode exceptionType = catchStatement.getExceptionType();
+            String exceptionTypeInternalName = BytecodeHelper.getClassInternalName(exceptionType);
+
+            // start catch block, label needed for exception table
+            Label catchStart = new Label();
+            mv.visitLabel(catchStart);
+            catches.startRange(catchStart);
+
+            // create exception variable and store the exception
+            Parameter exceptionVariable = catchStatement.getVariable();
+            compileStack.pushState();
+            compileStack.defineVariable(exceptionVariable, true);
+            // handle catch body
+            catchStatement.visit(controller.getAcg());
+            // place holder to avoid problems with empty catch blocks
+            mv.visitInsn(NOP);
+            // pop for the variable
+            controller.getCompileStack().pop();
+
+            // end of catch
+            Label catchEnd = new Label();
+            mv.visitLabel(catchEnd);
+            catches.closeRange(catchEnd);
+
+            // goto finally start
+            mv.visitJumpInsn(GOTO, finallyStart);
+            compileStack.writeExceptionTable(tryBlock, catchStart, exceptionTypeInternalName);
+        }
+
+        // Label used to handle exceptions in catches and regularly
+        // visited finals.
+        Label catchAny = new Label();
+
+        // add "catch any" block to exception table for try part we do this 
+        // after the exception blocks, because else this one would supersede
+        // any of those otherwise
+        compileStack.writeExceptionTable(tryBlock, catchAny, null);
+        // same for the catch parts
+        compileStack.writeExceptionTable(catches, catchAny, null);
+
+        // pop for "makeBlockRecorder(catches)"
+        compileStack.pop();
+
+        // start finally
+        mv.visitLabel(finallyStart);
+        finallyStatement.visit(controller.getAcg());
+        mv.visitInsn(NOP);  //**
+
+        // goto after all-catching block
+        Label skipCatchAll = new Label();
+        mv.visitJumpInsn(GOTO, skipCatchAll);
+
+        // start a block catching any Exception
+        mv.visitLabel(catchAny);
+        //store exception
+        //TODO: maybe define a Throwable and use it here instead of Object
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        final int anyExceptionIndex = compileStack.defineTemporaryVariable("exception", true);
+
+        finallyStatement.visit(controller.getAcg());
+
+        // load the exception and rethrow it
+        mv.visitVarInsn(ALOAD, anyExceptionIndex);
+        mv.visitInsn(ATHROW);
+
+        mv.visitLabel(skipCatchAll);
+        compileStack.removeVar(anyExceptionIndex);
+    }
+    
+    private BlockRecorder makeBlockRecorder(final Statement finallyStatement) {
+        final BlockRecorder block = new BlockRecorder();
+        Runnable tryRunner = new Runnable() {
+            public void run() {
+                controller.getCompileStack().pushBlockRecorderVisit(block);
+                finallyStatement.visit(controller.getAcg());
+                controller.getCompileStack().popBlockRecorderVisit(block);
+            }
+        };
+        block.excludedStatement = tryRunner;
+        controller.getCompileStack().pushBlockRecorder(block);
+        return block;
+    }
+
+    public void writeSwitch(SwitchStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitSwitch");
+        writeStatementLabel(statement);
+
+        statement.getExpression().visit(controller.getAcg());
+
+        // switch does not have a continue label. use its parent's for continue
+        Label breakLabel = controller.getCompileStack().pushSwitch();
+
+        final int switchVariableIndex = controller.getCompileStack().defineTemporaryVariable("switch", true);
+
+        List caseStatements = statement.getCaseStatements();
+        int caseCount = caseStatements.size();
+        Label[] labels = new Label[caseCount + 1];
+        for (int i = 0; i < caseCount; i++) {
+            labels[i] = new Label();
+        }
+
+        int i = 0;
+        for (Iterator iter = caseStatements.iterator(); iter.hasNext(); i++) {
+            CaseStatement caseStatement = (CaseStatement) iter.next();
+            writeCaseStatement(caseStatement, switchVariableIndex, labels[i], labels[i + 1]);
+        }
+
+        statement.getDefaultStatement().visit(controller.getAcg());
+
+        controller.getMethodVisitor().visitLabel(breakLabel);
+
+        controller.getCompileStack().removeVar(switchVariableIndex);
+        controller.getCompileStack().pop();   
+    }
+    
+    protected void writeCaseStatement(
+            CaseStatement statement, int switchVariableIndex,
+            Label thisLabel, Label nextLabel) 
+    {
+        controller.getAcg().onLineNumber(statement, "visitCaseStatement");
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+
+        mv.visitVarInsn(ALOAD, switchVariableIndex);
+        
+        statement.getExpression().visit(controller.getAcg());
+        operandStack.box();
+        controller.getBinaryExpressionHelper().getIsCaseMethod().call(mv);
+        operandStack.replace(ClassHelper.boolean_TYPE);
+
+        Label l0 = controller.getOperandStack().jump(IFEQ);
+
+        mv.visitLabel(thisLabel);
+
+        statement.getCode().visit(controller.getAcg());
+
+        // now if we don't finish with a break we need to jump past
+        // the next comparison
+        if (nextLabel != null) {
+            mv.visitJumpInsn(GOTO, nextLabel);
+        }
+
+        mv.visitLabel(l0);
+    }
+
+    public void writeBreak(BreakStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitBreakStatement");
+        writeStatementLabel(statement);
+
+        String name = statement.getLabel();
+        Label breakLabel = controller.getCompileStack().getNamedBreakLabel(name);
+        controller.getCompileStack().applyFinallyBlocks(breakLabel, true);
+
+        controller.getMethodVisitor().visitJumpInsn(GOTO, breakLabel);
+    }
+
+    public void writeContinue(ContinueStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitContinueStatement");
+        writeStatementLabel(statement);
+
+        String name = statement.getLabel();
+        Label continueLabel = controller.getCompileStack().getContinueLabel();
+        if (name != null) continueLabel = controller.getCompileStack().getNamedContinueLabel(name);
+        controller.getCompileStack().applyFinallyBlocks(continueLabel, false);
+        controller.getMethodVisitor().visitJumpInsn(GOTO, continueLabel);
+    }
+
+    public void writeSynchronized(SynchronizedStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitSynchronizedStatement");
+        writeStatementLabel(statement);
+        final MethodVisitor mv = controller.getMethodVisitor();
+        CompileStack compileStack = controller.getCompileStack();
+
+        statement.getExpression().visit(controller.getAcg());
+        controller.getOperandStack().box();
+        final int index = compileStack.defineTemporaryVariable("synchronized", ClassHelper.OBJECT_TYPE, true);
+
+        final Label synchronizedStart = new Label();
+        final Label synchronizedEnd = new Label();
+        final Label catchAll = new Label();
+
+        mv.visitVarInsn(ALOAD, index);
+        mv.visitInsn(MONITORENTER);
+        mv.visitLabel(synchronizedStart);
+        // place holder for "empty" synchronized blocks, for example
+        // if there is only a break/continue.
+        mv.visitInsn(NOP);
+
+        Runnable finallyPart = new Runnable() {
+            public void run() {
+                mv.visitVarInsn(ALOAD, index);
+                mv.visitInsn(MONITOREXIT);
+            }
+        };
+        BlockRecorder fb = new BlockRecorder(finallyPart);
+        fb.startRange(synchronizedStart);
+        compileStack.pushBlockRecorder(fb);
+        statement.getCode().visit(controller.getAcg());
+
+        fb.closeRange(catchAll);
+        compileStack.writeExceptionTable(fb, catchAll, null);
+        compileStack.pop(); //pop fb
+
+        finallyPart.run();
+        mv.visitJumpInsn(GOTO, synchronizedEnd);
+        mv.visitLabel(catchAll);
+        finallyPart.run();
+        mv.visitInsn(ATHROW);
+
+        mv.visitLabel(synchronizedEnd);
+        compileStack.removeVar(index);
+    }
+
+    public void writeAssert(AssertStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitAssertStatement");
+        writeStatementLabel(statement);
+        controller.getAssertionWriter().writeAssertStatement(statement);
+    }
+
+    public void writeThrow(ThrowStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitThrowStatement");
+        writeStatementLabel(statement);
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        statement.getExpression().visit(controller.getAcg());
+
+        // we should infer the type of the exception from the expression
+        mv.visitTypeInsn(CHECKCAST, "java/lang/Throwable");
+        mv.visitInsn(ATHROW);
+        
+        controller.getOperandStack().remove(1);
+    }
+
+    public void writeReturn(ReturnStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitReturnStatement");
+        writeStatementLabel(statement);
+        MethodVisitor mv = controller.getMethodVisitor();
+        OperandStack operandStack = controller.getOperandStack();
+        ClassNode returnType = controller.getReturnType();
+
+        if (returnType == ClassHelper.VOID_TYPE) {
+            if (!(statement.isReturningNullOrVoid())) {
+                //TODO: move to Verifier
+                controller.getAcg().throwException("Cannot use return statement with an expression on a method that returns void");
+            }
+            controller.getCompileStack().applyBlockRecorder();
+            mv.visitInsn(RETURN);
+            return;
+        }
+
+        Expression expression = statement.getExpression();
+        expression.visit(controller.getAcg());
+
+        operandStack.doGroovyCast(returnType);
+
+        if (controller.getCompileStack().hasBlockRecorder()) {
+            ClassNode type = operandStack.getTopOperand();
+            int returnValueIdx = controller.getCompileStack().defineTemporaryVariable("returnValue", returnType, true);
+            controller.getCompileStack().applyBlockRecorder();
+            operandStack.load(type, returnValueIdx);
+            controller.getCompileStack().removeVar(returnValueIdx);
+        }
+
+        BytecodeHelper.doReturn(mv, returnType);
+        operandStack.remove(1);
+    }
+
+    public void writeExpressionStatement(ExpressionStatement statement) {
+        controller.getAcg().onLineNumber(statement, "visitExpressionStatement: " + statement.getExpression().getClass().getName());
+        writeStatementLabel(statement);
+
+        Expression expression = statement.getExpression();
+
+        int mark = controller.getOperandStack().getStackLength();
+        expression.visit(controller.getAcg());
+        controller.getOperandStack().popDownTo(mark);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/TypeChooser.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/TypeChooser.java b/src/main/java/org/codehaus/groovy/classgen/asm/TypeChooser.java
new file mode 100644
index 0000000..ec552b3
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/TypeChooser.java
@@ -0,0 +1,42 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * Interface for modules which are capable of resolving the type of an expression.
+ * Several implementations are available, depending on whether you are in a dynamic
+ * or static compilation mode.
+ *
+ * @author Cedric Champeau
+ */
+public interface TypeChooser {
+
+    /**
+     * Resolve the type of an expression. Depending on the implementations, the
+     * returned type may be the declared type or an inferred type.
+     * @param expression the expression for which the type must be returned.
+     * @param classNode the classnode this expression belongs to
+     * @return the resolved type.
+     */
+    ClassNode resolveType(final Expression expression, ClassNode classNode);
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/UnaryExpressionHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/UnaryExpressionHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/UnaryExpressionHelper.java
new file mode 100644
index 0000000..0ebd9b4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/UnaryExpressionHelper.java
@@ -0,0 +1,87 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.BitwiseNegationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.NotExpression;
+import org.codehaus.groovy.ast.expr.UnaryMinusExpression;
+import org.codehaus.groovy.ast.expr.UnaryPlusExpression;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+
+/**
+ * A helper class used to generate bytecode for unary expressions. AST transformations willing to use
+ * a custom unary expression helper may set the {@link WriterControllerFactory} node metadata on a
+ * class node to provide a custom {@link WriterController} which would in turn use a custom expression
+ * helper.
+ *
+ * @see BinaryExpressionHelper
+ *
+ * @author Cedric Champeau
+ */
+public class UnaryExpressionHelper {
+
+    // unary plus, unary minus, bitwise negation
+    static final MethodCaller unaryPlus = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "unaryPlus");
+    static final MethodCaller unaryMinus = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "unaryMinus");
+    static final MethodCaller bitwiseNegate = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "bitwiseNegate");
+
+    private final WriterController controller;
+
+    public UnaryExpressionHelper(final WriterController controller) {
+        this.controller = controller;
+    }
+
+    public void writeUnaryPlus(UnaryPlusExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(controller.getAcg());
+        controller.getOperandStack().box();
+        unaryPlus.call(controller.getMethodVisitor());
+        controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE);
+        controller.getAssertionWriter().record(expression);
+    }
+
+    public void writeUnaryMinus(UnaryMinusExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(controller.getAcg());
+        controller.getOperandStack().box();
+        unaryMinus.call(controller.getMethodVisitor());
+        controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE);
+        controller.getAssertionWriter().record(expression);
+    }
+
+    public void writeBitwiseNegate(BitwiseNegationExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(controller.getAcg());
+        controller.getOperandStack().box();
+        bitwiseNegate.call(controller.getMethodVisitor());
+        controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE);
+        controller.getAssertionWriter().record(expression);
+    }
+
+    public void writeNotExpression(NotExpression expression) {
+        Expression subExpression = expression.getExpression();
+        int mark = controller.getOperandStack().getStackLength();
+        subExpression.visit(controller.getAcg());
+        controller.getOperandStack().castToBool(mark, true);
+        BytecodeHelper.negateBoolean(controller.getMethodVisitor());
+        controller.getAssertionWriter().record(expression);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/VariableSlotLoader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/VariableSlotLoader.java b/src/main/java/org/codehaus/groovy/classgen/asm/VariableSlotLoader.java
new file mode 100644
index 0000000..63e48ca
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/VariableSlotLoader.java
@@ -0,0 +1,50 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.classgen.BytecodeExpression;
+import org.objectweb.asm.MethodVisitor;
+
+public class VariableSlotLoader extends BytecodeExpression {
+
+    private final int idx;
+    private final OperandStack operandStack;
+    
+    public VariableSlotLoader(ClassNode type, int index, OperandStack os) {
+        super(type);
+        this.idx = index;
+        this.operandStack = os;
+    }
+    
+    public VariableSlotLoader(int index, OperandStack os) {
+        this.idx = index;
+        this.operandStack = os;
+    }
+    
+    @Override
+    public void visit(MethodVisitor mv) {
+        operandStack.load(this.getType(), idx);
+        operandStack.remove(1);
+    }
+
+    public int getIndex(){
+        return idx;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java
new file mode 100644
index 0000000..952814c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/WriterController.java
@@ -0,0 +1,401 @@
+/*
+ *  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.classgen.asm;
+
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.InterfaceHelperClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.GeneratorContext;
+import org.codehaus.groovy.classgen.asm.indy.IndyBinHelper;
+import org.codehaus.groovy.classgen.asm.indy.IndyCallSiteWriter;
+import org.codehaus.groovy.classgen.asm.indy.InvokeDynamicWriter;
+import org.codehaus.groovy.classgen.asm.util.LoggableClassVisitor;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class WriterController {
+    private static final String GROOVY_LOG_CLASSGEN = "groovy.log.classgen";
+    private static final boolean LOG_CLASSGEN;
+    static {
+        LOG_CLASSGEN = Boolean.valueOf(System.getProperty(GROOVY_LOG_CLASSGEN));
+    }
+    private AsmClassGenerator acg;
+    private MethodVisitor methodVisitor;
+    private CompileStack compileStack;
+    private OperandStack operandStack;
+    private ClassNode classNode;
+    private CallSiteWriter callSiteWriter;
+    private ClassVisitor cv;
+    private ClosureWriter closureWriter;
+    private String internalClassName;
+    private InvocationWriter invocationWriter;
+    private BinaryExpressionHelper binaryExpHelper, fastPathBinaryExpHelper;
+    private UnaryExpressionHelper unaryExpressionHelper, fastPathUnaryExpressionHelper;
+    private AssertionWriter assertionWriter;
+    private String internalBaseClassName;
+    private ClassNode outermostClass;
+    private MethodNode methodNode;
+    private SourceUnit sourceUnit;
+    private ConstructorNode constructorNode;
+    private GeneratorContext context;
+    private InterfaceHelperClassNode interfaceClassLoadingClass;
+    public boolean optimizeForInt = true;
+    private StatementWriter statementWriter;
+    private boolean fastPath = false;
+    private TypeChooser typeChooser;
+    private int bytecodeVersion = Opcodes.V1_5;
+    private int lineNumber = -1;
+    private int helperMethodIndex = 0;
+    private List<String> superMethodNames = new ArrayList<String>();
+
+    public void init(AsmClassGenerator asmClassGenerator, GeneratorContext gcon, ClassVisitor cv, ClassNode cn) {
+        CompilerConfiguration config = cn.getCompileUnit().getConfig();
+        Map<String,Boolean> optOptions = config.getOptimizationOptions();
+        boolean invokedynamic=false;
+        if (optOptions.isEmpty()) {
+            // IGNORE
+        } else if (Boolean.FALSE.equals(optOptions.get("all"))) {
+            optimizeForInt=false;
+            // set other optimizations options to false here
+        } else {
+            if (Boolean.TRUE.equals(optOptions.get(CompilerConfiguration.INVOKEDYNAMIC))) invokedynamic=true;
+            if (Boolean.FALSE.equals(optOptions.get("int"))) optimizeForInt=false;
+            if (invokedynamic) optimizeForInt=false;
+            // set other optimizations options to false here
+        }
+        this.classNode = cn;
+        this.outermostClass = null;
+        this.internalClassName = BytecodeHelper.getClassInternalName(classNode);
+
+        bytecodeVersion = chooseBytecodeVersion(invokedynamic, config.getTargetBytecode());
+
+        if (invokedynamic) {
+            this.invocationWriter = new InvokeDynamicWriter(this);
+            this.callSiteWriter = new IndyCallSiteWriter(this);
+            this.binaryExpHelper = new IndyBinHelper(this);
+        } else {
+            this.callSiteWriter = new CallSiteWriter(this);
+            this.invocationWriter = new InvocationWriter(this);
+            this.binaryExpHelper = new BinaryExpressionHelper(this);
+        }
+
+        this.unaryExpressionHelper = new UnaryExpressionHelper(this);
+        if (optimizeForInt) {
+            this.fastPathBinaryExpHelper = new BinaryExpressionMultiTypeDispatcher(this);
+            // todo: replace with a real fast path unary expression helper when available
+            this.fastPathUnaryExpressionHelper = new UnaryExpressionHelper(this);
+        } else {
+            this.fastPathBinaryExpHelper = this.binaryExpHelper;
+            this.fastPathUnaryExpressionHelper = new UnaryExpressionHelper(this);
+        }
+
+        this.operandStack = new OperandStack(this);
+        this.assertionWriter = new AssertionWriter(this);
+        this.closureWriter = new ClosureWriter(this);
+        this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
+        this.acg = asmClassGenerator;
+        this.sourceUnit = acg.getSourceUnit();
+        this.context = gcon;
+        this.compileStack = new CompileStack(this);
+        this.cv = this.createClassVisitor(cv);
+        if (optimizeForInt) {
+            this.statementWriter = new OptimizingStatementWriter(this);
+        } else {
+            this.statementWriter = new StatementWriter(this);
+        }
+        this.typeChooser = new StatementMetaTypeChooser();
+    }
+
+    private ClassVisitor createClassVisitor(ClassVisitor cv) {
+        if (!LOG_CLASSGEN) {
+            return cv;
+        }
+        if (cv instanceof LoggableClassVisitor) {
+            return cv;
+        }
+        return new LoggableClassVisitor(cv);
+    }
+    private static int chooseBytecodeVersion(final boolean invokedynamic, final String targetBytecode) {
+        if (invokedynamic) {
+            if (CompilerConfiguration.JDK8.equals(targetBytecode)) {
+                return Opcodes.V1_8;
+            }
+            return Opcodes.V1_7;
+        } else {
+            Integer bytecodeVersion = CompilerConfiguration.JDK_TO_BYTECODE_VERSION_MAP.get(targetBytecode);
+
+            if (null != bytecodeVersion) {
+                return bytecodeVersion;
+            }
+        }
+
+        throw new GroovyBugError("Bytecode version ["+targetBytecode+"] is not supported by the compiler");
+    }
+
+    public AsmClassGenerator getAcg() {
+        return acg;
+    }
+
+    public void setMethodVisitor(MethodVisitor methodVisitor) {
+        this.methodVisitor = methodVisitor;
+    }
+
+    public MethodVisitor getMethodVisitor() {
+        return methodVisitor;
+    }
+
+    public CompileStack getCompileStack() {
+        return compileStack;
+    }
+
+    public OperandStack getOperandStack() {
+        return operandStack;
+    }
+
+    public ClassNode getClassNode() {
+        return classNode;
+    }
+
+    public CallSiteWriter getCallSiteWriter() {
+        return callSiteWriter;
+    }
+
+    public ClassVisitor getClassVisitor() {
+        return cv;
+    }
+
+    public ClosureWriter getClosureWriter() {
+        return closureWriter;
+    }
+
+    public ClassVisitor getCv() {
+        return cv;
+    }
+
+    public String getInternalClassName() {
+        return internalClassName;
+    }
+
+    public InvocationWriter getInvocationWriter() {
+        return invocationWriter;
+    }
+
+    public BinaryExpressionHelper getBinaryExpressionHelper() {
+        if (fastPath) {
+            return fastPathBinaryExpHelper;
+        } else {
+            return binaryExpHelper;
+        }
+    }
+
+    public UnaryExpressionHelper getUnaryExpressionHelper() {
+        if (fastPath) {
+            return fastPathUnaryExpressionHelper;
+        } else {
+            return unaryExpressionHelper;
+        }
+    }
+
+    public AssertionWriter getAssertionWriter() {
+        return assertionWriter;
+    }
+
+    public TypeChooser getTypeChooser() {
+        return typeChooser;
+    }
+
+    public String getInternalBaseClassName() {
+        return internalBaseClassName;
+    }
+
+    public MethodNode getMethodNode() {
+        return methodNode;
+    }
+
+    public void setMethodNode(MethodNode mn) {
+        methodNode = mn;
+        constructorNode = null;
+    }
+
+    public ConstructorNode getConstructorNode(){
+        return constructorNode;
+    }
+
+    public void setConstructorNode(ConstructorNode cn) {
+        constructorNode = cn;
+        methodNode = null;
+    }
+
+    public boolean isNotClinit() {
+        return methodNode == null || !methodNode.getName().equals("<clinit>");
+    }
+
+    public SourceUnit getSourceUnit() {
+        return sourceUnit;
+    }
+
+    public boolean isStaticContext() {
+        if (compileStack!=null && compileStack.getScope()!=null) {
+            return compileStack.getScope().isInStaticContext();
+        }
+        if (!isInClosure()) return false;
+        if (constructorNode != null) return false;
+        return classNode.isStaticClass() || methodNode.isStatic();
+    }
+
+    public boolean isInClosure() {
+        return classNode.getOuterClass() != null
+                && classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE;
+    }
+
+    public boolean isInClosureConstructor() {
+        return constructorNode != null
+                && classNode.getOuterClass() != null
+                && classNode.getSuperClass() == ClassHelper.CLOSURE_TYPE;
+    }
+
+    public boolean isNotExplicitThisInClosure(boolean implicitThis) {
+        return implicitThis || !isInClosure();
+    }
+
+
+    public boolean isStaticMethod() {
+        return methodNode != null && methodNode.isStatic();
+    }
+
+    public ClassNode getReturnType() {
+        if (methodNode != null) {
+            return methodNode.getReturnType();
+        } else if (constructorNode != null) {
+            return constructorNode.getReturnType();
+        } else {
+            throw new GroovyBugError("I spotted a return that is neither in a method nor in a constructor... I can not handle that");
+        }
+    }
+
+    public boolean isStaticConstructor() {
+        return methodNode != null && methodNode.getName().equals("<clinit>");
+    }
+
+    public boolean isConstructor() {
+        return constructorNode!=null;
+    }
+
+    /**
+     * @return true if we are in a script body, where all variables declared are no longer
+     *         local variables but are properties
+     */
+    public boolean isInScriptBody() {
+        if (classNode.isScriptBody()) {
+            return true;
+        } else {
+            return classNode.isScript() && methodNode != null && methodNode.getName().equals("run");
+        }
+    }
+
+    public String getClassName() {
+        String className;
+        if (!classNode.isInterface() || interfaceClassLoadingClass == null) {
+            className = internalClassName;
+        } else {
+            className = BytecodeHelper.getClassInternalName(interfaceClassLoadingClass);
+        }
+        return className;
+    }
+
+    public ClassNode getOutermostClass() {
+        if (outermostClass == null) {
+            outermostClass = classNode;
+            while (outermostClass instanceof InnerClassNode) {
+                outermostClass = outermostClass.getOuterClass();
+            }
+        }
+        return outermostClass;
+    }
+
+    public GeneratorContext getContext() {
+        return context;
+    }
+
+    public void setInterfaceClassLoadingClass(InterfaceHelperClassNode ihc) {
+        interfaceClassLoadingClass = ihc;
+    }
+
+    public InterfaceHelperClassNode getInterfaceClassLoadingClass() {
+        return interfaceClassLoadingClass;
+    }
+
+    public boolean shouldOptimizeForInt() {
+        return optimizeForInt;
+    }
+
+    public StatementWriter getStatementWriter() {
+        return statementWriter;
+    }
+
+    public void switchToFastPath() {
+        fastPath = true;
+        resetLineNumber();
+    }
+
+    public void switchToSlowPath() {
+        fastPath = false;
+        resetLineNumber();
+    }
+
+    public boolean isFastPath() {
+        return fastPath;
+    }
+
+    public int getBytecodeVersion() {
+        return bytecodeVersion;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public void setLineNumber(int n) {
+        lineNumber = n;
+    }
+
+    public void resetLineNumber() {
+        setLineNumber(-1);
+    }
+
+    public int getNextHelperMethodIndex() {
+        return helperMethodIndex++;
+    }
+
+    public List<String> getSuperMethodNames() {
+        return superMethodNames;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/WriterControllerFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/WriterControllerFactory.java b/src/main/java/org/codehaus/groovy/classgen/asm/WriterControllerFactory.java
new file mode 100644
index 0000000..a47f309
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/WriterControllerFactory.java
@@ -0,0 +1,27 @@
+/*
+ *  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.classgen.asm;
+
+/**
+ * A non static factory to get alternative writer controller to be stored in the meta data
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public interface WriterControllerFactory {
+    WriterController makeController(WriterController normalController);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyBinHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyBinHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyBinHelper.java
new file mode 100644
index 0000000..68ec884
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyBinHelper.java
@@ -0,0 +1,44 @@
+/*
+ *  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.classgen.asm.indy;
+
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.classgen.asm.BinaryExpressionHelper;
+import org.codehaus.groovy.classgen.asm.InvocationWriter;
+import org.codehaus.groovy.classgen.asm.WriterController;
+
+public class IndyBinHelper extends BinaryExpressionHelper {
+
+    public IndyBinHelper(WriterController wc) {
+        super(wc);
+    }
+
+    @Override
+    protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
+        getController().getInvocationWriter().makeCall(
+                orig, EmptyExpression.INSTANCE, 
+                new ConstantExpression(method), 
+                MethodCallExpression.NO_ARGUMENTS, 
+                InvocationWriter.invokeMethod, 
+                false, false, false);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java
new file mode 100644
index 0000000..d0aac70
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/indy/IndyCallSiteWriter.java
@@ -0,0 +1,65 @@
+/*
+ *  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.classgen.asm.indy;
+
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.classgen.asm.CallSiteWriter;
+import org.codehaus.groovy.classgen.asm.WriterController;
+
+/**
+ * Dummy class used by the indy implementation.
+ * This class mostly contains empty stubs for calls to the call site writer,
+ * since this class is normally used to prepare call site caching and in indy
+ * call site caching is done by the jvm.
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class IndyCallSiteWriter extends CallSiteWriter {
+    private final WriterController controller;
+    public IndyCallSiteWriter(WriterController controller) {
+        super(controller);
+        this.controller = controller;
+    }
+    
+    @Override
+    public void generateCallSiteArray() {}
+    @Override
+    public void makeCallSite(Expression receiver, String message,
+            Expression arguments, boolean safe, boolean implicitThis,
+            boolean callCurrent, boolean callStatic) {}
+    @Override
+    public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) {}
+    @Override
+    public void prepareCallSite(String message) {}    
+    @Override
+    public void makeSiteEntry() {}
+    @Override
+    public void makeCallSiteArrayInitializer() {}
+    
+    @Override
+    public void makeGetPropertySite(Expression receiver, String name, boolean safe, boolean implicitThis) {
+        InvokeDynamicWriter idw = (InvokeDynamicWriter)controller.getInvocationWriter();
+        idw.writeGetProperty(receiver, name, safe, implicitThis, false);
+    }
+    @Override
+    public void makeGroovyObjectGetPropertySite(Expression receiver, String name, boolean safe, boolean implicitThis) {
+        InvokeDynamicWriter idw = (InvokeDynamicWriter)controller.getInvocationWriter();
+        idw.writeGetProperty(receiver, name, safe, implicitThis, true);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
new file mode 100644
index 0000000..4e677d9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/indy/InvokeDynamicWriter.java
@@ -0,0 +1,234 @@
+/*
+ *  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.classgen.asm.indy;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.tools.WideningCategories;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.classgen.asm.CompileStack;
+import org.codehaus.groovy.classgen.asm.InvocationWriter;
+import org.codehaus.groovy.classgen.asm.MethodCallerMultiAdapter;
+import org.codehaus.groovy.classgen.asm.OperandStack;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.runtime.wrappers.Wrapper;
+import org.codehaus.groovy.vmplugin.v7.IndyInterface;
+import org.objectweb.asm.Handle;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+
+import static org.codehaus.groovy.classgen.asm.BytecodeHelper.getTypeDescription;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.CALL_TYPES.CAST;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.CALL_TYPES.GET;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.CALL_TYPES.INIT;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.CALL_TYPES.METHOD;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.GROOVY_OBJECT;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.IMPLICIT_THIS;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.SAFE_NAVIGATION;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.SPREAD_CALL;
+import static org.codehaus.groovy.vmplugin.v7.IndyInterface.THIS_CALL;
+import static org.objectweb.asm.Opcodes.H_INVOKESTATIC;
+
+/**
+ * This Writer is used to generate the call invocation byte codes
+ * for usage by invokedynamic.
+ * 
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class InvokeDynamicWriter extends InvocationWriter {
+    
+    
+    private static final String INDY_INTERFACE_NAME = IndyInterface.class.getName().replace('.', '/');
+    private static final String BSM_METHOD_TYPE_DESCRIPTOR = 
+        MethodType.methodType(
+                CallSite.class, Lookup.class, String.class, MethodType.class,
+                String.class, int.class
+        ).toMethodDescriptorString();
+    private static final Handle BSM = 
+        new Handle(
+                H_INVOKESTATIC,
+                INDY_INTERFACE_NAME,
+                "bootstrap",
+                BSM_METHOD_TYPE_DESCRIPTOR);
+
+    private final WriterController controller;
+
+    public InvokeDynamicWriter(WriterController wc) {
+        super(wc);
+        this.controller = wc;
+    }
+
+    @Override
+    protected boolean makeCachedCall(Expression origin, ClassExpression sender,
+            Expression receiver, Expression message, Expression arguments,
+            MethodCallerMultiAdapter adapter, boolean safe, boolean spreadSafe,
+            boolean implicitThis, boolean containsSpreadExpression
+    ) {
+        // fixed number of arguments && name is a real String and no GString
+        if ((adapter == null || adapter == invokeMethod || adapter == invokeMethodOnCurrent || adapter == invokeStaticMethod) && !spreadSafe) {
+            String methodName = getMethodName(message);
+            if (methodName != null) {
+                makeIndyCall(adapter, receiver, implicitThis, safe, methodName, arguments);
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private String prepareIndyCall(Expression receiver, boolean implicitThis) {
+        CompileStack compileStack = controller.getCompileStack();
+        OperandStack operandStack = controller.getOperandStack();
+
+        compileStack.pushLHS(false);
+        
+        // load normal receiver as first argument
+        compileStack.pushImplicitThis(implicitThis);
+        receiver.visit(controller.getAcg());
+        compileStack.popImplicitThis();
+        return "("+getTypeDescription(operandStack.getTopOperand());
+    }
+    
+    private void finishIndyCall(Handle bsmHandle, String methodName, String sig, int numberOfArguments, Object... bsmArgs) {
+        CompileStack compileStack = controller.getCompileStack();
+        OperandStack operandStack = controller.getOperandStack();
+
+        controller.getMethodVisitor().visitInvokeDynamicInsn(methodName, sig, bsmHandle, bsmArgs);
+
+        operandStack.replace(ClassHelper.OBJECT_TYPE, numberOfArguments);
+        compileStack.popLHS();
+    }
+    
+    private void makeIndyCall(MethodCallerMultiAdapter adapter, Expression receiver, boolean implicitThis, boolean safe, String methodName, Expression arguments) {
+        OperandStack operandStack = controller.getOperandStack();
+        
+        StringBuilder sig = new StringBuilder(prepareIndyCall(receiver, implicitThis));
+        
+        // load arguments
+        int numberOfArguments = 1;
+        ArgumentListExpression ae = makeArgumentList(arguments);
+        boolean containsSpreadExpression = AsmClassGenerator.containsSpreadExpression(arguments);
+        if (containsSpreadExpression) {
+            controller.getAcg().despreadList(ae.getExpressions(), true);
+            sig.append(getTypeDescription(Object[].class));
+        } else {
+            for (Expression arg : ae.getExpressions()) {
+                arg.visit(controller.getAcg());
+                if (arg instanceof CastExpression) {
+                    operandStack.box();
+                    controller.getAcg().loadWrapper(arg);
+                    sig.append(getTypeDescription(Wrapper.class));
+                } else {
+                    sig.append(getTypeDescription(operandStack.getTopOperand()));
+                }
+                numberOfArguments++;
+            }
+        }
+
+        sig.append(")Ljava/lang/Object;");
+        String callSiteName = METHOD.getCallSiteName();
+        if (adapter==null) callSiteName = INIT.getCallSiteName();
+        int flags = getMethodCallFlags(adapter, safe, containsSpreadExpression);
+        finishIndyCall(BSM, callSiteName, sig.toString(), numberOfArguments, methodName, flags);
+    }
+    
+    private static int getMethodCallFlags(MethodCallerMultiAdapter adapter, boolean safe, boolean spread) {
+        int ret = 0;
+        if (safe)                           ret |= SAFE_NAVIGATION;
+        if (adapter==invokeMethodOnCurrent) ret |= THIS_CALL;
+        if (spread)                         ret |= SPREAD_CALL;
+        return ret;
+    }
+
+    @Override
+    public void makeSingleArgumentCall(Expression receiver, String message, Expression arguments, boolean safe) {
+        makeIndyCall(invokeMethod, receiver, false, safe, message, arguments);
+    }
+
+    private static int getPropertyFlags(boolean safe, boolean implicitThis, boolean groovyObject) {
+        int flags = 0;
+        if (implicitThis)   flags |= IMPLICIT_THIS;
+        if (groovyObject)   flags |= GROOVY_OBJECT;
+        if (safe)           flags |= SAFE_NAVIGATION;
+        return flags;
+    }
+
+    protected void writeGetProperty(Expression receiver, String propertyName, boolean safe, boolean implicitThis, boolean groovyObject) {
+        String sig = prepareIndyCall(receiver, implicitThis);
+        sig += ")Ljava/lang/Object;";
+        int flags = getPropertyFlags(safe,implicitThis,groovyObject);
+        finishIndyCall(BSM, GET.getCallSiteName(), sig, 1, propertyName, flags);
+    }
+    
+    @Override
+    protected void writeNormalConstructorCall(ConstructorCallExpression call) {
+        makeCall(call, new ClassExpression(call.getType()), new ConstantExpression("<init>"), call.getArguments(), null, false, false, false);
+    }
+    
+    @Override
+    public void coerce(ClassNode from, ClassNode target) {
+        ClassNode wrapper = ClassHelper.getWrapper(target);
+        makeIndyCall(invokeMethod, EmptyExpression.INSTANCE, false, false, "asType", new ClassExpression(wrapper));
+        if (ClassHelper.boolean_TYPE.equals(target) || ClassHelper.Boolean_TYPE.equals(target)) {
+            writeIndyCast(ClassHelper.OBJECT_TYPE,target);
+        } else {
+            BytecodeHelper.doCast(controller.getMethodVisitor(), wrapper);
+            controller.getOperandStack().replace(wrapper);
+            controller.getOperandStack().doGroovyCast(target);
+        }
+    }
+
+    @Override
+    public void castToNonPrimitiveIfNecessary(ClassNode sourceType, ClassNode targetType) {
+        ClassNode boxedType = ClassHelper.getWrapper(sourceType);
+        if (WideningCategories.implementsInterfaceOrSubclassOf(boxedType, targetType)) {
+            controller.getOperandStack().box();
+            return;
+        }
+        writeIndyCast(sourceType, targetType);
+    }
+
+    private void writeIndyCast(ClassNode sourceType, ClassNode targetType) {
+        StringBuilder sig = new StringBuilder();
+        sig.append('(');
+        sig.append(getTypeDescription(sourceType));
+        sig.append(')');
+        sig.append(getTypeDescription(targetType));
+
+        controller.getMethodVisitor().visitInvokeDynamicInsn(
+                //TODO: maybe use a different bootstrap method since no arguments are needed here
+                CAST.getCallSiteName(), sig.toString(), BSM, "()", 0);
+        controller.getOperandStack().replace(targetType);
+    }
+
+    @Override
+    public void castNonPrimitiveToBool(ClassNode sourceType) {
+        writeIndyCast(sourceType, ClassHelper.boolean_TYPE);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java b/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java
new file mode 100644
index 0000000..ebcf2a8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/indy/sc/IndyStaticTypesMultiTypeDispatcher.java
@@ -0,0 +1,94 @@
+/*
+ *  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.classgen.asm.indy.sc;
+
+import org.codehaus.groovy.classgen.asm.BinaryExpressionWriter;
+import org.codehaus.groovy.classgen.asm.MethodCaller;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.classgen.asm.sc.StaticTypesBinaryExpressionMultiTypeDispatcher;
+import org.codehaus.groovy.vmplugin.v7.IndyInterface;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.MethodVisitor;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+/**
+ * Multi type dispatcher for binary expression backend combining indy and static compilation
+ * @author Jochen Theodorou
+ * @since 2.5.0
+ */
+public class IndyStaticTypesMultiTypeDispatcher extends StaticTypesBinaryExpressionMultiTypeDispatcher {
+    public IndyStaticTypesMultiTypeDispatcher(WriterController wc) {
+        super(wc);
+
+    }
+
+    private static final String INDY_INTERFACE_NAME = IndyInterface.class.getName().replace('.', '/');
+    private static final String BSM_METHOD_TYPE_DESCRIPTOR =
+            MethodType.methodType(
+                    CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class
+            ).toMethodDescriptorString();
+    private static final Handle BSM =
+            new Handle(
+                    H_INVOKESTATIC,
+                    INDY_INTERFACE_NAME,
+                    "staticArrayAccess",
+                    BSM_METHOD_TYPE_DESCRIPTOR);
+    private static class GenericArrayAccess extends MethodCaller {
+        private final String name, signature;
+        public GenericArrayAccess(String name, String signature) {
+            this.name = name;
+            this.signature = signature;
+        }
+        @Override public void call(MethodVisitor mv) {
+            mv.visitInvokeDynamicInsn(name, signature, BSM);
+        }
+    }
+
+    protected BinaryExpressionWriter[] initializeDelegateHelpers() {
+        BinaryExpressionWriter[] bewArray = super.initializeDelegateHelpers();
+        /* 1: int    */
+        bewArray[1].setArraySetAndGet(  new GenericArrayAccess("set","([III)V"),
+                                        new GenericArrayAccess("get","([II)I"));
+        /* 2: long   */
+        bewArray[2].setArraySetAndGet(  new GenericArrayAccess("set","([JIJ)V"),
+                                        new GenericArrayAccess("get","([JI)J"));
+        /* 3: double */
+        bewArray[3].setArraySetAndGet(  new GenericArrayAccess("set","([DID)V"),
+                                        new GenericArrayAccess("get","([DI)D"));
+        /* 4: char   */
+        bewArray[4].setArraySetAndGet(  new GenericArrayAccess("set","([CIC)V"),
+                                        new GenericArrayAccess("get","([CI)C"));
+        /* 5: byte   */
+        bewArray[5].setArraySetAndGet(  new GenericArrayAccess("set","([BIB)V"),
+                                        new GenericArrayAccess("get","([BI)B"));
+        /* 6: short  */
+        bewArray[6].setArraySetAndGet(  new GenericArrayAccess("set","([SIS)V"),
+                                        new GenericArrayAccess("get","([SI)S"));
+        /* 7: float  */
+        bewArray[7].setArraySetAndGet(  new GenericArrayAccess("get","([FIF)V"),
+                                        new GenericArrayAccess("set","([FI)F"));
+        /* 8: bool   */
+        bewArray[8].setArraySetAndGet(  new GenericArrayAccess("get","([ZIZ)V"),
+                                        new GenericArrayAccess("set","([ZI)Z"));
+        return bewArray;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/package.html b/src/main/java/org/codehaus/groovy/classgen/asm/package.html
new file mode 100644
index 0000000..cd40f7e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/package.html
@@ -0,0 +1,29 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.classgen.asm.*</title>
+  </head>
+  <body>
+    <p>Helper classes for ASMClassGenerator. All classes in this package 
+    are for internal usage only.</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticCompilationMopWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticCompilationMopWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticCompilationMopWriter.java
new file mode 100644
index 0000000..5a09829
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticCompilationMopWriter.java
@@ -0,0 +1,62 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.classgen.asm.MopWriter;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+
+import java.util.LinkedList;
+
+/**
+ * A MOP Writer that skips the generation of MOP methods. This writer is used
+ * when a class is *fully* statically compiled. In mixed mode, MOP methods are
+ * still generated.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public class StaticCompilationMopWriter extends MopWriter {
+
+    public static final MopWriter.Factory FACTORY = new MopWriter.Factory() {
+        @Override
+        public MopWriter create(final WriterController controller) {
+            return new StaticCompilationMopWriter(controller);
+        }
+    };
+
+    private final StaticTypesWriterController controller;
+
+    public StaticCompilationMopWriter(final WriterController wc) {
+        super(wc);
+        this.controller = (StaticTypesWriterController) wc;
+    }
+
+
+    public void createMopMethods() {
+        ClassNode classNode = controller.getClassNode();
+        LinkedList<MethodNode> requiredMopMethods = classNode.getNodeMetaData(StaticTypesMarker.SUPER_MOP_METHOD_REQUIRED);
+        if (requiredMopMethods!=null) {
+            generateMopCalls(requiredMopMethods, false);
+        }
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
new file mode 100644
index 0000000..9fb9a81
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -0,0 +1,2103 @@
+/*
+ *  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.classgen;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.InterfaceHelperClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.PackageNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+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.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.EmptyExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+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.MethodCallExpression;
+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.Statement;
+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.ast.tools.WideningCategories;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.classgen.asm.BytecodeVariable;
+import org.codehaus.groovy.classgen.asm.MethodCaller;
+import org.codehaus.groovy.classgen.asm.MethodCallerMultiAdapter;
+import org.codehaus.groovy.classgen.asm.MopWriter;
+import org.codehaus.groovy.classgen.asm.OperandStack;
+import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.classgen.asm.WriterControllerFactory;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.syntax.RuntimeParserException;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Generates Java class versions of Groovy classes using ASM.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * @author <a href='mailto:the[dot]mindstorm[at]gmail[dot]com'>Alex Popescu</a>
+ * @author Alex Tkachman
+ */
+public class AsmClassGenerator extends ClassGenerator {
+
+    private ClassVisitor cv;
+    private final GeneratorContext context;
+    private final String sourceFile;
+
+    // fields and properties
+    static final MethodCallerMultiAdapter setField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setField", false, false);
+    public static final MethodCallerMultiAdapter getField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getField", false, false);
+    static final MethodCallerMultiAdapter setGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setGroovyObjectField", false, false);
+    public static final MethodCallerMultiAdapter getGroovyObjectField = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getGroovyObjectField", false, false);
+    static final MethodCallerMultiAdapter setFieldOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setFieldOnSuper", false, false);
+    static final MethodCallerMultiAdapter getFieldOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getFieldOnSuper", false, false);
+
+    public static final MethodCallerMultiAdapter setProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setProperty", false, false);
+    static final MethodCallerMultiAdapter getProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getProperty", false, false);
+    static final MethodCallerMultiAdapter setGroovyObjectProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setGroovyObjectProperty", false, false);
+    static final MethodCallerMultiAdapter getGroovyObjectProperty = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getGroovyObjectProperty", false, false);
+    static final MethodCallerMultiAdapter setPropertyOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "setPropertyOnSuper", false, false);
+    static final MethodCallerMultiAdapter getPropertyOnSuper = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "getPropertyOnSuper", false, false);
+
+     // spread expressions
+    static final MethodCaller spreadMap = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "spreadMap");
+    static final MethodCaller despreadList = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "despreadList");
+    // Closure
+    static final MethodCaller getMethodPointer = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "getMethodPointer");
+
+    // type conversions
+    static final MethodCaller createListMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createList");
+    static final MethodCaller createMapMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createMap");
+    static final MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange");
+
+    // wrapper creation methods
+    static final MethodCaller createPojoWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createPojoWrapper");
+    static final MethodCaller createGroovyObjectWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createGroovyObjectWrapper");
+
+    // exception blocks list
+    private final Map<String,ClassNode> referencedClasses = new HashMap<String,ClassNode>();
+    private boolean passingParams;
+
+    public static final boolean CREATE_DEBUG_INFO = true;
+    public static final boolean CREATE_LINE_NUMBER_INFO = true;
+    public static final boolean ASM_DEBUG = false; // add marker in the bytecode to show source-bytecode relationship
+
+    private ASTNode currentASTNode = null;
+    private final Map genericParameterNames;
+    private final SourceUnit source;
+    private WriterController controller;
+    
+    public AsmClassGenerator(
+            SourceUnit source, GeneratorContext context,
+            ClassVisitor classVisitor, String sourceFile
+    ) {
+        this.source = source;
+        this.context = context;
+        this.cv = classVisitor;
+        this.sourceFile = sourceFile;
+        genericParameterNames = new HashMap();
+    }
+
+    public SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    public WriterController getController() {
+        return controller;
+    }
+
+    // GroovyClassVisitor interface
+    //-------------------------------------------------------------------------
+    public void visitClass(ClassNode classNode) {
+        referencedClasses.clear();
+        WriterControllerFactory factory = classNode.getNodeMetaData(WriterControllerFactory.class);
+        WriterController normalController = new WriterController();
+        if (factory!=null) {
+            this.controller = factory.makeController(normalController);
+        } else {
+            this.controller = normalController;
+        }
+        this.controller.init(this, context, cv, classNode);
+        this.cv = this.controller.getClassVisitor();
+
+        if (controller.shouldOptimizeForInt() || factory!=null) {
+            OptimizingStatementWriter.setNodeMeta(controller.getTypeChooser(),classNode);
+        }
+
+        try {
+            cv.visit(
+                    controller.getBytecodeVersion(),
+                    adjustedClassModifiersForClassWriting(classNode),
+                    controller.getInternalClassName(),
+                    BytecodeHelper.getGenericsSignature(classNode),
+                    controller.getInternalBaseClassName(),
+                    BytecodeHelper.getClassInternalNames(classNode.getInterfaces())
+            );
+            cv.visitSource(sourceFile, null);
+            if (classNode instanceof InnerClassNode) {
+                InnerClassNode innerClass = (InnerClassNode) classNode;
+                MethodNode enclosingMethod = innerClass.getEnclosingMethod();
+                if (enclosingMethod != null) {
+                    String outerClassName = BytecodeHelper.getClassInternalName(innerClass.getOuterClass().getName());
+                    cv.visitOuterClass(outerClassName, enclosingMethod.getName(), BytecodeHelper.getMethodDescriptor(enclosingMethod));
+                }
+            }
+            if (classNode.getName().endsWith("package-info")) {
+                PackageNode packageNode = classNode.getPackage();
+                if (packageNode != null) {
+                    // pull them out of package node but treat them like they were on class node
+                    visitAnnotations(classNode, packageNode, cv);
+                }
+                cv.visitEnd();
+                return;
+            } else {
+                visitAnnotations(classNode, cv);
+            }
+
+            if (classNode.isInterface()) {
+                ClassNode owner = classNode;
+                if (owner instanceof InnerClassNode) {
+                    owner = owner.getOuterClass();
+                }
+                String outerClassName = classNode.getName();
+                String name = outerClassName + "$" + context.getNextInnerClassIdx();
+                controller.setInterfaceClassLoadingClass(
+                        new InterfaceHelperClassNode (
+                                owner, name, ACC_SUPER | ACC_SYNTHETIC | ACC_STATIC, ClassHelper.OBJECT_TYPE,
+                                controller.getCallSiteWriter().getCallSites()));
+                super.visitClass(classNode);
+                createInterfaceSyntheticStaticFields();
+            } else {
+                super.visitClass(classNode);
+                MopWriter.Factory mopWriterFactory = classNode.getNodeMetaData(MopWriter.Factory.class);
+                if (mopWriterFactory==null) {
+                    mopWriterFactory = MopWriter.FACTORY;
+                }
+                MopWriter mopWriter = mopWriterFactory.create(controller);
+                mopWriter.createMopMethods();
+                controller.getCallSiteWriter().generateCallSiteArray();
+                createSyntheticStaticFields();
+            }
+
+            // GROOVY-6750 and GROOVY-6808
+            for (Iterator<InnerClassNode> iter = classNode.getInnerClasses(); iter.hasNext();) {
+                InnerClassNode innerClass = iter.next();
+                makeInnerClassEntry(innerClass);
+            }
+            makeInnerClassEntry(classNode);
+
+            cv.visitEnd();
+        } catch (GroovyRuntimeException e) {
+            e.setModule(classNode.getModule());
+            throw e;
+        } catch (NegativeArraySizeException nase) {
+            throw new GroovyRuntimeException("NegativeArraySizeException while processing "+sourceFile, nase);
+        } catch (NullPointerException npe) {
+            throw new GroovyRuntimeException("NPE while processing "+sourceFile, npe);
+        }
+    }
+
+    private void makeInnerClassEntry(ClassNode cn) {
+        if (!(cn instanceof InnerClassNode)) return;
+        InnerClassNode innerClass = (InnerClassNode) cn;
+        String innerClassName = innerClass.getName();
+        String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
+        {
+            int index = innerClassName.lastIndexOf('$');
+            if (index >= 0) innerClassName = innerClassName.substring(index + 1);
+        }
+        String outerClassName = BytecodeHelper.getClassInternalName(innerClass.getOuterClass().getName());
+        MethodNode enclosingMethod = innerClass.getEnclosingMethod();
+        if (enclosingMethod != null) {
+            // local inner classes do not specify the outer class name
+            outerClassName = null;
+            if (innerClass.isAnonymous()) innerClassName = null;
+        }
+        int mods = adjustedClassModifiersForInnerClassTable(cn);
+
+
+        if (Modifier.isPrivate(mods)) {
+            mods = mods ^ Modifier.PRIVATE;
+            innerClass.setModifiers(mods);
+        }
+        cv.visitInnerClass(
+                innerClassInternalName,
+                outerClassName,
+                innerClassName,
+                mods);
+    }
+
+    /*
+     * Classes but not interfaces should have ACC_SUPER set
+     * See http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.6-300-D.2-5
+     * for what flags are allowed depending on the fact we are writing the inner class table
+     * or the class itself
+     */
+    private static int adjustedClassModifiersForInnerClassTable(ClassNode classNode) {
+        int modifiers = classNode.getModifiers();
+        modifiers = modifiers & ~ACC_SUPER;
+        // (JLS §9.1.1.1). Such a class file must not have its ACC_FINAL, ACC_SUPER or ACC_ENUM flags set.
+        if (classNode.isInterface()) {
+            modifiers = modifiers & ~ACC_ENUM;
+            modifiers = modifiers & ~ACC_FINAL;
+        }
+        modifiers = fixInnerClassModifiers(classNode, modifiers);
+        return modifiers;
+    }
+
+    private static int fixInnerClassModifiers(final ClassNode classNode, int modifiers) {
+        // on the inner class node itself, private/protected are not allowed
+        if (classNode instanceof InnerClassNode) {
+            if (Modifier.isPrivate(modifiers)) {
+                // GROOVY-6357 : The JVM does not allow private modifier on inner classes: should be package private
+                modifiers = modifiers & ~Modifier.PRIVATE;
+            }
+            if (Modifier.isProtected(modifiers)) {
+                // GROOVY-6357 : Following Java's behavior for protected modifier on inner classes: should be public
+                modifiers = (modifiers & ~Modifier.PROTECTED) | Modifier.PUBLIC;
+            }
+        }
+        return modifiers;
+    }
+
+    /*
+     * Classes but not interfaces should have ACC_SUPER set
+     * See http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.6-300-D.2-5
+     * for what flags are allowed depending on the fact we are writing the inner class table
+     * or the class itself
+     */
+    private static int adjustedClassModifiersForClassWriting(ClassNode classNode) {
+        int modifiers = classNode.getModifiers();
+        boolean needsSuper = !classNode.isInterface();
+        modifiers = needsSuper ? modifiers | ACC_SUPER : modifiers & ~ACC_SUPER;
+        // eliminate static
+        modifiers = modifiers & ~ACC_STATIC;
+        modifiers = fixInnerClassModifiers(classNode, modifiers);
+
+        // (JLS §9.1.1.1). Such a class file must not have its ACC_FINAL, ACC_SUPER or ACC_ENUM flags set.
+        if (classNode.isInterface()) {
+            modifiers = modifiers & ~ACC_ENUM;
+            modifiers = modifiers & ~ACC_FINAL;
+        }
+        return modifiers;
+    }
+
+
+    public void visitGenericType(GenericsType genericsType) {
+        ClassNode type = genericsType.getType();
+        genericParameterNames.put(type.getName(), genericsType);
+    }
+
+    private static String[] buildExceptions(ClassNode[] exceptions) {
+        if (exceptions == null) return null;
+        String[] ret = new String[exceptions.length];
+        for (int i = 0; i < exceptions.length; i++) {
+            ret[i] = BytecodeHelper.getClassInternalName(exceptions[i]);
+        }
+        return ret;
+    }
+
+    protected void visitConstructorOrMethod(MethodNode node, boolean isConstructor) {
+        controller.resetLineNumber();
+    	Parameter[] parameters = node.getParameters();
+        String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), parameters);
+        String signature = BytecodeHelper.getGenericsMethodSignature(node);
+        int modifiers = node.getModifiers();
+        if (isVargs(node.getParameters())) modifiers |= Opcodes.ACC_VARARGS;
+        MethodVisitor mv = cv.visitMethod(modifiers, node.getName(), methodType, signature, buildExceptions(node.getExceptions()));
+        controller.setMethodVisitor(mv);
+
+        visitAnnotations(node, mv);
+        for (int i = 0; i < parameters.length; i++) {
+            visitParameterAnnotations(parameters[i], i, mv);
+        }
+
+        // Add parameter names to the MethodVisitor (jdk8+ only)
+        if (getCompileUnit().getConfig().getParameters()) {
+            for (int i = 0; i < parameters.length; i++) {
+                // TODO handle ACC_SYNTHETIC for enum method parameters?
+                mv.visitParameter(parameters[i].getName(), 0);
+            }
+        }
+
+        if (controller.getClassNode().isAnnotationDefinition() && !node.isStaticConstructor()) {
+            visitAnnotationDefault(node, mv);
+        } else if (!node.isAbstract()) {
+            Statement code = node.getCode();
+            mv.visitCode();
+
+            // fast path for getter/setters etc.
+            if (code instanceof BytecodeSequence && ((BytecodeSequence)code).getInstructions().size() == 1 && ((BytecodeSequence)code).getInstructions().get(0) instanceof BytecodeInstruction) {
+               ((BytecodeInstruction)((BytecodeSequence)code).getInstructions().get(0)).visit(mv);
+            } else {
+                visitStdMethod(node, isConstructor, parameters, code);
+            }
+            // we use this NOP to have a valid jump target for the various labels
+            //mv.visitInsn(NOP);
+            try {
+                mv.visitMaxs(0, 0);
+            } catch (Exception e) {
+                throw new GroovyRuntimeException("ASM reporting processing error for "+controller.getClassNode()+"#"+node.getName()+" with signature "+node.getTypeDescriptor()+" in "+sourceFile+":"+node.getLineNumber(), e);
+            }
+        }
+        mv.visitEnd();
+    }
+
+    private void visitStdMethod(MethodNode node, boolean isConstructor, Parameter[] parameters, Statement code) {
+        controller.getCompileStack().init(node.getVariableScope(), parameters);
+        controller.getCallSiteWriter().makeSiteEntry();
+
+        MethodVisitor mv = controller.getMethodVisitor();
+        final ClassNode superClass = controller.getClassNode().getSuperClass();
+        if (isConstructor && (code == null || !((ConstructorNode) node).firstStatementIsSpecialConstructorCall())) {
+            boolean hasCallToSuper = false;
+            if (code!=null && controller.getClassNode() instanceof InnerClassNode) {
+                // if the class not is an inner class node, there are chances that the call to super is already added
+                // so we must ensure not to add it twice (see GROOVY-4471)
+                if (code instanceof BlockStatement) {
+                    for (Statement statement : ((BlockStatement) code).getStatements()) {
+                        if (statement instanceof ExpressionStatement) {
+                            final Expression expression = ((ExpressionStatement) statement).getExpression();
+                            if (expression instanceof ConstructorCallExpression) {
+                                ConstructorCallExpression call = (ConstructorCallExpression) expression;
+                                if (call.isSuperCall()) {
+                                    hasCallToSuper = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (!hasCallToSuper) {
+                // invokes the super class constructor
+                mv.visitVarInsn(ALOAD, 0);
+                mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(superClass), "<init>", "()V", false);
+            }
+        }
+
+        // handle body
+        super.visitConstructorOrMethod(node, isConstructor);
+
+        controller.getCompileStack().clear();
+        if (node.isVoidMethod()) {
+            mv.visitInsn(RETURN);
+        } else {
+            // we make a dummy return for label ranges that reach here
+            ClassNode type = node.getReturnType().redirect();
+            if (ClassHelper.isPrimitiveType(type)) {
+                mv.visitLdcInsn(0);
+                controller.getOperandStack().push(ClassHelper.int_TYPE);
+                controller.getOperandStack().doGroovyCast(type);
+                BytecodeHelper.doReturn(mv, type);
+                controller.getOperandStack().remove(1);
+            } else {
+                mv.visitInsn(ACONST_NULL);
+                BytecodeHelper.doReturn(mv, type);
+            }
+        }
+    }
+
+    void visitAnnotationDefaultExpression(AnnotationVisitor av, ClassNode type, Expression exp) {
+        if (exp instanceof ClosureExpression) {
+            ClassNode closureClass = controller.getClosureWriter().getOrAddClosureClass((ClosureExpression) exp, ACC_PUBLIC);
+            Type t = Type.getType(BytecodeHelper.getTypeDescription(closureClass));
+            av.visit(null, t);
+        } else if (type.isArray()) {
+            AnnotationVisitor avl = av.visitArray(null);
+            ClassNode componentType = type.getComponentType();
+            if (exp instanceof ListExpression) {
+                ListExpression list = (ListExpression) exp;
+                for (Expression lExp : list.getExpressions()) {
+                    visitAnnotationDefaultExpression(avl, componentType, lExp);
+                }
+            } else {
+                visitAnnotationDefaultExpression(avl, componentType, exp);
+            }
+        } else if (ClassHelper.isPrimitiveType(type) || type.equals(ClassHelper.STRING_TYPE)) {
+            ConstantExpression constExp = (ConstantExpression) exp;
+            av.visit(null, constExp.getValue());
+        } else if (ClassHelper.CLASS_Type.equals(type)) {
+            ClassNode clazz = exp.getType();
+            Type t = Type.getType(BytecodeHelper.getTypeDescription(clazz));
+            av.visit(null, t);
+        } else if (type.isDerivedFrom(ClassHelper.Enum_Type)) {
+            PropertyExpression pExp = (PropertyExpression) exp;
+            ClassExpression cExp = (ClassExpression) pExp.getObjectExpression();
+            String desc = BytecodeHelper.getTypeDescription(cExp.getType());
+            String name = pExp.getPropertyAsString();
+            av.visitEnum(null, desc, name);
+        } else if (type.implementsInterface(ClassHelper.Annotation_TYPE)) {
+            AnnotationConstantExpression avExp = (AnnotationConstantExpression) exp;
+            AnnotationNode value = (AnnotationNode) avExp.getValue();
+            AnnotationVisitor avc = av.visitAnnotation(null, BytecodeHelper.getTypeDescription(avExp.getType()));
+            visitAnnotationAttributes(value, avc);
+        } else {
+            throw new GroovyBugError("unexpected annotation type " + type.getName());
+        }
+        av.visitEnd();
+    }
+
+    private void visitAnnotationDefault(MethodNode node, MethodVisitor mv) {
+        if (!node.hasAnnotationDefault()) return;
+        Expression exp = ((ReturnStatement) node.getCode()).getExpression();
+        AnnotationVisitor av = mv.visitAnnotationDefault();
+        visitAnnotationDefaultExpression(av,node.getReturnType(),exp);
+    }
+
+    private static boolean isVargs(Parameter[] p) {
+        if (p.length==0) return false;
+        ClassNode clazz = p[p.length-1].getType();
+        return (clazz.isArray());
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+        controller.setConstructorNode(node);
+        super.visitConstructor(node);
+    }
+
+    public void visitMethod(MethodNode node) {
+        controller.setMethodNode(node);
+        super.visitMethod(node);
+    }
+
+    public void visitField(FieldNode fieldNode) {
+        onLineNumber(fieldNode, "visitField: " + fieldNode.getName());
+        ClassNode t = fieldNode.getType();
+        String signature = BytecodeHelper.getGenericsBounds(t);
+
+        Expression initialValueExpression = fieldNode.getInitialValueExpression();
+        ConstantExpression cexp = initialValueExpression instanceof ConstantExpression? (ConstantExpression) initialValueExpression :null;
+        if (cexp!=null) {
+            cexp = Verifier.transformToPrimitiveConstantIfPossible(cexp);
+        }
+        Object value = cexp!=null && ClassHelper.isStaticConstantInitializerType(cexp.getType())
+                && cexp.getType().equals(t)
+                && fieldNode.isStatic() && fieldNode.isFinal()
+                ?cexp.getValue() // GROOVY-5150
+                :null;
+        if (value!=null) {
+            // byte, char and short require an extra cast
+            if (ClassHelper.byte_TYPE.equals(t) || ClassHelper.short_TYPE.equals(t)) {
+                value = ((Number) value).intValue();
+            } else if (ClassHelper.char_TYPE.equals(t)) {
+                value = Integer.valueOf((Character)value);
+            }
+        }
+        FieldVisitor fv = cv.visitField(
+                fieldNode.getModifiers(),
+                fieldNode.getName(),
+                BytecodeHelper.getTypeDescription(t),
+                signature,
+                value);
+        visitAnnotations(fieldNode, fv);
+        fv.visitEnd();
+    }
+
+    public void visitProperty(PropertyNode statement) {
+        // the verifier created the field and the setter/getter methods, so here is
+        // not really something to do
+        onLineNumber(statement, "visitProperty:" + statement.getField().getName());
+        controller.setMethodNode(null);
+    }
+
+    // GroovyCodeVisitor interface
+    //-------------------------------------------------------------------------
+
+    // Statements
+    //-------------------------------------------------------------------------
+
+    protected void visitStatement(Statement statement) {
+        throw new GroovyBugError("visitStatement should not be visited here.");
+    }
+
+    @Override
+    public void visitCatchStatement(CatchStatement statement) {
+        statement.getCode().visit(this);
+    }
+
+    public void visitBlockStatement(BlockStatement block) {
+        controller.getStatementWriter().writeBlockStatement(block);
+    }
+
+    public void visitForLoop(ForStatement loop) {
+        controller.getStatementWriter().writeForStatement(loop);
+    }
+
+    public void visitWhileLoop( WhileStatement loop) {
+        controller.getStatementWriter().writeWhileLoop(loop);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        controller.getStatementWriter().writeDoWhileLoop(loop);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        controller.getStatementWriter().writeIfElse(ifElse);
+    }
+
+    public void visitAssertStatement(AssertStatement statement) {
+        controller.getStatementWriter().writeAssert(statement);
+    }
+
+    public void visitTryCatchFinally(TryCatchStatement statement) {
+        controller.getStatementWriter().writeTryCatchFinally(statement);
+    }
+
+    public void visitSwitch(SwitchStatement statement) {
+        controller.getStatementWriter().writeSwitch(statement);
+    }
+
+    public void visitCaseStatement(CaseStatement statement) {}
+
+    public void visitBreakStatement(BreakStatement statement) {
+        controller.getStatementWriter().writeBreak(statement);
+    }
+
+    public void visitContinueStatement(ContinueStatement statement) {
+        controller.getStatementWriter().writeContinue(statement);
+    }
+
+    public void visitSynchronizedStatement(SynchronizedStatement statement) {
+        controller.getStatementWriter().writeSynchronized(statement);
+    }
+
+    public void visitThrowStatement(ThrowStatement statement) {
+        controller.getStatementWriter().writeThrow(statement);
+    }
+
+    public void visitReturnStatement(ReturnStatement statement) {
+        controller.getStatementWriter().writeReturn(statement);
+    }
+
+    public void visitExpressionStatement(ExpressionStatement statement) {
+        controller.getStatementWriter().writeExpressionStatement(statement);
+    }
+
+    // Expressions
+    //-------------------------------------------------------------------------
+
+    public void visitTernaryExpression(TernaryExpression expression) {
+        onLineNumber(expression, "visitTernaryExpression");
+        controller.getBinaryExpressionHelper().evaluateTernary(expression);
+    }
+
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        onLineNumber(expression, "visitDeclarationExpression: \"" + expression.getText() + "\"");
+        controller.getBinaryExpressionHelper().evaluateEqual(expression,true);
+    }
+
+    public void visitBinaryExpression(BinaryExpression expression) {
+        onLineNumber(expression, "visitBinaryExpression: \"" + expression.getOperation().getText() + "\" ");
+        controller.getBinaryExpressionHelper().eval(expression);
+        controller.getAssertionWriter().record(expression.getOperation());
+    }
+
+    public void visitPostfixExpression(PostfixExpression expression) {
+        controller.getBinaryExpressionHelper().evaluatePostfixMethod(expression);
+        controller.getAssertionWriter().record(expression);
+    }
+
+    public void throwException(String s) {
+        throw new RuntimeParserException(s, currentASTNode);
+    }
+
+    public void visitPrefixExpression(PrefixExpression expression) {
+        controller.getBinaryExpressionHelper().evaluatePrefixMethod(expression);
+        controller.getAssertionWriter().record(expression);
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        controller.getClosureWriter().writeClosure(expression);
+    }
+
+    /**
+     * Loads either this object or if we're inside a closure then load the top level owner
+     */
+    protected void loadThisOrOwner() {
+        if (isInnerClass()) {
+            visitFieldExpression(new FieldExpression(controller.getClassNode().getDeclaredField("owner")));
+        } else {
+            loadThis(null);
+        }
+    }
+
+    /**
+     * Generate byte code for constants
+     *
+     * @see <a href="http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#14152">Class field types</a>
+     */
+    public void visitConstantExpression(ConstantExpression expression) {
+        final String constantName = expression.getConstantName();
+        if (controller.isStaticConstructor() || constantName == null) {
+            controller.getOperandStack().pushConstant(expression);
+        } else {
+            controller.getMethodVisitor().visitFieldInsn(GETSTATIC, controller.getInternalClassName(),constantName, BytecodeHelper.getTypeDescription(expression.getType()));
+            controller.getOperandStack().push(expression.getType());
+        }
+    }
+
+    public void visitSpreadExpression(SpreadExpression expression) {
+        throw new GroovyBugError("SpreadExpression should not be visited here");
+    }
+
+    public void visitSpreadMapExpression(SpreadMapExpression expression) {
+        Expression subExpression = expression.getExpression();
+        // to not record the underlying MapExpression twice,
+        // we disable the assertion tracker
+        // see https://issues.apache.org/jira/browse/GROOVY-3421
+        controller.getAssertionWriter().disableTracker();
+        subExpression.visit(this);
+        controller.getOperandStack().box();
+        spreadMap.call(controller.getMethodVisitor());
+        controller.getAssertionWriter().reenableTracker();
+        controller.getOperandStack().replace(ClassHelper.OBJECT_TYPE);
+    }
+
+    public void visitMethodPointerExpression(MethodPointerExpression expression) {
+        Expression subExpression = expression.getExpression();
+        subExpression.visit(this);
+        controller.getOperandStack().box();
+        controller.getOperandStack().pushDynamicName(expression.getMethodName());
+        getMethodPointer.call(controller.getMethodVisitor());
+        controller.getOperandStack().replace(ClassHelper.CLOSURE_TYPE,2);
+    }
+
+    public void visitUnaryMinusExpression(UnaryMinusExpression expression) {
+        controller.getUnaryExpressionHelper().writeUnaryMinus(expression);
+    }
+
+    public void visitUnaryPlusExpression(UnaryPlusExpression expression) {
+        controller.getUnaryExpressionHelper().writeUnaryPlus(expression);
+    }
+
+    public void visitBitwiseNegationExpression(BitwiseNegationExpression expression) {
+        controller.getUnaryExpressionHelper().writeBitwiseNegate(expression);
+    }
+
+    public void visitCastExpression(CastExpression castExpression) {
+        ClassNode type = castExpression.getType();
+        Expression subExpression = castExpression.getExpression();
+        subExpression.visit(this);
+        if (ClassHelper.OBJECT_TYPE.equals(type)) return;
+        if (castExpression.isCoerce()) {
+            controller.getOperandStack().doAsType(type);
+        } else {
+            if (isNullConstant(subExpression) && !ClassHelper.isPrimitiveType(type)) {
+                controller.getOperandStack().replace(type);
+            } else {
+                ClassNode subExprType = controller.getTypeChooser().resolveType(subExpression, controller.getClassNode());
+                if (castExpression.isStrict() ||
+                        (!ClassHelper.isPrimitiveType(type) && WideningCategories.implementsInterfaceOrSubclassOf(subExprType, type))) {
+                    BytecodeHelper.doCast(controller.getMethodVisitor(), type);
+                    controller.getOperandStack().replace(type);
+                } else {
+                    controller.getOperandStack().doGroovyCast(type);
+                }
+            }
+        }
+    }
+
+    public void visitNotExpression(NotExpression expression) {
+        controller.getUnaryExpressionHelper().writeNotExpression(expression);
+    }
+
+    /**
+     * return a primitive boolean value of the BooleanExpression.
+     *
+     * @param expression
+     */
+    public void visitBooleanExpression(BooleanExpression expression) {
+        controller.getCompileStack().pushBooleanExpression();
+        int mark = controller.getOperandStack().getStackLength();
+        Expression inner = expression.getExpression();
+        inner.visit(this);
+        controller.getOperandStack().castToBool(mark, true);
+        controller.getCompileStack().pop();
+    }
+
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        onLineNumber(call, "visitMethodCallExpression: \"" + call.getMethod() + "\":");
+        controller.getInvocationWriter().writeInvokeMethod(call);
+        controller.getAssertionWriter().record(call.getMethod());
+    }
+
+    protected boolean emptyArguments(Expression arguments) {
+        return argumentSize(arguments) == 0;
+    }
+
+    public static boolean containsSpreadExpression(Expression arguments) {
+        List args = null;
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tupleExpression = (TupleExpression) arguments;
+            args = tupleExpression.getExpressions();
+        } else if (arguments instanceof ListExpression) {
+            ListExpression le = (ListExpression) arguments;
+            args = le.getExpressions();
+        } else {
+            return arguments instanceof SpreadExpression;
+        }
+        for (Iterator iter = args.iterator(); iter.hasNext();) {
+            if (iter.next() instanceof SpreadExpression) return true;
+        }
+        return false;
+    }
+
+    public static int argumentSize(Expression arguments) {
+        if (arguments instanceof TupleExpression) {
+            TupleExpression tupleExpression = (TupleExpression) arguments;
+            int size = tupleExpression.getExpressions().size();
+            return size;
+        }
+        return 1;
+    }
+
+    public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
+        onLineNumber(call, "visitStaticMethodCallExpression: \"" + call.getMethod() + "\":");
+        controller.getInvocationWriter().writeInvokeStaticMethod(call);
+        controller.getAssertionWriter().record(call);
+    }
+
+    public static boolean isNullConstant(Expression expr) {
+        return expr instanceof ConstantExpression && ((ConstantExpression) expr).getValue()==null;
+    }
+
+    public void visitConstructorCallExpression(ConstructorCallExpression call) {
+        onLineNumber(call, "visitConstructorCallExpression: \"" + call.getType().getName() + "\":");
+
+        if (call.isSpecialCall()) {
+            controller.getInvocationWriter().writeSpecialConstructorCall(call);
+            return;
+        }
+        controller.getInvocationWriter().writeInvokeConstructor(call);
+        controller.getAssertionWriter().record(call);
+    }
+
+    private static String makeFieldClassName(ClassNode type) {
+        String internalName = BytecodeHelper.getClassInternalName(type);
+        StringBuilder ret = new StringBuilder(internalName.length());
+        for (int i = 0; i < internalName.length(); i++) {
+            char c = internalName.charAt(i);
+            if (c == '/') {
+                ret.append('$');
+            } else if (c == ';') {
+                //append nothing -> delete ';'
+            } else {
+                ret.append(c);
+            }
+        }
+        return ret.toString();
+    }
+
+    private static String getStaticFieldName(ClassNode type) {
+        ClassNode componentType = type;
+        StringBuilder prefix = new StringBuilder();
+        for (; componentType.isArray(); componentType = componentType.getComponentType()) {
+            prefix.append("$");
+        }
+        if (prefix.length() != 0) prefix.insert(0, "array");
+        String name = prefix + "$class$" + makeFieldClassName(componentType);
+        return name;
+    }
+
+    private void visitAttributeOrProperty(PropertyExpression expression, MethodCallerMultiAdapter adapter) {
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        Expression objectExpression = expression.getObjectExpression();
+        ClassNode classNode = controller.getClassNode();
+        if (isThisOrSuper(objectExpression)) {
+            // let's use the field expression if it's available
+            String name = expression.getPropertyAsString();
+            if (name != null) {
+                FieldNode field = null;
+                boolean privateSuperField = false;
+                if (isSuperExpression(objectExpression)) {
+                    field = classNode.getSuperClass().getDeclaredField(name);
+                    if (field != null && ((field.getModifiers() & ACC_PRIVATE) != 0)) {
+                        privateSuperField = true;
+                    }
+                } else {
+                	if (controller.isNotExplicitThisInClosure(expression.isImplicitThis())) {
+                        field = classNode.getDeclaredField(name);
+                        if (field==null && classNode instanceof InnerClassNode) {
+                            ClassNode outer = classNode.getOuterClass();
+                            FieldNode outerClassField;
+                            while (outer!=null) {
+                                outerClassField = outer.getDeclaredField(name);
+                                if (outerClassField!=null && outerClassField.isStatic() && outerClassField.isFinal()) {
+                                    if (outer!=classNode.getOuterClass() && Modifier.isPrivate(outerClassField.getModifiers())) {
+                                        throw new GroovyBugError("Trying to access private constant field ["+outerClassField.getDeclaringClass()+"#"+outerClassField.getName()+"] from inner class");
+                                    }
+                                    PropertyExpression pexp = new PropertyExpression(
+                                            new ClassExpression(outer),
+                                            expression.getProperty()
+                                    );
+                                    pexp.visit(controller.getAcg());
+                                    return;
+                                }
+                                outer = outer.getSuperClass();
+                            }
+                        }
+                        if (field==null
+                                && expression instanceof AttributeExpression
+                                && isThisExpression(objectExpression)
+                                && controller.isStaticContext()) {
+                            // GROOVY-6183
+                            ClassNode current = classNode.getSuperClass();
+                            while (field==null && current!=null) {
+                                field = current.getDeclaredField(name);
+                                current = current.getSuperClass();
+                            }
+                            if (field!=null && (field.isProtected() || field.isPublic())) {
+                                visitFieldExpression(new FieldExpression(field));
+                                return;
+                            }
+                        }
+                	}
+                }
+                if (field != null && !privateSuperField) {//GROOVY-4497: don't visit super field if it is private
+                    visitFieldExpression(new FieldExpression(field));
+                    return;
+                }
+                if (isSuperExpression(objectExpression)) {
+                    String prefix;
+                    if (controller.getCompileStack().isLHS()) {
+                        throw new GroovyBugError("Unexpected super property set for:" + expression.getText());
+                    } else {
+                        prefix = "get";
+                    }
+                    String propName = prefix + MetaClassHelper.capitalize(name);
+                    visitMethodCallExpression(new MethodCallExpression(objectExpression, propName, MethodCallExpression.NO_ARGUMENTS));
+                    return;
+                }
+            }
+        }
+
+        final String propName = expression.getPropertyAsString();
+        //TODO: add support for super here too
+        if (expression.getObjectExpression() instanceof ClassExpression &&
+            propName!=null && propName.equals("this"))
+        {
+            // we have something like A.B.this, and need to make it
+            // into this.this$0.this$0, where this.this$0 returns
+            // A.B and this.this$0.this$0 return A.
+            ClassNode type = objectExpression.getType();
+            ClassNode iterType = classNode;
+            if (controller.getCompileStack().isInSpecialConstructorCall() && classNode instanceof InnerClassNode) {
+                boolean staticInnerClass = classNode.isStaticClass();
+                // Outer.this in a special constructor call
+                if (classNode.getOuterClass().equals(type)) {
+                    ConstructorNode ctor = controller.getConstructorNode();
+                    Expression receiver = !staticInnerClass ? new VariableExpression(ctor.getParameters()[0]) : new ClassExpression(type);
+                    receiver.setSourcePosition(expression);
+                    receiver.visit(this);
+                    return;
+                }
+            }
+            mv.visitVarInsn(ALOAD, 0);
+            while (!iterType.equals(type)) {
+                String ownerName = BytecodeHelper.getClassInternalName(iterType);
+                if (iterType.getOuterClass()==null) break;
+                FieldNode thisField = iterType.getField("this$0");
+                iterType = iterType.getOuterClass();
+                if (thisField == null) {
+                    // closure within inner class
+                    mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ClassHelper.CLOSURE_TYPE), "getThisObject", "()Ljava/lang/Object;", false);
+                    mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(iterType));
+                } else {
+                    ClassNode thisFieldType = thisField.getType();
+                    if (ClassHelper.CLOSURE_TYPE.equals(thisFieldType)) {
+                        mv.visitFieldInsn(GETFIELD, ownerName, "this$0", BytecodeHelper.getTypeDescription(ClassHelper.CLOSURE_TYPE));
+                        mv.visitMethodInsn(INVOKEVIRTUAL, BytecodeHelper.getClassInternalName(ClassHelper.CLOSURE_TYPE), "getThisObject", "()Ljava/lang/Object;", false);
+                        mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(iterType));
+                    } else {
+                        String typeName = BytecodeHelper.getTypeDescription(iterType);
+                        mv.visitFieldInsn(GETFIELD, ownerName, "this$0", typeName);
+                    }
+                }
+            }
+            controller.getOperandStack().push(type);
+            return;
+        }
+
+        if (adapter == getProperty && !expression.isSpreadSafe() && propName != null) {
+            controller.getCallSiteWriter().makeGetPropertySite(objectExpression, propName, expression.isSafe(), expression.isImplicitThis());
+        } else if (adapter == getGroovyObjectProperty && !expression.isSpreadSafe() && propName != null) {
+            controller.getCallSiteWriter().makeGroovyObjectGetPropertySite(objectExpression, propName, expression.isSafe(), expression.isImplicitThis());
+        } else {
+            // todo: for improved modularity and extensibility, this should be moved into a writer
+            if (controller.getCompileStack().isLHS()) controller.getOperandStack().box();
+            controller.getInvocationWriter().makeCall(
+                    expression,
+                    objectExpression, // receiver
+                    new CastExpression(ClassHelper.STRING_TYPE, expression.getProperty()), // messageName
+                    MethodCallExpression.NO_ARGUMENTS, adapter,
+                    expression.isSafe(), expression.isSpreadSafe(), expression.isImplicitThis()
+            );
+        }
+    }
+
+    private boolean isThisOrSuperInStaticContext(Expression objectExpression) {
+        if (controller.isInClosure()) return false;
+        return controller.isStaticContext() && isThisOrSuper(objectExpression);
+    }
+
+    public void visitPropertyExpression(PropertyExpression expression) {
+        Expression objectExpression = expression.getObjectExpression();
+        OperandStack operandStack = controller.getOperandStack();
+        int mark = operandStack.getStackLength()-1;
+        MethodCallerMultiAdapter adapter;
+        if (controller.getCompileStack().isLHS()) {
+            //operandStack.box();
+            adapter = setProperty;
+            if (isGroovyObject(objectExpression)) adapter = setGroovyObjectProperty;
+            if (isThisOrSuperInStaticContext(objectExpression)) adapter = setProperty;
+        } else {
+            adapter = getProperty;
+            if (isGroovyObject(objectExpression)) adapter = getGroovyObjectProperty;
+            if (isThisOrSuperInStaticContext(objectExpression)) adapter = getProperty;
+        }
+        visitAttributeOrProperty(expression, adapter);
+        if (controller.getCompileStack().isLHS()) {
+            // remove surplus values
+            operandStack.remove(operandStack.getStackLength()-mark);
+        } else {
+            controller.getAssertionWriter().record(expression.getProperty());
+        }
+    }
+
+    public void visitAttributeExpression(AttributeExpression expression) {
+        Expression objectExpression = expression.getObjectExpression();
+        MethodCallerMultiAdapter adapter;
+        OperandStack operandStack = controller.getOperandStack();
+        int mark = operandStack.getStackLength()-1;
+        if (controller.getCompileStack().isLHS()) {
+            adapter = setField;
+            if (isGroovyObject(objectExpression)) adapter = setGroovyObjectField;
+            if (usesSuper(expression)) adapter = setFieldOnSuper;
+        } else {
+            adapter = getField;
+            if (isGroovyObject(objectExpression)) adapter = getGroovyObjectField;
+            if (usesSuper(expression)) adapter = getFieldOnSuper;
+        }
+        visitAttributeOrProperty(expression, adapter);
+        if (!controller.getCompileStack().isLHS()) {
+            controller.getAssertionWriter().record(expression.getProperty());
+        } else {
+            operandStack.remove(operandStack.getStackLength() - mark);
+        }
+    }
+
+    private static boolean usesSuper(PropertyExpression pe) {
+        Expression expression = pe.getObjectExpression();
+        if (expression instanceof VariableExpression) {
+            VariableExpression varExp = (VariableExpression) expression;
+            String variable = varExp.getName();
+            return variable.equals("super");
+        }
+        return false;
+    }
+
+    private static boolean isGroovyObject(Expression objectExpression) {
+        return isThisExpression(objectExpression) || objectExpression.getType().isDerivedFromGroovyObject() && !(objectExpression instanceof ClassExpression);
+    }
+
+    public void visitFieldExpression(FieldExpression expression) {
+        FieldNode field = expression.getField();
+
+        if (field.isStatic()) {
+            if (controller.getCompileStack().isLHS()) {
+                storeStaticField(expression);
+            } else {
+                loadStaticField(expression);
+            }
+        } else {
+            if (controller.getCompileStack().isLHS()) {
+                storeThisInstanceField(expression);
+            } else {
+                loadInstanceField(expression);
+            }
+        }
+        if (controller.getCompileStack().isLHS()) controller.getAssertionWriter().record(expression);
+    }
+
+    /**
+     * @param fldExp
+     */
+    public void loadStaticField(FieldExpression fldExp) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        FieldNode field = fldExp.getField();
+        boolean holder = field.isHolder() && !controller.isInClosureConstructor();
+        ClassNode type = field.getType();
+
+        String ownerName = (field.getOwner().equals(controller.getClassNode()))
+                ? controller.getInternalClassName()
+                : BytecodeHelper.getClassInternalName(field.getOwner());
+        if (holder) {
+            mv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
+            mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;", false);
+            controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
+        } else {
+            mv.visitFieldInsn(GETSTATIC, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
+            controller.getOperandStack().push(field.getType());
+        }
+    }
+
+    /**
+     * RHS instance field. should move most of the code in the BytecodeHelper
+     *
+     * @param fldExp
+     */
+    public void loadInstanceField(FieldExpression fldExp) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        FieldNode field = fldExp.getField();
+        boolean holder = field.isHolder() && !controller.isInClosureConstructor();
+        ClassNode type = field.getType();
+        String ownerName = (field.getOwner().equals(controller.getClassNode()))
+                ? controller.getInternalClassName()
+                : BytecodeHelper.getClassInternalName(field.getOwner());
+
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitFieldInsn(GETFIELD, ownerName, fldExp.getFieldName(), BytecodeHelper.getTypeDescription(type));
+
+        if (holder) {
+            mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "get", "()Ljava/lang/Object;", false);
+            controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
+        } else {
+            controller.getOperandStack().push(field.getType());
+        }
+    }
+
+    private void storeThisInstanceField(FieldExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        FieldNode field = expression.getField();
+
+        boolean setReferenceFromReference = field.isHolder() && expression.isUseReferenceDirectly();
+        String ownerName = (field.getOwner().equals(controller.getClassNode())) ?
+                controller.getInternalClassName() : BytecodeHelper.getClassInternalName(field.getOwner());
+        OperandStack operandStack = controller.getOperandStack();
+
+        if (setReferenceFromReference) {
+            // rhs is ready to use reference, just put it in the field
+            mv.visitVarInsn(ALOAD, 0);
+            operandStack.push(controller.getClassNode());
+            operandStack.swap();
+            mv.visitFieldInsn(PUTFIELD, ownerName, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
+        } else if (field.isHolder()){
+            // rhs is normal value, set the value in the Reference
+            operandStack.doGroovyCast(field.getOriginType());
+            operandStack.box();
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitFieldInsn(GETFIELD, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
+            mv.visitInsn(SWAP);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V", false);
+        } else {
+            // rhs is normal value, set normal value
+            operandStack.doGroovyCast(field.getOriginType());
+            mv.visitVarInsn(ALOAD, 0);
+            operandStack.push(controller.getClassNode());
+            operandStack.swap();
+            mv.visitFieldInsn(PUTFIELD, ownerName, field.getName(), BytecodeHelper.getTypeDescription(field.getType()));
+        }
+    }
+
+    private void storeStaticField(FieldExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        FieldNode field = expression.getField();
+
+        boolean holder = field.isHolder() && !controller.isInClosureConstructor();
+        controller.getOperandStack().doGroovyCast(field);
+
+        String ownerName = (field.getOwner().equals(controller.getClassNode())) ?
+                controller.getInternalClassName() : BytecodeHelper.getClassInternalName(field.getOwner());
+        if (holder) {
+            controller.getOperandStack().box();
+            mv.visitFieldInsn(GETSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
+            mv.visitInsn(SWAP);
+            mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Reference", "set", "(Ljava/lang/Object;)V", false);
+        } else {
+            mv.visitFieldInsn(PUTSTATIC, ownerName, expression.getFieldName(), BytecodeHelper.getTypeDescription(field.getType()));
+        }
+        controller.getOperandStack().remove(1);
+    }
+
+    /**
+     * Visits a bare (unqualified) variable expression.
+     */
+    public void visitVariableExpression(VariableExpression expression) {
+        String variableName = expression.getName();
+
+        //-----------------------------------------------------------------------
+        // SPECIAL CASES
+
+        // "this" for static methods is the Class instance
+        ClassNode classNode = controller.getClassNode();
+        //if (controller.isInClosure()) classNode = controller.getOutermostClass();
+
+        if (variableName.equals("this")) {
+            if (controller.isStaticMethod() || (!controller.getCompileStack().isImplicitThis() && controller.isStaticContext())) {
+                if (controller.isInClosure()) classNode = controller.getOutermostClass();
+                visitClassExpression(new ClassExpression(classNode));
+            } else {
+                loadThis(expression);
+            }
+            return;
+        }
+
+        // "super" also requires special handling
+        if (variableName.equals("super")) {
+            if (controller.isStaticMethod()) {
+                visitClassExpression(new ClassExpression(classNode.getSuperClass()));
+            } else {
+                loadThis(expression);
+            }
+            return;
+        }
+
+        BytecodeVariable variable = controller.getCompileStack().getVariable(variableName, false);
+        if (variable == null) {
+            processClassVariable(expression);
+        } else {
+            controller.getOperandStack().loadOrStoreVariable(variable, expression.isUseReferenceDirectly());
+        }
+        if (!controller.getCompileStack().isLHS()) controller.getAssertionWriter().record(expression);
+    }
+
+    private void loadThis(VariableExpression thisExpression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        mv.visitVarInsn(ALOAD, 0);
+        if (controller.isInClosure() && !controller.getCompileStack().isImplicitThis()) {
+            mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Closure", "getThisObject", "()Ljava/lang/Object;", false);
+            ClassNode expectedType = thisExpression!=null?controller.getTypeChooser().resolveType(thisExpression, controller.getOutermostClass()):null;
+            if (!ClassHelper.OBJECT_TYPE.equals(expectedType) && !ClassHelper.isPrimitiveType(expectedType)) {
+                BytecodeHelper.doCast(mv, expectedType);
+                controller.getOperandStack().push(expectedType);
+            } else {
+                controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
+            }
+        } else {
+            controller.getOperandStack().push(controller.getClassNode());
+        }
+    }
+
+    private void processClassVariable(VariableExpression expression) {
+        if (passingParams && controller.isInScriptBody()) {
+            //TODO: check if this part is actually used
+            MethodVisitor mv = controller.getMethodVisitor();
+            // let's create a ScriptReference to pass into the closure
+            mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/ScriptReference");
+            mv.visitInsn(DUP);
+
+            loadThisOrOwner();
+            mv.visitLdcInsn(expression.getName());
+
+            mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/ScriptReference", "<init>", "(Lgroovy/lang/Script;Ljava/lang/String;)V", false);
+        } else {
+            PropertyExpression pexp = new PropertyExpression(new VariableExpression("this"), expression.getName());
+            pexp.getObjectExpression().setSourcePosition(expression);
+            pexp.getProperty().setSourcePosition(expression);
+            pexp.setImplicitThis(true);
+            visitPropertyExpression(pexp);
+        }
+    }
+
+    protected void createInterfaceSyntheticStaticFields() {
+        ClassNode icl =  controller.getInterfaceClassLoadingClass();
+
+        if (referencedClasses.isEmpty()) {
+            Iterator<InnerClassNode> it = controller.getClassNode().getInnerClasses();
+            while(it.hasNext()) {
+                InnerClassNode inner = it.next();
+                if (inner==icl) {
+                    it.remove();
+                    return;
+                }
+            }
+            return;
+        }
+
+        addInnerClass(icl);
+        for (Map.Entry<String, ClassNode> entry : referencedClasses.entrySet()) {            // generate a field node
+            String staticFieldName = entry.getKey();
+            ClassNode cn = entry.getValue();
+            icl.addField(staticFieldName, ACC_STATIC + ACC_SYNTHETIC, ClassHelper.CLASS_Type.getPlainNodeReference(), new ClassExpression(cn));
+        }
+    }
+
+    protected void createSyntheticStaticFields() {
+        if (referencedClasses.isEmpty()) {
+            return;
+        }
+        MethodVisitor mv;
+        for (Map.Entry<String, ClassNode> entry : referencedClasses.entrySet()) {
+            String staticFieldName = entry.getKey();
+            ClassNode cn = entry.getValue();
+            // generate a field node
+            FieldNode fn = controller.getClassNode().getDeclaredField(staticFieldName);
+            if (fn != null) {
+                boolean type = fn.getType().redirect() == ClassHelper.CLASS_Type;
+                boolean modifiers = fn.getModifiers() == ACC_STATIC + ACC_SYNTHETIC;
+                if (!type || !modifiers) {
+                    String text = "";
+                    if (!type) text = " with wrong type: " + fn.getType() + " (java.lang.Class needed)";
+                    if (!modifiers)
+                        text = " with wrong modifiers: " + fn.getModifiers() + " (" + (ACC_STATIC + ACC_SYNTHETIC) + " needed)";
+                    throwException(
+                            "tried to set a static synthetic field " + staticFieldName + " in " + controller.getClassNode().getName() +
+                                    " for class resolving, but found already a node of that" +
+                                    " name " + text);
+                }
+            } else {
+                cv.visitField(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, staticFieldName, "Ljava/lang/Class;", null, null);
+            }
+
+            mv = cv.visitMethod(ACC_PRIVATE + ACC_STATIC + ACC_SYNTHETIC, "$get$" + staticFieldName,"()Ljava/lang/Class;",null, null);
+            mv.visitCode();
+            mv.visitFieldInsn(GETSTATIC,controller.getInternalClassName(),staticFieldName,"Ljava/lang/Class;");
+            mv.visitInsn(DUP);
+            Label l0 = new Label();
+            mv.visitJumpInsn(IFNONNULL,l0);
+            mv.visitInsn(POP);
+            mv.visitLdcInsn(BytecodeHelper.getClassLoadingTypeDescription(cn));
+            mv.visitMethodInsn(INVOKESTATIC, controller.getInternalClassName(), "class$", "(Ljava/lang/String;)Ljava/lang/Class;", false);
+            mv.visitInsn(DUP);
+            mv.visitFieldInsn(PUTSTATIC,controller.getInternalClassName(),staticFieldName,"Ljava/lang/Class;");
+            mv.visitLabel(l0);
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(0,0);
+            mv.visitEnd();
+        }
+
+        mv =    cv.visitMethod(
+                        ACC_STATIC + ACC_SYNTHETIC,
+                        "class$",
+                        "(Ljava/lang/String;)Ljava/lang/Class;",
+                        null,
+                        null);
+        Label l0 = new Label();
+        mv.visitLabel(l0);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
+        Label l1 = new Label();
+        mv.visitLabel(l1);
+        mv.visitInsn(ARETURN);
+        Label l2 = new Label();
+        mv.visitLabel(l2);
+        mv.visitVarInsn(ASTORE, 1);
+        mv.visitTypeInsn(NEW, "java/lang/NoClassDefFoundError");
+        mv.visitInsn(DUP);
+        mv.visitVarInsn(ALOAD, 1);
+        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/ClassNotFoundException", "getMessage", "()Ljava/lang/String;", false);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/NoClassDefFoundError", "<init>", "(Ljava/lang/String;)V", false);
+        mv.visitInsn(ATHROW);
+        mv.visitTryCatchBlock(l0, l2, l2, "java/lang/ClassNotFoundException"); // br using l2 as the 2nd param seems create the right table entry
+        mv.visitMaxs(3, 2);
+    }
+
+    /**
+     * load class object on stack
+     */
+    public void visitClassExpression(ClassExpression expression) {
+        ClassNode type = expression.getType();
+        MethodVisitor mv = controller.getMethodVisitor();
+        if (BytecodeHelper.isClassLiteralPossible(type) || BytecodeHelper.isSameCompilationUnit(controller.getClassNode(), type)) {
+            if (controller.getClassNode().isInterface()) {
+                InterfaceHelperClassNode interfaceClassLoadingClass = controller.getInterfaceClassLoadingClass();
+                if (BytecodeHelper.isClassLiteralPossible(interfaceClassLoadingClass)) {
+                    BytecodeHelper.visitClassLiteral(mv, interfaceClassLoadingClass);
+                    controller.getOperandStack().push(ClassHelper.CLASS_Type);
+                    return;
+                }
+            } else {
+                BytecodeHelper.visitClassLiteral(mv, type);
+                controller.getOperandStack().push(ClassHelper.CLASS_Type);
+                return;
+            }
+        }
+        String staticFieldName = getStaticFieldName(type);
+        referencedClasses.put(staticFieldName, type);
+
+        String internalClassName = controller.getInternalClassName();
+        if (controller.getClassNode().isInterface()) {
+            internalClassName = BytecodeHelper.getClassInternalName(controller.getInterfaceClassLoadingClass());
+            mv.visitFieldInsn(GETSTATIC, internalClassName, staticFieldName, "Ljava/lang/Class;");
+        } else {
+            mv.visitMethodInsn(INVOKESTATIC, internalClassName, "$get$" + staticFieldName, "()Ljava/lang/Class;", false);
+        }
+        controller.getOperandStack().push(ClassHelper.CLASS_Type);
+    }
+
+    public void visitRangeExpression(RangeExpression expression) {
+        OperandStack operandStack = controller.getOperandStack();
+        expression.getFrom().visit(this);
+        operandStack.box();
+        expression.getTo().visit(this);
+        operandStack.box();
+        operandStack.pushBool(expression.isInclusive());
+
+        createRangeMethod.call(controller.getMethodVisitor());
+        operandStack.replace(ClassHelper.RANGE_TYPE, 3);
+    }
+
+    public void visitMapEntryExpression(MapEntryExpression expression) {
+        throw new GroovyBugError("MapEntryExpression should not be visited here");
+    }
+
+    public void visitMapExpression(MapExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        List entries = expression.getMapEntryExpressions();
+        int size = entries.size();
+        BytecodeHelper.pushConstant(mv, size * 2);
+
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+        int i = 0;
+        for (Iterator iter = entries.iterator(); iter.hasNext();) {
+            Object object = iter.next();
+            MapEntryExpression entry = (MapEntryExpression) object;
+
+            mv.visitInsn(DUP);
+            BytecodeHelper.pushConstant(mv, i++);
+            entry.getKeyExpression().visit(this);
+            controller.getOperandStack().box();
+            mv.visitInsn(AASTORE);
+
+            mv.visitInsn(DUP);
+            BytecodeHelper.pushConstant(mv, i++);
+            entry.getValueExpression().visit(this);
+            controller.getOperandStack().box();
+            mv.visitInsn(AASTORE);
+
+            controller.getOperandStack().remove(2);
+        }
+        createMapMethod.call(mv);
+        controller.getOperandStack().push(ClassHelper.MAP_TYPE);
+    }
+
+    public void visitArgumentlistExpression(ArgumentListExpression ale) {
+        if (containsSpreadExpression(ale)) {
+            despreadList(ale.getExpressions(), true);
+        } else {
+            visitTupleExpression(ale, true);
+        }
+    }
+
+    public void despreadList(List expressions, boolean wrap) {
+        ArrayList spreadIndexes = new ArrayList();
+        ArrayList spreadExpressions = new ArrayList();
+        ArrayList normalArguments = new ArrayList();
+        for (int i = 0; i < expressions.size(); i++) {
+            Object expr = expressions.get(i);
+            if (!(expr instanceof SpreadExpression)) {
+                normalArguments.add(expr);
+            } else {
+                spreadIndexes.add(new ConstantExpression(Integer.valueOf(i - spreadExpressions.size()),true));
+                spreadExpressions.add(((SpreadExpression) expr).getExpression());
+            }
+        }
+
+        //load normal arguments as array
+        visitTupleExpression(new ArgumentListExpression(normalArguments), wrap);
+        //load spread expressions as array
+        (new TupleExpression(spreadExpressions)).visit(this);
+        //load insertion index
+        (new ArrayExpression(ClassHelper.int_TYPE, spreadIndexes, null)).visit(this);
+        controller.getOperandStack().remove(1);
+        despreadList.call(controller.getMethodVisitor());
+    }
+
+    public void visitTupleExpression(TupleExpression expression) {
+        visitTupleExpression(expression, false);
+    }
+
+    void visitTupleExpression(TupleExpression expression, boolean useWrapper) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        int size = expression.getExpressions().size();
+
+        BytecodeHelper.pushConstant(mv, size);
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+        for (int i = 0; i < size; i++) {
+            mv.visitInsn(DUP);
+            BytecodeHelper.pushConstant(mv, i);
+            Expression argument = expression.getExpression(i);
+            argument.visit(this);
+            controller.getOperandStack().box();
+            if (useWrapper && argument instanceof CastExpression) loadWrapper(argument);
+
+            mv.visitInsn(AASTORE);
+            controller.getOperandStack().remove(1);
+        }
+    }
+
+    public void loadWrapper(Expression argument) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        ClassNode goalClass = argument.getType();
+        visitClassExpression(new ClassExpression(goalClass));
+        if (goalClass.isDerivedFromGroovyObject()) {
+            createGroovyObjectWrapperMethod.call(mv);
+        } else {
+            createPojoWrapperMethod.call(mv);
+        }
+        controller.getOperandStack().remove(1);
+    }
+
+    public void visitArrayExpression(ArrayExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        ClassNode elementType = expression.getElementType();
+        String arrayTypeName = BytecodeHelper.getClassInternalName(elementType);
+        List sizeExpression = expression.getSizeExpression();
+
+        int size = 0;
+        int dimensions = 0;
+        if (sizeExpression != null) {
+            for (Iterator iter = sizeExpression.iterator(); iter.hasNext();) {
+                Expression element = (Expression) iter.next();
+                if (element == ConstantExpression.EMPTY_EXPRESSION) break;
+                dimensions++;
+                // let's convert to an int
+                element.visit(this);
+                controller.getOperandStack().doGroovyCast(ClassHelper.int_TYPE);
+            }
+            controller.getOperandStack().remove(dimensions);
+        } else {
+            size = expression.getExpressions().size();
+            BytecodeHelper.pushConstant(mv, size);
+        }
+
+        int storeIns = AASTORE;
+        if (sizeExpression != null) {
+            arrayTypeName = BytecodeHelper.getTypeDescription(expression.getType());
+            mv.visitMultiANewArrayInsn(arrayTypeName, dimensions);
+        } else if (ClassHelper.isPrimitiveType(elementType)) {
+            int primType = 0;
+            if (elementType == ClassHelper.boolean_TYPE) {
+                primType = T_BOOLEAN;
+                storeIns = BASTORE;
+            } else if (elementType == ClassHelper.char_TYPE) {
+                primType = T_CHAR;
+                storeIns = CASTORE;
+            } else if (elementType == ClassHelper.float_TYPE) {
+                primType = T_FLOAT;
+                storeIns = FASTORE;
+            } else if (elementType == ClassHelper.double_TYPE) {
+                primType = T_DOUBLE;
+                storeIns = DASTORE;
+            } else if (elementType == ClassHelper.byte_TYPE) {
+                primType = T_BYTE;
+                storeIns = BASTORE;
+            } else if (elementType == ClassHelper.short_TYPE) {
+                primType = T_SHORT;
+                storeIns = SASTORE;
+            } else if (elementType == ClassHelper.int_TYPE) {
+                primType = T_INT;
+                storeIns = IASTORE;
+            } else if (elementType == ClassHelper.long_TYPE) {
+                primType = T_LONG;
+                storeIns = LASTORE;
+            }
+            mv.visitIntInsn(NEWARRAY, primType);
+        } else {
+            mv.visitTypeInsn(ANEWARRAY, arrayTypeName);
+        }
+
+        for (int i = 0; i < size; i++) {
+            mv.visitInsn(DUP);
+            BytecodeHelper.pushConstant(mv, i);
+            Expression elementExpression = expression.getExpression(i);
+            if (elementExpression == null) {
+                ConstantExpression.NULL.visit(this);
+            } else {
+                elementExpression.visit(this);
+                controller.getOperandStack().doGroovyCast(elementType);
+            }
+            mv.visitInsn(storeIns);
+            controller.getOperandStack().remove(1);
+        }
+
+        controller.getOperandStack().push(expression.getType());
+    }
+
+    public void visitClosureListExpression(ClosureListExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        controller.getCompileStack().pushVariableScope(expression.getVariableScope());
+
+        List<Expression> expressions = expression.getExpressions();
+        final int size = expressions.size();
+        // init declarations
+        LinkedList<DeclarationExpression> declarations = new LinkedList<DeclarationExpression>();
+        for (int i = 0; i < size; i++) {
+            Expression expr = expressions.get(i);
+            if (expr instanceof DeclarationExpression) {
+                declarations.add((DeclarationExpression) expr);
+                DeclarationExpression de = (DeclarationExpression) expr;
+                BinaryExpression be = new BinaryExpression(
+                        de.getLeftExpression(),
+                        de.getOperation(),
+                        de.getRightExpression());
+                expressions.set(i, be);
+                de.setRightExpression(ConstantExpression.NULL);
+                visitDeclarationExpression(de);
+            }
+        }
+
+        LinkedList instructions = new LinkedList();
+        BytecodeSequence seq = new BytecodeSequence(instructions);
+        BlockStatement bs = new BlockStatement();
+        bs.addStatement(seq);
+        Parameter closureIndex = new Parameter(ClassHelper.int_TYPE, "__closureIndex");
+        ClosureExpression ce = new ClosureExpression(new Parameter[]{closureIndex}, bs);
+        ce.setVariableScope(expression.getVariableScope());
+
+        // to keep stack height put a null on stack
+        instructions.add(ConstantExpression.NULL);
+
+        // init table
+        final Label dflt = new Label();
+        final Label tableEnd = new Label();
+        final Label[] labels = new Label[size];
+        instructions.add(new BytecodeInstruction() {
+            public void visit(MethodVisitor mv) {
+                mv.visitVarInsn(ILOAD, 1);
+                mv.visitTableSwitchInsn(0, size - 1, dflt, labels);
+            }
+        });
+
+        // visit cases
+        for (int i = 0; i < size; i++) {
+            final Label label = new Label();
+            Object expr = expressions.get(i);
+            final boolean isStatement = expr instanceof Statement;
+            labels[i] = label;
+            instructions.add(new BytecodeInstruction() {
+                public void visit(MethodVisitor mv) {
+                    mv.visitLabel(label);
+                    // expressions will leave a value on stack, statements not
+                    // so expressions need to pop the alibi null
+                    if (!isStatement) mv.visitInsn(POP);
+                }
+            });
+            instructions.add(expr);
+            instructions.add(new BytecodeInstruction() {
+                public void visit(MethodVisitor mv) {
+                    mv.visitJumpInsn(GOTO, tableEnd);
+                }
+            });
+        }
+
+        // default case
+        {
+            instructions.add(new BytecodeInstruction() {
+                public void visit(MethodVisitor mv) {
+                    mv.visitLabel(dflt);
+                }
+            });
+            ConstantExpression text = new ConstantExpression("invalid index for closure");
+            ConstructorCallExpression cce = new ConstructorCallExpression(ClassHelper.make(IllegalArgumentException.class), text);
+            ThrowStatement ts = new ThrowStatement(cce);
+            instructions.add(ts);
+        }
+
+        // return
+        instructions.add(new BytecodeInstruction() {
+            public void visit(MethodVisitor mv) {
+                mv.visitLabel(tableEnd);
+                mv.visitInsn(ARETURN);
+            }
+        });
+
+        // load main Closure
+        visitClosureExpression(ce);
+
+        // we need later an array to store the curried
+        // closures, so we create it here and ave it
+        // in a temporary variable
+        BytecodeHelper.pushConstant(mv, size);
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+        int listArrayVar = controller.getCompileStack().defineTemporaryVariable("_listOfClosures", true);
+
+        // add curried versions
+        for (int i = 0; i < size; i++) {
+            // stack: closure
+
+            // we need to create a curried closure version
+            // so we store the type on stack
+            mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/CurriedClosure");
+            // stack: closure, type
+            // for a constructor call we need the type two times
+
+            // and the closure after them
+            mv.visitInsn(DUP2);
+            mv.visitInsn(SWAP);
+            // stack: closure,type,type,closure
+
+            // so we can create the curried closure
+            mv.visitInsn(ICONST_1);
+            mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+            mv.visitInsn(DUP);
+            mv.visitInsn(ICONST_0);
+            mv.visitLdcInsn(i);
+            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
+            mv.visitInsn(AASTORE);
+            mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/CurriedClosure", "<init>", "(Lgroovy/lang/Closure;[Ljava/lang/Object;)V", false);
+            // stack: closure,curriedClosure
+
+            // we need to save the result
+            mv.visitVarInsn(ALOAD, listArrayVar);
+            mv.visitInsn(SWAP);
+            BytecodeHelper.pushConstant(mv, i);
+            mv.visitInsn(SWAP);
+            mv.visitInsn(AASTORE);
+            // stack: closure
+        }
+
+        // we don't need the closure any longer, so remove it
+        mv.visitInsn(POP);
+        // we load the array and create a list from it
+        mv.visitVarInsn(ALOAD, listArrayVar);
+        createListMethod.call(mv);
+
+        // remove the temporary variable to keep the
+        // stack clean
+        controller.getCompileStack().removeVar(listArrayVar);
+        controller.getOperandStack().pop();
+    }
+
+    public void visitBytecodeSequence(BytecodeSequence bytecodeSequence) {
+        MethodVisitor mv = controller.getMethodVisitor();
+        List instructions = bytecodeSequence.getInstructions();
+        int mark = controller.getOperandStack().getStackLength();
+        for (Iterator iterator = instructions.iterator(); iterator.hasNext();) {
+            Object part = iterator.next();
+            if (part == EmptyExpression.INSTANCE) {
+                mv.visitInsn(ACONST_NULL);
+            } else if (part instanceof Expression) {
+                ((Expression) part).visit(this);
+            } else if (part instanceof Statement) {
+                Statement stm = (Statement) part;
+                stm.visit(this);
+                mv.visitInsn(ACONST_NULL);
+            } else {
+                BytecodeInstruction runner = (BytecodeInstruction) part;
+                runner.visit(mv);
+            }
+        }
+        controller.getOperandStack().remove(mark-controller.getOperandStack().getStackLength());
+    }
+
+    public void visitListExpression(ListExpression expression) {
+        onLineNumber(expression,"ListExpression" );
+
+        int size = expression.getExpressions().size();
+        boolean containsSpreadExpression = containsSpreadExpression(expression);
+        boolean containsOnlyConstants = !containsSpreadExpression && containsOnlyConstants(expression);
+        OperandStack operandStack = controller.getOperandStack();
+        if (!containsSpreadExpression) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            BytecodeHelper.pushConstant(mv, size);
+            mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+            int maxInit = 1000;
+            if (size<maxInit || !containsOnlyConstants) {
+                for (int i = 0; i < size; i++) {
+                    mv.visitInsn(DUP);
+                    BytecodeHelper.pushConstant(mv, i);
+                    expression.getExpression(i).visit(this);
+                    operandStack.box();
+                    mv.visitInsn(AASTORE);
+                }
+                controller.getOperandStack().remove(size);
+            } else {
+                List<Expression> expressions = expression.getExpressions();
+                List<String> methods = new ArrayList();
+                MethodVisitor oldMv = mv;
+                int index = 0;
+                while (index<size) {
+                    String methodName = "$createListEntry_" + controller.getNextHelperMethodIndex();
+                    methods.add(methodName);
+                    mv = controller.getClassVisitor().visitMethod(
+                            ACC_PRIVATE+ACC_STATIC+ACC_SYNTHETIC,
+                            methodName,
+                            "([Ljava/lang/Object;)V",
+                            null, null);
+                    controller.setMethodVisitor(mv);
+                    mv.visitCode();
+                    int methodBlockSize = Math.min(size-index, maxInit);
+                    int methodBlockEnd = index + methodBlockSize;
+                    for (; index < methodBlockEnd; index++) {
+                        mv.visitVarInsn(ALOAD, 0);
+                        mv.visitLdcInsn(index);
+                        expressions.get(index).visit(this);
+                        operandStack.box();
+                        mv.visitInsn(AASTORE);
+                    }
+                    operandStack.remove(methodBlockSize);
+                    mv.visitInsn(RETURN);
+                    mv.visitMaxs(0,0);
+                    mv.visitEnd();
+                }
+                mv = oldMv;
+                controller.setMethodVisitor(mv);
+                for (String methodName : methods) {
+                    mv.visitInsn(DUP);
+                    mv.visitMethodInsn(INVOKESTATIC, controller.getInternalClassName(), methodName, "([Ljava/lang/Object;)V", false);
+                }
+            }
+        } else {
+            despreadList(expression.getExpressions(), false);
+        }
+        createListMethod.call(controller.getMethodVisitor());
+        operandStack.push(ClassHelper.LIST_TYPE);
+    }
+
+    private static boolean containsOnlyConstants(ListExpression list) {
+        for (Expression exp : list.getExpressions()) {
+            if (exp instanceof ConstantExpression) continue;
+            return false;
+        }
+        return true;
+    }
+
+    public void visitGStringExpression(GStringExpression expression) {
+        MethodVisitor mv = controller.getMethodVisitor();
+
+        mv.visitTypeInsn(NEW, "org/codehaus/groovy/runtime/GStringImpl");
+        mv.visitInsn(DUP);
+
+        int size = expression.getValues().size();
+        BytecodeHelper.pushConstant(mv, size);
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+        for (int i = 0; i < size; i++) {
+            mv.visitInsn(DUP);
+            BytecodeHelper.pushConstant(mv, i);
+            expression.getValue(i).visit(this);
+            controller.getOperandStack().box();
+            mv.visitInsn(AASTORE);
+        }
+        controller.getOperandStack().remove(size);
+
+        List strings = expression.getStrings();
+        size = strings.size();
+        BytecodeHelper.pushConstant(mv, size);
+        mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+        for (int i = 0; i < size; i++) {
+            mv.visitInsn(DUP);
+            BytecodeHelper.pushConstant(mv, i);
+            controller.getOperandStack().pushConstant((ConstantExpression) strings.get(i));
+       

<TRUNCATED>

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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/FileReaderSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/FileReaderSource.java b/src/main/java/org/codehaus/groovy/control/io/FileReaderSource.java
new file mode 100644
index 0000000..6171f7a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/FileReaderSource.java
@@ -0,0 +1,91 @@
+/*
+ *  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.control.io;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URI;
+import java.nio.charset.Charset;
+
+/**
+ *  A ReaderSource for source files.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+public class FileReaderSource extends AbstractReaderSource {
+    private final File file;  // The File from which we produce Readers.
+    private final Charset UTF8 = Charset.forName("UTF-8");
+
+   /**
+    *  Creates the ReaderSource from a File descriptor.
+    * @param file script source file
+    * @param configuration configuration for compiling source
+    */
+    public FileReaderSource( File file, CompilerConfiguration configuration ) {
+       super( configuration );
+        this.file = file;
+    }
+
+    public File getFile() {
+        return file;
+    }
+
+    /**
+    *  Returns a new Reader on the underlying source object.  
+    */
+    public Reader getReader() throws IOException {
+       // we want to remove the BOM windows adds from a file if the encoding is UTF-8
+       // in other cases we depend on the charsets 
+       Charset cs = Charset.forName(configuration.getSourceEncoding());
+       InputStream in = new BufferedInputStream(new FileInputStream(file));
+       if (UTF8.name().equalsIgnoreCase(cs.name())) {
+           in.mark(3);
+           boolean hasBOM = true;
+           try {
+               int i = in.read();
+               hasBOM &= i == 0xEF;
+               i = in.read();
+               hasBOM &= i == 0xBB;
+               i = in.read();
+               hasBOM &= i == 0xFF;
+           } catch (IOException ioe) {
+               hasBOM= false;
+           }
+           if (!hasBOM) in.reset();
+       }
+       return new InputStreamReader( in, cs );
+    }
+
+    /**
+     * Returns a URI for the file of this source.
+     *
+     * @return URI for the file of this source.
+     */
+    public URI getURI() {
+        return file.toURI();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/InputStreamReaderSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/InputStreamReaderSource.java b/src/main/java/org/codehaus/groovy/control/io/InputStreamReaderSource.java
new file mode 100644
index 0000000..d018698
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/InputStreamReaderSource.java
@@ -0,0 +1,76 @@
+/*
+ *  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.control.io;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URI;
+
+/**
+ * A ReaderSource for source strings.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+public class InputStreamReaderSource extends AbstractReaderSource {
+    private InputStream stream;  // The InputStream from which we produce a Reader.
+
+    /**
+     * Creates the ReaderSource from a File descriptor.
+     *
+     * @param stream        stream containing source
+     * @param configuration configuration for compiling source
+     */
+    public InputStreamReaderSource(InputStream stream, CompilerConfiguration configuration) {
+        super(configuration);
+        this.stream = stream;
+    }
+
+    /**
+     * Returns a new Reader on the underlying source object.
+     */
+    public Reader getReader() throws IOException {
+        if (stream != null) {
+            Reader reader = new InputStreamReader(stream, configuration.getSourceEncoding());
+            stream = null;
+            return reader;
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if the source can be restarted (ie. if getReader()
+     * will return non-null on subsequent calls.
+     */
+    public boolean canReopenSource() {
+        return false;
+    }
+
+    /**
+     * TODO: Should return the URI for this source, but we can't know what it is here.
+     *
+     * @return null
+     */
+    public URI getURI() {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/NullWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/NullWriter.java b/src/main/java/org/codehaus/groovy/control/io/NullWriter.java
new file mode 100644
index 0000000..c783249
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/NullWriter.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.control.io;
+
+import java.io.Writer;
+
+/**
+ *  An Writer than eats its input.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+public class NullWriter extends Writer {
+    public static final NullWriter DEFAULT = new NullWriter();
+    
+    public void close() {}
+    
+    public void flush() {}
+    
+    public void write( char[] cbuf, int off, int len ) {}
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/ReaderSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/ReaderSource.java b/src/main/java/org/codehaus/groovy/control/io/ReaderSource.java
new file mode 100644
index 0000000..76ddd3c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/ReaderSource.java
@@ -0,0 +1,70 @@
+/*
+ *  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.control.io;
+
+import org.codehaus.groovy.control.HasCleanup;
+import org.codehaus.groovy.control.Janitor;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.net.URI;
+
+/**
+ *  An interface for things that can supply (and potentially resupply) a Reader
+ *  on a source stream.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+public interface ReaderSource extends HasCleanup {
+   /**
+    *  Returns a new Reader on the underlying source object.  Returns
+    *  null if the source can't be reopened.
+    * @throws java.io.IOException if there was an error opening for stream
+    * @return the reader to the resource
+    */
+    Reader getReader() throws IOException;
+    
+   /**
+    *  Returns true if the source can be restarted (ie. if getReader()
+    *  will return non-null on subsequent calls.
+    * @return true if the resource can be reopened for reading
+    */
+    boolean canReopenSource();
+    
+   /**
+    *  Returns a line from the source, or null, if unavailable.  If
+    *  you supply a Janitor, resources will be cached.
+    * @param lineNumber the number of the line of interest
+    * @param janitor helper to clean up afterwards
+    * @return the line of interest
+    */
+    String getLine( int lineNumber, Janitor janitor );
+    
+   /**
+    *  Cleans up any cached resources used by getLine().
+    */
+    void cleanup();
+
+    /**
+     * Returns a URI for this source.
+     *
+     * @since 2.3.0
+     */
+    URI getURI();
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/StringReaderSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/StringReaderSource.java b/src/main/java/org/codehaus/groovy/control/io/StringReaderSource.java
new file mode 100644
index 0000000..5e83de0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/StringReaderSource.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.control.io;
+
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+/**
+ *  A ReaderSource for source strings.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class StringReaderSource extends AbstractReaderSource {
+    private final String string;  // The String from which we produce Readers.
+
+   /**
+    * Creates the ReaderSource from a File descriptor.
+    *
+    * @param string string containing script source
+    * @param configuration configuration for compiling source
+    */
+   public StringReaderSource( String string, CompilerConfiguration configuration ) {
+       super( configuration );
+       this.string = string;
+   }
+    
+   /**
+    *  Returns a new Reader on the underlying source object.  
+    */
+   public Reader getReader() throws IOException {
+       return new StringReader( string );
+   }
+
+    /**
+     * Returns a Data URI (RFC 2397) containing the literal value of this source string.
+     *
+     * @return Data URI containing the literal value of this source string.
+     */
+    public URI getURI() {
+        try {
+            return new URI("data", "," + string, null);
+        } catch (URISyntaxException e) {
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/URLReaderSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/URLReaderSource.java b/src/main/java/org/codehaus/groovy/control/io/URLReaderSource.java
new file mode 100644
index 0000000..7c92559
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/URLReaderSource.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.control.io;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.control.CompilerConfiguration;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+/**
+ *  A ReaderSource for source files hosted at a URL.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+public class URLReaderSource extends AbstractReaderSource {
+    private final URL url;  // The URL from which we produce Readers.
+    
+   /**
+    *  Creates the ReaderSource from a File descriptor.
+    * @param url url pointing to script source
+    * @param configuration configuration for compiling source
+    */
+    public URLReaderSource( URL url, CompilerConfiguration configuration ) {
+       super( configuration );
+        this.url = url;
+    }
+
+   /**
+    *  Returns a new Reader on the underlying source object.  
+    */
+    public Reader getReader() throws IOException {
+       return new InputStreamReader( url.openStream(), configuration.getSourceEncoding() );
+    }
+
+    /**
+     * Returns a URI for the URL of this source.
+     *
+     * @return URI for the URL of this source.
+     */
+    public URI getURI() {
+        try {
+            return url.toURI();
+        } catch (URISyntaxException e) {
+            throw new GroovyRuntimeException("Unable to convert the URL <" + url + "> to a URI!", e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/io/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/io/package.html b/src/main/java/org/codehaus/groovy/control/io/package.html
new file mode 100644
index 0000000..9f92588
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/io/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.control.io.*</title>
+  </head>
+  <body>
+    <p>Internal classes for Groovier Input/Output.</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/messages/ExceptionMessage.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/messages/ExceptionMessage.java b/src/main/java/org/codehaus/groovy/control/messages/ExceptionMessage.java
new file mode 100644
index 0000000..363b9f5
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/messages/ExceptionMessage.java
@@ -0,0 +1,88 @@
+/*
+ *  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.control.messages;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.ProcessingUnit;
+
+import java.io.PrintWriter;
+
+
+
+/**
+ *  A class for error messages produced by the parser system.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class ExceptionMessage extends Message
+{
+    protected boolean verbose = true;
+
+    private Exception cause = null;   // The exception source of the message, if any
+    ProcessingUnit owner = null;
+
+    public ExceptionMessage( Exception cause, boolean v, ProcessingUnit owner )
+    {
+        this.verbose = v;
+        this.cause = cause;
+        this.owner = owner;
+    }
+    
+    
+   
+   /**
+    *  Returns the underlying Exception.
+    */
+
+    public Exception getCause()
+    {
+        return this.cause;
+    }
+    
+
+
+   /**
+    *  Writes out a nicely formatted summary of the exception. 
+    */
+    
+    public void write( PrintWriter output, Janitor janitor )
+    {
+        String description = "General error during " + owner.getPhaseDescription() + ": "; 
+        
+        String message = cause.getMessage();
+        if( message != null )
+        {
+            output.println( description + message );
+        }
+        else
+        {
+            output.println( description + cause );
+        }
+        output.println();
+
+        //if (verbose) {
+            cause.printStackTrace(output);
+        //}
+    }
+    
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/messages/LocatedMessage.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/messages/LocatedMessage.java b/src/main/java/org/codehaus/groovy/control/messages/LocatedMessage.java
new file mode 100644
index 0000000..d3368ac
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/messages/LocatedMessage.java
@@ -0,0 +1,80 @@
+/*
+ *  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.control.messages;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.CSTNode;
+
+import java.io.PrintWriter;
+
+
+
+/**
+ *  A base class for compilation messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class LocatedMessage extends SimpleMessage
+{
+    protected CSTNode context;  // The CSTNode that indicates the location to which the message applies
+    
+    public LocatedMessage( String message, CSTNode context, SourceUnit source ) 
+    {
+        super( message, source );
+        this.context = context;
+    }
+    
+    
+    public LocatedMessage( String message, Object data, CSTNode context, SourceUnit source ) 
+    {
+        super( message, data, source );
+        this.context = context;
+    }
+    
+    
+    public void write( PrintWriter writer, Janitor janitor )
+    {
+        if (owner instanceof SourceUnit) {
+            SourceUnit source = (SourceUnit) owner;
+
+            String name   = source.getName();
+            int    line   = context.getStartLine();
+            int    column = context.getStartColumn();
+            String sample = source.getSample( line, column, janitor );
+
+            if( sample != null )
+            {
+                writer.println( source.getSample(line, column, janitor) );
+            }
+
+            writer.println( name + ": " + line + ": " + this.message );
+            writer.println("");
+        } else {
+            writer.println( "<No Relevant Source>: " + this.message );
+            writer.println("");
+        }
+    }
+    
+}
+
+
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/messages/Message.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/messages/Message.java b/src/main/java/org/codehaus/groovy/control/messages/Message.java
new file mode 100644
index 0000000..0c2feab
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/messages/Message.java
@@ -0,0 +1,101 @@
+/*
+ *  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.control.messages;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.ProcessingUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+import java.io.PrintWriter;
+
+
+
+/**
+ *  A base class for compilation messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public abstract class Message
+{
+    
+    
+   /**
+    *  Writes the message to the specified PrintWriter.  The supplied
+    *  ProcessingUnit is the unit that holds this Message.
+    */
+    
+    public abstract void write( PrintWriter writer, Janitor janitor );
+    
+    
+   /**
+    *  A synonym for write( writer, owner, null ).
+    */
+    
+    public final void write( PrintWriter writer)
+    {
+        write( writer,  null );
+    }
+    
+    
+    
+  //---------------------------------------------------------------------------
+  // FACTORY METHODS
+    
+    
+   /**
+    *  Creates a new Message from the specified text.
+    */
+    
+    public static Message create( String text, ProcessingUnit owner )
+    {
+        return new SimpleMessage( text, owner );
+    }
+    
+    
+          
+   /**
+    *  Creates a new Message from the specified text.
+    */
+     
+    public static Message create( String text, Object data, ProcessingUnit owner  )
+    {
+        return new SimpleMessage( text, data, owner);
+    }
+     
+     
+           
+   /**
+    *  Creates a new Message from the specified SyntaxException.
+    */
+      
+    public static Message create( SyntaxException error, SourceUnit owner )
+    {
+        return new SyntaxErrorMessage( error, owner );
+    }
+      
+    
+      
+    
+}
+
+
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/messages/SimpleMessage.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/messages/SimpleMessage.java b/src/main/java/org/codehaus/groovy/control/messages/SimpleMessage.java
new file mode 100644
index 0000000..2cbc9d8
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/messages/SimpleMessage.java
@@ -0,0 +1,77 @@
+/*
+ *  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.control.messages;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.ProcessingUnit;
+import org.codehaus.groovy.control.SourceUnit;
+
+import java.io.PrintWriter;
+
+
+
+/**
+ *  A base class for compilation messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class SimpleMessage extends Message
+{
+    protected String message;  // Message text
+    protected Object data;     // Data, when the message text is an I18N identifier
+    protected ProcessingUnit owner;
+    
+    public SimpleMessage( String message, ProcessingUnit source ) 
+    {
+        this( message, null, source );
+    }
+    
+    public SimpleMessage( String message, Object data, ProcessingUnit source )
+    {
+        this.message = message;
+        this.data    = null;
+        this.owner = source;
+    }
+    
+    
+    public void write( PrintWriter writer, Janitor janitor )
+    {
+        if( owner instanceof SourceUnit )
+        {
+            String name = ((SourceUnit)owner).getName();
+            writer.println( "" + name + ": " + message );
+        }
+        else
+        {
+            writer.println( message );
+        }
+    }
+    
+    
+    public String getMessage()
+    {
+        return message;
+    }
+    
+}
+
+
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/messages/SyntaxErrorMessage.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/messages/SyntaxErrorMessage.java b/src/main/java/org/codehaus/groovy/control/messages/SyntaxErrorMessage.java
new file mode 100644
index 0000000..be9339d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/messages/SyntaxErrorMessage.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.control.messages;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+import java.io.PrintWriter;
+
+/**
+ * A class for error messages produced by the parser system.
+ *
+ * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class SyntaxErrorMessage extends Message {
+    protected SyntaxException cause;
+    protected SourceUnit source;
+    
+    public SyntaxErrorMessage(SyntaxException cause, SourceUnit source) {
+        this.cause = cause;
+        this.source = source;
+        cause.setSourceLocator(source.getName());
+    }
+
+    /**
+     * Returns the underlying SyntaxException.
+     */
+
+    public SyntaxException getCause() {
+        return this.cause;
+    }
+
+    /**
+     * Writes out a nicely formatted summary of the syntax error.
+     */
+
+    public void write(PrintWriter output, Janitor janitor) {
+        String name = source.getName();
+        int line = getCause().getStartLine();
+        int column = getCause().getStartColumn();
+        String sample = source.getSample(line, column, janitor);
+
+        output.print(name + ": " + line + ": " + getCause().getMessage());
+        if (sample != null) {
+            output.println();
+            output.print(sample);
+            output.println();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/messages/WarningMessage.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/messages/WarningMessage.java b/src/main/java/org/codehaus/groovy/control/messages/WarningMessage.java
new file mode 100644
index 0000000..969f29f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/messages/WarningMessage.java
@@ -0,0 +1,118 @@
+/*
+ *  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.control.messages;
+
+import org.codehaus.groovy.control.Janitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.CSTNode;
+
+import java.io.PrintWriter;
+
+
+
+/**
+ *  A class for warning messages.
+ *
+ *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
+ */
+
+public class WarningMessage extends LocatedMessage
+{
+  //---------------------------------------------------------------------------
+  // WARNING LEVELS
+
+    public static final int NONE            = 0;  // For querying, ignore all errors
+    public static final int LIKELY_ERRORS   = 1;  // Warning indicates likely error
+    public static final int POSSIBLE_ERRORS = 2;  // Warning indicates possible error
+    public static final int PARANOIA        = 3;  // Warning indicates paranoia on the part of the compiler
+    
+    
+   /**
+    *  Returns true if a warning would be relevant to the specified level.
+    */
+    
+    public static boolean isRelevant( int actual, int limit )
+    {
+        return actual <= limit;
+    }
+    
+    
+    
+   /**
+    *  Returns true if this message is as or more important than the 
+    *  specified importance level.
+    */
+    
+    public boolean isRelevant( int importance )
+    {
+        return isRelevant( this.importance, importance );
+    }
+    
+    
+    
+  //---------------------------------------------------------------------------
+  // CONSTRUCTION AND DATA ACCESS
+
+    private final int importance;  // The warning level, for filtering
+    
+    
+   /**
+    *  Creates a new warning message.
+    * 
+    *  @param importance the warning level 
+    *  @param message    the message text
+    *  @param context    context information for locating the offending source text
+    */
+     
+    public WarningMessage( int importance, String message, CSTNode context, SourceUnit owner )
+    {
+        super( message, context, owner );
+        this.importance = importance;
+    }
+
+    
+    
+   /**
+    *  Creates a new warning message.
+    *
+    *  @param importance the warning level 
+    *  @param message    the message text
+    *  @param data       additional data needed when generating the message
+    *  @param context    context information for locating the offending source text
+    */
+     
+    public WarningMessage( int importance, String message, Object data, CSTNode context, SourceUnit owner )
+    {
+        super( message, data, context, owner );
+        this.importance = importance;
+    }
+    
+    
+    public void write( PrintWriter writer, Janitor janitor )
+    {
+        writer.print( "warning: " );
+        super.write( writer, janitor );
+    }
+
+     
+     
+}
+
+
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/messages/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/messages/package.html b/src/main/java/org/codehaus/groovy/control/messages/package.html
new file mode 100644
index 0000000..412a4df
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/messages/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.control.messages.*</title>
+  </head>
+  <body>
+    <p>Error message classes.</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/control/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/control/package.html b/src/main/java/org/codehaus/groovy/control/package.html
new file mode 100644
index 0000000..4a9ec85
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.control.*</title>
+  </head>
+  <body>
+    <p>Compiler control classes.</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/package.html b/src/main/java/org/codehaus/groovy/package.html
new file mode 100644
index 0000000..1ff6757
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.*</title>
+  </head>
+  <body>
+    <p>Groovy Language for the JVM</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/plugin/GroovyRunner.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/plugin/GroovyRunner.java b/src/main/java/org/codehaus/groovy/plugin/GroovyRunner.java
new file mode 100644
index 0000000..40bd257
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/plugin/GroovyRunner.java
@@ -0,0 +1,28 @@
+/*
+ *  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.plugin;
+
+/**
+ * Classes which can run scripts should implement this interface.
+ *
+ * @deprecated use {@link org.apache.groovy.plugin.GroovyRunner}
+ */
+@Deprecated
+public interface GroovyRunner extends org.apache.groovy.plugin.GroovyRunner {
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/AccessPermissionChecker.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/AccessPermissionChecker.java b/src/main/java/org/codehaus/groovy/reflection/AccessPermissionChecker.java
new file mode 100644
index 0000000..dc8194d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/AccessPermissionChecker.java
@@ -0,0 +1,84 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.GroovyObject;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ReflectPermission;
+import java.security.AccessControlException;
+
+final class AccessPermissionChecker {
+
+    private static final ReflectPermission REFLECT_PERMISSION = new ReflectPermission("suppressAccessChecks");
+
+    private AccessPermissionChecker() {
+    }
+
+    private static void checkAccessPermission(Class<?> declaringClass, final int modifiers, boolean isAccessible) {
+        final SecurityManager securityManager = System.getSecurityManager();
+        if (securityManager != null && isAccessible) {
+            if (((modifiers & Modifier.PRIVATE) != 0
+                    || ((modifiers & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0
+                    && packageCanNotBeAddedAnotherClass(declaringClass)))
+                    && !GroovyObject.class.isAssignableFrom(declaringClass)) {
+                securityManager.checkPermission(REFLECT_PERMISSION);
+            } else if ((modifiers & (Modifier.PROTECTED)) != 0 && declaringClass.equals(ClassLoader.class)) {
+                securityManager.checkCreateClassLoader();
+            }
+        }
+    }
+
+    private static boolean packageCanNotBeAddedAnotherClass(Class<?> declaringClass) {
+        return declaringClass.getName().startsWith("java.");
+    }
+
+    static void checkAccessPermission(Method method) {
+        try {
+            checkAccessPermission(method.getDeclaringClass(), method.getModifiers(), method.isAccessible());
+        } catch (AccessControlException e) {
+            throw createCacheAccessControlExceptionOf(method, e);
+        }
+    }
+
+    private static CacheAccessControlException createCacheAccessControlExceptionOf(Method method, AccessControlException e) {
+        return new CacheAccessControlException(
+                "Groovy object can not access method " + method.getName()
+                        + " cacheAccessControlExceptionOf class " + method.getDeclaringClass().getName()
+                        + " with modifiers \"" + Modifier.toString(method.getModifiers()) + "\"", e);
+    }
+
+    static void checkAccessPermission(Field field) {
+        try {
+            checkAccessPermission(field.getDeclaringClass(), field.getModifiers(), field.isAccessible());
+        } catch (AccessControlException e) {
+            throw createCacheAccessControlExceptionOf(field, e);
+        }
+    }
+
+    private static CacheAccessControlException createCacheAccessControlExceptionOf(Field field, AccessControlException e) {
+        return new CacheAccessControlException(
+                "Groovy object can not access field " + field.getName()
+                        + " cacheAccessControlExceptionOf class " + field.getDeclaringClass().getName()
+                        + " with modifiers \"" + Modifier.toString(field.getModifiers()) + "\"", e);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/CacheAccessControlException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/CacheAccessControlException.java b/src/main/java/org/codehaus/groovy/reflection/CacheAccessControlException.java
new file mode 100644
index 0000000..c538813
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/CacheAccessControlException.java
@@ -0,0 +1,27 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.GroovyRuntimeException;
+
+public class CacheAccessControlException extends GroovyRuntimeException {
+    public CacheAccessControlException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/CachedClass.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/CachedClass.java b/src/main/java/org/codehaus/groovy/reflection/CachedClass.java
new file mode 100644
index 0000000..c4cb542
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/CachedClass.java
@@ -0,0 +1,542 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.Closure;
+import groovy.lang.ExpandoMetaClass;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaClassImpl;
+import groovy.lang.MetaMethod;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.runtime.callsite.CallSiteClassLoader;
+import org.codehaus.groovy.runtime.metaclass.ClosureMetaClass;
+import org.codehaus.groovy.util.FastArray;
+import org.codehaus.groovy.util.LazyReference;
+import org.codehaus.groovy.util.ReferenceBundle;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class CachedClass {
+    private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
+    private final Class cachedClass;
+    public ClassInfo classInfo;
+    
+    private static ReferenceBundle softBundle = ReferenceBundle.getSoftBundle();
+
+    private final LazyReference<CachedField[]> fields = new LazyReference<CachedField[]>(softBundle) {
+        public CachedField[] initValue() {
+            final Field[] declaredFields = (Field[])
+               AccessController.doPrivileged(new PrivilegedAction<Field[]>() {
+                   public Field[] run() {
+                       Field[] df = getTheClass().getDeclaredFields();
+                       df = (Field[]) makeAccessible(df);
+                       return df;                                                   
+                   }
+               });
+            CachedField [] fields = new CachedField[declaredFields.length];
+            for (int i = 0; i != fields.length; ++i)
+                fields[i] = new CachedField(declaredFields[i]);
+            return fields;
+        }
+    };
+
+    private final LazyReference<CachedConstructor[]> constructors = new LazyReference<CachedConstructor[]>(softBundle) {
+        public CachedConstructor[] initValue() {
+            final Constructor[] declaredConstructors = (Constructor[])
+               AccessController.doPrivileged(new PrivilegedAction/*<Constructor[]>*/() {
+                   public /*Constructor[]*/ Object run() {
+                       return getTheClass().getDeclaredConstructors();
+                   }
+               });
+            CachedConstructor [] constructors = new CachedConstructor[declaredConstructors.length];
+            for (int i = 0; i != constructors.length; ++i)
+                constructors[i] = new CachedConstructor(CachedClass.this, declaredConstructors[i]);
+            return constructors;
+        }
+    };
+
+    // to be run in PrivilegedAction!
+    private static AccessibleObject[] makeAccessible(final AccessibleObject[] aoa) {
+        try {
+            AccessibleObject.setAccessible(aoa, true);
+            return aoa;
+        } catch (Throwable outer) {
+            // swallow for strict security managers, module systems, android or others,
+            // but try one-by-one to get the allowed ones at least
+            final ArrayList<AccessibleObject> ret = new ArrayList<>(aoa.length);
+            for (final AccessibleObject ao : aoa) {
+                try {
+                    ao.setAccessible(true);
+                    ret.add(ao);
+                } catch (Throwable inner) {
+                    // swallow for strict security managers, module systems, android or others
+                }
+            }
+            return ret.toArray((AccessibleObject[]) Array.newInstance(aoa.getClass().getComponentType(), ret.size()));
+        }
+    }
+
+    private final LazyReference<CachedMethod[]> methods = new LazyReference<CachedMethod[]>(softBundle) {
+        public CachedMethod[] initValue() {
+            final Method[] declaredMethods = (Method[])
+               AccessController.doPrivileged(new PrivilegedAction/*<Method[]>*/() {
+                   public /*Method[]*/ Object run() {
+                       try {
+                           Method[] dm = getTheClass().getDeclaredMethods();
+                           dm = (Method[]) makeAccessible(dm);
+                           return dm;
+                       } catch (Throwable e) {
+                           // Typically, Android can throw ClassNotFoundException
+                           return EMPTY_METHOD_ARRAY;
+                       }
+                   }
+               });
+            List<CachedMethod> methods = new ArrayList<CachedMethod>(declaredMethods.length);
+            List<CachedMethod> mopMethods = new ArrayList<CachedMethod>(declaredMethods.length);
+            for (int i = 0; i != declaredMethods.length; ++i) {
+                final CachedMethod cachedMethod = new CachedMethod(CachedClass.this, declaredMethods[i]);
+                final String name = cachedMethod.getName();
+
+                if (declaredMethods[i].isBridge() || name.indexOf('+') >= 0) {
+                    // Skip Synthetic methods inserted by JDK 1.5 compilers and later
+                    continue;
+                } /*else if (Modifier.isAbstract(reflectionMethod.getModifiers())) {
+                   continue;
+                }*/
+
+                if (name.startsWith("this$") || name.startsWith("super$"))
+                  mopMethods.add(cachedMethod);
+                else
+                  methods.add(cachedMethod);
+            }
+            CachedMethod [] resMethods = methods.toArray(new CachedMethod[methods.size()]);
+            Arrays.sort(resMethods);
+
+            final CachedClass superClass = getCachedSuperClass();
+            if (superClass != null) {
+                superClass.getMethods();
+                final CachedMethod[] superMopMethods = superClass.mopMethods;
+                for (int i = 0; i != superMopMethods.length; ++i)
+                  mopMethods.add(superMopMethods[i]);
+            }
+            CachedClass.this.mopMethods = mopMethods.toArray(new CachedMethod[mopMethods.size()]);
+            Arrays.sort(CachedClass.this.mopMethods, CachedMethodComparatorByName.INSTANCE);
+
+            return resMethods;
+        }
+    };
+
+    private final LazyReference<CachedClass> cachedSuperClass = new LazyReference<CachedClass>(softBundle) {
+        public CachedClass initValue() {
+            if (!isArray)
+              return ReflectionCache.getCachedClass(getTheClass().getSuperclass());
+            else
+              if (cachedClass.getComponentType().isPrimitive() || cachedClass.getComponentType() == Object.class)
+                return ReflectionCache.OBJECT_CLASS;
+              else
+                return ReflectionCache.OBJECT_ARRAY_CLASS;
+        }
+    };
+
+    private final LazyReference<CallSiteClassLoader> callSiteClassLoader = new LazyReference<CallSiteClassLoader>(softBundle) {
+        public CallSiteClassLoader initValue() {
+            return
+               AccessController.doPrivileged(new PrivilegedAction<CallSiteClassLoader>() {
+                   public CallSiteClassLoader run() {
+                       return new CallSiteClassLoader(CachedClass.this.cachedClass);
+                   }
+               });
+        }
+    };
+
+    private final LazyReference<LinkedList<ClassInfo>> hierarchy = new LazyReference<LinkedList<ClassInfo>>(softBundle) {
+        public LinkedList<ClassInfo> initValue() {
+            Set<ClassInfo> res = new LinkedHashSet<ClassInfo> ();
+
+            res.add(classInfo);
+
+            for (CachedClass iface : getDeclaredInterfaces())
+              res.addAll(iface.getHierarchy());
+
+            final CachedClass superClass = getCachedSuperClass();
+            if (superClass != null)
+              res.addAll(superClass.getHierarchy());
+
+            if (isInterface)
+              res.add(ReflectionCache.OBJECT_CLASS.classInfo);
+
+            return new LinkedList<ClassInfo> (res);
+        }
+    };
+
+    static final MetaMethod[] EMPTY = new MetaMethod[0];
+
+    int hashCode;
+
+    public  CachedMethod [] mopMethods;
+    public static final CachedClass[] EMPTY_ARRAY = new CachedClass[0];
+
+    private final LazyReference<Set<CachedClass>> declaredInterfaces = new LazyReference<Set<CachedClass>> (softBundle) {
+        public Set<CachedClass> initValue() {
+            Set<CachedClass> res = new HashSet<CachedClass> (0);
+
+            Class[] classes = getTheClass().getInterfaces();
+            for (Class cls : classes) {
+                res.add(ReflectionCache.getCachedClass(cls));
+            }
+            return res;
+        }
+    };
+
+    private final LazyReference<Set<CachedClass>> interfaces = new LazyReference<Set<CachedClass>> (softBundle) {
+        public Set<CachedClass> initValue() {
+            Set<CachedClass> res = new HashSet<CachedClass> (0);
+
+            if (getTheClass().isInterface())
+              res.add(CachedClass.this);
+
+            Class[] classes = getTheClass().getInterfaces();
+            for (Class cls : classes) {
+                final CachedClass aClass = ReflectionCache.getCachedClass(cls);
+                if (!res.contains(aClass))
+                    res.addAll(aClass.getInterfaces());
+            }
+
+            final CachedClass superClass = getCachedSuperClass();
+            if (superClass != null)
+              res.addAll(superClass.getInterfaces());
+
+            return res;
+        }
+    };
+
+    public final boolean isArray;
+    public final boolean isPrimitive;
+    public final int modifiers;
+    int distance = -1;
+    public final boolean isInterface;
+    public final boolean isNumber;
+
+    public CachedClass(Class klazz, ClassInfo classInfo) {
+        cachedClass = klazz;
+        this.classInfo = classInfo;
+        isArray = klazz.isArray();
+        isPrimitive = klazz.isPrimitive();
+        modifiers = klazz.getModifiers();
+        isInterface = klazz.isInterface();
+        isNumber = Number.class.isAssignableFrom(klazz);
+
+        for (CachedClass inf : getInterfaces()) {
+            ReflectionCache.isAssignableFrom(klazz, inf.cachedClass);
+        }
+
+        for (CachedClass cur = this; cur != null; cur = cur.getCachedSuperClass()) {
+            ReflectionCache.setAssignableFrom(cur.cachedClass, klazz);
+        }
+    }
+
+    public CachedClass getCachedSuperClass() {
+        return cachedSuperClass.get();
+    }
+
+    public Set<CachedClass> getInterfaces() {
+        return interfaces.get();
+    }
+
+    public Set<CachedClass> getDeclaredInterfaces() {
+        return declaredInterfaces.get();
+    }
+
+    public CachedMethod[] getMethods() {
+        return methods.get();
+    }
+
+    public CachedField[] getFields() {
+        return fields.get();
+    }
+
+    public CachedConstructor[] getConstructors() {
+        return constructors.get();
+    }
+
+    public CachedMethod searchMethods(String name, CachedClass[] parameterTypes) {
+        CachedMethod[] methods = getMethods();
+
+        CachedMethod res = null;
+        for (CachedMethod m : methods) {
+            if (m.getName().equals(name)
+                    && ReflectionCache.arrayContentsEq(parameterTypes, m.getParameterTypes())
+                    && (res == null || res.getReturnType().isAssignableFrom(m.getReturnType())))
+                res = m;
+        }
+
+        return res;
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    public Object coerceArgument(Object argument) {
+        return argument;
+    }
+    
+    public int getSuperClassDistance() {
+        if (distance>=0) return distance;
+
+        int distance = 0;
+        for (Class klazz= getTheClass(); klazz != null; klazz = klazz.getSuperclass()) {
+            distance++;
+        }
+        this.distance = distance;
+        return distance;
+    }
+
+    public int hashCode() {
+        if (hashCode == 0) {
+          hashCode = super.hashCode();
+          if (hashCode == 0)
+            hashCode = 0xcafebebe;
+        }
+        return hashCode;
+    }
+
+    public boolean isPrimitive() {
+        return isPrimitive;
+    }
+
+    public boolean isVoid() {
+        return getTheClass() == void.class;
+    }
+    
+    public boolean isInterface() {
+        return isInterface;
+    }
+
+    public String getName() {
+        return getTheClass().getName();
+    }
+
+    public String getTypeDescription() {
+        return BytecodeHelper.getTypeDescription(getTheClass());
+    }
+
+    public final Class getTheClass() {
+        return cachedClass;
+    }
+
+    public MetaMethod[] getNewMetaMethods() {
+        List<MetaMethod> arr = new ArrayList<MetaMethod>();
+        arr.addAll(Arrays.asList(classInfo.newMetaMethods));
+
+        final MetaClass metaClass = classInfo.getStrongMetaClass();
+        if (metaClass != null && metaClass instanceof ExpandoMetaClass) {
+            arr.addAll(((ExpandoMetaClass)metaClass).getExpandoMethods());
+        }
+
+        if (isInterface) {
+            MetaClass mc = ReflectionCache.OBJECT_CLASS.classInfo.getStrongMetaClass();
+            addSubclassExpandos(arr, mc);
+        }
+        else {
+            for (CachedClass cls = this; cls != null; cls = cls.getCachedSuperClass()) {
+                MetaClass mc = cls.classInfo.getStrongMetaClass();
+                addSubclassExpandos(arr, mc);
+            }
+        }
+
+        for (CachedClass inf : getInterfaces()) {
+            MetaClass mc = inf.classInfo.getStrongMetaClass();
+            addSubclassExpandos(arr, mc);
+        }
+
+        return arr.toArray(new MetaMethod[arr.size()]);
+    }
+
+    private void addSubclassExpandos(List<MetaMethod> arr, MetaClass mc) {
+        if (mc != null && mc instanceof ExpandoMetaClass) {
+            ExpandoMetaClass emc = (ExpandoMetaClass) mc;
+            for (Object mm : emc.getExpandoSubclassMethods()) {
+                if (mm instanceof MetaMethod) {
+                    MetaMethod method = (MetaMethod) mm;
+                    if (method.getDeclaringClass() == this)
+                      arr.add(method);
+                }
+                else {
+                    FastArray farr = (FastArray) mm;
+                    for (int i = 0; i != farr.size; ++i) {
+                        MetaMethod method = (MetaMethod) farr.get(i);
+                        if (method.getDeclaringClass() == this)
+                          arr.add(method);
+                    }
+                }
+            }
+        }
+    }
+
+    public void setNewMopMethods(List<MetaMethod> arr) {
+        final MetaClass metaClass = classInfo.getStrongMetaClass();
+        if (metaClass != null) {
+          if (metaClass.getClass() == MetaClassImpl.class) {
+              classInfo.setStrongMetaClass(null);
+              updateSetNewMopMethods(arr);
+              classInfo.setStrongMetaClass(new MetaClassImpl(metaClass.getTheClass()));
+              return;
+          }
+
+          if (metaClass.getClass() == ExpandoMetaClass.class) {
+              classInfo.setStrongMetaClass(null);
+              updateSetNewMopMethods(arr);
+              ExpandoMetaClass newEmc = new ExpandoMetaClass(metaClass.getTheClass());
+              newEmc.initialize();
+              classInfo.setStrongMetaClass(newEmc);
+              return;
+          }
+
+          throw new GroovyRuntimeException("Can't add methods to class " + getTheClass().getName() + ". Strong custom meta class already set.");
+        }
+
+        classInfo.setWeakMetaClass(null);
+        updateSetNewMopMethods(arr);
+    }
+
+    private void updateSetNewMopMethods(List<MetaMethod> arr) {
+        if (arr != null) {
+            final MetaMethod[] metaMethods = arr.toArray(new MetaMethod[arr.size()]);
+            classInfo.dgmMetaMethods = metaMethods;
+            classInfo.newMetaMethods = metaMethods;
+        }
+        else
+            classInfo.newMetaMethods = classInfo.dgmMetaMethods;
+    }
+
+    public void addNewMopMethods(List<MetaMethod> arr) {
+        final MetaClass metaClass = classInfo.getStrongMetaClass();
+        if (metaClass != null) {
+          if (metaClass.getClass() == MetaClassImpl.class) {
+              classInfo.setStrongMetaClass(null);
+              List<MetaMethod> res = new ArrayList<MetaMethod>();
+              Collections.addAll(res, classInfo.newMetaMethods);
+              res.addAll(arr);
+              updateSetNewMopMethods(res);
+              MetaClassImpl answer = new MetaClassImpl(((MetaClassImpl)metaClass).getRegistry(),metaClass.getTheClass());
+              answer.initialize();
+              classInfo.setStrongMetaClass(answer);
+              return;
+          }
+
+          if (metaClass.getClass() == ExpandoMetaClass.class) {
+              ExpandoMetaClass emc = (ExpandoMetaClass)metaClass;
+              classInfo.setStrongMetaClass(null);
+              updateAddNewMopMethods(arr);
+              ExpandoMetaClass newEmc = new ExpandoMetaClass(metaClass.getTheClass());
+              for (MetaMethod mm : emc.getExpandoMethods()) {
+                  newEmc.registerInstanceMethod(mm);
+              }
+              newEmc.initialize();
+              classInfo.setStrongMetaClass(newEmc);
+              return;
+          }
+
+          throw new GroovyRuntimeException("Can't add methods to class " + getTheClass().getName() + ". Strong custom meta class already set.");
+        }
+
+        classInfo.setWeakMetaClass(null);
+
+        updateAddNewMopMethods(arr);
+    }
+
+    private void updateAddNewMopMethods(List<MetaMethod> arr) {
+        List<MetaMethod> res = new ArrayList<MetaMethod>();
+        res.addAll(Arrays.asList(classInfo.newMetaMethods));
+        res.addAll(arr);
+        classInfo.newMetaMethods = res.toArray(new MetaMethod[res.size()]);
+        Class theClass = classInfo.getCachedClass().getTheClass();
+        if (theClass==Closure.class || theClass==Class.class) {
+            ClosureMetaClass.resetCachedMetaClasses();
+        }
+    }
+
+    public boolean isAssignableFrom(Class argument) {
+        return argument == null || ReflectionCache.isAssignableFrom(getTheClass(), argument);
+    }
+
+    public boolean isDirectlyAssignable(Object argument) {
+        return ReflectionCache.isAssignableFrom(getTheClass(), argument.getClass());
+    }
+
+    public CallSiteClassLoader getCallSiteLoader() {
+        return callSiteClassLoader.get();
+    }
+
+    public Collection<ClassInfo> getHierarchy() {
+        return hierarchy.get();
+    }
+
+    public static class CachedMethodComparatorByName implements Comparator {
+        public static final Comparator INSTANCE = new CachedMethodComparatorByName();
+
+        public int compare(Object o1, Object o2) {
+              return ((CachedMethod)o1).getName().compareTo(((CachedMethod)o2).getName());
+        }
+    }
+
+    public static class CachedMethodComparatorWithString implements Comparator {
+        public static final Comparator INSTANCE = new CachedMethodComparatorWithString();
+
+        public int compare(Object o1, Object o2) {
+            if (o1 instanceof CachedMethod)
+              return ((CachedMethod)o1).getName().compareTo((String)o2);
+            else
+              return ((String)o1).compareTo(((CachedMethod)o2).getName());
+        }
+    }
+
+    public String toString() {
+        return cachedClass.toString();
+    }
+
+    /**
+     * compatibility method
+     * @return this
+     */
+    public CachedClass getCachedClass () {
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java b/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java
new file mode 100644
index 0000000..74d9b71
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/CachedConstructor.java
@@ -0,0 +1,116 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.InvokerInvocationException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * @author Alex.Tkachman
+ */
+public class CachedConstructor extends ParameterTypes {
+    CachedClass clazz;
+
+    public final Constructor cachedConstructor;
+
+    public CachedConstructor(CachedClass clazz, final Constructor c) {
+        this.cachedConstructor = c;
+        this.clazz = clazz;
+        try {
+            AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    c.setAccessible(true);
+                    return null;
+                }
+            });
+        } catch (SecurityException e) {
+            // IGNORE
+        } catch (RuntimeException re) {
+            // test for JDK9 JIGSAW
+            if (!"java.lang.reflect.InaccessibleObjectException".equals(re.getClass().getName())) throw re;
+            // else IGNORE
+        }
+    }
+
+    public CachedConstructor(Constructor c) {
+        this(ReflectionCache.getCachedClass(c.getDeclaringClass()), c);
+    }
+
+    protected Class[] getPT() {
+        return cachedConstructor.getParameterTypes();
+    }
+
+    public static CachedConstructor find(Constructor constructor) {
+        CachedConstructor[] constructors = ReflectionCache.getCachedClass(constructor.getDeclaringClass()).getConstructors();
+        for (int i = 0; i < constructors.length; i++) {
+            CachedConstructor cachedConstructor = constructors[i];
+            if (cachedConstructor.cachedConstructor.equals(constructor))
+                return cachedConstructor;
+        }
+        throw new RuntimeException("Couldn't find method: " + constructor);
+    }
+
+    public Object doConstructorInvoke(Object[] argumentArray) {
+        argumentArray = coerceArgumentsToClasses(argumentArray);
+        return invoke(argumentArray);
+    }
+
+    public Object invoke(Object[] argumentArray) {
+        Constructor constr = cachedConstructor;
+        try {
+            return constr.newInstance(argumentArray);
+        } catch (InvocationTargetException e) {
+            throw e.getCause() instanceof RuntimeException ? (RuntimeException)e.getCause() : new InvokerInvocationException(e);
+        } catch (IllegalArgumentException e) {
+            throw createException("failed to invoke constructor: ", constr, argumentArray, e, false);
+        } catch (IllegalAccessException e) {
+            throw createException("could not access constructor: ", constr, argumentArray, e, false);
+        } catch (Exception e) {
+            if (e instanceof RuntimeException)
+                throw (RuntimeException)e;
+            else
+                throw createException("failed to invoke constructor: ", constr, argumentArray, e, true);
+        }
+    }
+
+    private static GroovyRuntimeException createException(String init, Constructor constructor, Object[] argumentArray, Throwable e, boolean setReason) {
+        return new GroovyRuntimeException(
+                init
+                        + constructor
+                        + " with arguments: "
+                        + InvokerHelper.toString(argumentArray)
+                        + " reason: "
+                        + e,
+                setReason ? e : null);
+    }
+
+    public int getModifiers () {
+        return cachedConstructor.getModifiers();
+    }
+    
+    public CachedClass getCachedClass() {
+        return clazz;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/reflection/CachedField.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/reflection/CachedField.java b/src/main/java/org/codehaus/groovy/reflection/CachedField.java
new file mode 100644
index 0000000..a5ce0c2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/reflection/CachedField.java
@@ -0,0 +1,81 @@
+/*
+ *  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.reflection;
+
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaProperty;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+public class CachedField extends MetaProperty {
+    public final Field field;
+
+    public CachedField(Field field) {
+        super (field.getName(), field.getType());
+        this.field = field;
+    }
+
+    public boolean isStatic() {
+        return Modifier.isStatic(getModifiers());
+    }
+
+    public boolean isFinal() {
+        return Modifier.isFinal(getModifiers());
+    }
+
+    public int getModifiers() {
+        return field.getModifiers();
+    }
+
+    /**
+     * @return the property of the given object
+     * @throws RuntimeException if the property could not be evaluated
+     */
+    public Object getProperty(final Object object) {
+        AccessPermissionChecker.checkAccessPermission(field);
+        try {
+            return field.get(object);
+        } catch (IllegalAccessException e) {
+            throw new GroovyRuntimeException("Cannot get the property '" + name + "'.", e);
+        }
+    }
+
+    /**
+     * Sets the property on the given object to the new value
+     *
+     * @param object on which to set the property
+     * @param newValue the new value of the property
+     * @throws RuntimeException if the property could not be set
+     */
+    public void setProperty(final Object object, Object newValue) {
+        AccessPermissionChecker.checkAccessPermission(field);
+        final Object goalValue = DefaultTypeTransformation.castToType(newValue, field.getType());
+
+        if (isFinal()) {
+            throw new GroovyRuntimeException("Cannot set the property '" + name + "' because the backing field is final.");
+        }
+        try {
+            field.set(object, goalValue);
+        } catch (IllegalAccessException ex) {
+            throw new GroovyRuntimeException("Cannot set the property '" + name + "'.", ex);
+        }
+    }
+}


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

Posted by cc...@apache.org.
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);
+        }
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/expr/VariableExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/VariableExpression.java b/src/main/java/org/codehaus/groovy/ast/expr/VariableExpression.java
new file mode 100644
index 0000000..4ddf07b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/VariableExpression.java
@@ -0,0 +1,199 @@
+/*
+ *  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.expr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Variable;
+
+/**
+ * Represents a local variable name, the simplest form of expression. e.g.&#160;"foo".
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class VariableExpression extends Expression implements Variable {
+    // The following fields are only used internally; every occurrence of a user-defined expression of the same kind
+    // has its own instance so as to preserve line information. Consequently, to test for such an expression, don't
+    // compare against the field but call isXXXExpression() instead.
+    public static final VariableExpression THIS_EXPRESSION = new VariableExpression("this", ClassHelper.DYNAMIC_TYPE);
+    public static final VariableExpression SUPER_EXPRESSION = new VariableExpression("super", ClassHelper.DYNAMIC_TYPE);
+
+    private final String variable;
+    private int modifiers;
+    private boolean inStaticContext;
+    private boolean isDynamicTyped=false;
+    private Variable accessedVariable;
+    boolean closureShare=false;
+    boolean useRef=false;
+    private final ClassNode originType;
+
+    public Variable getAccessedVariable() {
+        return accessedVariable;
+    }
+
+    public void setAccessedVariable(Variable origin) {
+        this.accessedVariable = origin;
+    }
+
+    public VariableExpression(String variable, ClassNode type) {
+        this.variable = variable;
+        originType = type;
+        setType(ClassHelper.getWrapper(type));
+    }
+    
+    public VariableExpression(String variable) {
+        this(variable, ClassHelper.DYNAMIC_TYPE);
+    }
+    
+    public VariableExpression(Variable variable) {
+        this(variable.getName(), variable.getOriginType());
+        setAccessedVariable(variable);
+        setModifiers(variable.getModifiers());
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitVariableExpression(this);
+    }
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+
+    public String getText() {
+        return variable;
+    }
+    
+    public String getName() {
+        return variable;
+    }
+
+    public String toString() {
+        return super.toString() + "[variable: " + variable + (this.isDynamicTyped() ? "" : " type: " + getType()) + "]";
+    }
+
+    public Expression getInitialExpression() {
+        return null;
+    }
+
+    public boolean hasInitialExpression() {
+        return false;
+    }
+    
+    public boolean isInStaticContext() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.isInStaticContext();
+        return inStaticContext;
+    }
+    
+    public void setInStaticContext(boolean inStaticContext) {
+        this.inStaticContext = inStaticContext;
+    }
+
+    /**
+     * Set the type of this variable. If you call this method from an AST transformation and that
+     * the {@link #getAccessedVariable() accessed variable} is ({@link #isClosureSharedVariable() shared},
+     * this operation is unsafe and may lead to a verify error at compile time. Instead, set the type of
+     * the {@link #getAccessedVariable() accessed variable}
+     * @param cn the type to be set on this variable
+     */
+    public void setType(ClassNode cn){
+        super.setType(cn);
+        isDynamicTyped |= ClassHelper.DYNAMIC_TYPE==cn;
+    }
+    
+    public boolean isDynamicTyped() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.isDynamicTyped();
+        return isDynamicTyped;
+    }
+
+    /**
+     * Tells if this variable or the accessed variable is used in a closure context, like in the following
+     * example :
+     * <pre>def str = 'Hello'
+     * def cl = { println str }
+     * </pre>
+     * The "str" variable is closure shared.
+     * @return true if this variable is used in a closure
+     */
+    public boolean isClosureSharedVariable() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.isClosureSharedVariable();
+        return closureShare;
+    }
+
+    /**
+     * Use this method to tell if a variable is used in a closure, like in the following example:
+     * <pre>def str = 'Hello'
+     * def cl = { println str }
+     * </pre>
+     * The "str" variable is closure shared. The variable expression inside the closure references an
+     * accessed variable "str" which must have the closure shared flag set.
+     * @param inClosure tells if this variable is later referenced in a closure
+     */
+    public void setClosureSharedVariable(boolean inClosure) {
+        closureShare = inClosure;        
+    }
+
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    /**
+     * For internal use only. This flag is used by compiler internals and should probably
+     * be converted to a node metadata in future.
+     * @param useRef
+     */
+    public void setUseReferenceDirectly(boolean useRef) {
+        this.useRef = useRef;        
+    }
+    
+    /**
+     * For internal use only. This flag is used by compiler internals and should probably
+     * be converted to a node metadata in future.
+     */
+    public boolean isUseReferenceDirectly() {
+        return useRef;
+    }
+    
+    public ClassNode getType() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.getType();
+        return super.getType();
+    }
+
+    /**
+     * Returns the type which was used when this variable expression was created. For example,
+     * {@link #getType()} may return a boxed type while this method would return the primitive type.
+     * @return the type which was used to define this variable expression
+     */
+    public ClassNode getOriginType() {
+        if (accessedVariable!=null && accessedVariable!=this) return accessedVariable.getOriginType();
+        return originType;
+    }
+
+    public boolean isThisExpression() {
+        return "this".equals(variable);
+    }
+
+    public boolean isSuperExpression() {
+        return "super".equals(variable);
+    }
+
+    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/expr/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/expr/package.html b/src/main/java/org/codehaus/groovy/ast/expr/package.html
new file mode 100644
index 0000000..806854e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/expr/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ast.expr.*</title>
+  </head>
+  <body>
+    <p>AST nodes for Groovy expressions</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/package.html b/src/main/java/org/codehaus/groovy/ast/package.html
new file mode 100644
index 0000000..f8f132a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ast.*</title>
+  </head>
+  <body>
+    <p>Groovy AST nodes for the syntax of the language</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/AssertStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/AssertStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/AssertStatement.java
new file mode 100644
index 0000000..3f1fb33
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/AssertStatement.java
@@ -0,0 +1,66 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * Represents an assert statement.
+ * E.g.:
+ * <code>
+ * assert i != 0 : "should never be zero";
+ * </code>
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class AssertStatement extends Statement {
+
+    private BooleanExpression booleanExpression;
+    private Expression messageExpression;
+    
+    public AssertStatement(BooleanExpression booleanExpression) {
+        this(booleanExpression, ConstantExpression.NULL);
+    }
+    
+    public AssertStatement(BooleanExpression booleanExpression, Expression messageExpression) {
+        this.booleanExpression = booleanExpression;
+        this.messageExpression = messageExpression;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitAssertStatement(this);
+    }
+
+    public Expression getMessageExpression() {
+        return messageExpression;
+    }
+
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+    public void setMessageExpression(Expression messageExpression) {
+        this.messageExpression = messageExpression;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/BlockStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/BlockStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/BlockStatement.java
new file mode 100644
index 0000000..5013726
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/BlockStatement.java
@@ -0,0 +1,117 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.VariableScope;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A list of statements and a scope. 
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class BlockStatement extends Statement {
+
+    private List<Statement> statements = new ArrayList<Statement>();
+    private VariableScope scope;
+    
+    public BlockStatement() {
+        this(new ArrayList<Statement>(), new VariableScope());
+    }
+
+    /**
+     * Creates a BlockStatement with a scope and children statements.
+     * @param statements
+     *      the statements. Do not pass null. If you do, no exception will occur,
+     *      but a NullPointerException will eventually occur later. Also, a reference
+     *      to the list is kept, so modifying the List later does effect this class.
+     * @param scope
+     *      the scope
+     */
+    public BlockStatement(List<Statement> statements, VariableScope scope) {
+        this.statements = statements;
+        this.scope = scope;
+    }
+    
+    /**
+     * Creates a BlockStatement with a scope and children statements.
+     * @param statements
+     *      the statements, which cannot be null or an exception occurs. No reference
+     *      to the array is held, so modifying the array later has no effect on this
+     *      class.
+     * @param scope
+     *      the scope
+     */
+    public BlockStatement(Statement[] statements, VariableScope scope) {
+        this.statements.addAll(Arrays.asList(statements));
+        this.scope = scope;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBlockStatement(this);
+    }
+
+    public List<Statement> getStatements() {
+        return statements;
+    }
+
+    public void addStatement(Statement statement) {
+        statements.add(statement);
+    }
+
+    public void addStatements(List<Statement> listOfStatements) {
+        statements.addAll(listOfStatements);
+    }
+
+    public String toString() {
+        return super.toString() + statements;
+    }
+
+    public String getText() {
+        StringBuilder buffer = new StringBuilder("{ ");
+        boolean first = true;
+        for (Statement statement : statements) {
+            if (first) {
+                first = false;
+            }
+            else {
+                buffer.append("; ");
+            }
+            buffer.append(statement.getText());
+        }
+        buffer.append(" }");
+        return buffer.toString();
+    }
+
+    public boolean isEmpty() {
+        return statements.isEmpty();
+    }
+
+    public void setVariableScope(VariableScope scope) {
+        this.scope = scope;
+    }
+    
+    public VariableScope getVariableScope() {
+        return scope;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/BreakStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/BreakStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/BreakStatement.java
new file mode 100644
index 0000000..5257991
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/BreakStatement.java
@@ -0,0 +1,48 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents a break statement in a switch or loop statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class BreakStatement extends Statement {
+
+    private String label;
+    
+    public BreakStatement() {
+        this(null);
+    }
+    
+    public BreakStatement(String label) {
+        this.label = label;
+    }
+    
+    public String getLabel() {
+        return label;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBreakStatement(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java
new file mode 100644
index 0000000..7c06e69
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/CaseStatement.java
@@ -0,0 +1,63 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a case statement in a switch statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class CaseStatement extends Statement {
+
+    private Statement code;
+    private Expression expression;
+    
+    public CaseStatement(Expression expression, Statement code) {
+        this.expression = expression;
+        this.code = code;
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+
+    public void setCode(Statement code) {
+        this.code = code;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+    
+    public void setExpression(Expression e) {
+        expression=e;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCaseStatement(this);
+    }
+    
+    public String toString() {
+        return super.toString() + "[expression: " + expression + "; code: " + code + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java
new file mode 100644
index 0000000..3f40957
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/CatchStatement.java
@@ -0,0 +1,61 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+
+
+/**
+ * Represents a catch (Exception var) { } statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class CatchStatement extends Statement {
+
+    private Parameter variable;
+
+    private Statement code;
+    
+    public CatchStatement(Parameter variable, Statement code) {
+        this.variable = variable;
+        this.code = code;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitCatchStatement(this);
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+
+    public ClassNode getExceptionType() {
+        return variable.getType();
+    }
+
+    public Parameter getVariable() {
+        return variable;
+    }
+
+    public void setCode(Statement code) {
+        this.code = code;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java
new file mode 100644
index 0000000..034dcf2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ContinueStatement.java
@@ -0,0 +1,48 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+
+
+/**
+ * Represents a continue statement in a loop statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ContinueStatement extends Statement {
+
+    private String label;
+    
+    public ContinueStatement() {
+        this(null);
+    }
+    
+    public ContinueStatement(String label) {
+        this.label = label;
+    }
+    
+    public String getLabel() {
+        return label;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitContinueStatement(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
new file mode 100644
index 0000000..a7b518b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/DoWhileStatement.java
@@ -0,0 +1,58 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents a do { ... } while (condition) loop in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class DoWhileStatement extends Statement implements LoopingStatement {
+
+    private BooleanExpression booleanExpression;
+    private Statement loopBlock;
+    
+
+    public DoWhileStatement(BooleanExpression booleanExpression, Statement loopBlock) {
+        this.booleanExpression = booleanExpression;
+        this.loopBlock = loopBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitDoWhileLoop(this);
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+
+    public void setLoopBlock(Statement loopBlock) {
+        this.loopBlock = loopBlock;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java
new file mode 100644
index 0000000..2ef78af
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/EmptyStatement.java
@@ -0,0 +1,115 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.NodeMetaDataHandler;
+
+import java.util.Map;
+
+/**
+ * Represents an empty statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+
+public class EmptyStatement extends Statement {
+    public static final EmptyStatement INSTANCE = new EmptyStatement();
+
+    /**
+     * use EmptyStatement.INSTANCE instead
+     */
+//    @Deprecated
+    private EmptyStatement() {
+        // org.spockframework.compiler.ConditionRewriter will create EmptyStatement via calling the constructor
+        // so we keep the constructor for the time being, but it will be removed finally.
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+    }
+
+    public boolean isEmpty() {
+        return true;
+    }
+
+    @Override
+    public void setStatementLabel(String label) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void addStatementLabel(String label) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setLineNumber(int lineNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setColumnNumber(int columnNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setLastLineNumber(int lastLineNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setLastColumnNumber(int lastColumnNumber) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setSourcePosition(ASTNode node) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void copyNodeMetaData(NodeMetaDataHandler other) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setNodeMetaData(Object key, Object value) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public Object putNodeMetaData(Object key, Object value) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void removeNodeMetaData(Object key) {
+        throw createUnsupportedOperationException();
+    }
+
+    @Override
+    public void setMetaDataMap(Map<?, ?> metaDataMap) {
+        throw createUnsupportedOperationException();
+    }
+
+    private UnsupportedOperationException createUnsupportedOperationException() {
+        return new UnsupportedOperationException("EmptyStatement.INSTANCE is immutable");
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
new file mode 100644
index 0000000..c6376b2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ExpressionStatement.java
@@ -0,0 +1,61 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * A simple statement such as a method call where the return value is ignored
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ExpressionStatement extends Statement {
+
+    private Expression expression;
+
+    public ExpressionStatement(Expression expression) {
+        if (expression == null) {
+            throw new IllegalArgumentException("expression cannot be null");
+        }
+        this.expression = expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitExpressionStatement(this);
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public String getText() {
+        return expression.getText();
+    }
+
+    public String toString() {
+        return super.toString() + "[expression:" + expression + "]";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java
new file mode 100644
index 0000000..072ee6e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ForStatement.java
@@ -0,0 +1,83 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.VariableScope;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * Represents a standard for loop in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ForStatement extends Statement implements LoopingStatement {
+    public static final Parameter FOR_LOOP_DUMMY = new Parameter(ClassHelper.OBJECT_TYPE,"forLoopDummyParameter");
+
+    private Parameter variable;
+    private Expression collectionExpression;
+    private Statement loopBlock;
+    private VariableScope scope;
+    
+
+    public ForStatement(Parameter variable, Expression collectionExpression, Statement loopBlock) {
+        this.variable = variable; 
+        this.collectionExpression = collectionExpression;
+        this.loopBlock = loopBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitForLoop(this);
+    }
+    
+    public Expression getCollectionExpression() {
+        return collectionExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+
+    public Parameter getVariable() {
+        return variable;
+    }
+    
+    public ClassNode getVariableType() {
+        return variable.getType();
+    }
+    
+    public void setCollectionExpression(Expression collectionExpression) {
+        this.collectionExpression = collectionExpression;
+    }
+
+    public void setVariableScope(VariableScope variableScope) {
+       scope = variableScope;        
+    }
+
+    public VariableScope getVariableScope() {
+        return scope;
+    }
+
+    public void setLoopBlock(Statement loopBlock) {
+        this.loopBlock = loopBlock;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.java
new file mode 100644
index 0000000..3f614cc
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/IfStatement.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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents an if (condition) { ... } else { ... } statement in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class IfStatement extends Statement {
+
+    private BooleanExpression booleanExpression;
+    private Statement ifBlock;
+    private Statement elseBlock;
+    
+
+    public IfStatement(BooleanExpression booleanExpression, Statement ifBlock, Statement elseBlock) {
+        this.booleanExpression = booleanExpression;
+        this.ifBlock = ifBlock;
+        this.elseBlock = elseBlock;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitIfElse(this);
+    }
+    
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+    
+    public Statement getIfBlock() {
+        return ifBlock;
+    }
+
+    public Statement getElseBlock() {
+        return elseBlock;
+    }
+
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+
+    public void setIfBlock(Statement statement) {
+        ifBlock = statement;
+    }
+
+    public void setElseBlock(Statement statement) {
+        elseBlock = statement;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java
new file mode 100644
index 0000000..4568103
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/LoopingStatement.java
@@ -0,0 +1,38 @@
+/*
+ *  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.stmt;
+
+/**
+* This is an AST Node that provides some sort of looping mechanism. Typically
+* in the form of a block that will be executed repeatedly. 
+* DoWhileStatements, WhileStatements, and ForStatements are all examples of LoopingStatements. 
+*
+* @author Hamlet D'Arcy
+*/ 
+public interface LoopingStatement {
+
+     /**
+     * Gets the loop block. 
+     */
+     Statement getLoopBlock();
+     /**
+     * Sets the loop block. 
+     */
+     void setLoopBlock(Statement loopBlock);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java
new file mode 100644
index 0000000..9e08ebd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ReturnStatement.java
@@ -0,0 +1,72 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+
+/**
+ * A return statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ReturnStatement extends Statement {
+    /**
+     * Only used for synthetic return statements emitted by the compiler.
+     * For comparisons use isReturningNullOrVoid() instead.
+     */
+    public static final ReturnStatement RETURN_NULL_OR_VOID = new ReturnStatement(ConstantExpression.NULL);
+
+    private Expression expression;
+    
+    public ReturnStatement(ExpressionStatement statement) {
+        this(statement.getExpression());
+        setStatementLabel(statement.getStatementLabel());
+    }
+    
+    public ReturnStatement(Expression expression) {
+        this.expression = expression;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitReturnStatement(this);
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public String getText() {
+        return "return " + expression.getText();
+    }
+
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    public boolean isReturningNullOrVoid() {
+        return expression instanceof ConstantExpression
+            && ((ConstantExpression)expression).isNullExpression();
+    }
+
+    public String toString() {
+        return super.toString() + "[expression:" + expression + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java b/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java
new file mode 100644
index 0000000..80dbc4d
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/Statement.java
@@ -0,0 +1,64 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.ASTNode;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Base class for any statement
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class Statement extends ASTNode {
+
+    private List<String> statementLabels;
+
+    public Statement() {
+        statementLabels = null;
+    }
+
+    public List<String> getStatementLabels() {
+        return statementLabels;
+    }
+
+    // TODO @Deprecated
+    public String getStatementLabel() {
+        // last label by default which is added first by APP
+        return statementLabels == null ? null : statementLabels.get(0);
+    }
+
+    // TODO @Deprecated
+    public void setStatementLabel(String label) {
+        if (statementLabels == null) statementLabels = new LinkedList<String>();
+        statementLabels.add(label);
+    }
+
+    public void addStatementLabel(String label) {
+        if (statementLabels == null) statementLabels = new LinkedList<String>();
+        statementLabels.add(label);
+    }
+
+    public boolean isEmpty() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java
new file mode 100644
index 0000000..bad0194
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/SwitchStatement.java
@@ -0,0 +1,91 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a switch (object) { case value: ... case [1, 2, 3]: ...  default: ... } statement in Groovy.
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class SwitchStatement extends Statement {
+
+    private Expression expression;
+    private List<CaseStatement> caseStatements = new ArrayList<CaseStatement>();
+    private Statement defaultStatement;
+    
+
+    public SwitchStatement(Expression expression) {
+        this(expression, EmptyStatement.INSTANCE);
+    }
+
+    public SwitchStatement(Expression expression, Statement defaultStatement) {
+        this.expression = expression;
+        this.defaultStatement = defaultStatement;
+    }
+
+    public SwitchStatement(Expression expression, List<CaseStatement> caseStatements, Statement defaultStatement) {
+        this.expression = expression;
+        this.caseStatements = caseStatements;
+        this.defaultStatement = defaultStatement;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSwitch(this);
+    }
+    
+    public List<CaseStatement> getCaseStatements() {
+        return caseStatements;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void setExpression(Expression e) {
+        expression=e;
+    }
+    
+    public Statement getDefaultStatement() {
+        return defaultStatement;
+    }
+
+    public void setDefaultStatement(Statement defaultStatement) {
+        this.defaultStatement = defaultStatement;
+    }
+
+    public void addCase(CaseStatement caseStatement) {
+        caseStatements.add(caseStatement);
+    }
+
+    /**
+     * @return the case statement of the given index or null
+     */
+    public CaseStatement getCaseStatement(int idx) {
+        if (idx >= 0 && idx < caseStatements.size()) {
+            return caseStatements.get(idx);
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
new file mode 100644
index 0000000..1fd3e5c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/SynchronizedStatement.java
@@ -0,0 +1,58 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a synchronized statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class SynchronizedStatement extends Statement {
+
+    private Statement code;
+    private Expression expression;
+    
+    public SynchronizedStatement(Expression expression, Statement code) {
+        this.expression = expression;
+        this.code = code;
+    }
+    
+    public Statement getCode() {
+        return code;
+    }
+    
+    public void setCode(Statement statement) {
+        code = statement;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitSynchronizedStatement(this);
+    }
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java
new file mode 100644
index 0000000..a217840
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/ThrowStatement.java
@@ -0,0 +1,54 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+
+
+/**
+ * Represents a throw statement
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ThrowStatement extends Statement {
+
+    private Expression expression;
+    
+    public ThrowStatement(Expression expression) {
+        this.expression = expression;
+    }
+    
+    public Expression getExpression() {
+        return expression;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitThrowStatement(this);
+    }
+    public void setExpression(Expression expression) {
+        this.expression = expression;
+    }
+
+    @Override
+    public String getText() {
+        return "throw " + expression.getText();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
new file mode 100644
index 0000000..f05460f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/TryCatchStatement.java
@@ -0,0 +1,108 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a try { ... } catch () finally {} statement in Groovy
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class TryCatchStatement extends Statement {
+
+    private Statement tryStatement;
+    private List<ExpressionStatement> resourceStatements = new ArrayList<ExpressionStatement>();
+    private List<CatchStatement> catchStatements = new ArrayList<CatchStatement>();
+    private Statement finallyStatement;
+    
+
+    public TryCatchStatement(Statement tryStatement, Statement finallyStatement) {
+        this.tryStatement = tryStatement;
+        this.finallyStatement = finallyStatement;
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitTryCatchFinally(this);
+    }
+
+    public List<ExpressionStatement> getResourceStatements() {
+        return resourceStatements;
+    }
+
+    public List<CatchStatement> getCatchStatements() {
+        return catchStatements;
+    }
+
+    public Statement getFinallyStatement() {
+        return finallyStatement;
+    }
+
+    public Statement getTryStatement() {
+        return tryStatement;
+    }
+
+    public void addResource(ExpressionStatement resourceStatement) {
+        if (!(resourceStatement.getExpression() instanceof DeclarationExpression)) {
+            throw new IllegalArgumentException("resourceStatement should be a variable declaration statement");
+        }
+
+        resourceStatements.add(resourceStatement);
+    }
+
+    public void addCatch(CatchStatement catchStatement) {
+        catchStatements.add(catchStatement);
+    }
+
+    /**
+     * @return the catch statement of the given index or null
+     */
+    public CatchStatement getCatchStatement(int idx) {
+        if (idx >= 0 && idx < catchStatements.size()) {
+            return catchStatements.get(idx);
+        }
+        return null;
+    }
+
+    /**
+     * @return the resource statement of the given index or null
+     */
+    public ExpressionStatement getResourceStatement(int idx) {
+        if (idx >= 0 && idx < resourceStatements.size()) {
+            return resourceStatements.get(idx);
+        }
+        return null;
+    }
+
+    public void setTryStatement(Statement tryStatement) {
+        this.tryStatement = tryStatement;
+    }
+
+    public void setCatchStatement(int idx, CatchStatement catchStatement) {
+        catchStatements.set(idx, catchStatement);
+    }
+
+    public void setFinallyStatement(Statement finallyStatement) {
+        this.finallyStatement = finallyStatement;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java b/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java
new file mode 100644
index 0000000..e325481
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/WhileStatement.java
@@ -0,0 +1,59 @@
+/*
+ *  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.stmt;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+
+/**
+ * Represents a while (condition) { ... } loop in Groovy
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class WhileStatement extends Statement implements LoopingStatement {
+
+    private BooleanExpression booleanExpression;
+    private Statement loopBlock;
+
+
+    public WhileStatement(BooleanExpression booleanExpression, Statement loopBlock) {
+        this.booleanExpression = booleanExpression;
+        this.loopBlock = loopBlock;
+    }
+
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitWhileLoop(this);
+    }
+
+    public BooleanExpression getBooleanExpression() {
+        return booleanExpression;
+    }
+
+    public Statement getLoopBlock() {
+        return loopBlock;
+    }
+
+    public void setBooleanExpression(BooleanExpression booleanExpression) {
+        this.booleanExpression = booleanExpression;
+    }
+
+    public void setLoopBlock(Statement loopBlock) {
+        this.loopBlock = loopBlock;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/stmt/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/stmt/package.html b/src/main/java/org/codehaus/groovy/ast/stmt/package.html
new file mode 100644
index 0000000..8226776
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/stmt/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.ast.stmt.*</title>
+  </head>
+  <body>
+    <p>AST nodes for Groovy statements</p>
+  </body>
+</html>

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java
new file mode 100644
index 0000000..32d4a81
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/BeanUtils.java
@@ -0,0 +1,120 @@
+/*
+ *  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.tools;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PropertyNode;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static java.beans.Introspector.decapitalize;
+
+public class BeanUtils {
+    static final String GET_PREFIX = "get";
+    static final String IS_PREFIX = "is";
+
+    /**
+     * Get all properties including JavaBean pseudo properties matching getter conventions.
+     *
+     * @param type the ClassNode
+     * @param includeSuperProperties whether to include super properties
+     * @param includeStatic whether to include static properties
+     * @param includePseudoGetters whether to include JavaBean pseudo (getXXX/isYYY) properties with no corresponding field
+     * @return the list of found property nodes
+     */
+    public static List<PropertyNode> getAllProperties(ClassNode type, boolean includeSuperProperties, boolean includeStatic, boolean includePseudoGetters) {
+        // TODO add generics support so this can be used for @EAHC
+        // TODO add an includePseudoSetters so this can be used for @TupleConstructor
+        ClassNode node = type;
+        List<PropertyNode> result = new ArrayList<PropertyNode>();
+        Set<String> names = new HashSet<String>();
+        while (node != null) {
+            addExplicitProperties(node, result, names, includeStatic);
+            if (!includeSuperProperties) break;
+            node = node.getSuperClass();
+        }
+        addPseudoProperties(type, result, names, includeStatic, includePseudoGetters, includeSuperProperties);
+        return result;
+    }
+
+    private static void addExplicitProperties(ClassNode cNode, List<PropertyNode> result, Set<String> names, boolean includeStatic) {
+        for (PropertyNode pNode : cNode.getProperties()) {
+            if (includeStatic || !pNode.isStatic()) {
+                if (!names.contains(pNode.getName())) {
+                    result.add(pNode);
+                    names.add(pNode.getName());
+                }
+            }
+        }
+    }
+
+    private static void addPseudoProperties(ClassNode cNode, List<PropertyNode> result, Set<String> names, boolean includeStatic, boolean includePseudoGetters, boolean includeSuperProperties) {
+        if (!includePseudoGetters) return;
+        List<MethodNode> methods = cNode.getAllDeclaredMethods();
+        ClassNode node = cNode.getSuperClass();
+        if (includeSuperProperties) {
+            while (node != null) {
+                for (MethodNode next : node.getAllDeclaredMethods()) {
+                    if (!next.isPrivate()) {
+                        methods.add(next);
+                    }
+                }
+                node = node.getSuperClass();
+            }
+        }
+        for (MethodNode mNode : methods) {
+            if (!includeStatic && mNode.isStatic()) continue;
+            String name = mNode.getName();
+            if ((name.length() <= 3 && !name.startsWith(IS_PREFIX)) || name.equals("getClass") || name.equals("getMetaClass") || name.equals("getDeclaringClass")) {
+                // Optimization: skip invalid propertyNames
+                continue;
+            }
+            if (mNode.getDeclaringClass() != cNode && mNode.isPrivate()) {
+                // skip private super methods
+                continue;
+            }
+            int paramCount = mNode.getParameters().length;
+            ClassNode returnType = mNode.getReturnType();
+            if (paramCount == 0) {
+                if (name.startsWith(GET_PREFIX)) {
+                    // Simple getter
+                    String propName = decapitalize(name.substring(3));
+                    if (!names.contains(propName)) {
+                        result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null));
+                        names.add(propName);
+                    }
+                } else {
+                    if (name.startsWith(IS_PREFIX) && returnType.equals(ClassHelper.boolean_TYPE)) {
+                        // boolean getter
+                        String propName = decapitalize(name.substring(2));
+                        if (!names.contains(propName)) {
+                            names.add(propName);
+                            result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null));
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java
new file mode 100644
index 0000000..5c43586
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/ClassNodeUtils.java
@@ -0,0 +1,80 @@
+/*
+ * 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.tools;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.Map;
+
+@Deprecated
+public class ClassNodeUtils {
+    @Deprecated
+    public static void addInterfaceMethods(ClassNode cNode, Map<String, MethodNode> methodsMap) {
+        org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromInterfaces(cNode, methodsMap);
+    }
+
+    @Deprecated
+    public static Map<String, MethodNode> getDeclaredMethodMapsFromInterfaces(ClassNode cNode) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.getDeclaredMethodsFromInterfaces(cNode);
+    }
+
+    @Deprecated
+    public static void addDeclaredMethodMapsFromSuperInterfaces(ClassNode cNode, Map<String, MethodNode> methodsMap) {
+        org.apache.groovy.ast.tools.ClassNodeUtils.addDeclaredMethodsFromAllInterfaces(cNode, methodsMap);
+    }
+
+    @Deprecated
+    public static boolean hasPossibleStaticMethod(ClassNode cNode, String name, Expression arguments, boolean trySpread) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticMethod(cNode, name, arguments, trySpread);
+    }
+
+    @Deprecated
+    public static boolean hasPossibleStaticProperty(ClassNode cNode, String methodName) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.hasPossibleStaticProperty(cNode, methodName);
+    }
+
+    @Deprecated
+    public static String getPropNameForAccessor(String accessorName) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.getPropNameForAccessor(accessorName);
+    }
+
+    @Deprecated
+    public static boolean isValidAccessorName(String accessorName) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.isValidAccessorName(accessorName);
+    }
+
+    @Deprecated
+    public static boolean hasStaticProperty(ClassNode cNode, String propName) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.hasStaticProperty(cNode, propName);
+    }
+
+    @Deprecated
+    public static PropertyNode getStaticProperty(ClassNode cNode, String propName) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.getStaticProperty(cNode, propName);
+    }
+
+    @Deprecated
+    public static boolean isInnerClass(ClassNode cNode) {
+        return org.apache.groovy.ast.tools.ClassNodeUtils.isInnerClass(cNode);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.java
new file mode 100644
index 0000000..06d4995
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/ast/tools/ClosureUtils.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.tools;
+
+import groovy.lang.Closure;
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.control.io.ReaderSource;
+/**
+ * Handy methods when working with Closure AST data structures.
+ */
+
+public class ClosureUtils {
+
+    /**
+     * Converts a ClosureExpression into the String source.
+     *
+     * @param readerSource a source
+     * @param expression a closure. Can't be null
+     * @return the source the closure was created from
+     * @throws java.lang.IllegalArgumentException when expression is null
+     * @throws java.lang.Exception when closure can't be read from source
+     */
+    public static String convertClosureToSource(ReaderSource readerSource, ClosureExpression expression) throws Exception {
+        String source = GeneralUtils.convertASTToSource(readerSource, expression);
+        if (!source.startsWith("{")) {
+            throw new Exception("Error converting ClosureExpression into source code. Closures must start with {. Found: " + source);
+        }
+        return source;
+    }
+
+    /**
+     * Does the Closure have a single char-like (char or Character) argument.
+     * @param c a Closure
+     * @return true if it has exactly one argument and the type is char or Character
+     */
+    public static boolean hasSingleCharacterArg(Closure c) {
+        if (c.getMaximumNumberOfParameters() != 1) return false;
+        String typeName = c.getParameterTypes()[0].getName();
+        return typeName.equals("char") || typeName.equals("java.lang.Character");
+    }
+
+    /**
+     * Does the Closure have a single String argument.
+     * @param c a Closure
+     * @return true if it has exactly one argument and the type is String
+     */
+    public static boolean hasSingleStringArg(Closure c) {
+        if (c.getMaximumNumberOfParameters() != 1) return false;
+        String typeName = c.getParameterTypes()[0].getName();
+        return typeName.equals("java.lang.String");
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/CompilerCustomizationBuilder.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/CompilerCustomizationBuilder.groovy b/src/main/groovy/CompilerCustomizationBuilder.groovy
new file mode 100644
index 0000000..59b8cc5
--- /dev/null
+++ b/src/main/groovy/CompilerCustomizationBuilder.groovy
@@ -0,0 +1,64 @@
+/*
+ *  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.control.customizers.builder
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+
+/**
+ * <p>A builder which allows easy configuration of compilation customizers. Instead of creating
+ * various compilation customizers by hand, you may use this builder instead, which provides a
+ * shorter syntax and removes most of the verbosity.
+ *
+ */
+@CompileStatic
+class CompilerCustomizationBuilder extends FactoryBuilderSupport {
+    public CompilerCustomizationBuilder() {
+        registerFactories()
+    }
+
+    public static CompilerConfiguration withConfig(CompilerConfiguration config, Closure code) {
+        CompilerCustomizationBuilder builder = new CompilerCustomizationBuilder()
+        config.invokeMethod('addCompilationCustomizers', builder.invokeMethod('customizers', code))
+
+        config
+    }
+
+    @Override
+    protected Object postNodeCompletion(final Object parent, final Object node) {
+        Object value = super.postNodeCompletion(parent, node)
+        Object factory = getContextAttribute(CURRENT_FACTORY)
+        if (factory instanceof PostCompletionFactory) {
+            value = factory.postCompleteNode(this, parent, value)
+            setParent(parent, value)
+        }
+
+        value
+    }
+
+    private void registerFactories() {
+        registerFactory("ast", new ASTTransformationCustomizerFactory())
+        registerFactory("customizers", new CustomizersFactory())
+        registerFactory("imports", new ImportCustomizerFactory())
+        registerFactory("inline", new InlinedASTCustomizerFactory())
+        registerFactory("secureAst", new SecureASTCustomizerFactory())
+        registerFactory("source", new SourceAwareCustomizerFactory())
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/ConditionalInterruptibleASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/ConditionalInterruptibleASTTransformation.groovy b/src/main/groovy/ConditionalInterruptibleASTTransformation.groovy
new file mode 100644
index 0000000..2cda121
--- /dev/null
+++ b/src/main/groovy/ConditionalInterruptibleASTTransformation.groovy
@@ -0,0 +1,145 @@
+/*
+ *  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.transform
+
+import groovy.transform.ConditionalInterrupt
+import org.codehaus.groovy.ast.AnnotatedNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.FieldNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.PropertyNode
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.tools.ClosureUtils
+import org.codehaus.groovy.control.CompilePhase
+
+/**
+ * Allows "interrupt-safe" executions of scripts by adding a custom conditional
+ * check on loops (for, while, do) and first statement of closures. By default, also adds an interrupt check
+ * statement on the beginning of method calls.
+ *
+ * @see groovy.transform.ConditionalInterrupt
+ * @author Cedric Champeau
+ * @author Hamlet D'Arcy
+ * @author Paul King
+ * @since 1.8.0
+ */
+@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
+public class ConditionalInterruptibleASTTransformation extends AbstractInterruptibleASTTransformation {
+
+  private static final ClassNode MY_TYPE = ClassHelper.make(ConditionalInterrupt)
+
+  private ClosureExpression conditionNode
+  private String conditionMethod
+  private MethodCallExpression conditionCallExpression
+  private ClassNode currentClass
+
+  protected ClassNode type() {
+    return MY_TYPE
+  }
+
+  protected void setupTransform(AnnotationNode node) {
+    super.setupTransform(node)
+    def member = node.getMember("value")
+    if (!member || !(member instanceof ClosureExpression)) internalError("Expected closure value for annotation parameter 'value'. Found $member")
+    conditionNode = member;
+    conditionMethod = 'conditionalTransform' + node.hashCode() + '$condition'
+    conditionCallExpression = new MethodCallExpression(new VariableExpression('this'), conditionMethod, new ArgumentListExpression())
+  }
+
+  protected String getErrorMessage() {
+    'Execution interrupted. The following condition failed: ' + convertClosureToSource(conditionNode)
+  }
+
+  void visitClass(ClassNode type) {
+    currentClass = type
+    def method = type.addMethod(conditionMethod, ACC_PRIVATE | ACC_SYNTHETIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, conditionNode.code)
+    method.synthetic = true
+    if (applyToAllMembers) {
+      super.visitClass(type)
+    }
+  }
+
+  protected Expression createCondition() {
+    conditionCallExpression
+  }
+
+  @Override
+  void visitAnnotations(AnnotatedNode node) {
+    // this transformation does not apply on annotation nodes
+    // visiting could lead to stack overflows
+  }
+
+  @Override
+  void visitField(FieldNode node) {
+    if (!node.isStatic() && !node.isSynthetic()) {
+      super.visitField node
+    }
+  }
+
+  @Override
+  void visitProperty(PropertyNode node) {
+    if (!node.isStatic() && !node.isSynthetic()) {
+      super.visitProperty node
+    }
+  }
+
+  @Override
+  void visitClosureExpression(ClosureExpression closureExpr) {
+    if (closureExpr == conditionNode) return // do not visit the closure from the annotation itself
+    def code = closureExpr.code
+    closureExpr.code = wrapBlock(code)
+    super.visitClosureExpression closureExpr
+  }
+
+  @Override
+  void visitMethod(MethodNode node) {
+    if (node.name == conditionMethod && !node.isSynthetic()) return // do not visit the generated method
+    if (node.name == 'run' && currentClass.isScript() && node.parameters.length == 0) {
+      // the run() method should not have the statement added, otherwise the script binding won't be set before
+      // the condition is actually tested
+      super.visitMethod(node)
+    } else {
+      if (checkOnMethodStart && !node.isSynthetic() && !node.isStatic() && !node.isAbstract()) {
+        def code = node.code
+        node.code = wrapBlock(code);
+      }
+      if (!node.isSynthetic() && !node.isStatic()) super.visitMethod(node)
+    }
+  }
+
+  /**
+   * Converts a ClosureExpression into the String source.
+   * @param expression a closure
+   * @return the source the closure was created from
+   */
+  private String convertClosureToSource(ClosureExpression expression) {
+    try {
+        return ClosureUtils.convertClosureToSource(this.source.source, expression);
+    } catch(Exception e) {
+        return e.message
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/GrapeMain.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/GrapeMain.groovy b/src/main/groovy/GrapeMain.groovy
new file mode 100644
index 0000000..c78d25e
--- /dev/null
+++ b/src/main/groovy/GrapeMain.groovy
@@ -0,0 +1,308 @@
+/*
+ *  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.tools
+
+import groovy.grape.Grape
+import groovy.transform.Field
+import org.apache.commons.cli.CommandLine
+import org.apache.commons.cli.DefaultParser
+import org.apache.commons.cli.HelpFormatter
+import org.apache.commons.cli.Option
+import org.apache.commons.cli.OptionGroup
+import org.apache.commons.cli.Options
+import org.apache.ivy.util.DefaultMessageLogger
+import org.apache.ivy.util.Message
+
+//commands
+
+@Field install = {arg, cmd ->
+    if (arg.size() > 5 || arg.size() < 3) {
+        println 'install requires two to four arguments: <group> <module> [<version> [<classifier>]]'
+        return
+    }
+    def ver = '*'
+    if (arg.size() >= 4) {
+        ver = arg[3]
+    }
+    def classifier = null
+    if (arg.size() >= 5) {
+        classifier = arg[4]
+    }
+
+    // set the instance so we can re-set the logger
+    Grape.getInstance()
+    setupLogging()
+
+    cmd.getOptionValues('r')?.each { String url ->
+        Grape.addResolver(name:url, root:url)
+    }
+
+    try {
+        Grape.grab(autoDownload: true, group: arg[1], module: arg[2], version: ver, classifier: classifier, noExceptions: true)
+    } catch (Exception e) {
+        println "An error occured : $ex"
+    }
+}
+
+@Field uninstall = {arg, cmd ->
+    if (arg.size() != 4) {
+        println 'uninstall requires three arguments: <group> <module> <version>'
+        // TODO make version optional? support classifier?
+//        println 'uninstall requires two to four arguments, <group> <module> [<version>] [<classifier>]'
+        return
+    }
+    String group = arg[1]
+    String module = arg[2]
+    String ver = arg[3]
+//    def classifier = null
+
+    // set the instance so we can re-set the logger
+    Grape.getInstance()
+    setupLogging()
+
+    if (!Grape.enumerateGrapes().find {String groupName, Map g ->
+        g.any {String moduleName, List<String> versions ->
+            group == groupName && module == moduleName && ver in versions
+        }
+    }) {
+        println "uninstall did not find grape matching: $group $module $ver"
+        def fuzzyMatches = Grape.enumerateGrapes().findAll { String groupName, Map g ->
+            g.any {String moduleName, List<String> versions ->
+                groupName.contains(group) || moduleName.contains(module) ||
+                group.contains(groupName) || module.contains(moduleName)
+            }
+        }
+        if (fuzzyMatches) {
+            println 'possible matches:'
+            fuzzyMatches.each { String groupName, Map g -> println "    $groupName: $g" }
+        }
+        return
+    }
+    Grape.instance.uninstallArtifact(group, module, ver)
+}
+
+@Field list = {arg, cmd ->
+    println ""
+
+    int moduleCount = 0
+    int versionCount = 0
+
+    // set the instance so we can re-set the logger
+    Grape.getInstance()
+    setupLogging()
+
+    Grape.enumerateGrapes().each {String groupName, Map group ->
+        group.each {String moduleName, List<String> versions ->
+            println "$groupName $moduleName  $versions"
+            moduleCount++
+            versionCount += versions.size()
+        }
+    }
+    println ""
+    println "$moduleCount Grape modules cached"
+    println "$versionCount Grape module versions cached"
+}
+
+@Field resolve = {arg, cmd ->
+    Options options = new Options();
+    options.addOption(Option.builder("a").hasArg(false).longOpt("ant").build());
+    options.addOption(Option.builder("d").hasArg(false).longOpt("dos").build());
+    options.addOption(Option.builder("s").hasArg(false).longOpt("shell").build());
+    options.addOption(Option.builder("i").hasArg(false).longOpt("ivy").build());
+    CommandLine cmd2 = new DefaultParser().parse(options, arg[1..-1] as String[], true);
+    arg = cmd2.args
+
+    // set the instance so we can re-set the logger
+    Grape.getInstance()
+    setupLogging(Message.MSG_ERR)
+
+    if ((arg.size() % 3) != 0) {
+        println 'There needs to be a multiple of three arguments: (group module version)+'
+        return
+    }
+    if (args.size() < 3) {
+        println 'At least one Grape reference is required'
+        return
+    }
+    def before, between, after
+    def ivyFormatRequested = false
+
+    if (cmd2.hasOption('a')) {
+        before = '<pathelement location="'
+        between = '">\n<pathelement location="'
+        after = '">'
+    } else if (cmd2.hasOption('d')) {
+        before = 'set CLASSPATH='
+        between = ';'
+        after = ''
+    } else if (cmd2.hasOption('s')) {
+        before = 'export CLASSPATH='
+        between = ':'
+        after = ''
+    } else if (cmd2.hasOption('i')) {
+        ivyFormatRequested = true
+        before = '<dependency '
+        between = '">\n<dependency '
+        after = '">'
+    } else {
+        before = ''
+        between = '\n'
+        after = '\n'
+    }
+
+    iter = arg.iterator()
+    def params = [[:]]
+    def depsInfo = [] // this list will contain the module/group/version info of all resolved dependencies
+    if(ivyFormatRequested) {
+        params << depsInfo
+    }
+    while (iter.hasNext()) {
+        params.add([group: iter.next(), module: iter.next(), version: iter.next()])
+    }
+    try {
+        def results = []
+        def uris = Grape.resolve(* params)
+        if(!ivyFormatRequested) {
+            for (URI uri: uris) {
+                if (uri.scheme == 'file') {
+                    results += new File(uri).path
+                } else {
+                    results += uri.toASCIIString()
+                }
+            }
+        } else {
+            depsInfo.each { dep ->
+                results += ('org="' + dep.group + '" name="' + dep.module + '" revision="' + dep.revision)
+            }
+        }
+
+        if (results) {
+            println "${before}${results.join(between)}${after}"
+        } else {
+            println 'Nothing was resolved'
+        }
+    } catch (Exception e) {
+        println "Error in resolve:\n\t$e.message"
+        if (e.message =~ /unresolved dependency/) println "Perhaps the grape is not installed?"
+    }
+}
+
+@Field help = { arg, cmd -> grapeHelp() }
+
+@Field commands = [
+    'install': [closure: install,
+        shortHelp: 'Installs a particular grape'],
+    'uninstall': [closure: uninstall,
+        shortHelp: 'Uninstalls a particular grape (non-transitively removes the respective jar file from the grape cache)'],
+    'list': [closure: list,
+        shortHelp: 'Lists all installed grapes'],
+    'resolve': [closure: resolve,
+        shortHelp: 'Enumerates the jars used by a grape'],
+    'help': [closure: help,
+        shortHelp: 'Usage information']
+]
+
+@Field grapeHelp = {
+    int spacesLen = commands.keySet().max {it.length()}.length() + 3
+    String spaces = ' ' * spacesLen
+
+    PrintWriter pw = new PrintWriter(binding.variables.out ?: System.out)
+    new HelpFormatter().printHelp(
+            pw,
+            80,
+            "grape [options] <command> [args]\n",
+            "options:",
+            options,
+            2,
+            4,
+            null, // footer
+            true);
+    pw.flush()
+
+    println ""
+    println "commands:"
+    commands.each {String k, v ->
+        println "  ${(k + spaces).substring(0, spacesLen)} $v.shortHelp"
+    }
+    println ""
+}
+
+@Field setupLogging = {int defaultLevel = 2 -> // = Message.MSG_INFO -> some parsing error :(
+    if (cmd.hasOption('q')) {
+        Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_ERR))
+    } else if (cmd.hasOption('w')) {
+        Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_WARN))
+    } else if (cmd.hasOption('i')) {
+        Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_INFO))
+    } else if (cmd.hasOption('V')) {
+        Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_VERBOSE))
+    } else if (cmd.hasOption('d')) {
+        Message.setDefaultLogger(new DefaultMessageLogger(Message.MSG_DEBUG))
+    } else {
+        Message.setDefaultLogger(new DefaultMessageLogger(defaultLevel))
+    }
+}
+
+// command line parsing
+@Field Options options = new Options();
+
+options.addOption(Option.builder("D").longOpt("define").desc("define a system property").numberOfArgs(2).valueSeparator().argName("name=value").build());
+options.addOption(Option.builder("r").longOpt("resolver").desc("define a grab resolver (for install)").hasArg(true).argName("url").build());
+options.addOption(Option.builder("h").hasArg(false).desc("usage information").longOpt("help").build());
+
+// Logging Level Options
+options.addOptionGroup(
+        new OptionGroup()
+                .addOption(Option.builder("q").hasArg(false).desc("Log level 0 - only errors").longOpt("quiet").build())
+                .addOption(Option.builder("w").hasArg(false).desc("Log level 1 - errors and warnings").longOpt("warn").build())
+                .addOption(Option.builder("i").hasArg(false).desc("Log level 2 - info").longOpt("info").build())
+                .addOption(Option.builder("V").hasArg(false).desc("Log level 3 - verbose").longOpt("verbose").build())
+                .addOption(Option.builder("d").hasArg(false).desc("Log level 4 - debug").longOpt("debug").build())
+)
+options.addOption(Option.builder("v").hasArg(false).desc("display the Groovy and JVM versions").longOpt("version").build());
+
+@Field CommandLine cmd
+
+cmd = new DefaultParser().parse(options, args, true);
+
+if (cmd.hasOption('h')) {
+    grapeHelp()
+    return
+}
+
+if (cmd.hasOption('v')) {
+    String version = GroovySystem.getVersion();
+    println "Groovy Version: $version JVM: ${System.getProperty('java.version')}"
+    return
+}
+
+if (options.hasOption('D')) {
+    options.getOptionProperties('D')?.each { k, v ->
+        System.setProperty(k, v)
+    }
+}
+
+String[] arg = cmd.args
+if (arg?.length == 0) {
+    grapeHelp()
+} else if (commands.containsKey(arg[0])) {
+    commands[arg[0]].closure(arg, cmd)
+} else {
+    println "grape: '${arg[0]}' is not a grape command. See 'grape --help'"
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/HasRecursiveCalls.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/HasRecursiveCalls.groovy b/src/main/groovy/HasRecursiveCalls.groovy
new file mode 100644
index 0000000..79f8e6d
--- /dev/null
+++ b/src/main/groovy/HasRecursiveCalls.groovy
@@ -0,0 +1,64 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.CodeVisitorSupport
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression
+
+/**
+ *
+ * Check if there are any recursive calls in a method
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class HasRecursiveCalls extends CodeVisitorSupport {
+    MethodNode method
+    boolean hasRecursiveCalls = false
+
+    public void visitMethodCallExpression(MethodCallExpression call) {
+        if (isRecursive(call)) {
+            hasRecursiveCalls = true
+        } else {
+            super.visitMethodCallExpression(call)
+        }
+    }
+
+    public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
+        if (isRecursive(call)) {
+            hasRecursiveCalls = true
+        } else {
+            super.visitStaticMethodCallExpression(call)
+        }
+    }
+
+    private boolean isRecursive(call) {
+        new RecursivenessTester().isRecursive(method: method, call: call)
+    }
+
+    synchronized boolean test(MethodNode method) {
+        hasRecursiveCalls = false
+        this.method = method
+        this.method.code.visit(this)
+        hasRecursiveCalls
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/InWhileLoopWrapper.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/InWhileLoopWrapper.groovy b/src/main/groovy/InWhileLoopWrapper.groovy
new file mode 100644
index 0000000..981f146
--- /dev/null
+++ b/src/main/groovy/InWhileLoopWrapper.groovy
@@ -0,0 +1,81 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.VariableScope
+import org.codehaus.groovy.ast.expr.BooleanExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.CatchStatement
+import org.codehaus.groovy.ast.stmt.ContinueStatement
+import org.codehaus.groovy.ast.stmt.EmptyStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.ast.stmt.TryCatchStatement
+import org.codehaus.groovy.ast.stmt.WhileStatement
+
+/**
+ * Wrap the body of a method in a while loop, nested in a try-catch.
+ * This is the first step in making a tail recursive method iterative.
+ *
+ * There are two ways to invoke the next iteration step:
+ * 1. "continue _RECURE_HERE_" is used by recursive calls outside of closures
+ * 2. "throw LOOP_EXCEPTION" is used by recursive calls within closures b/c you cannot invoke "continue" from there
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class InWhileLoopWrapper {
+	
+	static final String LOOP_LABEL = '_RECUR_HERE_'
+    static final GotoRecurHereException  LOOP_EXCEPTION = new GotoRecurHereException()
+
+	void wrap(MethodNode method) {
+		BlockStatement oldBody = method.code as BlockStatement
+        TryCatchStatement tryCatchStatement = new TryCatchStatement(
+                oldBody,
+                EmptyStatement.INSTANCE
+        )
+        tryCatchStatement.addCatch(new CatchStatement(
+                new Parameter(ClassHelper.make(GotoRecurHereException), 'ignore'),
+                new ContinueStatement(InWhileLoopWrapper.LOOP_LABEL)
+        ))
+
+        WhileStatement whileLoop = new WhileStatement(
+                new BooleanExpression(new ConstantExpression(true)),
+                new BlockStatement([tryCatchStatement] as List<Statement>, new VariableScope(method.variableScope))
+        )
+        List<Statement> whileLoopStatements = ((BlockStatement) whileLoop.loopBlock).statements
+        if (whileLoopStatements.size() > 0)
+            whileLoopStatements[0].statementLabel = LOOP_LABEL
+		BlockStatement newBody = new BlockStatement([] as List<Statement>, new VariableScope(method.variableScope))
+		newBody.addStatement(whileLoop)
+		method.code = newBody
+	}
+}
+
+/**
+ * Exception will be thrown by recursive calls in closures and caught in while loop to continue to LOOP_LABEL
+ */
+class GotoRecurHereException extends Throwable {
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/RecursivenessTester.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/RecursivenessTester.groovy b/src/main/groovy/RecursivenessTester.groovy
new file mode 100644
index 0000000..7c9545a
--- /dev/null
+++ b/src/main/groovy/RecursivenessTester.groovy
@@ -0,0 +1,100 @@
+/*
+ *  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.transform.tailrec
+
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+
+/**
+ *
+ * Test if a method call is recursive if called within a given method node.
+ * Handles static calls as well.
+ * 
+ * Currently known simplifications:
+ * - Does not check for method overloading or overridden methods.
+ * - Does not check for matching return types; even void and any object type are considered to be compatible.
+ * - Argument type matching could be more specific in case of static compilation.
+ * - Method names via a GString are never considered to be recursive
+ * 
+ * @author Johannes Link
+ */
+class RecursivenessTester {
+	public boolean isRecursive(params) {
+		assert params.method.class == MethodNode
+		assert params.call.class == MethodCallExpression || StaticMethodCallExpression
+
+		isRecursive(params.method, params.call)
+	}
+
+	public boolean isRecursive(MethodNode method, MethodCallExpression call) {
+		if (!isCallToThis(call))
+			return false
+        // Could be a GStringExpression
+        if (! (call.method instanceof ConstantExpression))
+            return false
+		if (call.method.value != method.name)
+			return false
+		methodParamsMatchCallArgs(method, call)
+	}
+
+    public boolean isRecursive(MethodNode method, StaticMethodCallExpression call) {
+        if (!method.isStatic())
+            return false
+        if (method.declaringClass != call.ownerType)
+            return false
+        if (call.method != method.name)
+            return false
+        methodParamsMatchCallArgs(method, call)
+    }
+
+	private boolean isCallToThis(MethodCallExpression call) {
+		if (call.objectExpression == null)
+			return call.isImplicitThis()
+        if (! (call.objectExpression instanceof VariableExpression)) {
+            return false
+        }
+		return call.objectExpression.isThisExpression()
+	}
+	
+	private boolean methodParamsMatchCallArgs(method, call) {
+        if (method.parameters.size() != call.arguments.expressions.size())
+            return false
+        def classNodePairs = [method.parameters*.type, call.arguments*.type].transpose()
+        return classNodePairs.every { ClassNode paramType, ClassNode argType  ->
+            return areTypesCallCompatible(argType, paramType)
+        }
+	}
+
+    /**
+     * Parameter type and calling argument type can both be derived from the other since typing information is
+     * optional in Groovy.
+     * Since int is not derived from Integer (nor the other way around) we compare the boxed types
+     */
+    private areTypesCallCompatible(ClassNode argType, ClassNode paramType) {
+        ClassNode boxedArg = ClassHelper.getWrapper(argType)
+        ClassNode boxedParam = ClassHelper.getWrapper(paramType)
+        return boxedArg.isDerivedFrom(boxedParam) || boxedParam.isDerivedFrom(boxedArg)
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/ReturnAdderForClosures.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/ReturnAdderForClosures.groovy b/src/main/groovy/ReturnAdderForClosures.groovy
new file mode 100644
index 0000000..64ebce7
--- /dev/null
+++ b/src/main/groovy/ReturnAdderForClosures.groovy
@@ -0,0 +1,48 @@
+/*
+ *  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.transform.tailrec
+
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.CodeVisitorSupport
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.classgen.ReturnAdder
+
+/**
+ * Adds explicit return statements to implicit return points in a closure. This is necessary since
+ * tail-recursion is detected by having the recursive call within the return statement.
+ *
+ * @author Johannes Link
+ */
+class ReturnAdderForClosures extends CodeVisitorSupport {
+
+    synchronized void visitMethod(MethodNode method) {
+        method.code.visit(this)
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        //Create a dummy method with the closure's code as the method's code. Then user ReturnAdder, which only works for methods.
+        MethodNode node = new MethodNode("dummy", 0, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, expression.code);
+        new ReturnAdder().visitMethod(node);
+        super.visitClosureExpression(expression)
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/ReturnStatementToIterationConverter.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/ReturnStatementToIterationConverter.groovy b/src/main/groovy/ReturnStatementToIterationConverter.groovy
new file mode 100644
index 0000000..2c75f4f
--- /dev/null
+++ b/src/main/groovy/ReturnStatementToIterationConverter.groovy
@@ -0,0 +1,148 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.expr.BinaryExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression
+import org.codehaus.groovy.ast.expr.TupleExpression
+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.ReturnStatement
+import org.codehaus.groovy.ast.stmt.Statement
+
+import static org.codehaus.groovy.ast.tools.GeneralUtils.assignS
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX
+
+/**
+ * Translates all return statements into an invocation of the next iteration. This can be either
+ * - "continue LOOP_LABEL": Outside closures
+ * - "throw LOOP_EXCEPTION": Inside closures
+ *
+ * Moreover, before adding the recur statement the iteration parameters (originally the method args)
+ * are set to their new value. To prevent variable aliasing parameters will be copied into temp vars
+ * before they are changes so that their current iteration value can be used when setting other params.
+ *
+ * There's probably place for optimizing the amount of variable copying being done, e.g.
+ * parameters that are only handed through must not be copied at all.
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class ReturnStatementToIterationConverter {
+
+    Statement recurStatement = AstHelper.recurStatement()
+
+    Statement convert(ReturnStatement statement, Map<Integer, Map> positionMapping) {
+        Expression recursiveCall = statement.expression
+        if (!isAMethodCalls(recursiveCall))
+            return statement
+
+        Map<String, Map> tempMapping = [:]
+        Map tempDeclarations = [:]
+        List<ExpressionStatement> argAssignments = []
+
+        BlockStatement result = new BlockStatement()
+        result.statementLabel = statement.statementLabel
+
+        /* Create temp declarations for all method arguments.
+         * Add the declarations and var mapping to tempMapping and tempDeclarations for further reference.
+         */
+        getArguments(recursiveCall).eachWithIndex { Expression expression, int index ->
+            ExpressionStatement tempDeclaration = createTempDeclaration(index, positionMapping, tempMapping, tempDeclarations)
+            result.addStatement(tempDeclaration)
+        }
+
+        /*
+         * Assign the iteration variables their new value before recuring
+         */
+        getArguments(recursiveCall).eachWithIndex { Expression expression, int index ->
+            ExpressionStatement argAssignment = createAssignmentToIterationVariable(expression, index, positionMapping)
+            argAssignments.add(argAssignment)
+            result.addStatement(argAssignment)
+        }
+
+        Set<String> unusedTemps = replaceAllArgUsages(argAssignments, tempMapping)
+        for (String temp : unusedTemps) {
+            result.statements.remove(tempDeclarations[temp])
+        }
+        result.addStatement(recurStatement)
+
+        return result
+    }
+
+    private ExpressionStatement createAssignmentToIterationVariable(Expression expression, int index, Map<Integer, Map> positionMapping) {
+        String argName = positionMapping[index]['name']
+        ClassNode argAndTempType = positionMapping[index]['type'] as ClassNode
+        ExpressionStatement argAssignment = (ExpressionStatement) assignS(varX(argName, argAndTempType), expression)
+        argAssignment
+    }
+
+    private ExpressionStatement createTempDeclaration(int index,  Map<Integer, Map> positionMapping, Map<String, Map> tempMapping, Map tempDeclarations) {
+        String argName = positionMapping[index]['name']
+        String tempName = "_${argName}_"
+        ClassNode argAndTempType = positionMapping[index]['type'] as ClassNode
+        ExpressionStatement tempDeclaration = AstHelper.createVariableAlias(tempName, argAndTempType, argName)
+        tempMapping[argName] = [name: tempName, type: argAndTempType]
+        tempDeclarations[tempName] = tempDeclaration
+        return tempDeclaration
+    }
+
+    private List<Expression> getArguments(Expression recursiveCall) {
+        if (recursiveCall instanceof MethodCallExpression)
+            return ((TupleExpression) ((MethodCallExpression) recursiveCall).arguments).expressions
+        if (recursiveCall instanceof StaticMethodCallExpression)
+            return ((TupleExpression) ((StaticMethodCallExpression) recursiveCall).arguments).expressions
+    }
+
+    private boolean isAMethodCalls(Expression expression) {
+        expression.class in [MethodCallExpression, StaticMethodCallExpression]
+    }
+
+    private Set<String> replaceAllArgUsages(List<ExpressionStatement> iterationVariablesAssignmentNodes, Map<String, Map> tempMapping) {
+        Set<String> unusedTempNames = tempMapping.values().collect {Map nameAndType -> (String) nameAndType['name']} as Set<String>
+        VariableReplacedListener tracker = new UsedVariableTracker()
+        for (ExpressionStatement statement : iterationVariablesAssignmentNodes) {
+            replaceArgUsageByTempUsage((BinaryExpression) statement.expression, tempMapping, tracker)
+        }
+        unusedTempNames = unusedTempNames - tracker.usedVariableNames
+        return unusedTempNames
+    }
+
+    private void replaceArgUsageByTempUsage(BinaryExpression binary, Map tempMapping, UsedVariableTracker tracker) {
+        VariableAccessReplacer replacer = new VariableAccessReplacer(nameAndTypeMapping: tempMapping, listener: tracker)
+        // Replacement must only happen in binary.rightExpression. It's a hack in VariableExpressionReplacer which takes care of that.
+        replacer.replaceIn(binary)
+    }
+}
+
+@CompileStatic
+class UsedVariableTracker implements VariableReplacedListener {
+
+    final Set<String> usedVariableNames = [] as Set
+
+    @Override
+    void variableReplaced(VariableExpression oldVar, VariableExpression newVar) {
+        usedVariableNames.add(newVar.name)
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/StatementReplacer.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/StatementReplacer.groovy b/src/main/groovy/StatementReplacer.groovy
new file mode 100644
index 0000000..3a9dab3
--- /dev/null
+++ b/src/main/groovy/StatementReplacer.groovy
@@ -0,0 +1,109 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.CodeVisitorSupport
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.DoWhileStatement
+import org.codehaus.groovy.ast.stmt.ForStatement
+import org.codehaus.groovy.ast.stmt.IfStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.ast.stmt.WhileStatement
+
+/**
+ * Tool for replacing Statement objects in an AST by other Statement instances.
+ *
+ * Within @TailRecursive it is used to swap ReturnStatements with looping back to RECUR label
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class StatementReplacer extends CodeVisitorSupport {
+
+    Closure<Boolean> when = { Statement node -> false }
+    Closure<Statement> replaceWith = { Statement statement -> statement }
+    int closureLevel = 0
+
+    void replaceIn(ASTNode root) {
+        root.visit(this)
+    }
+
+    public void visitClosureExpression(ClosureExpression expression) {
+        closureLevel++
+        try {
+            super.visitClosureExpression(expression)
+        } finally {
+            closureLevel--
+        }
+    }
+
+    public void visitBlockStatement(BlockStatement block) {
+        List<Statement> copyOfStatements = new ArrayList<Statement>(block.statements)
+        copyOfStatements.eachWithIndex { Statement statement, int index ->
+            replaceIfNecessary(statement) { Statement node -> block.statements[index] = node }
+        }
+        super.visitBlockStatement(block);
+    }
+
+    public void visitIfElse(IfStatement ifElse) {
+        replaceIfNecessary(ifElse.ifBlock) { Statement s -> ifElse.ifBlock = s }
+        replaceIfNecessary(ifElse.elseBlock) { Statement s -> ifElse.elseBlock = s }
+        super.visitIfElse(ifElse);
+    }
+
+    public void visitForLoop(ForStatement forLoop) {
+        replaceIfNecessary(forLoop.loopBlock) { Statement s -> forLoop.loopBlock = s }
+        super.visitForLoop(forLoop);
+    }
+
+    public void visitWhileLoop(WhileStatement loop) {
+        replaceIfNecessary(loop.loopBlock) { Statement s -> loop.loopBlock = s }
+        super.visitWhileLoop(loop);
+    }
+
+    public void visitDoWhileLoop(DoWhileStatement loop) {
+        replaceIfNecessary(loop.loopBlock) { Statement s -> loop.loopBlock = s }
+        super.visitDoWhileLoop(loop);
+    }
+
+
+    private void replaceIfNecessary(Statement nodeToCheck, Closure replacementCode) {
+        if (conditionFulfilled(nodeToCheck)) {
+            ASTNode replacement = replaceWith(nodeToCheck)
+            replacement.setSourcePosition(nodeToCheck);
+            replacement.copyNodeMetaData(nodeToCheck);
+            replacementCode(replacement)
+        }
+    }
+
+    private boolean conditionFulfilled(ASTNode nodeToCheck) {
+        if (when.maximumNumberOfParameters < 2)
+            return when(nodeToCheck)
+        else
+            return when(nodeToCheck, isInClosure())
+    }
+
+    private boolean isInClosure() {
+        closureLevel > 0
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/StringUtil.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/StringUtil.groovy b/src/main/groovy/StringUtil.groovy
new file mode 100644
index 0000000..ed83e53
--- /dev/null
+++ b/src/main/groovy/StringUtil.groovy
@@ -0,0 +1,57 @@
+/*
+ *  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.util
+
+import groovy.transform.CompileStatic
+
+/**
+ * String utility functions.
+ */
+@CompileStatic
+class StringUtil {
+    /**
+     * Provides Groovy with functionality similar to the unix tr command
+     * which translates a string replacing characters from a source set
+     * with characters from a replacement set.
+     *
+     * @since 1.7.3
+     */
+    static String tr(String text, String source, String replacement) {
+        if (!text || !source) { return text }
+        source = expandHyphen(source)
+        replacement = expandHyphen(replacement)
+
+        // padding replacement with a last character, if necessary
+        replacement = replacement.padRight(source.size(), replacement[replacement.size() - 1])
+
+        return text.collect { String original ->
+            if (source.contains(original)) {
+                replacement[source.lastIndexOf(original)]
+            } else {
+                original
+            }
+        }.join('')
+    }
+
+    // no expansion for hyphen at start or end of Strings
+    private static String expandHyphen(String text) {
+        if (!text.contains('-')) { return text }
+        return text.replaceAll(/(.)-(.)/, { all, begin, end -> (begin..end).join('') })
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/TailRecursiveASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/TailRecursiveASTTransformation.groovy b/src/main/groovy/TailRecursiveASTTransformation.groovy
new file mode 100644
index 0000000..0605f18
--- /dev/null
+++ b/src/main/groovy/TailRecursiveASTTransformation.groovy
@@ -0,0 +1,261 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import groovy.transform.Memoized
+import groovy.transform.TailRecursive
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression
+import org.codehaus.groovy.ast.expr.TernaryExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.ReturnStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.classgen.ReturnAdder
+import org.codehaus.groovy.classgen.VariableScopeVisitor
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.AbstractASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+
+/**
+ * Handles generation of code for the @TailRecursive annotation.
+ *
+ * It's doing its work in the earliest possible compile phase
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
+class TailRecursiveASTTransformation extends AbstractASTTransformation {
+
+    private static final Class MY_CLASS = TailRecursive.class;
+    private static final ClassNode MY_TYPE = new ClassNode(MY_CLASS);
+    static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage()
+    private HasRecursiveCalls hasRecursiveCalls = new HasRecursiveCalls()
+    private TernaryToIfStatementConverter ternaryToIfStatement = new TernaryToIfStatementConverter()
+
+
+    @Override
+    public void visit(ASTNode[] nodes, SourceUnit source) {
+        init(nodes, source);
+
+        MethodNode method = nodes[1] as MethodNode
+
+        if (method.isAbstract()) {
+            addError("Annotation " + MY_TYPE_NAME + " cannot be used for abstract methods.", method);
+            return;
+        }
+
+        if (hasAnnotation(method, ClassHelper.make(Memoized))) {
+            ClassNode memoizedClassNode = ClassHelper.make(Memoized)
+            for (AnnotationNode annotationNode in method.annotations) {
+                if (annotationNode.classNode == MY_TYPE)
+                    break
+                if (annotationNode.classNode == memoizedClassNode) {
+                    addError("Annotation " + MY_TYPE_NAME + " must be placed before annotation @Memoized.", annotationNode)
+                    return
+                }
+            }
+        }
+
+        if (!hasRecursiveMethodCalls(method)) {
+            AnnotationNode annotationNode = method.getAnnotations(ClassHelper.make(TailRecursive))[0]
+            addError("No recursive calls detected. You must remove annotation " + MY_TYPE_NAME + ".", annotationNode)
+            return;
+        }
+
+        transformToIteration(method, source)
+        ensureAllRecursiveCallsHaveBeenTransformed(method)
+    }
+
+    private boolean hasAnnotation(MethodNode methodNode, ClassNode annotation) {
+        List annots = methodNode.getAnnotations(annotation);
+        return (annots != null && annots.size() > 0);
+    }
+
+
+    private void transformToIteration(MethodNode method, SourceUnit source) {
+        if (method.isVoidMethod()) {
+            transformVoidMethodToIteration(method, source)
+        } else {
+            transformNonVoidMethodToIteration(method, source)
+        }
+    }
+
+    private void transformVoidMethodToIteration(MethodNode method, SourceUnit source) {
+        addError("Void methods are not supported by @TailRecursive yet.", method)
+    }
+
+    private void transformNonVoidMethodToIteration(MethodNode method, SourceUnit source) {
+        addMissingDefaultReturnStatement(method)
+        replaceReturnsWithTernariesToIfStatements(method)
+        wrapMethodBodyWithWhileLoop(method)
+
+        Map<String, Map> nameAndTypeMapping = name2VariableMappingFor(method)
+        replaceAllAccessToParams(method, nameAndTypeMapping)
+        addLocalVariablesForAllParameters(method, nameAndTypeMapping) //must happen after replacing access to params
+
+        Map<Integer, Map> positionMapping = position2VariableMappingFor(method)
+        replaceAllRecursiveReturnsWithIteration(method, positionMapping)
+        repairVariableScopes(source, method)
+    }
+
+    private void repairVariableScopes(SourceUnit source, MethodNode method) {
+        new VariableScopeVisitor(source).visitClass(method.declaringClass)
+    }
+
+    private void replaceReturnsWithTernariesToIfStatements(MethodNode method) {
+        Closure<Boolean> whenReturnWithTernary = { ASTNode node ->
+            if (!(node instanceof ReturnStatement)) {
+                return false
+            }
+            return (((ReturnStatement) node).expression instanceof TernaryExpression)
+        }
+        Closure<Statement> replaceWithIfStatement = { ReturnStatement statement ->
+            ternaryToIfStatement.convert(statement)
+        }
+        StatementReplacer replacer = new StatementReplacer(when: whenReturnWithTernary, replaceWith: replaceWithIfStatement)
+        replacer.replaceIn(method.code)
+
+    }
+
+    private void addLocalVariablesForAllParameters(MethodNode method, Map<String, Map> nameAndTypeMapping) {
+        BlockStatement code = method.code as BlockStatement
+        nameAndTypeMapping.each { String paramName, Map localNameAndType ->
+            code.statements.add(0, AstHelper.createVariableDefinition(
+                    (String) localNameAndType['name'],
+                    (ClassNode) localNameAndType['type'],
+                    new VariableExpression(paramName, (ClassNode) localNameAndType['type'])
+            ))
+        }
+    }
+
+    private void replaceAllAccessToParams(MethodNode method, Map<String, Map> nameAndTypeMapping) {
+        new VariableAccessReplacer(nameAndTypeMapping: nameAndTypeMapping).replaceIn(method.code)
+    }
+
+    // Public b/c there are tests for this method
+    Map<String, Map> name2VariableMappingFor(MethodNode method) {
+        Map<String, Map> nameAndTypeMapping = [:]
+        method.parameters.each { Parameter param ->
+            String paramName = param.name
+            ClassNode paramType = param.type as ClassNode
+            String iterationVariableName = iterationVariableName(paramName)
+            nameAndTypeMapping[paramName] = [name: iterationVariableName, type: paramType]
+        }
+        return nameAndTypeMapping
+    }
+
+    // Public b/c there are tests for this method
+    Map<Integer, Map> position2VariableMappingFor(MethodNode method) {
+        Map<Integer, Map> positionMapping = [:]
+        method.parameters.eachWithIndex { Parameter param, int index ->
+            String paramName = param.name
+            ClassNode paramType = param.type as ClassNode
+            String iterationVariableName = this.iterationVariableName(paramName)
+            positionMapping[index] = [name: iterationVariableName, type: paramType]
+        }
+        return positionMapping
+    }
+
+    private String iterationVariableName(String paramName) {
+        '_' + paramName + '_'
+    }
+
+    private void replaceAllRecursiveReturnsWithIteration(MethodNode method, Map positionMapping) {
+        replaceRecursiveReturnsOutsideClosures(method, positionMapping)
+        replaceRecursiveReturnsInsideClosures(method, positionMapping)
+    }
+
+    private void replaceRecursiveReturnsOutsideClosures(MethodNode method, Map<Integer, Map> positionMapping) {
+        Closure<Boolean> whenRecursiveReturn = { Statement statement, boolean inClosure ->
+            if (inClosure)
+                return false
+            if (!(statement instanceof ReturnStatement)) {
+                return false
+            }
+            Expression inner = ((ReturnStatement) statement).expression
+            if (!(inner instanceof MethodCallExpression) && !(inner instanceof StaticMethodCallExpression)) {
+                return false
+            }
+            return isRecursiveIn(inner, method)
+        }
+        Closure<Statement> replaceWithContinueBlock = { ReturnStatement statement ->
+            new ReturnStatementToIterationConverter().convert(statement, positionMapping)
+        }
+        def replacer = new StatementReplacer(when: whenRecursiveReturn, replaceWith: replaceWithContinueBlock)
+        replacer.replaceIn(method.code)
+    }
+
+    private void replaceRecursiveReturnsInsideClosures(MethodNode method, Map<Integer, Map> positionMapping) {
+        Closure<Boolean> whenRecursiveReturn = { Statement statement, boolean inClosure ->
+            if (!inClosure)
+                return false
+            if (!(statement instanceof ReturnStatement)) {
+                return false
+            }
+            Expression inner = ((ReturnStatement )statement).expression
+            if (!(inner instanceof MethodCallExpression) && !(inner instanceof StaticMethodCallExpression)) {
+                return false
+            }
+            return isRecursiveIn(inner, method)
+        }
+        Closure<Statement> replaceWithThrowLoopException = { ReturnStatement statement ->
+            new ReturnStatementToIterationConverter(recurStatement: AstHelper.recurByThrowStatement()).convert(statement, positionMapping)
+        }
+        StatementReplacer replacer = new StatementReplacer(when: whenRecursiveReturn, replaceWith: replaceWithThrowLoopException)
+        replacer.replaceIn(method.code)
+    }
+
+    private void wrapMethodBodyWithWhileLoop(MethodNode method) {
+        new InWhileLoopWrapper().wrap(method)
+    }
+
+    private void addMissingDefaultReturnStatement(MethodNode method) {
+        new ReturnAdder().visitMethod(method)
+        new ReturnAdderForClosures().visitMethod(method)
+    }
+
+    private void ensureAllRecursiveCallsHaveBeenTransformed(MethodNode method) {
+        List<Expression> remainingRecursiveCalls = new CollectRecursiveCalls().collect(method)
+        for(Expression expression : remainingRecursiveCalls) {
+            addError("Recursive call could not be transformed by @TailRecursive. Maybe it's not a tail call.", expression)
+        }
+    }
+
+    private boolean hasRecursiveMethodCalls(MethodNode method) {
+        hasRecursiveCalls.test(method)
+    }
+
+    private boolean isRecursiveIn(Expression methodCall, MethodNode method) {
+        if (methodCall instanceof MethodCallExpression)
+            return new RecursivenessTester().isRecursive(method, (MethodCallExpression) methodCall)
+        if (methodCall instanceof StaticMethodCallExpression)
+            return new RecursivenessTester().isRecursive(method, (StaticMethodCallExpression) methodCall)
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/TernaryToIfStatementConverter.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/TernaryToIfStatementConverter.groovy b/src/main/groovy/TernaryToIfStatementConverter.groovy
new file mode 100644
index 0000000..c47e1d2
--- /dev/null
+++ b/src/main/groovy/TernaryToIfStatementConverter.groovy
@@ -0,0 +1,42 @@
+/*
+ *  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.transform.tailrec
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.expr.TernaryExpression
+import org.codehaus.groovy.ast.stmt.IfStatement
+import org.codehaus.groovy.ast.stmt.ReturnStatement
+import org.codehaus.groovy.ast.stmt.Statement
+
+/**
+ * Since a ternary statement has more than one exit point tail-recursiveness testing cannot be easily done.
+ * Therefore this class translates a ternary statement (or Elvis operator) into the equivalent if-else statement.
+ *
+ * @author Johannes Link
+ */
+@CompileStatic
+class TernaryToIfStatementConverter {
+
+    Statement convert(ReturnStatement statementWithInnerTernaryExpression) {
+        if (!(statementWithInnerTernaryExpression.expression instanceof TernaryExpression))
+            return statementWithInnerTernaryExpression
+        TernaryExpression ternary = statementWithInnerTernaryExpression.expression as TernaryExpression
+        return new IfStatement(ternary.booleanExpression, new ReturnStatement(ternary.trueExpression), new ReturnStatement(ternary.falseExpression))
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/ThreadInterruptibleASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/ThreadInterruptibleASTTransformation.groovy b/src/main/groovy/ThreadInterruptibleASTTransformation.groovy
new file mode 100644
index 0000000..a4fb4c3
--- /dev/null
+++ b/src/main/groovy/ThreadInterruptibleASTTransformation.groovy
@@ -0,0 +1,98 @@
+/*
+ *  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.transform
+
+import groovy.transform.CompileStatic
+import groovy.transform.ThreadInterrupt
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ClassExpression
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.control.CompilePhase
+
+/**
+ * Allows "interrupt-safe" executions of scripts by adding Thread.currentThread().isInterrupted()
+ * checks on loops (for, while, do) and first statement of closures. By default, also adds an interrupt check
+ * statement on the beginning of method calls.
+ *
+ * @see groovy.transform.ThreadInterrupt
+ *
+ * @author Cedric Champeau
+ * @author Hamlet D'Arcy
+ *
+ * @since 1.8.0
+ */
+@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
+@CompileStatic
+public class ThreadInterruptibleASTTransformation extends AbstractInterruptibleASTTransformation {
+
+    private static final ClassNode MY_TYPE = ClassHelper.make(ThreadInterrupt)
+    private static final ClassNode THREAD_TYPE = ClassHelper.make(Thread)
+    private static final MethodNode CURRENTTHREAD_METHOD
+    private static final MethodNode ISINTERRUPTED_METHOD
+
+    static {
+        CURRENTTHREAD_METHOD = THREAD_TYPE.getMethod('currentThread', Parameter.EMPTY_ARRAY)
+        ISINTERRUPTED_METHOD = THREAD_TYPE.getMethod('isInterrupted', Parameter.EMPTY_ARRAY)
+    }
+
+    protected ClassNode type() {
+        return MY_TYPE;
+    }
+
+    protected String getErrorMessage() {
+        'Execution interrupted. The current thread has been interrupted.'
+    }
+
+    protected Expression createCondition() {
+        def currentThread = new MethodCallExpression(new ClassExpression(THREAD_TYPE),
+                'currentThread',
+                ArgumentListExpression.EMPTY_ARGUMENTS)
+        currentThread.methodTarget = CURRENTTHREAD_METHOD
+        def isInterrupted = new MethodCallExpression(
+                currentThread,
+                'isInterrupted', ArgumentListExpression.EMPTY_ARGUMENTS)
+        isInterrupted.methodTarget = ISINTERRUPTED_METHOD
+        [currentThread, isInterrupted]*.implicitThis = false
+
+        isInterrupted
+    }
+
+
+    @Override
+    public void visitClosureExpression(ClosureExpression closureExpr) {
+        def code = closureExpr.code
+        closureExpr.code = wrapBlock(code)
+        super.visitClosureExpression closureExpr
+    }
+
+    @Override
+    public void visitMethod(MethodNode node) {
+        if (checkOnMethodStart && !node.isSynthetic() && !node.isAbstract()) {
+            def code = node.code
+            node.code = wrapBlock(code);
+        }
+        super.visitMethod(node)
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/TimedInterruptibleASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/TimedInterruptibleASTTransformation.groovy b/src/main/groovy/TimedInterruptibleASTTransformation.groovy
new file mode 100644
index 0000000..fbc923b
--- /dev/null
+++ b/src/main/groovy/TimedInterruptibleASTTransformation.groovy
@@ -0,0 +1,321 @@
+/*
+ *  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.transform
+
+import groovy.transform.TimedInterrupt
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.AnnotatedNode
+import org.codehaus.groovy.ast.AnnotationNode
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.FieldNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.PropertyNode
+import org.codehaus.groovy.ast.expr.ClosureExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.DeclarationExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.DoWhileStatement
+import org.codehaus.groovy.ast.stmt.ForStatement
+import org.codehaus.groovy.ast.stmt.WhileStatement
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+
+import static org.codehaus.groovy.ast.ClassHelper.make
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.constX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ifS
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ltX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.plusX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.propX
+import static org.codehaus.groovy.ast.tools.GeneralUtils.throwS
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX
+
+/**
+ * Allows "interrupt-safe" executions of scripts by adding timer expiration
+ * checks on loops (for, while, do) and first statement of closures. By default,
+ * also adds an interrupt check statement on the beginning of method calls.
+ *
+ * @author Cedric Champeau
+ * @author Hamlet D'Arcy
+ * @author Paul King
+ * @see groovy.transform.ThreadInterrupt
+ * @since 1.8.0
+ */
+@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
+public class TimedInterruptibleASTTransformation extends AbstractASTTransformation {
+
+    private static final ClassNode MY_TYPE = make(TimedInterrupt)
+    private static final String CHECK_METHOD_START_MEMBER = 'checkOnMethodStart'
+    private static final String APPLY_TO_ALL_CLASSES = 'applyToAllClasses'
+    private static final String APPLY_TO_ALL_MEMBERS = 'applyToAllMembers'
+    private static final String THROWN_EXCEPTION_TYPE = "thrown"
+
+    public void visit(ASTNode[] nodes, SourceUnit source) {
+        init(nodes, source);
+        AnnotationNode node = nodes[0]
+        AnnotatedNode annotatedNode = nodes[1]
+        if (!MY_TYPE.equals(node.getClassNode())) {
+            internalError("Transformation called from wrong annotation: $node.classNode.name")
+        }
+
+        def checkOnMethodStart = getConstantAnnotationParameter(node, CHECK_METHOD_START_MEMBER, Boolean.TYPE, true)
+        def applyToAllMembers = getConstantAnnotationParameter(node, APPLY_TO_ALL_MEMBERS, Boolean.TYPE, true)
+        def applyToAllClasses = applyToAllMembers ? getConstantAnnotationParameter(node, APPLY_TO_ALL_CLASSES, Boolean.TYPE, true) : false
+        def maximum = getConstantAnnotationParameter(node, 'value', Long.TYPE, Long.MAX_VALUE)
+        def thrown = AbstractInterruptibleASTTransformation.getClassAnnotationParameter(node, THROWN_EXCEPTION_TYPE, make(TimeoutException))
+
+        Expression unit = node.getMember('unit') ?: propX(classX(TimeUnit), "SECONDS")
+
+        // should be limited to the current SourceUnit or propagated to the whole CompilationUnit
+        // DO NOT inline visitor creation in code below. It has state that must not persist between calls
+        if (applyToAllClasses) {
+            // guard every class and method defined in this script
+            source.getAST()?.classes?.each { ClassNode it ->
+                def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode())
+                visitor.visitClass(it)
+            }
+        } else if (annotatedNode instanceof ClassNode) {
+            // only guard this particular class
+            def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode())
+            visitor.visitClass annotatedNode
+        } else if (!applyToAllMembers && annotatedNode instanceof MethodNode) {
+            // only guard this particular method (plus initCode for class)
+            def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode())
+            visitor.visitMethod annotatedNode
+            visitor.visitClass annotatedNode.declaringClass
+        } else if (!applyToAllMembers && annotatedNode instanceof FieldNode) {
+            // only guard this particular field (plus initCode for class)
+            def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode())
+            visitor.visitField annotatedNode
+            visitor.visitClass annotatedNode.declaringClass
+        } else if (!applyToAllMembers && annotatedNode instanceof DeclarationExpression) {
+            // only guard this particular declaration (plus initCode for class)
+            def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode())
+            visitor.visitDeclarationExpression annotatedNode
+            visitor.visitClass annotatedNode.declaringClass
+        } else {
+            // only guard the script class
+            source.getAST()?.classes?.each { ClassNode it ->
+                if (it.isScript()) {
+                    def visitor = new TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, node.hashCode())
+                    visitor.visitClass(it)
+                }
+            }
+        }
+    }
+
+    static def getConstantAnnotationParameter(AnnotationNode node, String parameterName, Class type, defaultValue) {
+        def member = node.getMember(parameterName)
+        if (member) {
+            if (member instanceof ConstantExpression) {
+                // TODO not sure this try offers value - testing Groovy annotation type handing - throw GroovyBugError or remove?
+                try {
+                    return member.value.asType(type)
+                } catch (ignore) {
+                    internalError("Expecting boolean value for ${parameterName} annotation parameter. Found $member")
+                }
+            } else {
+                internalError("Expecting boolean value for ${parameterName} annotation parameter. Found $member")
+            }
+        }
+        return defaultValue
+    }
+
+    private static void internalError(String message) {
+        throw new RuntimeException("Internal error: $message")
+    }
+
+    private static class TimedInterruptionVisitor extends ClassCodeVisitorSupport {
+        final private SourceUnit source
+        final private boolean checkOnMethodStart
+        final private boolean applyToAllClasses
+        final private boolean applyToAllMembers
+        private FieldNode expireTimeField = null
+        private FieldNode startTimeField = null
+        private final Expression unit
+        private final maximum
+        private final ClassNode thrown
+        private final String basename
+
+        TimedInterruptionVisitor(source, checkOnMethodStart, applyToAllClasses, applyToAllMembers, maximum, unit, thrown, hash) {
+            this.source = source
+            this.checkOnMethodStart = checkOnMethodStart
+            this.applyToAllClasses = applyToAllClasses
+            this.applyToAllMembers = applyToAllMembers
+            this.unit = unit
+            this.maximum = maximum
+            this.thrown = thrown
+            this.basename = 'timedInterrupt' + hash
+        }
+
+        /**
+         * @return Returns the interruption check statement.
+         */
+        final createInterruptStatement() {
+            ifS(
+
+                    ltX(
+                            propX(varX("this"), basename + '$expireTime'),
+                            callX(make(System), 'nanoTime')
+                    ),
+                    throwS(
+                            ctorX(thrown,
+                                    args(
+                                            plusX(
+                                                    plusX(
+                                                            constX('Execution timed out after ' + maximum + ' '),
+                                                            callX(callX(unit, 'name'), 'toLowerCase', propX(classX(Locale), 'US'))
+                                                    ),
+                                                    plusX(
+                                                            constX('. Start time: '),
+                                                            propX(varX("this"), basename + '$startTime')
+                                                    )
+                                            )
+
+                                    )
+                            )
+                    )
+            )
+        }
+
+        /**
+         * Takes a statement and wraps it into a block statement which first element is the interruption check statement.
+         * @param statement the statement to be wrapped
+         * @return a {@link BlockStatement block statement}    which first element is for checking interruption, and the
+         * second one the statement to be wrapped.
+         */
+        private wrapBlock(statement) {
+            def stmt = new BlockStatement();
+            stmt.addStatement(createInterruptStatement());
+            stmt.addStatement(statement);
+            stmt
+        }
+
+        @Override
+        void visitClass(ClassNode node) {
+            if (node.getDeclaredField(basename + '$expireTime')) {
+                return
+            }
+            expireTimeField = node.addField(basename + '$expireTime',
+                    ACC_FINAL | ACC_PRIVATE,
+                    ClassHelper.long_TYPE,
+                    plusX(
+                            callX(make(System), 'nanoTime'),
+                            callX(
+                                    propX(classX(TimeUnit), 'NANOSECONDS'),
+                                    'convert',
+                                    args(constX(maximum, true), unit)
+                            )
+                    )
+            );
+            expireTimeField.synthetic = true
+            startTimeField = node.addField(basename + '$startTime',
+                    ACC_FINAL | ACC_PRIVATE,
+                    make(Date),
+                    ctorX(make(Date))
+            )
+            startTimeField.synthetic = true
+
+            // force these fields to be initialized first
+            node.fields.remove(expireTimeField)
+            node.fields.remove(startTimeField)
+            node.fields.add(0, startTimeField)
+            node.fields.add(0, expireTimeField)
+            if (applyToAllMembers) {
+                super.visitClass node
+            }
+        }
+
+        @Override
+        void visitClosureExpression(ClosureExpression closureExpr) {
+            def code = closureExpr.code
+            if (code instanceof BlockStatement) {
+                code.statements.add(0, createInterruptStatement())
+            } else {
+                closureExpr.code = wrapBlock(code)
+            }
+            super.visitClosureExpression closureExpr
+        }
+
+        @Override
+        void visitField(FieldNode node) {
+            if (!node.isStatic() && !node.isSynthetic()) {
+                super.visitField node
+            }
+        }
+
+        @Override
+        void visitProperty(PropertyNode node) {
+            if (!node.isStatic() && !node.isSynthetic()) {
+                super.visitProperty node
+            }
+        }
+
+        /**
+         * Shortcut method which avoids duplicating code for every type of loop.
+         * Actually wraps the loopBlock of different types of loop statements.
+         */
+        private visitLoop(loopStatement) {
+            def statement = loopStatement.loopBlock
+            loopStatement.loopBlock = wrapBlock(statement)
+        }
+
+        @Override
+        void visitForLoop(ForStatement forStatement) {
+            visitLoop(forStatement)
+            super.visitForLoop(forStatement)
+        }
+
+        @Override
+        void visitDoWhileLoop(final DoWhileStatement doWhileStatement) {
+            visitLoop(doWhileStatement)
+            super.visitDoWhileLoop(doWhileStatement)
+        }
+
+        @Override
+        void visitWhileLoop(final WhileStatement whileStatement) {
+            visitLoop(whileStatement)
+            super.visitWhileLoop(whileStatement)
+        }
+
+        @Override
+        void visitMethod(MethodNode node) {
+            if (checkOnMethodStart && !node.isSynthetic() && !node.isStatic() && !node.isAbstract()) {
+                def code = node.code
+                node.code = wrapBlock(code);
+            }
+            if (!node.isSynthetic() && !node.isStatic()) {
+                super.visitMethod(node)
+            }
+        }
+
+        protected SourceUnit getSourceUnit() {
+            return source;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/groovy/TransformTestHelper.groovy
----------------------------------------------------------------------
diff --git a/src/main/groovy/TransformTestHelper.groovy b/src/main/groovy/TransformTestHelper.groovy
new file mode 100644
index 0000000..d9921d5
--- /dev/null
+++ b/src/main/groovy/TransformTestHelper.groovy
@@ -0,0 +1,123 @@
+/*
+ *  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.tools.ast
+
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.classgen.GeneratorContext
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilationUnit.PrimaryClassNodeOperation
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.ASTTransformation
+
+import java.security.CodeSource
+
+/*
+* This TestHarness exists so that a global transform can be run without
+* using the Jar services mechanism, which requires building a jar.
+* 
+* To use this simply create an instance of TransformTestHelper with
+* an ASTTransformation and CompilePhase, then invoke parse(File) or
+* parse(String). 
+* 
+* This test harness is not exactly the same as executing a global transformation
+* but can greatly aide in debugging and testing a transform. You should still
+* test your global transformation when packaged as a jar service before
+* releasing it. 
+* 
+* @author Hamlet D'Arcy
+*/
+class TransformTestHelper {
+
+    private final ASTTransformation transform
+    private final CompilePhase phase
+
+    /**
+     * Creates the test helper.
+     * @param transform
+     *      the transform to run when compiling the file later
+     * @param phase
+     *      the phase to run the transform in 
+     */
+    def TransformTestHelper(ASTTransformation transform, CompilePhase phase) {
+        this.transform = transform
+        this.phase = phase
+    }
+
+    /**
+     * Compiles the File into a Class applying the transform specified in the constructor.
+     * @input input
+     *      must be a groovy source file
+     */
+    public Class parse(File input) {
+        TestHarnessClassLoader loader = new TestHarnessClassLoader(transform, phase)
+        return loader.parseClass(input)
+    }
+
+    /**
+     * Compiles the String into a Class applying the transform specified in the constructor.
+     * @input input
+     *      must be a valid groovy source string
+     */
+    public Class parse(String input) {
+        TestHarnessClassLoader loader = new TestHarnessClassLoader(transform, phase)
+        return loader.parseClass(input)
+    }
+}
+
+/**
+* ClassLoader exists so that TestHarnessOperation can be wired into the compile. 
+*
+* @author Hamlet D'Arcy
+*/
+@groovy.transform.PackageScope class TestHarnessClassLoader extends GroovyClassLoader {
+
+    private final ASTTransformation transform
+    private final CompilePhase phase
+
+    TestHarnessClassLoader(ASTTransformation transform, CompilePhase phase) {
+        this.transform = transform
+        this.phase = phase
+    }
+
+    protected CompilationUnit createCompilationUnit(CompilerConfiguration config, CodeSource codeSource) {
+        CompilationUnit cu = super.createCompilationUnit(config, codeSource)
+        cu.addPhaseOperation(new TestHarnessOperation(transform), phase.getPhaseNumber())
+        return cu
+    }
+}
+
+/**
+* Operation exists so that an AstTransformation can be run against the SourceUnit.
+*
+* @author Hamlet D'Arcy
+*/
+@groovy.transform.PackageScope class TestHarnessOperation extends PrimaryClassNodeOperation {
+
+    private final ASTTransformation transform
+
+    def TestHarnessOperation(transform) {
+        this.transform = transform;
+    }
+
+    public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) {
+        transform.visit(null, source)
+    }
+}


[62/62] [abbrv] groovy git commit: Fix overlapping outputs for asciidoc task

Posted by cc...@apache.org.
Fix overlapping outputs for asciidoc task

This fixes the build cache issue and makes it much faster to rebuild. Note that the full
documentation now lives into the `target/asciidocAll` directory.


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/f8be7429
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/f8be7429
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/f8be7429

Branch: refs/heads/GROOVY_2_6_X
Commit: f8be74296fe8d5cee69046abff9dd2650177305d
Parents: c37615b
Author: Cedric Champeau <cc...@apache.org>
Authored: Sat Dec 16 22:48:22 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:59:58 2017 +0100

----------------------------------------------------------------------
 build.gradle | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/f8be7429/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index c24073e..3cf3f60 100644
--- a/build.gradle
+++ b/build.gradle
@@ -72,7 +72,6 @@ ext.modules = {
 }
 ext.isReleaseVersion = !groovyVersion.toLowerCase().endsWith("snapshot")
 
-apply from: 'gradle/filter.gradle'
 apply from: 'gradle/indy.gradle'
 apply from: 'gradle/publish.gradle'
 apply plugin: 'javadocHotfix'


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/apache/groovy/util/Maps.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/groovy/util/Maps.java b/src/main/java/org/apache/groovy/util/Maps.java
new file mode 100644
index 0000000..94ec26e
--- /dev/null
+++ b/src/main/java/org/apache/groovy/util/Maps.java
@@ -0,0 +1,5781 @@
+/*
+ *  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.apache.groovy.util;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Map utilities.
+ * @since 2.5.0
+ */
+public abstract class Maps {
+
+    public static <K, V> Map<K, V> of(K k1, V v1) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+        map.put(k55, v55);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55, K k56, V v56) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+        map.put(k55, v55);
+        map.put(k56, v56);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55, K k56, V v56, K k57, V v57) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+        map.put(k55, v55);
+        map.put(k56, v56);
+        map.put(k57, v57);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55, K k56, V v56, K k57, V v57, K k58, V v58) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+        map.put(k55, v55);
+        map.put(k56, v56);
+        map.put(k57, v57);
+        map.put(k58, v58);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55, K k56, V v56, K k57, V v57, K k58, V v58, K k59, V v59) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+        map.put(k55, v55);
+        map.put(k56, v56);
+        map.put(k57, v57);
+        map.put(k58, v58);
+        map.put(k59, v59);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55, K k56, V v56, K k57, V v57, K k58, V v58, K k59, V v59, K k60, V v60) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+        map.put(k55, v55);
+        map.put(k56, v56);
+        map.put(k57, v57);
+        map.put(k58, v58);
+        map.put(k59, v59);
+        map.put(k60, v60);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55, K k56, V v56, K k57, V v57, K k58, V v58, K k59, V v59, K k60, V v60, K k61, V v61) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put(k8, v8);
+        map.put(k9, v9);
+        map.put(k10, v10);
+        map.put(k11, v11);
+        map.put(k12, v12);
+        map.put(k13, v13);
+        map.put(k14, v14);
+        map.put(k15, v15);
+        map.put(k16, v16);
+        map.put(k17, v17);
+        map.put(k18, v18);
+        map.put(k19, v19);
+        map.put(k20, v20);
+        map.put(k21, v21);
+        map.put(k22, v22);
+        map.put(k23, v23);
+        map.put(k24, v24);
+        map.put(k25, v25);
+        map.put(k26, v26);
+        map.put(k27, v27);
+        map.put(k28, v28);
+        map.put(k29, v29);
+        map.put(k30, v30);
+        map.put(k31, v31);
+        map.put(k32, v32);
+        map.put(k33, v33);
+        map.put(k34, v34);
+        map.put(k35, v35);
+        map.put(k36, v36);
+        map.put(k37, v37);
+        map.put(k38, v38);
+        map.put(k39, v39);
+        map.put(k40, v40);
+        map.put(k41, v41);
+        map.put(k42, v42);
+        map.put(k43, v43);
+        map.put(k44, v44);
+        map.put(k45, v45);
+        map.put(k46, v46);
+        map.put(k47, v47);
+        map.put(k48, v48);
+        map.put(k49, v49);
+        map.put(k50, v50);
+        map.put(k51, v51);
+        map.put(k52, v52);
+        map.put(k53, v53);
+        map.put(k54, v54);
+        map.put(k55, v55);
+        map.put(k56, v56);
+        map.put(k57, v57);
+        map.put(k58, v58);
+        map.put(k59, v59);
+        map.put(k60, v60);
+        map.put(k61, v61);
+
+        return Collections.unmodifiableMap(map);
+    }
+
+    public static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10, K k11, V v11, K k12, V v12, K k13, V v13, K k14, V v14, K k15, V v15, K k16, V v16, K k17, V v17, K k18, V v18, K k19, V v19, K k20, V v20, K k21, V v21, K k22, V v22, K k23, V v23, K k24, V v24, K k25, V v25, K k26, V v26, K k27, V v27, K k28, V v28, K k29, V v29, K k30, V v30, K k31, V v31, K k32, V v32, K k33, V v33, K k34, V v34, K k35, V v35, K k36, V v36, K k37, V v37, K k38, V v38, K k39, V v39, K k40, V v40, K k41, V v41, K k42, V v42, K k43, V v43, K k44, V v44, K k45, V v45, K k46, V v46, K k47, V v47, K k48, V v48, K k49, V v49, K k50, V v50, K k51, V v51, K k52, V v52, K k53, V v53, K k54, V v54, K k55, V v55, K k56, V v56, K k57, V v57, K k58, V v58, K k59, V v59, K k60, V v60, K k61, V v61, K k62, V v62) {
+        Map<K, V> map = new LinkedHashMap<K, V>();
+
+        map.put(k1, v1);
+        map.put(k2, v2);
+        map.put(k3, v3);
+        map.put(k4, v4);
+        map.put(k5, v5);
+        map.put(k6, v6);
+        map.put(k7, v7);
+        map.put

<TRUNCATED>

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

Posted by cc...@apache.org.
Move Java source set into `src/main/java`


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/0edfcde9
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/0edfcde9
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/0edfcde9

Branch: refs/heads/GROOVY_2_6_X
Commit: 0edfcde99f3e7e5577e62882df1e13bc56c6f1c0
Parents: 9eea4eb
Author: Cedric Champeau <cc...@apache.org>
Authored: Sun Dec 17 14:28:12 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:28:12 2017 +0100

----------------------------------------------------------------------
 build.gradle                                    |    23 +-
 gradle/assemble.gradle                          |     1 +
 gradle/docs.gradle                              |     6 +-
 gradle/test.gradle                              |     2 +-
 src/main/groovy/ASTTestTransformation.groovy    |   233 +
 .../groovy/ASTTransformationCustomizer.groovy   |   301 +
 .../ASTTransformationCustomizerFactory.groovy   |    60 +
 src/main/groovy/AstBuilder.groovy               |   145 +
 src/main/groovy/AstHelper.groovy                |    76 +
 src/main/groovy/AstSpecificationCompiler.groovy |  1080 +
 src/main/groovy/AstStringCompiler.groovy        |    63 +
 src/main/groovy/CollectRecursiveCalls.groovy    |    62 +
 .../groovy/CompilerCustomizationBuilder.groovy  |    64 +
 ...itionalInterruptibleASTTransformation.groovy |   145 +
 src/main/groovy/GrapeMain.groovy                |   308 +
 src/main/groovy/HasRecursiveCalls.groovy        |    64 +
 src/main/groovy/InWhileLoopWrapper.groovy       |    81 +
 src/main/groovy/RecursivenessTester.groovy      |   100 +
 src/main/groovy/ReturnAdderForClosures.groovy   |    48 +
 .../ReturnStatementToIterationConverter.groovy  |   148 +
 src/main/groovy/StatementReplacer.groovy        |   109 +
 src/main/groovy/StringUtil.groovy               |    57 +
 .../TailRecursiveASTTransformation.groovy       |   261 +
 .../groovy/TernaryToIfStatementConverter.groovy |    42 +
 .../ThreadInterruptibleASTTransformation.groovy |    98 +
 .../TimedInterruptibleASTTransformation.groovy  |   321 +
 src/main/groovy/TransformTestHelper.groovy      |   123 +
 src/main/groovy/VariableAccessReplacer.groovy   |    73 +
 .../groovy/VariableExpressionReplacer.groovy    |   171 +
 .../groovy/VariableExpressionTransformer.groovy |    47 +
 src/main/groovy/genArrayAccess.groovy           |   146 +
 src/main/groovy/genArrays.groovy                |    53 +
 src/main/groovy/genDgmMath.groovy               |    87 +
 src/main/groovy/genMathModification.groovy      |   133 +
 .../apache/groovy/ast/tools/ClassNodeUtils.java |   273 +
 .../groovy/ast/tools/MethodNodeUtils.java       |    69 +
 .../internal/metaclass/MetaClassConstant.java   |    50 +
 .../apache/groovy/internal/util/Function.java   |    31 +
 .../internal/util/ReevaluatingReference.java    |    88 +
 .../apache/groovy/internal/util/Supplier.java   |    31 +
 .../groovy/internal/util/UncheckedThrow.java    |    38 +
 .../groovy/lang/annotation/Incubating.java      |    43 +
 .../org/apache/groovy/metaclass/MetaClass.java  |    41 +
 .../java/org/apache/groovy/metaclass/Realm.java |    91 +
 .../apache/groovy/plugin/DefaultRunners.java    |   218 +
 .../org/apache/groovy/plugin/GroovyRunner.java  |    49 +
 .../groovy/plugin/GroovyRunnerRegistry.java     |   468 +
 src/main/java/org/apache/groovy/util/Maps.java  |  5781 +++++
 .../java/org/apache/groovy/util/SystemUtil.java |    46 +
 .../ConcurrentLinkedHashMap.java                |  1600 ++
 .../concurrentlinkedhashmap/EntryWeigher.java   |    40 +
 .../EvictionListener.java                       |    48 +
 .../concurrentlinkedhashmap/LinkedDeque.java    |   462 +
 .../util/concurrentlinkedhashmap/Weigher.java   |    39 +
 .../util/concurrentlinkedhashmap/Weighers.java  |   282 +
 .../concurrentlinkedhashmap/package-info.java   |    41 +
 .../org/codehaus/groovy/GroovyBugError.java     |   111 +
 .../org/codehaus/groovy/GroovyException.java    |    52 +
 .../groovy/GroovyExceptionInterface.java        |    31 +
 .../groovy/antlr/ASTParserException.java        |    54 +
 .../groovy/antlr/ASTRuntimeException.java       |    55 +
 .../groovy/antlr/AntlrASTProcessSnippets.java   |    96 +
 .../groovy/antlr/AntlrASTProcessor.java         |    35 +
 .../groovy/antlr/AntlrParserPlugin.java         |  3269 +++
 .../groovy/antlr/AntlrParserPluginFactory.java  |    31 +
 .../org/codehaus/groovy/antlr/EnumHelper.java   |    68 +
 .../codehaus/groovy/antlr/GroovySourceAST.java  |   177 +
 .../groovy/antlr/GroovySourceToken.java         |   100 +
 .../org/codehaus/groovy/antlr/LexerFrame.java   |   279 +
 .../org/codehaus/groovy/antlr/LineColumn.java   |    65 +
 .../java/org/codehaus/groovy/antlr/Main.java    |   194 +
 .../org/codehaus/groovy/antlr/SourceBuffer.java |   111 +
 .../org/codehaus/groovy/antlr/SourceInfo.java   |    77 +
 .../groovy/antlr/UnicodeEscapingReader.java     |   190 +
 .../antlr/UnicodeLexerSharedInputState.java     |    51 +
 .../codehaus/groovy/antlr/java/Groovifier.java  |    74 +
 .../groovy/antlr/java/Java2GroovyConverter.java |   232 +
 .../groovy/antlr/java/Java2GroovyMain.java      |    44 +
 .../groovy/antlr/java/Java2GroovyProcessor.java |   187 +
 .../antlr/java/PreJava2GroovyConverter.java     |   147 +
 .../java/org/codehaus/groovy/antlr/package.html |    28 +
 .../antlr/treewalker/CompositeVisitor.java      |  1179 +
 .../antlr/treewalker/FlatNodeListTraversal.java |    63 +
 .../groovy/antlr/treewalker/MindMapPrinter.java |   379 +
 .../antlr/treewalker/NodeAsHTMLPrinter.java     |   319 +
 .../groovy/antlr/treewalker/NodeCollector.java  |    45 +
 .../groovy/antlr/treewalker/NodePrinter.java    |    52 +
 .../antlr/treewalker/PreOrderTraversal.java     |    45 +
 .../antlr/treewalker/SourceCodeTraversal.java   |   260 +
 .../groovy/antlr/treewalker/SourcePrinter.java  |  1097 +
 .../antlr/treewalker/TraversalHelper.java       |   557 +
 .../groovy/antlr/treewalker/Visitor.java        |   260 +
 .../groovy/antlr/treewalker/VisitorAdapter.java |   258 +
 .../groovy/antlr/treewalker/package.html        |    28 +
 .../java/org/codehaus/groovy/ast/ASTNode.java   |   158 +
 .../org/codehaus/groovy/ast/AnnotatedNode.java  |   112 +
 .../org/codehaus/groovy/ast/AnnotationNode.java |   189 +
 .../codehaus/groovy/ast/AstToTextHelper.java    |   111 +
 .../ast/ClassCodeExpressionTransformer.java     |   146 +
 .../groovy/ast/ClassCodeVisitorSupport.java     |   239 +
 .../org/codehaus/groovy/ast/ClassHelper.java    |   481 +
 .../java/org/codehaus/groovy/ast/ClassNode.java |  1503 ++
 .../codehaus/groovy/ast/CodeVisitorSupport.java |   345 +
 .../org/codehaus/groovy/ast/CompileUnit.java    |   193 +
 .../codehaus/groovy/ast/ConstructorNode.java    |    59 +
 .../codehaus/groovy/ast/DynamicVariable.java    |    76 +
 .../groovy/ast/EnumConstantClassNode.java       |    39 +
 .../java/org/codehaus/groovy/ast/FieldNode.java |   205 +
 .../org/codehaus/groovy/ast/GenericsType.java   |   500 +
 .../codehaus/groovy/ast/GroovyClassVisitor.java |    56 +
 .../codehaus/groovy/ast/GroovyCodeVisitor.java  |   191 +
 .../org/codehaus/groovy/ast/ImportNode.java     |   153 +
 .../org/codehaus/groovy/ast/InnerClassNode.java |   103 +
 .../groovy/ast/InterfaceHelperClassNode.java    |    51 +
 .../groovy/ast/MethodCallTransformation.java    |   116 +
 .../groovy/ast/MethodInvocationTrap.java        |    97 +
 .../org/codehaus/groovy/ast/MethodNode.java     |   284 +
 .../groovy/ast/MixinASTTransformation.java      |    88 +
 .../java/org/codehaus/groovy/ast/MixinNode.java |    47 +
 .../org/codehaus/groovy/ast/ModuleNode.java     |   488 +
 .../groovy/ast/NodeMetaDataHandler.java         |    82 +
 .../groovy/ast/NodeMetaDataHandlerHelper.java   |   138 +
 .../org/codehaus/groovy/ast/PackageNode.java    |    46 +
 .../java/org/codehaus/groovy/ast/Parameter.java |   126 +
 .../org/codehaus/groovy/ast/PropertyNode.java   |   135 +
 .../groovy/ast/TransformingCodeVisitor.java     |   371 +
 .../java/org/codehaus/groovy/ast/Variable.java  |    69 +
 .../org/codehaus/groovy/ast/VariableScope.java  |   200 +
 .../ast/builder/AstBuilderTransformation.java   |   186 +
 .../groovy/ast/decompiled/Annotations.java      |   136 +
 .../groovy/ast/decompiled/AsmDecompiler.java    |   218 +
 .../ast/decompiled/AsmReferenceResolver.java    |    92 +
 .../ast/decompiled/ClassSignatureParser.java    |    84 +
 .../groovy/ast/decompiled/ClassStub.java        |   117 +
 .../ast/decompiled/DecompiledClassNode.java     |   242 +
 .../ast/decompiled/FormalParameterParser.java   |    80 +
 .../ast/decompiled/MemberSignatureParser.java   |   155 +
 .../ast/decompiled/TypeSignatureParser.java     |   123 +
 .../ast/expr/AnnotationConstantExpression.java  |    50 +
 .../groovy/ast/expr/ArgumentListExpression.java |    78 +
 .../groovy/ast/expr/ArrayExpression.java        |   136 +
 .../groovy/ast/expr/AttributeExpression.java    |    50 +
 .../groovy/ast/expr/BinaryExpression.java       |   135 +
 .../ast/expr/BitwiseNegationExpression.java     |    58 +
 .../groovy/ast/expr/BooleanExpression.java      |    56 +
 .../groovy/ast/expr/CastExpression.java         |   111 +
 .../groovy/ast/expr/ClassExpression.java        |    51 +
 .../groovy/ast/expr/ClosureExpression.java      |   105 +
 .../groovy/ast/expr/ClosureListExpression.java  |    88 +
 .../groovy/ast/expr/ConstantExpression.java     |   124 +
 .../ast/expr/ConstructorCallExpression.java     |   105 +
 .../groovy/ast/expr/DeclarationExpression.java  |   168 +
 .../ast/expr/ElvisOperatorExpression.java       |    71 +
 .../groovy/ast/expr/EmptyExpression.java        |   140 +
 .../codehaus/groovy/ast/expr/Expression.java    |    81 +
 .../groovy/ast/expr/ExpressionTransformer.java  |    33 +
 .../groovy/ast/expr/FieldExpression.java        |    83 +
 .../groovy/ast/expr/GStringExpression.java      |   116 +
 .../groovy/ast/expr/LambdaExpression.java       |    47 +
 .../groovy/ast/expr/ListExpression.java         |    97 +
 .../groovy/ast/expr/MapEntryExpression.java     |    68 +
 .../codehaus/groovy/ast/expr/MapExpression.java |   100 +
 .../codehaus/groovy/ast/expr/MethodCall.java    |    34 +
 .../groovy/ast/expr/MethodCallExpression.java   |   214 +
 .../ast/expr/MethodPointerExpression.java       |    91 +
 .../ast/expr/MethodReferenceExpression.java     |    45 +
 .../ast/expr/NamedArgumentListExpression.java   |    45 +
 .../codehaus/groovy/ast/expr/NotExpression.java |    46 +
 .../groovy/ast/expr/PostfixExpression.java      |    75 +
 .../groovy/ast/expr/PrefixExpression.java       |    75 +
 .../groovy/ast/expr/PropertyExpression.java     |   133 +
 .../groovy/ast/expr/RangeExpression.java        |    70 +
 .../groovy/ast/expr/SpreadExpression.java       |    58 +
 .../groovy/ast/expr/SpreadMapExpression.java    |    60 +
 .../ast/expr/StaticMethodCallExpression.java    |    95 +
 .../groovy/ast/expr/TernaryExpression.java      |    86 +
 .../groovy/ast/expr/TupleExpression.java        |   120 +
 .../groovy/ast/expr/UnaryMinusExpression.java   |    62 +
 .../groovy/ast/expr/UnaryPlusExpression.java    |    62 +
 .../groovy/ast/expr/VariableExpression.java     |   199 +
 .../org/codehaus/groovy/ast/expr/package.html   |    28 +
 .../java/org/codehaus/groovy/ast/package.html   |    28 +
 .../groovy/ast/stmt/AssertStatement.java        |    66 +
 .../groovy/ast/stmt/BlockStatement.java         |   117 +
 .../groovy/ast/stmt/BreakStatement.java         |    48 +
 .../codehaus/groovy/ast/stmt/CaseStatement.java |    63 +
 .../groovy/ast/stmt/CatchStatement.java         |    61 +
 .../groovy/ast/stmt/ContinueStatement.java      |    48 +
 .../groovy/ast/stmt/DoWhileStatement.java       |    58 +
 .../groovy/ast/stmt/EmptyStatement.java         |   115 +
 .../groovy/ast/stmt/ExpressionStatement.java    |    61 +
 .../codehaus/groovy/ast/stmt/ForStatement.java  |    83 +
 .../codehaus/groovy/ast/stmt/IfStatement.java   |    69 +
 .../groovy/ast/stmt/LoopingStatement.java       |    38 +
 .../groovy/ast/stmt/ReturnStatement.java        |    72 +
 .../org/codehaus/groovy/ast/stmt/Statement.java |    64 +
 .../groovy/ast/stmt/SwitchStatement.java        |    91 +
 .../groovy/ast/stmt/SynchronizedStatement.java  |    58 +
 .../groovy/ast/stmt/ThrowStatement.java         |    54 +
 .../groovy/ast/stmt/TryCatchStatement.java      |   108 +
 .../groovy/ast/stmt/WhileStatement.java         |    59 +
 .../org/codehaus/groovy/ast/stmt/package.html   |    28 +
 .../codehaus/groovy/ast/tools/BeanUtils.java    |   120 +
 .../groovy/ast/tools/ClassNodeUtils.java        |    80 +
 .../codehaus/groovy/ast/tools/ClosureUtils.java |    69 +
 .../codehaus/groovy/ast/tools/GeneralUtils.java |   805 +
 .../groovy/ast/tools/GenericsUtils.java         |   614 +
 .../groovy/ast/tools/ParameterUtils.java        |    39 +
 .../groovy/ast/tools/PropertyNodeUtils.java     |    43 +
 .../groovy/ast/tools/WideningCategories.java    |   746 +
 .../groovy/classgen/AnnotationVisitor.java      |   344 +
 .../groovy/classgen/AsmClassGenerator.java      |  2103 ++
 .../groovy/classgen/BytecodeExpression.java     |    55 +
 .../groovy/classgen/BytecodeInstruction.java    |    32 +
 .../groovy/classgen/BytecodeSequence.java       |    81 +
 .../classgen/ClassCompletionVerifier.java       |   746 +
 .../groovy/classgen/ClassGenerator.java         |    48 +
 .../classgen/ClassGeneratorException.java       |    36 +
 .../groovy/classgen/DummyClassGenerator.java    |   180 +
 .../groovy/classgen/EnumCompletionVisitor.java  |   169 +
 .../codehaus/groovy/classgen/EnumVisitor.java   |   444 +
 .../groovy/classgen/ExtendedVerifier.java       |   342 +
 .../groovy/classgen/FinalVariableAnalyzer.java  |   363 +
 .../groovy/classgen/GeneratorContext.java       |   113 +
 .../classgen/InnerClassCompletionVisitor.java   |   454 +
 .../groovy/classgen/InnerClassVisitor.java      |   288 +
 .../classgen/InnerClassVisitorHelper.java       |   143 +
 .../codehaus/groovy/classgen/ReturnAdder.java   |   279 +
 .../groovy/classgen/VariableScopeVisitor.java   |   611 +
 .../org/codehaus/groovy/classgen/Verifier.java  |  1565 ++
 .../groovy/classgen/VerifierCodeVisitor.java    |   102 +
 .../groovy/classgen/asm/AssertionWriter.java    |   257 +
 .../asm/BinaryBooleanExpressionHelper.java      |    94 +
 .../asm/BinaryDoubleExpressionHelper.java       |   106 +
 .../classgen/asm/BinaryExpressionHelper.java    |   962 +
 .../BinaryExpressionMultiTypeDispatcher.java    |   422 +
 .../classgen/asm/BinaryExpressionWriter.java    |   328 +
 .../asm/BinaryFloatExpressionHelper.java        |   111 +
 .../classgen/asm/BinaryIntExpressionHelper.java |   293 +
 .../asm/BinaryLongExpressionHelper.java         |   144 +
 .../asm/BinaryObjectExpressionHelper.java       |    87 +
 .../groovy/classgen/asm/BytecodeDumper.java     |    52 +
 .../groovy/classgen/asm/BytecodeHelper.java     |   751 +
 .../groovy/classgen/asm/BytecodeVariable.java   |   124 +
 .../groovy/classgen/asm/CallSiteWriter.java     |   387 +
 .../groovy/classgen/asm/ClosureWriter.java      |   392 +
 .../groovy/classgen/asm/CompileStack.java       |   872 +
 .../classgen/asm/DelegatingController.java      |   276 +
 .../classgen/asm/ExpressionAsVariableSlot.java  |    81 +
 .../groovy/classgen/asm/InvocationWriter.java   |   928 +
 .../groovy/classgen/asm/MethodCaller.java       |    88 +
 .../classgen/asm/MethodCallerMultiAdapter.java  |    83 +
 .../codehaus/groovy/classgen/asm/MopWriter.java |   223 +
 .../groovy/classgen/asm/OperandStack.java       |   700 +
 .../classgen/asm/OptimizingStatementWriter.java |   948 +
 .../classgen/asm/StatementMetaTypeChooser.java  |    58 +
 .../groovy/classgen/asm/StatementWriter.java    |   638 +
 .../groovy/classgen/asm/TypeChooser.java        |    42 +
 .../classgen/asm/UnaryExpressionHelper.java     |    87 +
 .../groovy/classgen/asm/VariableSlotLoader.java |    50 +
 .../groovy/classgen/asm/WriterController.java   |   401 +
 .../classgen/asm/WriterControllerFactory.java   |    27 +
 .../groovy/classgen/asm/indy/IndyBinHelper.java |    44 +
 .../classgen/asm/indy/IndyCallSiteWriter.java   |    65 +
 .../classgen/asm/indy/InvokeDynamicWriter.java  |   234 +
 .../sc/IndyStaticTypesMultiTypeDispatcher.java  |    94 +
 .../codehaus/groovy/classgen/asm/package.html   |    29 +
 .../asm/sc/StaticCompilationMopWriter.java      |    62 +
 .../classgen/asm/sc/StaticInvocationWriter.java |   764 +
 .../asm/sc/StaticPropertyAccessHelper.java      |   133 +
 ...ypesBinaryExpressionMultiTypeDispatcher.java |   426 +
 .../asm/sc/StaticTypesCallSiteWriter.java       |   888 +
 .../asm/sc/StaticTypesClosureWriter.java        |   135 +
 .../asm/sc/StaticTypesStatementWriter.java      |   299 +
 .../classgen/asm/sc/StaticTypesTypeChooser.java |    75 +
 .../sc/StaticTypesUnaryExpressionHelper.java    |   178 +
 .../asm/sc/StaticTypesWriterController.java     |   186 +
 .../StaticTypesWriterControllerFactoryImpl.java |    33 +
 .../classgen/asm/util/LoggableClassVisitor.java |    34 +
 .../classgen/asm/util/LoggableTextifier.java    |   438 +
 .../org/codehaus/groovy/classgen/package.html   |    28 +
 .../codehaus/groovy/cli/GroovyPosixParser.java  |   281 +
 .../control/ASTTransformationsContext.java      |    53 +
 .../control/AnnotationConstantsVisitor.java     |   133 +
 .../groovy/control/BytecodeProcessor.java       |    23 +
 .../groovy/control/ClassNodeResolver.java       |   345 +
 .../control/CompilationFailedException.java     |    77 +
 .../groovy/control/CompilationUnit.java         |  1167 +
 .../codehaus/groovy/control/CompilePhase.java   |   118 +
 .../groovy/control/CompilerConfiguration.java   |   934 +
 .../groovy/control/ConfigurationException.java  |    92 +
 .../codehaus/groovy/control/ErrorCollector.java |   348 +
 .../groovy/control/GenericsVisitor.java         |   188 +
 .../org/codehaus/groovy/control/HasCleanup.java |    31 +
 .../org/codehaus/groovy/control/Janitor.java    |    55 +
 .../codehaus/groovy/control/LabelVerifier.java  |   174 +
 .../MultipleCompilationErrorsException.java     |    64 +
 .../groovy/control/OptimizerVisitor.java        |   149 +
 .../codehaus/groovy/control/ParserPlugin.java   |    36 +
 .../groovy/control/ParserPluginFactory.java     |    93 +
 .../codehaus/groovy/control/ParserVersion.java  |    50 +
 .../org/codehaus/groovy/control/Phases.java     |    67 +
 .../codehaus/groovy/control/ProcessingUnit.java |   180 +
 .../codehaus/groovy/control/ResolveVisitor.java |  1469 ++
 .../groovy/control/SourceExtensionHandler.java  |    66 +
 .../org/codehaus/groovy/control/SourceUnit.java |   344 +
 .../groovy/control/StaticImportVisitor.java     |   610 +
 .../codehaus/groovy/control/StaticVerifier.java |   204 +
 .../codehaus/groovy/control/XStreamUtils.java   |    68 +
 .../customizers/CompilationCustomizer.java      |    45 +
 .../customizers/DelegatingCustomizer.java       |    45 +
 .../control/customizers/ImportCustomizer.java   |   169 +
 .../customizers/SecureASTCustomizer.java        |  1189 ++
 .../customizers/SourceAwareCustomizer.java      |   105 +
 .../customizers/builder/CustomizersFactory.java |    59 +
 .../builder/ImportCustomizerFactory.java        |   134 +
 .../builder/InlinedASTCustomizerFactory.java    |    89 +
 .../builder/PostCompletionFactory.java          |    31 +
 .../builder/SecureASTCustomizerFactory.java     |    55 +
 .../builder/SourceAwareCustomizerFactory.java   |   160 +
 .../groovy/control/io/AbstractReaderSource.java |   120 +
 .../groovy/control/io/FileReaderSource.java     |    91 +
 .../control/io/InputStreamReaderSource.java     |    76 +
 .../codehaus/groovy/control/io/NullWriter.java  |    36 +
 .../groovy/control/io/ReaderSource.java         |    70 +
 .../groovy/control/io/StringReaderSource.java   |    69 +
 .../groovy/control/io/URLReaderSource.java      |    69 +
 .../org/codehaus/groovy/control/io/package.html |    28 +
 .../control/messages/ExceptionMessage.java      |    88 +
 .../groovy/control/messages/LocatedMessage.java |    80 +
 .../groovy/control/messages/Message.java        |   101 +
 .../groovy/control/messages/SimpleMessage.java  |    77 +
 .../control/messages/SyntaxErrorMessage.java    |    69 +
 .../groovy/control/messages/WarningMessage.java |   118 +
 .../groovy/control/messages/package.html        |    28 +
 .../org/codehaus/groovy/control/package.html    |    28 +
 src/main/java/org/codehaus/groovy/package.html  |    28 +
 .../codehaus/groovy/plugin/GroovyRunner.java    |    28 +
 .../reflection/AccessPermissionChecker.java     |    84 +
 .../reflection/CacheAccessControlException.java |    27 +
 .../codehaus/groovy/reflection/CachedClass.java |   542 +
 .../groovy/reflection/CachedConstructor.java    |   116 +
 .../codehaus/groovy/reflection/CachedField.java |    81 +
 .../groovy/reflection/CachedMethod.java         |   345 +
 .../codehaus/groovy/reflection/ClassInfo.java   |   505 +
 .../ClassLoaderForClassArtifacts.java           |    88 +
 .../groovy/reflection/GeneratedMetaMethod.java  |   240 +
 .../groovy/reflection/GroovyClassValue.java     |    36 +
 .../reflection/GroovyClassValueFactory.java     |    42 +
 .../reflection/GroovyClassValuePreJava7.java    |   104 +
 .../groovy/reflection/MixinInMetaClass.java     |   206 +
 .../groovy/reflection/ParameterTypes.java       |   385 +
 .../groovy/reflection/ReflectionCache.java      |   113 +
 .../groovy/reflection/ReflectionUtils.java      |   140 +
 .../groovy/reflection/SunClassLoader.java       |   117 +
 .../reflection/android/AndroidSupport.java      |    38 +
 .../org/codehaus/groovy/reflection/package.html |    28 +
 .../reflection/stdclasses/ArrayCachedClass.java |    55 +
 .../stdclasses/BigDecimalCachedClass.java       |    52 +
 .../stdclasses/BigIntegerCachedClass.java       |    50 +
 .../stdclasses/BooleanCachedClass.java          |    43 +
 .../reflection/stdclasses/ByteCachedClass.java  |    53 +
 .../stdclasses/CachedClosureClass.java          |    61 +
 .../reflection/stdclasses/CachedSAMClass.java   |   203 +
 .../stdclasses/CharacterCachedClass.java        |    44 +
 .../stdclasses/DoubleCachedClass.java           |    76 +
 .../reflection/stdclasses/FloatCachedClass.java |    71 +
 .../stdclasses/IntegerCachedClass.java          |    61 +
 .../reflection/stdclasses/LongCachedClass.java  |    61 +
 .../stdclasses/NumberCachedClass.java           |    65 +
 .../stdclasses/ObjectCachedClass.java           |    39 +
 .../reflection/stdclasses/ShortCachedClass.java |    56 +
 .../stdclasses/StringCachedClass.java           |    50 +
 .../reflection/v7/GroovyClassValueJava7.java    |    37 +
 .../groovy/runtime/AbstractComparator.java      |    30 +
 .../codehaus/groovy/runtime/ArrayTypeUtils.java |    98 +
 .../org/codehaus/groovy/runtime/ArrayUtil.java  |  1312 ++
 .../groovy/runtime/BytecodeInterface8.java      |   377 +
 .../codehaus/groovy/runtime/ClassExtender.java  |    89 +
 .../groovy/runtime/ComposedClosure.java         |   108 +
 .../groovy/runtime/ConversionHandler.java       |   224 +
 .../groovy/runtime/ConvertedClosure.java        |    58 +
 .../codehaus/groovy/runtime/ConvertedMap.java   |    80 +
 .../codehaus/groovy/runtime/CurriedClosure.java |   192 +
 .../groovy/runtime/DateGroovyMethods.java       |   775 +
 .../groovy/runtime/DefaultCachedMethodKey.java  |    47 +
 .../groovy/runtime/DefaultGroovyMethods.java    | 18930 +++++++++++++++++
 .../runtime/DefaultGroovyMethodsSupport.java    |   383 +
 .../runtime/DefaultGroovyStaticMethods.java     |   314 +
 .../groovy/runtime/DefaultMethodKey.java        |    44 +
 .../groovy/runtime/EncodingGroovyMethods.java   |   367 +
 .../runtime/EncodingGroovyMethodsSupport.java   |    90 +
 .../groovy/runtime/FlushingStreamWriter.java    |    50 +
 .../codehaus/groovy/runtime/GStringImpl.java    |    64 +
 .../groovy/runtime/GeneratedClosure.java        |    29 +
 .../groovy/runtime/GroovyCategorySupport.java   |   365 +
 .../groovy/runtime/HandleMetaClass.java         |   122 +
 .../groovy/runtime/IOGroovyMethods.java         |  1698 ++
 .../codehaus/groovy/runtime/InvokerHelper.java  |  1079 +
 .../runtime/InvokerInvocationException.java     |    44 +
 .../groovy/runtime/IteratorClosureAdapter.java  |    58 +
 .../groovy/runtime/MetaClassHelper.java         |  1034 +
 .../codehaus/groovy/runtime/MethodClosure.java  |   147 +
 .../org/codehaus/groovy/runtime/MethodKey.java  |   133 +
 .../groovy/runtime/MethodRankHelper.java        |   562 +
 .../org/codehaus/groovy/runtime/NullObject.java |   176 +
 .../groovy/runtime/NumberAwareComparator.java   |    60 +
 .../groovy/runtime/ProcessGroovyMethods.java    |   727 +
 .../groovy/runtime/ProxyGeneratorAdapter.java   |  1003 +
 .../org/codehaus/groovy/runtime/RangeInfo.java  |    31 +
 .../groovy/runtime/ReflectionMethodInvoker.java |    56 +
 .../org/codehaus/groovy/runtime/Reflector.java  |    39 +
 .../codehaus/groovy/runtime/RegexSupport.java   |    37 +
 .../groovy/runtime/ResourceGroovyMethods.java   |  2642 +++
 .../groovy/runtime/ReverseListIterator.java     |    65 +
 .../groovy/runtime/ScriptBytecodeAdapter.java   |   857 +
 .../groovy/runtime/ScriptReference.java         |    46 +
 .../groovy/runtime/SocketGroovyMethods.java     |   206 +
 .../groovy/runtime/StackTraceUtils.java         |   194 +
 .../groovy/runtime/StringBufferWriter.java      |   104 +
 .../groovy/runtime/StringGroovyMethods.java     |  3800 ++++
 .../codehaus/groovy/runtime/WritableFile.java   |    65 +
 .../runtime/callsite/AbstractCallSite.java      |   424 +
 .../runtime/callsite/BooleanClosureWrapper.java |    68 +
 .../callsite/BooleanReturningMethodInvoker.java |    76 +
 .../groovy/runtime/callsite/CallSite.java       |    69 +
 .../groovy/runtime/callsite/CallSiteArray.java  |   175 +
 .../callsite/CallSiteAwareMetaMethod.java       |    27 +
 .../runtime/callsite/CallSiteClassLoader.java   |    59 +
 .../runtime/callsite/CallSiteGenerator.java     |   268 +
 .../callsite/ClassMetaClassGetPropertySite.java |    55 +
 .../callsite/ConstructorMetaClassSite.java      |    41 +
 .../callsite/ConstructorMetaMethodSite.java     |    67 +
 .../runtime/callsite/ConstructorSite.java       |   154 +
 .../groovy/runtime/callsite/DummyCallSite.java  |    25 +
 .../callsite/GetEffectivePogoFieldSite.java     |    78 +
 .../callsite/GetEffectivePogoPropertySite.java  |    90 +
 .../callsite/GetEffectivePojoFieldSite.java     |    60 +
 .../callsite/GetEffectivePojoPropertySite.java  |    68 +
 .../runtime/callsite/GroovySunClassLoader.java  |    74 +
 .../callsite/MetaClassConstructorSite.java      |    55 +
 .../groovy/runtime/callsite/MetaClassSite.java  |    35 +
 .../groovy/runtime/callsite/MetaMethodSite.java |    38 +
 .../groovy/runtime/callsite/NullCallSite.java   |    54 +
 .../callsite/PerInstancePojoMetaClassSite.java  |    45 +
 .../runtime/callsite/PogoGetPropertySite.java   |    54 +
 .../runtime/callsite/PogoInterceptableSite.java |    59 +
 .../callsite/PogoMetaClassGetPropertySite.java  |    55 +
 .../runtime/callsite/PogoMetaClassSite.java     |    86 +
 .../runtime/callsite/PogoMetaMethodSite.java    |   257 +
 .../callsite/PojoMetaClassGetPropertySite.java  |    49 +
 .../runtime/callsite/PojoMetaClassSite.java     |    60 +
 .../runtime/callsite/PojoMetaMethodSite.java    |   280 +
 .../runtime/callsite/StaticMetaClassSite.java   |    72 +
 .../runtime/callsite/StaticMetaMethodSite.java  |   157 +
 .../groovy/runtime/dgmimpl/NumberNumberDiv.java |   330 +
 .../runtime/dgmimpl/NumberNumberMetaMethod.java |    61 +
 .../runtime/dgmimpl/NumberNumberMinus.java      |   391 +
 .../runtime/dgmimpl/NumberNumberMultiply.java   |   393 +
 .../runtime/dgmimpl/NumberNumberPlus.java       |   385 +
 .../dgmimpl/arrays/ArrayGetAtMetaMethod.java    |    29 +
 .../runtime/dgmimpl/arrays/ArrayMetaMethod.java |    45 +
 .../dgmimpl/arrays/ArrayPutAtMetaMethod.java    |    29 +
 .../arrays/BooleanArrayGetAtMetaMethod.java     |    65 +
 .../arrays/BooleanArrayPutAtMetaMethod.java     |    85 +
 .../arrays/ByteArrayGetAtMetaMethod.java        |    65 +
 .../arrays/ByteArrayPutAtMetaMethod.java        |    89 +
 .../arrays/CharacterArrayGetAtMetaMethod.java   |    65 +
 .../arrays/CharacterArrayPutAtMetaMethod.java   |    86 +
 .../arrays/DoubleArrayGetAtMetaMethod.java      |    65 +
 .../arrays/DoubleArrayPutAtMetaMethod.java      |    96 +
 .../arrays/FloatArrayGetAtMetaMethod.java       |    65 +
 .../arrays/FloatArrayPutAtMetaMethod.java       |    96 +
 .../arrays/IntegerArrayGetAtMetaMethod.java     |    65 +
 .../arrays/IntegerArrayPutAtMetaMethod.java     |    96 +
 .../arrays/LongArrayGetAtMetaMethod.java        |    65 +
 .../arrays/LongArrayPutAtMetaMethod.java        |    96 +
 .../arrays/ObjectArrayGetAtMetaMethod.java      |    70 +
 .../arrays/ObjectArrayPutAtMetaMethod.java      |    97 +
 .../arrays/ShortArrayGetAtMetaMethod.java       |    65 +
 .../arrays/ShortArrayPutAtMetaMethod.java       |    96 +
 .../groovy/runtime/m12n/ExtensionModule.java    |    61 +
 .../runtime/m12n/ExtensionModuleRegistry.java   |    66 +
 .../runtime/m12n/ExtensionModuleScanner.java    |    88 +
 .../runtime/m12n/MetaInfExtensionModule.java    |   108 +
 .../runtime/m12n/PropertiesModuleFactory.java   |    36 +
 .../runtime/m12n/SimpleExtensionModule.java     |   138 +
 .../m12n/StandardPropertiesModuleFactory.java   |    54 +
 .../groovy/runtime/memoize/CommonCache.java     |   217 +
 .../runtime/memoize/ConcurrentCommonCache.java  |   239 +
 .../groovy/runtime/memoize/EvictableCache.java  |   106 +
 .../groovy/runtime/memoize/LRUCache.java        |    66 +
 .../runtime/memoize/LRUProtectionStorage.java   |    79 +
 .../groovy/runtime/memoize/Memoize.java         |   183 +
 .../groovy/runtime/memoize/MemoizeCache.java    |    51 +
 .../runtime/memoize/NullProtectionStorage.java  |    37 +
 .../runtime/memoize/ProtectionStorage.java      |    29 +
 .../memoize/UnlimitedConcurrentCache.java       |    54 +
 .../runtime/metaclass/ClosureMetaClass.java     |   713 +
 .../runtime/metaclass/ClosureMetaMethod.java    |   192 +
 .../metaclass/ClosureStaticMetaMethod.java      |    89 +
 .../metaclass/ConcurrentReaderHashMap.java      |  1270 ++
 .../runtime/metaclass/DefaultMetaClassInfo.java |   346 +
 .../metaclass/MetaClassRegistryImpl.java        |   551 +
 .../runtime/metaclass/MetaMethodIndex.java      |   546 +
 .../groovy/runtime/metaclass/MethodHelper.java  |    40 +
 .../runtime/metaclass/MethodMetaProperty.java   |    80 +
 .../metaclass/MethodSelectionException.java     |   102 +
 .../MissingMethodExceptionNoStack.java          |    36 +
 .../metaclass/MissingMethodExecutionFailed.java |    36 +
 .../MissingPropertyExceptionNoStack.java        |    32 +
 .../runtime/metaclass/MixedInMetaClass.java     |    55 +
 .../metaclass/MixinInstanceMetaMethod.java      |    62 +
 .../metaclass/MixinInstanceMetaProperty.java    |    96 +
 .../metaclass/MultipleSetterProperty.java       |    88 +
 .../metaclass/NewInstanceMetaMethod.java        |    58 +
 .../groovy/runtime/metaclass/NewMetaMethod.java |    57 +
 .../runtime/metaclass/NewStaticMetaMethod.java  |    55 +
 .../runtime/metaclass/OwnedMetaClass.java       |   234 +
 .../runtime/metaclass/ReflectionMetaMethod.java |    75 +
 .../runtime/metaclass/ReflectorLoader.java      |   147 +
 .../runtime/metaclass/TemporaryMethodKey.java   |    59 +
 .../ThreadManagedMetaBeanProperty.java          |   227 +
 .../runtime/metaclass/TransformMetaMethod.java  |    59 +
 .../groovy/runtime/metaclass/package.html       |    28 +
 .../org/codehaus/groovy/runtime/package.html    |    28 +
 .../runtime/powerassert/AssertionRenderer.java  |   184 +
 .../powerassert/PowerAssertionError.java        |    35 +
 .../groovy/runtime/powerassert/SourceText.java  |   126 +
 .../SourceTextNotAvailableException.java        |    36 +
 .../groovy/runtime/powerassert/Value.java       |    43 +
 .../runtime/powerassert/ValueRecorder.java      |    45 +
 .../runtime/typehandling/BigDecimalMath.java    |    86 +
 .../runtime/typehandling/BigIntegerMath.java    |    86 +
 .../typehandling/DefaultTypeTransformation.java |   894 +
 .../runtime/typehandling/FloatingPointMath.java |    67 +
 .../typehandling/GroovyCastException.java       |    85 +
 .../runtime/typehandling/IntegerMath.java       |   101 +
 .../groovy/runtime/typehandling/LongMath.java   |   105 +
 .../groovy/runtime/typehandling/NumberMath.java |   294 +
 .../NumberMathModificationInfo.java             |  3732 ++++
 .../runtime/typehandling/ShortTypeHandling.java |    86 +
 .../groovy/runtime/typehandling/package.html    |    30 +
 .../groovy/runtime/wrappers/BooleanWrapper.java |    28 +
 .../groovy/runtime/wrappers/ByteWrapper.java    |    28 +
 .../groovy/runtime/wrappers/CharWrapper.java    |    28 +
 .../groovy/runtime/wrappers/DoubleWrapper.java  |    28 +
 .../groovy/runtime/wrappers/FloatWrapper.java   |    28 +
 .../runtime/wrappers/GroovyObjectWrapper.java   |    74 +
 .../groovy/runtime/wrappers/IntWrapper.java     |    28 +
 .../groovy/runtime/wrappers/LongWrapper.java    |    28 +
 .../groovy/runtime/wrappers/PojoWrapper.java    |    74 +
 .../groovy/runtime/wrappers/ShortWrapper.java   |    30 +
 .../groovy/runtime/wrappers/Wrapper.java        |    50 +
 .../groovy/runtime/wrappers/package.html        |    28 +
 .../org/codehaus/groovy/syntax/ASTHelper.java   |   162 +
 .../org/codehaus/groovy/syntax/CSTNode.java     |   583 +
 .../org/codehaus/groovy/syntax/Numbers.java     |   317 +
 .../codehaus/groovy/syntax/ParserException.java |    33 +
 .../codehaus/groovy/syntax/ReadException.java   |    58 +
 .../org/codehaus/groovy/syntax/Reduction.java   |   266 +
 .../groovy/syntax/RuntimeParserException.java   |    41 +
 .../codehaus/groovy/syntax/SyntaxException.java |   123 +
 .../java/org/codehaus/groovy/syntax/Token.java  |   393 +
 .../codehaus/groovy/syntax/TokenException.java  |    47 +
 .../groovy/syntax/TokenMismatchException.java   |    38 +
 .../org/codehaus/groovy/syntax/TokenUtil.java   |    88 +
 .../java/org/codehaus/groovy/syntax/Types.java  |  1454 ++
 .../org/codehaus/groovy/syntax/package.html     |    28 +
 .../org/codehaus/groovy/tools/Compiler.java     |   116 +
 .../org/codehaus/groovy/tools/DgmConverter.java |   230 +
 .../codehaus/groovy/tools/ErrorReporter.java    |   235 +
 .../groovy/tools/FileSystemCompiler.java        |   389 +
 .../org/codehaus/groovy/tools/GrapeUtil.java    |    45 +
 .../org/codehaus/groovy/tools/GroovyClass.java  |    45 +
 .../codehaus/groovy/tools/GroovyStarter.java    |   141 +
 .../groovy/tools/LoaderConfiguration.java       |   376 +
 .../org/codehaus/groovy/tools/RootLoader.java   |   181 +
 .../org/codehaus/groovy/tools/StringHelper.java |    85 +
 .../org/codehaus/groovy/tools/Utilities.java    |    77 +
 .../groovy/tools/gse/DependencyTracker.java     |   137 +
 .../codehaus/groovy/tools/gse/StringSetMap.java |    64 +
 .../tools/javac/JavaAwareCompilationUnit.java   |   163 +
 .../tools/javac/JavaAwareResolveVisitor.java    |    69 +
 .../groovy/tools/javac/JavaCompiler.java        |    30 +
 .../groovy/tools/javac/JavaCompilerFactory.java |    25 +
 .../tools/javac/JavaStubCompilationUnit.java    |   131 +
 .../groovy/tools/javac/JavaStubGenerator.java   |   981 +
 .../tools/javac/JavacCompilerFactory.java       |    27 +
 .../groovy/tools/javac/JavacJavaCompiler.java   |   214 +
 .../codehaus/groovy/tools/javac/package.html    |    28 +
 .../java/org/codehaus/groovy/tools/package.html |    30 +
 .../org/codehaus/groovy/tools/shell/IO.java     |   190 +
 .../groovy/tools/shell/util/Logger.java         |   134 +
 .../groovy/tools/shell/util/MessageSource.java  |   142 +
 .../groovy/tools/shell/util/Preferences.java    |   121 +
 .../org/codehaus/groovy/tools/xml/package.html  |    28 +
 .../groovy/transform/ASTTransformation.java     |    50 +
 .../ASTTransformationCollectorCodeVisitor.java  |   369 +
 .../transform/ASTTransformationVisitor.java     |   343 +
 .../transform/AbstractASTTransformUtil.java     |   184 +
 .../transform/AbstractASTTransformation.java    |   485 +
 .../AbstractInterruptibleASTTransformation.java |   235 +
 .../transform/AnnotationCollectorTransform.java |   369 +
 .../transform/AutoCloneASTTransformation.java   |   305 +
 .../transform/AutoFinalASTTransformation.java   |   191 +
 .../AutoImplementASTTransformation.java         |   183 +
 .../transform/BaseScriptASTTransformation.java  |   167 +
 .../transform/BuilderASTTransformation.java     |   278 +
 .../transform/CategoryASTTransformation.java    |   298 +
 .../transform/CompileDynamicProcessor.java      |    44 +
 .../transform/DelegateASTTransformation.java    |   384 +
 .../EqualsAndHashCodeASTTransformation.java     |   332 +
 .../groovy/transform/ErrorCollecting.java       |    31 +
 .../ExternalizeMethodsASTTransformation.java    |   129 +
 .../ExternalizeVerifierASTTransformation.java   |   107 +
 .../transform/FieldASTTransformation.java       |   282 +
 .../transform/GroovyASTTransformation.java      |    52 +
 .../transform/GroovyASTTransformationClass.java |    47 +
 .../transform/ImmutableASTTransformation.java   |   818 +
 .../IndexedPropertyASTTransformation.java       |   137 +
 .../InheritConstructorsASTTransformation.java   |   132 +
 .../groovy/transform/LazyASTTransformation.java |   243 +
 .../groovy/transform/LogASTTransformation.java  |   297 +
 .../MapConstructorASTTransformation.java        |   196 +
 .../transform/MemoizedASTTransformation.java    |   201 +
 .../transform/NewifyASTTransformation.java      |   324 +
 .../PackageScopeASTTransformation.java          |   201 +
 .../ReadWriteLockASTTransformation.java         |   143 +
 .../transform/SingletonASTTransformation.java   |   136 +
 .../transform/SortableASTTransformation.java    |   253 +
 .../transform/SourceURIASTTransformation.java   |   132 +
 .../transform/StaticTypesTransformation.java    |   115 +
 .../SynchronizedASTTransformation.java          |   114 +
 .../transform/ToStringASTTransformation.java    |   276 +
 .../TupleConstructorASTTransformation.java      |   331 +
 .../sc/ListOfExpressionsExpression.java         |    61 +
 .../sc/StaticCompilationMetadataKeys.java       |    36 +
 .../transform/sc/StaticCompilationVisitor.java  |   542 +
 .../sc/StaticCompileTransformation.java         |   100 +
 .../sc/TemporaryVariableExpression.java         |    77 +
 .../BinaryExpressionTransformer.java            |   393 +
 .../BooleanExpressionTransformer.java           |   183 +
 .../transformers/CastExpressionOptimizer.java   |    80 +
 .../ClosureExpressionTransformer.java           |    47 +
 .../transformers/CompareIdentityExpression.java |    84 +
 .../transformers/CompareToNullExpression.java   |    82 +
 .../ConstructorCallTransformer.java             |   193 +
 .../transformers/ListExpressionTransformer.java |    81 +
 .../MethodCallExpressionTransformer.java        |   197 +
 .../RangeExpressionTransformer.java             |    76 +
 .../StaticCompilationTransformer.java           |   175 +
 .../StaticMethodCallExpressionTransformer.java  |    51 +
 .../VariableExpressionTransformer.java          |    91 +
 .../stc/AbstractTypeCheckingExtension.java      |   450 +
 .../stc/DefaultTypeCheckingExtension.java       |   194 +
 .../transform/stc/DelegationMetadata.java       |    57 +
 .../transform/stc/ExtensionMethodNode.java      |    57 +
 .../stc/GroovyTypeCheckingExtensionSupport.java |   460 +
 .../transform/stc/PropertyLookupVisitor.java    |    62 +
 .../codehaus/groovy/transform/stc/Receiver.java |    59 +
 .../transform/stc/SecondPassExpression.java     |    71 +
 .../transform/stc/SharedVariableCollector.java  |    61 +
 .../groovy/transform/stc/SignatureCodec.java    |    34 +
 .../transform/stc/SignatureCodecVersion1.java   |   230 +
 .../stc/StaticTypeCheckingSupport.java          |  2437 +++
 .../stc/StaticTypeCheckingVisitor.java          |  5178 +++++
 .../groovy/transform/stc/StaticTypesMarker.java |    41 +
 .../stc/TraitTypeCheckingExtension.java         |   141 +
 .../transform/stc/TypeCheckingContext.java      |   365 +
 .../transform/stc/TypeCheckingExtension.java    |   404 +
 .../transform/stc/UnionTypeClassNode.java       |   476 +
 .../transform/trait/NAryOperationRewriter.java  |   130 +
 .../trait/SuperCallTraitTransformer.java        |   193 +
 .../transform/trait/TraitASTTransformation.java |   624 +
 .../groovy/transform/trait/TraitComposer.java   |   568 +
 .../transform/trait/TraitHelpersTuple.java      |    45 +
 .../trait/TraitReceiverTransformer.java         |   451 +
 .../codehaus/groovy/transform/trait/Traits.java |   378 +
 .../groovy/util/AbstractConcurrentMap.java      |   205 +
 .../groovy/util/AbstractConcurrentMapBase.java  |   345 +
 .../org/codehaus/groovy/util/ArrayIterator.java |    46 +
 .../groovy/util/CharSequenceReader.java         |   170 +
 .../codehaus/groovy/util/ComplexKeyHashMap.java |   176 +
 .../org/codehaus/groovy/util/FastArray.java     |   139 +
 .../org/codehaus/groovy/util/Finalizable.java   |    23 +
 .../codehaus/groovy/util/HashCodeHelper.java    |   131 +
 .../groovy/util/IteratorBufferedIterator.java   |    75 +
 .../org/codehaus/groovy/util/LazyReference.java |    74 +
 .../groovy/util/ListBufferedIterator.java       |    67 +
 .../org/codehaus/groovy/util/ListHashMap.java   |   220 +
 .../codehaus/groovy/util/LockableObject.java    |    73 +
 .../util/ManagedConcurrentLinkedQueue.java      |   180 +
 .../groovy/util/ManagedConcurrentMap.java       |   118 +
 .../groovy/util/ManagedConcurrentValueMap.java  |    77 +
 .../codehaus/groovy/util/ManagedLinkedList.java |   145 +
 .../codehaus/groovy/util/ManagedReference.java  |    55 +
 .../org/codehaus/groovy/util/Reference.java     |    25 +
 .../codehaus/groovy/util/ReferenceBundle.java   |    63 +
 .../codehaus/groovy/util/ReferenceManager.java  |   199 +
 .../org/codehaus/groovy/util/ReferenceType.java |   105 +
 .../org/codehaus/groovy/util/ReleaseInfo.java   |    80 +
 .../codehaus/groovy/util/SingleKeyHashMap.java  |   161 +
 .../codehaus/groovy/util/TripleKeyHashMap.java  |    86 +
 .../org/codehaus/groovy/vmplugin/VMPlugin.java  |    65 +
 .../groovy/vmplugin/VMPluginFactory.java        |    57 +
 .../org/codehaus/groovy/vmplugin/package.html   |    28 +
 .../groovy/vmplugin/v5/JUnit4Utils.java         |   102 +
 .../org/codehaus/groovy/vmplugin/v5/Java5.java  |   484 +
 .../vmplugin/v5/PluginDefaultGroovyMethods.java |   141 +
 .../codehaus/groovy/vmplugin/v5/package.html    |    28 +
 .../org/codehaus/groovy/vmplugin/v6/Java6.java  |    34 +
 .../groovy/vmplugin/v7/IndyArrayAccess.java     |   143 +
 .../v7/IndyGuardsFiltersAndSignatures.java      |   215 +
 .../groovy/vmplugin/v7/IndyInterface.java       |   250 +
 .../codehaus/groovy/vmplugin/v7/IndyMath.java   |   196 +
 .../org/codehaus/groovy/vmplugin/v7/Java7.java  |   108 +
 .../codehaus/groovy/vmplugin/v7/Selector.java   |  1065 +
 .../codehaus/groovy/vmplugin/v7/TypeHelper.java |   113 +
 .../groovy/vmplugin/v7/TypeTransformers.java    |   243 +
 .../org/codehaus/groovy/vmplugin/v8/Java8.java  |    66 +
 .../vmplugin/v8/PluginDefaultGroovyMethods.java |    68 +
 src/main/java/overview.html                     |    41 +
 src/main/java/overviewj.html                    |    41 +
 .../apache/groovy/ast/tools/ClassNodeUtils.java |   273 -
 .../groovy/ast/tools/MethodNodeUtils.java       |    69 -
 .../internal/metaclass/MetaClassConstant.java   |    50 -
 .../apache/groovy/internal/util/Function.java   |    31 -
 .../internal/util/ReevaluatingReference.java    |    88 -
 .../apache/groovy/internal/util/Supplier.java   |    31 -
 .../groovy/internal/util/UncheckedThrow.java    |    38 -
 .../groovy/lang/annotation/Incubating.java      |    43 -
 .../org/apache/groovy/metaclass/MetaClass.java  |    41 -
 src/main/org/apache/groovy/metaclass/Realm.java |    91 -
 .../apache/groovy/plugin/DefaultRunners.java    |   218 -
 .../org/apache/groovy/plugin/GroovyRunner.java  |    49 -
 .../groovy/plugin/GroovyRunnerRegistry.java     |   468 -
 src/main/org/apache/groovy/util/Maps.java       |  5781 -----
 src/main/org/apache/groovy/util/SystemUtil.java |    46 -
 .../ConcurrentLinkedHashMap.java                |  1600 --
 .../concurrentlinkedhashmap/EntryWeigher.java   |    40 -
 .../EvictionListener.java                       |    48 -
 .../concurrentlinkedhashmap/LinkedDeque.java    |   462 -
 .../util/concurrentlinkedhashmap/Weigher.java   |    39 -
 .../util/concurrentlinkedhashmap/Weighers.java  |   282 -
 .../concurrentlinkedhashmap/package-info.java   |    41 -
 .../org/codehaus/groovy/GroovyBugError.java     |   111 -
 .../org/codehaus/groovy/GroovyException.java    |    52 -
 .../groovy/GroovyExceptionInterface.java        |    31 -
 .../groovy/antlr/ASTParserException.java        |    54 -
 .../groovy/antlr/ASTRuntimeException.java       |    55 -
 .../groovy/antlr/AntlrASTProcessSnippets.java   |    96 -
 .../groovy/antlr/AntlrASTProcessor.java         |    35 -
 .../groovy/antlr/AntlrParserPlugin.java         |  3269 ---
 .../groovy/antlr/AntlrParserPluginFactory.java  |    31 -
 .../org/codehaus/groovy/antlr/EnumHelper.java   |    68 -
 .../codehaus/groovy/antlr/GroovySourceAST.java  |   177 -
 .../groovy/antlr/GroovySourceToken.java         |   100 -
 .../org/codehaus/groovy/antlr/LexerFrame.java   |   279 -
 .../org/codehaus/groovy/antlr/LineColumn.java   |    65 -
 src/main/org/codehaus/groovy/antlr/Main.java    |   194 -
 .../org/codehaus/groovy/antlr/SourceBuffer.java |   111 -
 .../org/codehaus/groovy/antlr/SourceInfo.java   |    77 -
 .../groovy/antlr/UnicodeEscapingReader.java     |   190 -
 .../antlr/UnicodeLexerSharedInputState.java     |    51 -
 .../codehaus/groovy/antlr/java/Groovifier.java  |    74 -
 .../groovy/antlr/java/Java2GroovyConverter.java |   232 -
 .../groovy/antlr/java/Java2GroovyMain.java      |    44 -
 .../groovy/antlr/java/Java2GroovyProcessor.java |   187 -
 .../antlr/java/PreJava2GroovyConverter.java     |   147 -
 src/main/org/codehaus/groovy/antlr/package.html |    28 -
 .../antlr/treewalker/CompositeVisitor.java      |  1179 -
 .../antlr/treewalker/FlatNodeListTraversal.java |    63 -
 .../groovy/antlr/treewalker/MindMapPrinter.java |   379 -
 .../antlr/treewalker/NodeAsHTMLPrinter.java     |   319 -
 .../groovy/antlr/treewalker/NodeCollector.java  |    45 -
 .../groovy/antlr/treewalker/NodePrinter.java    |    52 -
 .../antlr/treewalker/PreOrderTraversal.java     |    45 -
 .../antlr/treewalker/SourceCodeTraversal.java   |   260 -
 .../groovy/antlr/treewalker/SourcePrinter.java  |  1097 -
 .../antlr/treewalker/TraversalHelper.java       |   557 -
 .../groovy/antlr/treewalker/Visitor.java        |   260 -
 .../groovy/antlr/treewalker/VisitorAdapter.java |   258 -
 .../groovy/antlr/treewalker/package.html        |    28 -
 src/main/org/codehaus/groovy/ast/ASTNode.java   |   158 -
 .../org/codehaus/groovy/ast/AnnotatedNode.java  |   112 -
 .../org/codehaus/groovy/ast/AnnotationNode.java |   189 -
 .../codehaus/groovy/ast/AstToTextHelper.java    |   111 -
 .../ast/ClassCodeExpressionTransformer.java     |   146 -
 .../groovy/ast/ClassCodeVisitorSupport.java     |   239 -
 .../org/codehaus/groovy/ast/ClassHelper.java    |   481 -
 src/main/org/codehaus/groovy/ast/ClassNode.java |  1503 --
 .../codehaus/groovy/ast/CodeVisitorSupport.java |   345 -
 .../org/codehaus/groovy/ast/CompileUnit.java    |   193 -
 .../codehaus/groovy/ast/ConstructorNode.java    |    59 -
 .../codehaus/groovy/ast/DynamicVariable.java    |    76 -
 .../groovy/ast/EnumConstantClassNode.java       |    39 -
 src/main/org/codehaus/groovy/ast/FieldNode.java |   205 -
 .../org/codehaus/groovy/ast/GenericsType.java   |   500 -
 .../codehaus/groovy/ast/GroovyClassVisitor.java |    56 -
 .../codehaus/groovy/ast/GroovyCodeVisitor.java  |   191 -
 .../org/codehaus/groovy/ast/ImportNode.java     |   153 -
 .../org/codehaus/groovy/ast/InnerClassNode.java |   103 -
 .../groovy/ast/InterfaceHelperClassNode.java    |    51 -
 .../groovy/ast/MethodCallTransformation.java    |   116 -
 .../groovy/ast/MethodInvocationTrap.java        |    97 -
 .../org/codehaus/groovy/ast/MethodNode.java     |   284 -
 .../groovy/ast/MixinASTTransformation.java      |    88 -
 src/main/org/codehaus/groovy/ast/MixinNode.java |    47 -
 .../org/codehaus/groovy/ast/ModuleNode.java     |   488 -
 .../groovy/ast/NodeMetaDataHandler.java         |    82 -
 .../groovy/ast/NodeMetaDataHandlerHelper.java   |   138 -
 .../org/codehaus/groovy/ast/PackageNode.java    |    46 -
 src/main/org/codehaus/groovy/ast/Parameter.java |   126 -
 .../org/codehaus/groovy/ast/PropertyNode.java   |   135 -
 .../groovy/ast/TransformingCodeVisitor.java     |   371 -
 src/main/org/codehaus/groovy/ast/Variable.java  |    69 -
 .../org/codehaus/groovy/ast/VariableScope.java  |   200 -
 .../groovy/ast/builder/AstBuilder.groovy        |   145 -
 .../ast/builder/AstBuilderTransformation.java   |   186 -
 .../ast/builder/AstSpecificationCompiler.groovy |  1080 -
 .../groovy/ast/builder/AstStringCompiler.groovy |    63 -
 .../groovy/ast/decompiled/Annotations.java      |   136 -
 .../groovy/ast/decompiled/AsmDecompiler.java    |   218 -
 .../ast/decompiled/AsmReferenceResolver.java    |    92 -
 .../ast/decompiled/ClassSignatureParser.java    |    84 -
 .../groovy/ast/decompiled/ClassStub.java        |   117 -
 .../ast/decompiled/DecompiledClassNode.java     |   242 -
 .../ast/decompiled/FormalParameterParser.java   |    80 -
 .../ast/decompiled/MemberSignatureParser.java   |   155 -
 .../ast/decompiled/TypeSignatureParser.java     |   123 -
 .../ast/expr/AnnotationConstantExpression.java  |    50 -
 .../groovy/ast/expr/ArgumentListExpression.java |    78 -
 .../groovy/ast/expr/ArrayExpression.java        |   136 -
 .../groovy/ast/expr/AttributeExpression.java    |    50 -
 .../groovy/ast/expr/BinaryExpression.java       |   135 -
 .../ast/expr/BitwiseNegationExpression.java     |    58 -
 .../groovy/ast/expr/BooleanExpression.java      |    56 -
 .../groovy/ast/expr/CastExpression.java         |   111 -
 .../groovy/ast/expr/ClassExpression.java        |    51 -
 .../groovy/ast/expr/ClosureExpression.java      |   105 -
 .../groovy/ast/expr/ClosureListExpression.java  |    88 -
 .../groovy/ast/expr/ConstantExpression.java     |   124 -
 .../ast/expr/ConstructorCallExpression.java     |   105 -
 .../groovy/ast/expr/DeclarationExpression.java  |   168 -
 .../ast/expr/ElvisOperatorExpression.java       |    71 -
 .../groovy/ast/expr/EmptyExpression.java        |   140 -
 .../codehaus/groovy/ast/expr/Expression.java    |    81 -
 .../groovy/ast/expr/ExpressionTransformer.java  |    33 -
 .../groovy/ast/expr/FieldExpression.java        |    83 -
 .../groovy/ast/expr/GStringExpression.java      |   116 -
 .../groovy/ast/expr/LambdaExpression.java       |    47 -
 .../groovy/ast/expr/ListExpression.java         |    97 -
 .../groovy/ast/expr/MapEntryExpression.java     |    68 -
 .../codehaus/groovy/ast/expr/MapExpression.java |   100 -
 .../codehaus/groovy/ast/expr/MethodCall.java    |    34 -
 .../groovy/ast/expr/MethodCallExpression.java   |   214 -
 .../ast/expr/MethodPointerExpression.java       |    91 -
 .../ast/expr/MethodReferenceExpression.java     |    45 -
 .../ast/expr/NamedArgumentListExpression.java   |    45 -
 .../codehaus/groovy/ast/expr/NotExpression.java |    46 -
 .../groovy/ast/expr/PostfixExpression.java      |    75 -
 .../groovy/ast/expr/PrefixExpression.java       |    75 -
 .../groovy/ast/expr/PropertyExpression.java     |   133 -
 .../groovy/ast/expr/RangeExpression.java        |    70 -
 .../groovy/ast/expr/SpreadExpression.java       |    58 -
 .../groovy/ast/expr/SpreadMapExpression.java    |    60 -
 .../ast/expr/StaticMethodCallExpression.java    |    95 -
 .../groovy/ast/expr/TernaryExpression.java      |    86 -
 .../groovy/ast/expr/TupleExpression.java        |   120 -
 .../groovy/ast/expr/UnaryMinusExpression.java   |    62 -
 .../groovy/ast/expr/UnaryPlusExpression.java    |    62 -
 .../groovy/ast/expr/VariableExpression.java     |   199 -
 .../org/codehaus/groovy/ast/expr/package.html   |    28 -
 src/main/org/codehaus/groovy/ast/package.html   |    28 -
 .../groovy/ast/stmt/AssertStatement.java        |    66 -
 .../groovy/ast/stmt/BlockStatement.java         |   117 -
 .../groovy/ast/stmt/BreakStatement.java         |    48 -
 .../codehaus/groovy/ast/stmt/CaseStatement.java |    63 -
 .../groovy/ast/stmt/CatchStatement.java         |    61 -
 .../groovy/ast/stmt/ContinueStatement.java      |    48 -
 .../groovy/ast/stmt/DoWhileStatement.java       |    58 -
 .../groovy/ast/stmt/EmptyStatement.java         |   115 -
 .../groovy/ast/stmt/ExpressionStatement.java    |    61 -
 .../codehaus/groovy/ast/stmt/ForStatement.java  |    83 -
 .../codehaus/groovy/ast/stmt/IfStatement.java   |    69 -
 .../groovy/ast/stmt/LoopingStatement.java       |    38 -
 .../groovy/ast/stmt/ReturnStatement.java        |    72 -
 .../org/codehaus/groovy/ast/stmt/Statement.java |    64 -
 .../groovy/ast/stmt/SwitchStatement.java        |    91 -
 .../groovy/ast/stmt/SynchronizedStatement.java  |    58 -
 .../groovy/ast/stmt/ThrowStatement.java         |    54 -
 .../groovy/ast/stmt/TryCatchStatement.java      |   108 -
 .../groovy/ast/stmt/WhileStatement.java         |    59 -
 .../org/codehaus/groovy/ast/stmt/package.html   |    28 -
 .../codehaus/groovy/ast/tools/BeanUtils.java    |   120 -
 .../groovy/ast/tools/ClassNodeUtils.java        |    80 -
 .../codehaus/groovy/ast/tools/ClosureUtils.java |    69 -
 .../codehaus/groovy/ast/tools/GeneralUtils.java |   805 -
 .../groovy/ast/tools/GenericsUtils.java         |   614 -
 .../groovy/ast/tools/ParameterUtils.java        |    39 -
 .../groovy/ast/tools/PropertyNodeUtils.java     |    43 -
 .../groovy/ast/tools/WideningCategories.java    |   746 -
 .../groovy/classgen/AnnotationVisitor.java      |   344 -
 .../groovy/classgen/AsmClassGenerator.java      |  2103 --
 .../groovy/classgen/BytecodeExpression.java     |    55 -
 .../groovy/classgen/BytecodeInstruction.java    |    32 -
 .../groovy/classgen/BytecodeSequence.java       |    81 -
 .../classgen/ClassCompletionVerifier.java       |   746 -
 .../groovy/classgen/ClassGenerator.java         |    48 -
 .../classgen/ClassGeneratorException.java       |    36 -
 .../groovy/classgen/DummyClassGenerator.java    |   180 -
 .../groovy/classgen/EnumCompletionVisitor.java  |   169 -
 .../codehaus/groovy/classgen/EnumVisitor.java   |   444 -
 .../groovy/classgen/ExtendedVerifier.java       |   342 -
 .../groovy/classgen/FinalVariableAnalyzer.java  |   363 -
 .../groovy/classgen/GeneratorContext.java       |   113 -
 .../classgen/InnerClassCompletionVisitor.java   |   454 -
 .../groovy/classgen/InnerClassVisitor.java      |   288 -
 .../classgen/InnerClassVisitorHelper.java       |   143 -
 .../codehaus/groovy/classgen/ReturnAdder.java   |   279 -
 .../groovy/classgen/VariableScopeVisitor.java   |   611 -
 .../org/codehaus/groovy/classgen/Verifier.java  |  1565 --
 .../groovy/classgen/VerifierCodeVisitor.java    |   102 -
 .../groovy/classgen/asm/AssertionWriter.java    |   257 -
 .../asm/BinaryBooleanExpressionHelper.java      |    94 -
 .../asm/BinaryDoubleExpressionHelper.java       |   106 -
 .../classgen/asm/BinaryExpressionHelper.java    |   962 -
 .../BinaryExpressionMultiTypeDispatcher.java    |   422 -
 .../classgen/asm/BinaryExpressionWriter.java    |   328 -
 .../asm/BinaryFloatExpressionHelper.java        |   111 -
 .../classgen/asm/BinaryIntExpressionHelper.java |   293 -
 .../asm/BinaryLongExpressionHelper.java         |   144 -
 .../asm/BinaryObjectExpressionHelper.java       |    87 -
 .../groovy/classgen/asm/BytecodeDumper.java     |    52 -
 .../groovy/classgen/asm/BytecodeHelper.java     |   751 -
 .../groovy/classgen/asm/BytecodeVariable.java   |   124 -
 .../groovy/classgen/asm/CallSiteWriter.java     |   387 -
 .../groovy/classgen/asm/ClosureWriter.java      |   392 -
 .../groovy/classgen/asm/CompileStack.java       |   872 -
 .../classgen/asm/DelegatingController.java      |   276 -
 .../classgen/asm/ExpressionAsVariableSlot.java  |    81 -
 .../groovy/classgen/asm/InvocationWriter.java   |   928 -
 .../groovy/classgen/asm/MethodCaller.java       |    88 -
 .../classgen/asm/MethodCallerMultiAdapter.java  |    83 -
 .../codehaus/groovy/classgen/asm/MopWriter.java |   223 -
 .../groovy/classgen/asm/OperandStack.java       |   700 -
 .../classgen/asm/OptimizingStatementWriter.java |   948 -
 .../classgen/asm/StatementMetaTypeChooser.java  |    58 -
 .../groovy/classgen/asm/StatementWriter.java    |   638 -
 .../groovy/classgen/asm/TypeChooser.java        |    42 -
 .../classgen/asm/UnaryExpressionHelper.java     |    87 -
 .../groovy/classgen/asm/VariableSlotLoader.java |    50 -
 .../groovy/classgen/asm/WriterController.java   |   401 -
 .../classgen/asm/WriterControllerFactory.java   |    27 -
 .../groovy/classgen/asm/indy/IndyBinHelper.java |    44 -
 .../classgen/asm/indy/IndyCallSiteWriter.java   |    65 -
 .../classgen/asm/indy/InvokeDynamicWriter.java  |   234 -
 .../sc/IndyStaticTypesMultiTypeDispatcher.java  |    94 -
 .../codehaus/groovy/classgen/asm/package.html   |    29 -
 .../asm/sc/StaticCompilationMopWriter.java      |    62 -
 .../classgen/asm/sc/StaticInvocationWriter.java |   764 -
 .../asm/sc/StaticPropertyAccessHelper.java      |   133 -
 ...ypesBinaryExpressionMultiTypeDispatcher.java |   426 -
 .../asm/sc/StaticTypesCallSiteWriter.java       |   888 -
 .../asm/sc/StaticTypesClosureWriter.java        |   135 -
 .../asm/sc/StaticTypesStatementWriter.java      |   299 -
 .../classgen/asm/sc/StaticTypesTypeChooser.java |    75 -
 .../sc/StaticTypesUnaryExpressionHelper.java    |   178 -
 .../asm/sc/StaticTypesWriterController.java     |   186 -
 .../StaticTypesWriterControllerFactoryImpl.java |    33 -
 .../classgen/asm/util/LoggableClassVisitor.java |    34 -
 .../classgen/asm/util/LoggableTextifier.java    |   438 -
 .../groovy/classgen/genArrayAccess.groovy       |   146 -
 .../codehaus/groovy/classgen/genArrays.groovy   |    53 -
 .../codehaus/groovy/classgen/genDgmMath.groovy  |    87 -
 .../groovy/classgen/genMathModification.groovy  |   133 -
 .../org/codehaus/groovy/classgen/package.html   |    28 -
 .../codehaus/groovy/cli/GroovyPosixParser.java  |   281 -
 .../control/ASTTransformationsContext.java      |    53 -
 .../control/AnnotationConstantsVisitor.java     |   133 -
 .../groovy/control/BytecodeProcessor.java       |    23 -
 .../groovy/control/ClassNodeResolver.java       |   345 -
 .../control/CompilationFailedException.java     |    77 -
 .../groovy/control/CompilationUnit.java         |  1167 -
 .../codehaus/groovy/control/CompilePhase.java   |   118 -
 .../groovy/control/CompilerConfiguration.java   |   934 -
 .../groovy/control/ConfigurationException.java  |    92 -
 .../codehaus/groovy/control/ErrorCollector.java |   348 -
 .../groovy/control/GenericsVisitor.java         |   188 -
 .../org/codehaus/groovy/control/HasCleanup.java |    31 -
 .../org/codehaus/groovy/control/Janitor.java    |    55 -
 .../codehaus/groovy/control/LabelVerifier.java  |   174 -
 .../MultipleCompilationErrorsException.java     |    64 -
 .../groovy/control/OptimizerVisitor.java        |   149 -
 .../codehaus/groovy/control/ParserPlugin.java   |    36 -
 .../groovy/control/ParserPluginFactory.java     |    93 -
 .../codehaus/groovy/control/ParserVersion.java  |    50 -
 .../org/codehaus/groovy/control/Phases.java     |    67 -
 .../codehaus/groovy/control/ProcessingUnit.java |   180 -
 .../codehaus/groovy/control/ResolveVisitor.java |  1469 --
 .../groovy/control/SourceExtensionHandler.java  |    66 -
 .../org/codehaus/groovy/control/SourceUnit.java |   344 -
 .../groovy/control/StaticImportVisitor.java     |   610 -
 .../codehaus/groovy/control/StaticVerifier.java |   204 -
 .../codehaus/groovy/control/XStreamUtils.java   |    68 -
 .../ASTTransformationCustomizer.groovy          |   301 -
 .../customizers/CompilationCustomizer.java      |    45 -
 .../customizers/DelegatingCustomizer.java       |    45 -
 .../control/customizers/ImportCustomizer.java   |   169 -
 .../customizers/SecureASTCustomizer.java        |  1189 --
 .../customizers/SourceAwareCustomizer.java      |   105 -
 .../ASTTransformationCustomizerFactory.groovy   |    60 -
 .../builder/CompilerCustomizationBuilder.groovy |    64 -
 .../customizers/builder/CustomizersFactory.java |    59 -
 .../builder/ImportCustomizerFactory.java        |   134 -
 .../builder/InlinedASTCustomizerFactory.java    |    89 -
 .../builder/PostCompletionFactory.java          |    31 -
 .../builder/SecureASTCustomizerFactory.java     |    55 -
 .../builder/SourceAwareCustomizerFactory.java   |   160 -
 .../groovy/control/io/AbstractReaderSource.java |   120 -
 .../groovy/control/io/FileReaderSource.java     |    91 -
 .../control/io/InputStreamReaderSource.java     |    76 -
 .../codehaus/groovy/control/io/NullWriter.java  |    36 -
 .../groovy/control/io/ReaderSource.java         |    70 -
 .../groovy/control/io/StringReaderSource.java   |    69 -
 .../groovy/control/io/URLReaderSource.java      |    69 -
 .../org/codehaus/groovy/control/io/package.html |    28 -
 .../control/messages/ExceptionMessage.java      |    88 -
 .../groovy/control/messages/LocatedMessage.java |    80 -
 .../groovy/control/messages/Message.java        |   101 -
 .../groovy/control/messages/SimpleMessage.java  |    77 -
 .../control/messages/SyntaxErrorMessage.java    |    69 -
 .../groovy/control/messages/WarningMessage.java |   118 -
 .../groovy/control/messages/package.html        |    28 -
 .../org/codehaus/groovy/control/package.html    |    28 -
 src/main/org/codehaus/groovy/package.html       |    28 -
 .../codehaus/groovy/plugin/GroovyRunner.java    |    28 -
 .../reflection/AccessPermissionChecker.java     |    84 -
 .../reflection/CacheAccessControlException.java |    27 -
 .../codehaus/groovy/reflection/CachedClass.java |   542 -
 .../groovy/reflection/CachedConstructor.java    |   116 -
 .../codehaus/groovy/reflection/CachedField.java |    81 -
 .../groovy/reflection/CachedMethod.java         |   345 -
 .../codehaus/groovy/reflection/ClassInfo.java   |   505 -
 .../ClassLoaderForClassArtifacts.java           |    88 -
 .../groovy/reflection/GeneratedMetaMethod.java  |   240 -
 .../groovy/reflection/GroovyClassValue.java     |    36 -
 .../reflection/GroovyClassValueFactory.java     |    42 -
 .../reflection/GroovyClassValuePreJava7.java    |   104 -
 .../groovy/reflection/MixinInMetaClass.java     |   206 -
 .../groovy/reflection/ParameterTypes.java       |   385 -
 .../groovy/reflection/ReflectionCache.java      |   113 -
 .../groovy/reflection/ReflectionUtils.java      |   140 -
 .../groovy/reflection/SunClassLoader.java       |   117 -
 .../reflection/android/AndroidSupport.java      |    38 -
 .../org/codehaus/groovy/reflection/package.html |    28 -
 .../reflection/stdclasses/ArrayCachedClass.java |    55 -
 .../stdclasses/BigDecimalCachedClass.java       |    52 -
 .../stdclasses/BigIntegerCachedClass.java       |    50 -
 .../stdclasses/BooleanCachedClass.java          |    43 -
 .../reflection/stdclasses/ByteCachedClass.java  |    53 -
 .../stdclasses/CachedClosureClass.java          |    61 -
 .../reflection/stdclasses/CachedSAMClass.java   |   203 -
 .../stdclasses/CharacterCachedClass.java        |    44 -
 .../stdclasses/DoubleCachedClass.java           |    76 -
 .../reflection/stdclasses/FloatCachedClass.java |    71 -
 .../stdclasses/IntegerCachedClass.java          |    61 -
 .../reflection/stdclasses/LongCachedClass.java  |    61 -
 .../stdclasses/NumberCachedClass.java           |    65 -
 .../stdclasses/ObjectCachedClass.java           |    39 -
 .../reflection/stdclasses/ShortCachedClass.java |    56 -
 .../stdclasses/StringCachedClass.java           |    50 -
 .../reflection/v7/GroovyClassValueJava7.java    |    37 -
 .../groovy/runtime/AbstractComparator.java      |    30 -
 .../codehaus/groovy/runtime/ArrayTypeUtils.java |    98 -
 .../org/codehaus/groovy/runtime/ArrayUtil.java  |  1312 --
 .../groovy/runtime/BytecodeInterface8.java      |   377 -
 .../codehaus/groovy/runtime/ClassExtender.java  |    89 -
 .../groovy/runtime/ComposedClosure.java         |   108 -
 .../groovy/runtime/ConversionHandler.java       |   224 -
 .../groovy/runtime/ConvertedClosure.java        |    58 -
 .../codehaus/groovy/runtime/ConvertedMap.java   |    80 -
 .../codehaus/groovy/runtime/CurriedClosure.java |   192 -
 .../groovy/runtime/DateGroovyMethods.java       |   775 -
 .../groovy/runtime/DefaultCachedMethodKey.java  |    47 -
 .../groovy/runtime/DefaultGroovyMethods.java    | 18930 -----------------
 .../runtime/DefaultGroovyMethodsSupport.java    |   383 -
 .../runtime/DefaultGroovyStaticMethods.java     |   314 -
 .../groovy/runtime/DefaultMethodKey.java        |    44 -
 .../groovy/runtime/EncodingGroovyMethods.java   |   367 -
 .../runtime/EncodingGroovyMethodsSupport.java   |    90 -
 .../groovy/runtime/FlushingStreamWriter.java    |    50 -
 .../codehaus/groovy/runtime/GStringImpl.java    |    64 -
 .../groovy/runtime/GeneratedClosure.java        |    29 -
 .../groovy/runtime/GroovyCategorySupport.java   |   365 -
 .../groovy/runtime/HandleMetaClass.java         |   122 -
 .../groovy/runtime/IOGroovyMethods.java         |  1698 --
 .../codehaus/groovy/runtime/InvokerHelper.java  |  1079 -
 .../runtime/InvokerInvocationException.java     |    44 -
 .../groovy/runtime/IteratorClosureAdapter.java  |    58 -
 .../groovy/runtime/MetaClassHelper.java         |  1034 -
 .../codehaus/groovy/runtime/MethodClosure.java  |   147 -
 .../org/codehaus/groovy/runtime/MethodKey.java  |   133 -
 .../groovy/runtime/MethodRankHelper.java        |   562 -
 .../org/codehaus/groovy/runtime/NullObject.java |   176 -
 .../groovy/runtime/NumberAwareComparator.java   |    60 -
 .../groovy/runtime/ProcessGroovyMethods.java    |   727 -
 .../groovy/runtime/ProxyGeneratorAdapter.java   |  1003 -
 .../org/codehaus/groovy/runtime/RangeInfo.java  |    31 -
 .../groovy/runtime/ReflectionMethodInvoker.java |    56 -
 .../org/codehaus/groovy/runtime/Reflector.java  |    39 -
 .../codehaus/groovy/runtime/RegexSupport.java   |    37 -
 .../groovy/runtime/ResourceGroovyMethods.java   |  2642 ---
 .../groovy/runtime/ReverseListIterator.java     |    65 -
 .../groovy/runtime/ScriptBytecodeAdapter.java   |   857 -
 .../groovy/runtime/ScriptReference.java         |    46 -
 .../groovy/runtime/SocketGroovyMethods.java     |   206 -
 .../groovy/runtime/StackTraceUtils.java         |   194 -
 .../groovy/runtime/StringBufferWriter.java      |   104 -
 .../groovy/runtime/StringGroovyMethods.java     |  3800 ----
 .../codehaus/groovy/runtime/WritableFile.java   |    65 -
 .../runtime/callsite/AbstractCallSite.java      |   424 -
 .../runtime/callsite/BooleanClosureWrapper.java |    68 -
 .../callsite/BooleanReturningMethodInvoker.java |    76 -
 .../groovy/runtime/callsite/CallSite.java       |    69 -
 .../groovy/runtime/callsite/CallSiteArray.java  |   175 -
 .../callsite/CallSiteAwareMetaMethod.java       |    27 -
 .../runtime/callsite/CallSiteClassLoader.java   |    59 -
 .../runtime/callsite/CallSiteGenerator.java     |   268 -
 .../callsite/ClassMetaClassGetPropertySite.java |    55 -
 .../callsite/ConstructorMetaClassSite.java      |    41 -
 .../callsite/ConstructorMetaMethodSite.java     |    67 -
 .../runtime/callsite/ConstructorSite.java       |   154 -
 .../groovy/runtime/callsite/DummyCallSite.java  |    25 -
 .../callsite/GetEffectivePogoFieldSite.java     |    78 -
 .../callsite/GetEffectivePogoPropertySite.java  |    90 -
 .../callsite/GetEffectivePojoFieldSite.java     |    60 -
 .../callsite/GetEffectivePojoPropertySite.java  |    68 -
 .../runtime/callsite/GroovySunClassLoader.java  |    74 -
 .../callsite/MetaClassConstructorSite.java      |    55 -
 .../groovy/runtime/callsite/MetaClassSite.java  |    35 -
 .../groovy/runtime/callsite/MetaMethodSite.java |    38 -
 .../groovy/runtime/callsite/NullCallSite.java   |    54 -
 .../callsite/PerInstancePojoMetaClassSite.java  |    45 -
 .../runtime/callsite/PogoGetPropertySite.java   |    54 -
 .../runtime/callsite/PogoInterceptableSite.java |    59 -
 .../callsite/PogoMetaClassGetPropertySite.java  |    55 -
 .../runtime/callsite/PogoMetaClassSite.java     |    86 -
 .../runtime/callsite/PogoMetaMethodSite.java    |   257 -
 .../callsite/PojoMetaClassGetPropertySite.java  |    49 -
 .../runtime/callsite/PojoMetaClassSite.java     |    60 -
 .../runtime/callsite/PojoMetaMethodSite.java    |   280 -
 .../runtime/callsite/StaticMetaClassSite.java   |    72 -
 .../runtime/callsite/StaticMetaMethodSite.java  |   157 -
 .../groovy/runtime/dgmimpl/NumberNumberDiv.java |   330 -
 .../runtime/dgmimpl/NumberNumberMetaMethod.java |    61 -
 .../runtime/dgmimpl/NumberNumberMinus.java      |   391 -
 .../runtime/dgmimpl/NumberNumberMultiply.java   |   393 -
 .../runtime/dgmimpl/NumberNumberPlus.java       |   385 -
 .../dgmimpl/arrays/ArrayGetAtMetaMethod.java    |    29 -
 .../runtime/dgmimpl/arrays/ArrayMetaMethod.java |    45 -
 .../dgmimpl/arrays/ArrayPutAtMetaMethod.java    |    29 -
 .../arrays/BooleanArrayGetAtMetaMethod.java     |    65 -
 .../arrays/BooleanArrayPutAtMetaMethod.java     |    85 -
 .../arrays/ByteArrayGetAtMetaMethod.java        |    65 -
 .../arrays/ByteArrayPutAtMetaMethod.java        |    89 -
 .../arrays/CharacterArrayGetAtMetaMethod.java   |    65 -
 .../arrays/CharacterArrayPutAtMetaMethod.java   |    86 -
 .../arrays/DoubleArrayGetAtMetaMethod.java      |    65 -
 .../arrays/DoubleArrayPutAtMetaMethod.java      |    96 -
 .../arrays/FloatArrayGetAtMetaMethod.java       |    65 -
 .../arrays/FloatArrayPutAtMetaMethod.java       |    96 -
 .../arrays/IntegerArrayGetAtMetaMethod.java     |    65 -
 .../arrays/IntegerArrayPutAtMetaMethod.java     |    96 -
 .../arrays/LongArrayGetAtMetaMethod.java        |    65 -
 .../arrays/LongArrayPutAtMetaMethod.java        |    96 -
 .../arrays/ObjectArrayGetAtMetaMethod.java      |    70 -
 .../arrays/ObjectArrayPutAtMetaMethod.java      |    97 -
 .../arrays/ShortArrayGetAtMetaMethod.java       |    65 -
 .../arrays/ShortArrayPutAtMetaMethod.java       |    96 -
 .../groovy/runtime/m12n/ExtensionModule.java    |    61 -
 .../runtime/m12n/ExtensionModuleRegistry.java   |    66 -
 .../runtime/m12n/ExtensionModuleScanner.java    |    88 -
 .../runtime/m12n/MetaInfExtensionModule.java    |   108 -
 .../runtime/m12n/PropertiesModuleFactory.java   |    36 -
 .../runtime/m12n/SimpleExtensionModule.java     |   138 -
 .../m12n/StandardPropertiesModuleFactory.java   |    54 -
 .../groovy/runtime/memoize/CommonCache.java     |   217 -
 .../runtime/memoize/ConcurrentCommonCache.java  |   239 -
 .../groovy/runtime/memoize/EvictableCache.java  |   106 -
 .../groovy/runtime/memoize/LRUCache.java        |    66 -
 .../runtime/memoize/LRUProtectionStorage.java   |    79 -
 .../groovy/runtime/memoize/Memoize.java         |   183 -
 .../groovy/runtime/memoize/MemoizeCache.java    |    51 -
 .../runtime/memoize/NullProtectionStorage.java  |    37 -
 .../runtime/memoize/ProtectionStorage.java      |    29 -
 .../memoize/UnlimitedConcurrentCache.java       |    54 -
 .../runtime/metaclass/ClosureMetaClass.java     |   713 -
 .../runtime/metaclass/ClosureMetaMethod.java    |   192 -
 .../metaclass/ClosureStaticMetaMethod.java      |    89 -
 .../metaclass/ConcurrentReaderHashMap.java      |  1270 --
 .../runtime/metaclass/DefaultMetaClassInfo.java |   346 -
 .../metaclass/MetaClassRegistryImpl.java        |   551 -
 .../runtime/metaclass/MetaMethodIndex.java      |   546 -
 .../groovy/runtime/metaclass/MethodHelper.java  |    40 -
 .../runtime/metaclass/MethodMetaProperty.java   |    80 -
 .../metaclass/MethodSelectionException.java     |   102 -
 .../MissingMethodExceptionNoStack.java          |    36 -
 .../metaclass/MissingMethodExecutionFailed.java |    36 -
 .../MissingPropertyExceptionNoStack.java        |    32 -
 .../runtime/metaclass/MixedInMetaClass.java     |    55 -
 .../metaclass/MixinInstanceMetaMethod.java      |    62 -
 .../metaclass/MixinInstanceMetaProperty.java    |    96 -
 .../metaclass/MultipleSetterProperty.java       |    88 -
 .../metaclass/NewInstanceMetaMethod.java        |    58 -
 .../groovy/runtime/metaclass/NewMetaMethod.java |    57 -
 .../runtime/metaclass/NewStaticMetaMethod.java  |    55 -
 .../runtime/metaclass/OwnedMetaClass.java       |   234 -
 .../runtime/metaclass/ReflectionMetaMethod.java |    75 -
 .../runtime/metaclass/ReflectorLoader.java      |   147 -
 .../runtime/metaclass/TemporaryMethodKey.java   |    59 -
 .../ThreadManagedMetaBeanProperty.java          |   227 -
 .../runtime/metaclass/TransformMetaMethod.java  |    59 -
 .../groovy/runtime/metaclass/package.html       |    28 -
 .../org/codehaus/groovy/runtime/package.html    |    28 -
 .../runtime/powerassert/AssertionRenderer.java  |   184 -
 .../powerassert/PowerAssertionError.java        |    35 -
 .../groovy/runtime/powerassert/SourceText.java  |   126 -
 .../SourceTextNotAvailableException.java        |    36 -
 .../groovy/runtime/powerassert/Value.java       |    43 -
 .../runtime/powerassert/ValueRecorder.java      |    45 -
 .../runtime/typehandling/BigDecimalMath.java    |    86 -
 .../runtime/typehandling/BigIntegerMath.java    |    86 -
 .../typehandling/DefaultTypeTransformation.java |   894 -
 .../runtime/typehandling/FloatingPointMath.java |    67 -
 .../typehandling/GroovyCastException.java       |    85 -
 .../runtime/typehandling/IntegerMath.java       |   101 -
 .../groovy/runtime/typehandling/LongMath.java   |   105 -
 .../groovy/runtime/typehandling/NumberMath.java |   294 -
 .../NumberMathModificationInfo.java             |  3732 ----
 .../runtime/typehandling/ShortTypeHandling.java |    86 -
 .../groovy/runtime/typehandling/package.html    |    30 -
 .../groovy/runtime/wrappers/BooleanWrapper.java |    28 -
 .../groovy/runtime/wrappers/ByteWrapper.java    |    28 -
 .../groovy/runtime/wrappers/CharWrapper.java    |    28 -
 .../groovy/runtime/wrappers/DoubleWrapper.java  |    28 -
 .../groovy/runtime/wrappers/FloatWrapper.java   |    28 -
 .../runtime/wrappers/GroovyObjectWrapper.java   |    74 -
 .../groovy/runtime/wrappers/IntWrapper.java     |    28 -
 .../groovy/runtime/wrappers/LongWrapper.java    |    28 -
 .../groovy/runtime/wrappers/PojoWrapper.java    |    74 -
 .../groovy/runtime/wrappers/ShortWrapper.java   |    30 -
 .../groovy/runtime/wrappers/Wrapper.java        |    50 -
 .../groovy/runtime/wrappers/package.html        |    28 -
 .../org/codehaus/groovy/syntax/ASTHelper.java   |   162 -
 .../org/codehaus/groovy/syntax/CSTNode.java     |   583 -
 .../org/codehaus/groovy/syntax/Numbers.java     |   317 -
 .../codehaus/groovy/syntax/ParserException.java |    33 -
 .../codehaus/groovy/syntax/ReadException.java   |    58 -
 .../org/codehaus/groovy/syntax/Reduction.java   |   266 -
 .../groovy/syntax/RuntimeParserException.java   |    41 -
 .../codehaus/groovy/syntax/SyntaxException.java |   123 -
 src/main/org/codehaus/groovy/syntax/Token.java  |   393 -
 .../codehaus/groovy/syntax/TokenException.java  |    47 -
 .../groovy/syntax/TokenMismatchException.java   |    38 -
 .../org/codehaus/groovy/syntax/TokenUtil.java   |    88 -
 src/main/org/codehaus/groovy/syntax/Types.java  |  1454 --
 .../org/codehaus/groovy/syntax/package.html     |    28 -
 .../org/codehaus/groovy/tools/Compiler.java     |   116 -
 .../org/codehaus/groovy/tools/DgmConverter.java |   230 -
 .../codehaus/groovy/tools/ErrorReporter.java    |   235 -
 .../groovy/tools/FileSystemCompiler.java        |   389 -
 .../org/codehaus/groovy/tools/GrapeMain.groovy  |   308 -
 .../org/codehaus/groovy/tools/GrapeUtil.java    |    45 -
 .../org/codehaus/groovy/tools/GroovyClass.java  |    45 -
 .../codehaus/groovy/tools/GroovyStarter.java    |   141 -
 .../groovy/tools/LoaderConfiguration.java       |   376 -
 .../org/codehaus/groovy/tools/RootLoader.java   |   181 -
 .../org/codehaus/groovy/tools/StringHelper.java |    85 -
 .../org/codehaus/groovy/tools/Utilities.java    |    77 -
 .../groovy/tools/ast/TransformTestHelper.groovy |   123 -
 .../groovy/tools/gse/DependencyTracker.java     |   137 -
 .../codehaus/groovy/tools/gse/StringSetMap.java |    64 -
 .../tools/javac/JavaAwareCompilationUnit.java   |   163 -
 .../tools/javac/JavaAwareResolveVisitor.java    |    69 -
 .../groovy/tools/javac/JavaCompiler.java        |    30 -
 .../groovy/tools/javac/JavaCompilerFactory.java |    25 -
 .../tools/javac/JavaStubCompilationUnit.java    |   131 -
 .../groovy/tools/javac/JavaStubGenerator.java   |   981 -
 .../tools/javac/JavacCompilerFactory.java       |    27 -
 .../groovy/tools/javac/JavacJavaCompiler.java   |   214 -
 .../codehaus/groovy/tools/javac/package.html    |    28 -
 src/main/org/codehaus/groovy/tools/package.html |    30 -
 .../org/codehaus/groovy/tools/shell/IO.java     |   190 -
 .../groovy/tools/shell/util/Logger.java         |   134 -
 .../groovy/tools/shell/util/MessageSource.java  |   142 -
 .../groovy/tools/shell/util/Preferences.java    |   121 -
 .../org/codehaus/groovy/tools/xml/package.html  |    28 -
 .../transform/ASTTestTransformation.groovy      |   233 -
 .../groovy/transform/ASTTransformation.java     |    50 -
 .../ASTTransformationCollectorCodeVisitor.java  |   369 -
 .../transform/ASTTransformationVisitor.java     |   343 -
 .../transform/AbstractASTTransformUtil.java     |   184 -
 .../transform/AbstractASTTransformation.java    |   485 -
 .../AbstractInterruptibleASTTransformation.java |   235 -
 .../transform/AnnotationCollectorTransform.java |   369 -
 .../transform/AutoCloneASTTransformation.java   |   305 -
 .../transform/AutoFinalASTTransformation.java   |   191 -
 .../AutoImplementASTTransformation.java         |   183 -
 .../transform/BaseScriptASTTransformation.java  |   167 -
 .../transform/BuilderASTTransformation.java     |   278 -
 .../transform/CategoryASTTransformation.java    |   298 -
 .../transform/CompileDynamicProcessor.java      |    44 -
 ...itionalInterruptibleASTTransformation.groovy |   145 -
 .../transform/DelegateASTTransformation.java    |   384 -
 .../EqualsAndHashCodeASTTransformation.java     |   332 -
 .../groovy/transform/ErrorCollecting.java       |    31 -
 .../ExternalizeMethodsASTTransformation.java    |   129 -
 .../ExternalizeVerifierASTTransformation.java   |   107 -
 .../transform/FieldASTTransformation.java       |   282 -
 .../transform/GroovyASTTransformation.java      |    52 -
 .../transform/GroovyASTTransformationClass.java |    47 -
 .../transform/ImmutableASTTransformation.java   |   818 -
 .../IndexedPropertyASTTransformation.java       |   137 -
 .../InheritConstructorsASTTransformation.java   |   132 -
 .../groovy/transform/LazyASTTransformation.java |   243 -
 .../groovy/transform/LogASTTransformation.java  |   297 -
 .../MapConstructorASTTransformation.java        |   196 -
 .../transform/MemoizedASTTransformation.java    |   201 -
 .../transform/NewifyASTTransformation.java      |   324 -
 .../PackageScopeASTTransformation.java          |   201 -
 .../ReadWriteLockASTTransformation.java         |   143 -
 .../transform/SingletonASTTransformation.java   |   136 -
 .../transform/SortableASTTransformation.java    |   253 -
 .../transform/SourceURIASTTransformation.java   |   132 -
 .../transform/StaticTypesTransformation.java    |   115 -
 .../SynchronizedASTTransformation.java          |   114 -
 .../ThreadInterruptibleASTTransformation.groovy |    98 -
 .../TimedInterruptibleASTTransformation.groovy  |   321 -
 .../transform/ToStringASTTransformation.java    |   276 -
 .../TupleConstructorASTTransformation.java      |   331 -
 .../sc/ListOfExpressionsExpression.java         |    61 -
 .../sc/StaticCompilationMetadataKeys.java       |    36 -
 .../transform/sc/StaticCompilationVisitor.java  |   542 -
 .../sc/StaticCompileTransformation.java         |   100 -
 .../sc/TemporaryVariableExpression.java         |    77 -
 .../BinaryExpressionTransformer.java            |   393 -
 .../BooleanExpressionTransformer.java           |   183 -
 .../transformers/CastExpressionOptimizer.java   |    80 -
 .../ClosureExpressionTransformer.java           |    47 -
 .../transformers/CompareIdentityExpression.java |    84 -
 .../transformers/CompareToNullExpression.java   |    82 -
 .../ConstructorCallTransformer.java             |   193 -
 .../transformers/ListExpressionTransformer.java |    81 -
 .../MethodCallExpressionTransformer.java        |   197 -
 .../RangeExpressionTransformer.java             |    76 -
 .../StaticCompilationTransformer.java           |   175 -
 .../StaticMethodCallExpressionTransformer.java  |    51 -
 .../VariableExpressionTransformer.java          |    91 -
 .../stc/AbstractTypeCheckingExtension.java      |   450 -
 .../stc/DefaultTypeCheckingExtension.java       |   194 -
 .../transform/stc/DelegationMetadata.java       |    57 -
 .../transform/stc/ExtensionMethodNode.java      |    57 -
 .../stc/GroovyTypeCheckingExtensionSupport.java |   460 -
 .../transform/stc/PropertyLookupVisitor.java    |    62 -
 .../codehaus/groovy/transform/stc/Receiver.java |    59 -
 .../transform/stc/SecondPassExpression.java     |    71 -
 .../transform/stc/SharedVariableCollector.java  |    61 -
 .../groovy/transform/stc/SignatureCodec.java    |    34 -
 .../transform/stc/SignatureCodecVersion1.java   |   230 -
 .../stc/StaticTypeCheckingSupport.java          |  2437 ---
 .../stc/StaticTypeCheckingVisitor.java          |  5178 -----
 .../groovy/transform/stc/StaticTypesMarker.java |    41 -
 .../stc/TraitTypeCheckingExtension.java         |   141 -
 .../transform/stc/TypeCheckingContext.java      |   365 -
 .../transform/stc/TypeCheckingExtension.java    |   404 -
 .../transform/stc/UnionTypeClassNode.java       |   476 -
 .../groovy/transform/tailrec/AstHelper.groovy   |    76 -
 .../tailrec/CollectRecursiveCalls.groovy        |    62 -
 .../transform/tailrec/HasRecursiveCalls.groovy  |    64 -
 .../transform/tailrec/InWhileLoopWrapper.groovy |    81 -
 .../tailrec/RecursivenessTester.groovy          |   100 -
 .../tailrec/ReturnAdderForClosures.groovy       |    48 -
 .../ReturnStatementToIterationConverter.groovy  |   148 -
 .../transform/tailrec/StatementReplacer.groovy  |   109 -
 .../TailRecursiveASTTransformation.groovy       |   261 -
 .../TernaryToIfStatementConverter.groovy        |    42 -
 .../tailrec/VariableAccessReplacer.groovy       |    73 -
 .../tailrec/VariableExpressionReplacer.groovy   |   171 -
 .../VariableExpressionTransformer.groovy        |    47 -
 .../transform/trait/NAryOperationRewriter.java  |   130 -
 .../trait/SuperCallTraitTransformer.java        |   193 -
 .../transform/trait/TraitASTTransformation.java |   624 -
 .../groovy/transform/trait/TraitComposer.java   |   568 -
 .../transform/trait/TraitHelpersTuple.java      |    45 -
 .../trait/TraitReceiverTransformer.java         |   451 -
 .../codehaus/groovy/transform/trait/Traits.java |   378 -
 .../groovy/util/AbstractConcurrentMap.java      |   205 -
 .../groovy/util/AbstractConcurrentMapBase.java  |   345 -
 .../org/codehaus/groovy/util/ArrayIterator.java |    46 -
 .../groovy/util/CharSequenceReader.java         |   170 -
 .../codehaus/groovy/util/ComplexKeyHashMap.java |   176 -
 .../org/codehaus/groovy/util/FastArray.java     |   139 -
 .../org/codehaus/groovy/util/Finalizable.java   |    23 -
 .../codehaus/groovy/util/HashCodeHelper.java    |   131 -
 .../groovy/util/IteratorBufferedIterator.java   |    75 -
 .../org/codehaus/groovy/util/LazyReference.java |    74 -
 .../groovy/util/ListBufferedIterator.java       |    67 -
 .../org/codehaus/groovy/util/ListHashMap.java   |   220 -
 .../codehaus/groovy/util/LockableObject.java    |    73 -
 .../util/ManagedConcurrentLinkedQueue.java      |   180 -
 .../groovy/util/ManagedConcurrentMap.java       |   118 -
 .../groovy/util/ManagedConcurrentValueMap.java  |    77 -
 .../codehaus/groovy/util/ManagedLinkedList.java |   145 -
 .../codehaus/groovy/util/ManagedReference.java  |    55 -
 .../org/codehaus/groovy/util/Reference.java     |    25 -
 .../codehaus/groovy/util/ReferenceBundle.java   |    63 -
 .../codehaus/groovy/util/ReferenceManager.java  |   199 -
 .../org/codehaus/groovy/util/ReferenceType.java |   105 -
 .../org/codehaus/groovy/util/ReleaseInfo.java   |    80 -
 .../codehaus/groovy/util/SingleKeyHashMap.java  |   161 -
 .../org/codehaus/groovy/util/StringUtil.groovy  |    57 -
 .../codehaus/groovy/util/TripleKeyHashMap.java  |    86 -
 .../org/codehaus/groovy/vmplugin/VMPlugin.java  |    65 -
 .../groovy/vmplugin/VMPluginFactory.java        |    57 -
 .../org/codehaus/groovy/vmplugin/package.html   |    28 -
 .../groovy/vmplugin/v5/JUnit4Utils.java         |   102 -
 .../org/codehaus/groovy/vmplugin/v5/Java5.java  |   484 -
 .../vmplugin/v5/PluginDefaultGroovyMethods.java |   141 -
 .../codehaus/groovy/vmplugin/v5/package.html    |    28 -
 .../org/codehaus/groovy/vmplugin/v6/Java6.java  |    34 -
 .../groovy/vmplugin/v7/IndyArrayAccess.java     |   143 -
 .../v7/IndyGuardsFiltersAndSignatures.java      |   215 -
 .../groovy/vmplugin/v7/IndyInterface.java       |   250 -
 .../codehaus/groovy/vmplugin/v7/IndyMath.java   |   196 -
 .../org/codehaus/groovy/vmplugin/v7/Java7.java  |   108 -
 .../codehaus/groovy/vmplugin/v7/Selector.java   |  1065 -
 .../codehaus/groovy/vmplugin/v7/TypeHelper.java |   113 -
 .../groovy/vmplugin/v7/TypeTransformers.java    |   243 -
 .../org/codehaus/groovy/vmplugin/v8/Java8.java  |    66 -
 .../vmplugin/v8/PluginDefaultGroovyMethods.java |    68 -
 src/main/overview.html                          |    41 -
 src/main/overviewj.html                         |    41 -
 .../codehaus/groovy/tools/DocGeneratorMain.java |     2 +-
 .../codehaus/groovy/tools/DocGenerator.groovy   |     2 +-
 .../tools/groovydoc/GroovyDocToolTest.java      |    11 +-
 1447 files changed, 176819 insertions(+), 176828 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/build.gradle
----------------------------------------------------------------------
diff --git a/build.gradle b/build.gradle
index ddf2044..f8737b4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -134,12 +134,7 @@ task(copyTestResources, type: Copy)
         .include('**/*.txt', '**/*.xml', '**/*.properties', '**/*.png', '**/*.html', '**/*.gif', '**/*.ico', '**/*.css')
 test.dependsOn(copyTestResources)
 
-task sourceJar(type: Jar) {
-    classifier = 'sources'
-    from 'src/main'
-}
-
-subprojects {
+allprojects {
     task sourceJar(type: Jar) {
         classifier = 'sources'
         from sourceSets.main.allSource
@@ -280,20 +275,16 @@ ext.generatedDirectory = "${buildDir}/generated-sources"
 sourceSets {
     main {
         java {
-            srcDirs = [
-                    'src/main',
-                    "$generatedDirectory/src/main"
-            ]
+            // the only reason we add src/main/groovy here is for the bootstrap compiler
+            srcDir 'src/main/groovy'
+            srcDir "$generatedDirectory/src/main"
             if (!JavaVersion.current().isJava8Compatible()) {
                 exclude '**/v8/*'
                 exclude '**/vm8/*'
             }
         }
         groovy {
-            srcDirs = [
-                    'src/main',
-                    "$generatedDirectory/src/main"
-            ]
+            srcDir "$generatedDirectory/src/main"
             if (!JavaVersion.current().isJava8Compatible()) {
                 exclude '**/v8/*'
                 exclude '**/vm8/*'
@@ -398,7 +389,7 @@ task dgmConverter(dependsOn:compileJava) {
             arg(value: "$outputDir.absolutePath")
         }
     }
-    inputs.files fileTree('src').include('**/*GroovyMethods.java')
+    inputs.files fileTree('src/main').include('**/*GroovyMethods.java')
     outputs.dir outputDir
 }
 
@@ -444,7 +435,7 @@ allprojects {
         groovyOptions.encoding = 'UTF-8'
         groovyClasspath = files(
                 rootProject.compileJava.classpath,
-                rootProject.bootstrapJar.archivePath
+                files(project==rootProject?rootProject.bootstrapJar:rootProject.jar)
         )
 
         // TODO: this null check was required after adding JMH plugin to performance project

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index ae07964..819e4cf 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -143,6 +143,7 @@ allprojects {
             classifier = 'indy'
             appendix = 'raw'
             from sourceSets.main.java.outputDir
+            from sourceSets.main.groovy.outputDir
             from compileGroovyWithIndy.destinationDir
             from "${project.buildDir}/resources/main"
         }


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java
new file mode 100644
index 0000000..f33d377
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/IOGroovyMethods.java
@@ -0,0 +1,1698 @@
+/*
+ *  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.runtime;
+
+import groovy.io.GroovyPrintWriter;
+import groovy.lang.Closure;
+import groovy.lang.StringWriterIOException;
+import groovy.lang.Writable;
+import groovy.transform.stc.ClosureParams;
+import groovy.transform.stc.FirstParam;
+import groovy.transform.stc.FromString;
+import groovy.transform.stc.PickFirstResolver;
+import groovy.transform.stc.SimpleType;
+import org.codehaus.groovy.runtime.callsite.BooleanClosureWrapper;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Formatter;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import static org.codehaus.groovy.ast.tools.ClosureUtils.hasSingleStringArg;
+import static org.codehaus.groovy.runtime.DefaultGroovyMethods.callClosureForLine;
+
+/**
+ * This class defines new groovy methods for Files, URLs, URIs which appear
+ * on normal JDK classes inside the Groovy environment.
+ * Static methods are used with the first parameter being the destination class,
+ * i.e. <code>public static long size(File self)</code>
+ * provides a <code>size()</code> method for <code>File</code>.
+ * <p>
+ * NOTE: While this class contains many 'public' static methods, it is
+ * primarily regarded as an internal class (its internal package name
+ * suggests this also). We value backwards compatibility of these
+ * methods when used within Groovy but value less backwards compatibility
+ * at the Java method call level. I.e. future versions of Groovy may
+ * remove or move a method call in this file but would normally
+ * aim to keep the method available from within Groovy.
+ */
+public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
+
+    private static final Logger LOG = Logger.getLogger(IOGroovyMethods.class.getName());
+
+    /**
+     * Overloads the leftShift operator for Writer to allow an object to be written
+     * using Groovy's default representation for the object.
+     *
+     * @param self  a Writer
+     * @param value an Object whose default representation will be written to the Writer
+     * @return the writer on which this operation was invoked
+     * @throws IOException if an I/O error occurs.
+     * @since 1.0
+     */
+    public static Writer leftShift(Writer self, Object value) throws IOException {
+        InvokerHelper.write(self, value);
+        return self;
+    }
+
+    /**
+     * Overloads the leftShift operator for Appendable to allow an object to be appended
+     * using Groovy's default representation for the object.
+     *
+     * @param self  an Appendable
+     * @param value an Object whose default representation will be appended to the Appendable
+     * @return the Appendable on which this operation was invoked
+     * @throws IOException if an I/O error occurs.
+     * @since 2.1.0
+     */
+    public static Appendable leftShift(Appendable self, Object value) throws IOException {
+        InvokerHelper.append(self, value);
+        return self;
+    }
+
+    /**
+     * Invokes a Closure that uses a Formatter taking care of resource handling.
+     * A Formatter is created and passed to the Closure as its argument.
+     * After the Closure executes, the Formatter is flushed and closed releasing any
+     * associated resources.
+     *
+     * @param self    an Appendable
+     * @param closure a 1-arg Closure which will be called with a Formatter as its argument
+     * @return the Appendable on which this operation was invoked
+     * @since 2.1.0
+     */
+    public static Appendable withFormatter(Appendable self, @ClosureParams(value=SimpleType.class, options="java.util.Formatter") Closure closure) {
+        Formatter formatter = new Formatter(self);
+        callWithFormatter(closure, formatter);
+        return self;
+    }
+
+    /**
+     * Invokes a Closure that uses a Formatter taking care of resource handling.
+     * A Formatter is created using the given Locale and passed to the Closure as its argument.
+     * After the Closure executes, the Formatter is flushed and closed releasing any
+     * associated resources.
+     *
+     * @param self    an Appendable
+     * @param locale  a Locale used when creating the Formatter
+     * @param closure a 1-arg Closure which will be called with a Formatter as its argument
+     * @return the Appendable on which this operation was invoked
+     * @since 2.1.0
+     */
+    public static Appendable withFormatter(Appendable self, Locale locale, @ClosureParams(value=SimpleType.class, options="java.util.Formatter") Closure closure) {
+        Formatter formatter = new Formatter(self, locale);
+        callWithFormatter(closure, formatter);
+        return self;
+    }
+
+    private static void callWithFormatter(Closure closure, Formatter formatter) {
+        try {
+            closure.call(formatter);
+        } finally {
+            formatter.flush();
+            formatter.close();
+        }
+    }
+
+    /**
+     * A helper method so that dynamic dispatch of the writer.write(object) method
+     * will always use the more efficient Writable.writeTo(writer) mechanism if the
+     * object implements the Writable interface.
+     *
+     * @param self     a Writer
+     * @param writable an object implementing the Writable interface
+     * @throws IOException if an I/O error occurs.
+     * @since 1.0
+     */
+    public static void write(Writer self, Writable writable) throws IOException {
+        writable.writeTo(self);
+    }
+
+    /**
+     * Overloads the leftShift operator to provide an append mechanism to add values to a stream.
+     *
+     * @param self  an OutputStream
+     * @param value a value to append
+     * @return a Writer
+     * @throws java.io.IOException if an I/O error occurs.
+     * @since 1.0
+     */
+
+    public static Writer leftShift(OutputStream self, Object value) throws IOException {
+        OutputStreamWriter writer = new FlushingStreamWriter(self);
+        leftShift(writer, value);
+        return writer;
+    }
+
+    /**
+     * Overloads the leftShift operator to add objects to an ObjectOutputStream.
+     *
+     * @param self  an ObjectOutputStream
+     * @param value an object to write to the stream
+     * @throws IOException if an I/O error occurs.
+     * @since 1.5.0
+     */
+    public static void leftShift(ObjectOutputStream self, Object value) throws IOException {
+        self.writeObject(value);
+    }
+
+    /**
+     * Pipe an InputStream into an OutputStream for efficient stream copying.
+     *
+     * @param self stream on which to write
+     * @param in   stream to read from
+     * @return the outputstream itself
+     * @throws IOException if an I/O error occurs.
+     * @since 1.0
+     */
+    public static OutputStream leftShift(OutputStream self, InputStream in) throws IOException {
+        byte[] buf = new byte[1024];
+        while (true) {
+            int count = in.read(buf, 0, buf.length);
+            if (count == -1) break;
+            if (count == 0) {
+                Thread.yield();
+                continue;
+            }
+            self.write(buf, 0, count);
+        }
+        self.flush();
+        return self;
+    }
+
+    /**
+     * Overloads the leftShift operator to provide an append mechanism to add bytes to a stream.
+     *
+     * @param self  an OutputStream
+     * @param value a value to append
+     * @return an OutputStream
+     * @throws IOException if an I/O error occurs.
+     * @since 1.0
+     */
+    public static OutputStream leftShift(OutputStream self, byte[] value) throws IOException {
+        self.write(value);
+        self.flush();
+        return self;
+    }
+
+    /**
+     * Create an object output stream for this output stream.
+     *
+     * @param outputStream an output stream
+     * @return an object output stream
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.0
+     */
+    public static ObjectOutputStream newObjectOutputStream(OutputStream outputStream) throws IOException {
+        return new ObjectOutputStream(outputStream);
+    }
+
+    /**
+     * Create a new ObjectOutputStream for this output stream and then pass it to the
+     * closure.  This method ensures the stream is closed after the closure
+     * returns.
+     *
+     * @param outputStream am output stream
+     * @param closure      a closure
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #withStream(java.io.OutputStream, groovy.lang.Closure)
+     * @since 1.5.0
+     */
+    public static <T> T withObjectOutputStream(OutputStream outputStream, @ClosureParams(value=SimpleType.class, options="java.io.ObjectOutputStream") Closure<T> closure) throws IOException {
+        return withStream(newObjectOutputStream(outputStream), closure);
+    }
+
+    /**
+     * Create an object input stream for this input stream.
+     *
+     * @param inputStream an input stream
+     * @return an object input stream
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.0
+     */
+    public static ObjectInputStream newObjectInputStream(InputStream inputStream) throws IOException {
+        return new ObjectInputStream(inputStream);
+    }
+
+    /**
+     * Create an object input stream for this input stream using the given class loader.
+     *
+     * @param inputStream an input stream
+     * @param classLoader the class loader to use when loading the class
+     * @return an object input stream
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.0
+     */
+    public static ObjectInputStream newObjectInputStream(InputStream inputStream, final ClassLoader classLoader) throws IOException {
+        return new ObjectInputStream(inputStream) {
+            protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+                return Class.forName(desc.getName(), true, classLoader);
+
+            }
+        };
+    }
+
+    /**
+     * Iterates through the given object stream object by object. The
+     * ObjectInputStream is closed afterwards.
+     *
+     * @param ois     an ObjectInputStream, closed after the operation
+     * @param closure a closure
+     * @throws IOException            if an IOException occurs.
+     * @throws ClassNotFoundException if the class  is not found.
+     * @since 1.0
+     */
+    public static void eachObject(ObjectInputStream ois, Closure closure) throws IOException, ClassNotFoundException {
+        try {
+            while (true) {
+                try {
+                    Object obj = ois.readObject();
+                    // we allow null objects in the object stream
+                    closure.call(obj);
+                } catch (EOFException e) {
+                    break;
+                }
+            }
+            InputStream temp = ois;
+            ois = null;
+            temp.close();
+        } finally {
+            closeWithWarning(ois);
+        }
+    }
+
+    /**
+     * Create a new ObjectInputStream for this file and pass it to the closure.
+     * This method ensures the stream is closed after the closure returns.
+     *
+     * @param inputStream an input stream
+     * @param closure     a closure
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #withStream(java.io.InputStream, groovy.lang.Closure)
+     * @since 1.5.0
+     */
+    public static <T> T withObjectInputStream(InputStream inputStream, @ClosureParams(value=SimpleType.class, options="java.io.ObjectInputStream") Closure<T> closure) throws IOException {
+        return withStream(newObjectInputStream(inputStream), closure);
+    }
+
+    /**
+     * Create a new ObjectInputStream for this file and pass it to the closure.
+     * This method ensures the stream is closed after the closure returns.
+     *
+     * @param inputStream an input stream
+     * @param classLoader the class loader to use when loading the class
+     * @param closure     a closure
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #withStream(java.io.InputStream, groovy.lang.Closure)
+     * @since 1.5.0
+     */
+    public static <T> T withObjectInputStream(InputStream inputStream, ClassLoader classLoader, @ClosureParams(value=SimpleType.class, options="java.io.ObjectInputStream") Closure<T> closure) throws IOException {
+        return withStream(newObjectInputStream(inputStream, classLoader), closure);
+    }
+
+    /**
+     * Iterates through this stream reading with the provided charset, passing each line to the
+     * given 1 or 2 arg closure.  The stream is closed before this method returns.
+     *
+     * @param stream  a stream
+     * @param charset opens the stream with a specified charset
+     * @param closure a closure (arg 1 is line, optional arg 2 is line number starting at line 1)
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #eachLine(java.io.InputStream, java.lang.String, int, groovy.lang.Closure)
+     * @since 1.5.5
+     */
+    public static <T> T eachLine(InputStream stream, String charset, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+        return eachLine(stream, charset, 1, closure);
+    }
+
+    /**
+     * Iterates through this stream reading with the provided charset, passing each line to
+     * the given 1 or 2 arg closure.  The stream is closed after this method returns.
+     *
+     * @param stream    a stream
+     * @param charset   opens the stream with a specified charset
+     * @param firstLine the line number value used for the first line (default is 1, set to 0 to start counting from 0)
+     * @param closure   a closure (arg 1 is line, optional arg 2 is line number)
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #eachLine(java.io.Reader, int, groovy.lang.Closure)
+     * @since 1.5.7
+     */
+    public static <T> T eachLine(InputStream stream, String charset, int firstLine, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+        return eachLine(new InputStreamReader(stream, charset), firstLine, closure);
+    }
+
+    /**
+     * Iterates through this stream, passing each line to the given 1 or 2 arg closure.
+     * The stream is closed before this method returns.
+     *
+     * @param stream  a stream
+     * @param closure a closure (arg 1 is line, optional arg 2 is line number starting at line 1)
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #eachLine(java.io.InputStream, int, groovy.lang.Closure)
+     * @since 1.5.6
+     */
+    public static <T> T eachLine(InputStream stream, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+        return eachLine(stream, 1, closure);
+    }
+
+    /**
+     * Iterates through this stream, passing each line to the given 1 or 2 arg closure.
+     * The stream is closed before this method returns.
+     *
+     * @param stream    a stream
+     * @param firstLine the line number value used for the first line (default is 1, set to 0 to start counting from 0)
+     * @param closure   a closure (arg 1 is line, optional arg 2 is line number)
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #eachLine(java.io.Reader, int, groovy.lang.Closure)
+     * @since 1.5.7
+     */
+    public static <T> T eachLine(InputStream stream, int firstLine, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+        return eachLine(new InputStreamReader(stream), firstLine, closure);
+    }
+
+    /**
+     * Iterates through the given reader line by line.  Each line is passed to the
+     * given 1 or 2 arg closure. If the closure has two arguments, the line count is passed
+     * as the second argument. The Reader is closed before this method returns.
+     *
+     * @param self    a Reader, closed after the method returns
+     * @param closure a closure (arg 1 is line, optional arg 2 is line number starting at line 1)
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #eachLine(java.io.Reader, int, groovy.lang.Closure)
+     * @since 1.5.6
+     */
+    public static <T> T eachLine(Reader self, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+        return eachLine(self, 1, closure);
+    }
+
+    /**
+     * Iterates through the given reader line by line.  Each line is passed to the
+     * given 1 or 2 arg closure. If the closure has two arguments, the line count is passed
+     * as the second argument. The Reader is closed before this method returns.
+     *
+     * @param self      a Reader, closed after the method returns
+     * @param firstLine the line number value used for the first line (default is 1, set to 0 to start counting from 0)
+     * @param closure   a closure which will be passed each line (or for 2 arg closures the line and line count)
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.7
+     */
+    public static <T> T eachLine(Reader self, int firstLine, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+        BufferedReader br;
+        int count = firstLine;
+        T result = null;
+
+        if (self instanceof BufferedReader)
+            br = (BufferedReader) self;
+        else
+            br = new BufferedReader(self);
+
+        try {
+            while (true) {
+                String line = br.readLine();
+                if (line == null) {
+                    break;
+                } else {
+                    result = callClosureForLine(closure, line, count);
+                    count++;
+                }
+            }
+            Reader temp = self;
+            self = null;
+            temp.close();
+            return result;
+        } finally {
+            closeWithWarning(self);
+            closeWithWarning(br);
+        }
+    }
+
+    /**
+     * Iterates through the given reader line by line, splitting each line using
+     * the given regex separator. For each line, the given closure is called with
+     * a single parameter being the list of strings computed by splitting the line
+     * around matches of the given regular expression.  The Reader is closed afterwards.
+     * <p>
+     * Here is an example:
+     * <pre>
+     * def s = 'The 3 quick\nbrown 4 fox'
+     * def result = ''
+     * new StringReader(s).splitEachLine(/\d/){ parts ->
+     *     result += "${parts[0]}_${parts[1]}|"
+     * }
+     * assert result == 'The _ quick|brown _ fox|'
+     * </pre>
+     *
+     * @param self    a Reader, closed after the method returns
+     * @param regex   the delimiting regular expression
+     * @param closure a closure
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @throws java.util.regex.PatternSyntaxException
+     *                     if the regular expression's syntax is invalid
+     * @see java.lang.String#split(java.lang.String)
+     * @since 1.5.5
+     */
+    public static <T> T splitEachLine(Reader self, String regex, @ClosureParams(value=FromString.class,options={"List<String>","String[]"},conflictResolutionStrategy=PickFirstResolver.class) Closure<T> closure) throws IOException {
+        return splitEachLine(self, Pattern.compile(regex), closure);
+    }
+
+    /**
+     * Iterates through the given reader line by line, splitting each line using
+     * the given regex separator Pattern. For each line, the given closure is called with
+     * a single parameter being the list of strings computed by splitting the line
+     * around matches of the given regular expression.  The Reader is closed afterwards.
+     * <p>
+     * Here is an example:
+     * <pre>
+     * def s = 'The 3 quick\nbrown 4 fox'
+     * def result = ''
+     * new StringReader(s).splitEachLine(~/\d/){ parts ->
+     *     result += "${parts[0]}_${parts[1]}|"
+     * }
+     * assert result == 'The _ quick|brown _ fox|'
+     * </pre>
+     *
+     * @param self    a Reader, closed after the method returns
+     * @param pattern the regular expression Pattern for the delimiter
+     * @param closure a closure
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @throws java.util.regex.PatternSyntaxException
+     *                     if the regular expression's syntax is invalid
+     * @see java.lang.String#split(java.lang.String)
+     * @since 1.6.8
+     */
+    public static <T> T splitEachLine(Reader self, Pattern pattern, @ClosureParams(value=FromString.class,options={"List<String>","String[]"},conflictResolutionStrategy=PickFirstResolver.class) Closure<T> closure) throws IOException {
+        BufferedReader br;
+        T result = null;
+
+        if (self instanceof BufferedReader)
+            br = (BufferedReader) self;
+        else
+            br = new BufferedReader(self);
+
+        try {
+            while (true) {
+                String line = br.readLine();
+                if (line == null) {
+                    break;
+                } else {
+                    List vals = Arrays.asList(pattern.split(line));
+                    result = closure.call(hasSingleStringArg(closure) ? vals.get(0) : vals);
+                }
+            }
+            Reader temp = self;
+            self = null;
+            temp.close();
+            return result;
+        } finally {
+            closeWithWarning(self);
+            closeWithWarning(br);
+        }
+    }
+
+    /**
+     * Iterates through the given InputStream line by line using the specified
+     * encoding, splitting each line using the given separator.  The list of tokens
+     * for each line is then passed to the given closure. Finally, the stream
+     * is closed.
+     *
+     * @param stream  an InputStream
+     * @param regex   the delimiting regular expression
+     * @param charset opens the stream with a specified charset
+     * @param closure a closure
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @throws java.util.regex.PatternSyntaxException
+     *                     if the regular expression's syntax is invalid
+     * @see #splitEachLine(java.io.Reader, java.lang.String, groovy.lang.Closure)
+     * @since 1.5.5
+     */
+    public static <T> T splitEachLine(InputStream stream, String regex, String charset, @ClosureParams(value=FromString.class,options={"List<String>","String[]"},conflictResolutionStrategy=PickFirstResolver.class) Closure<T> closure) throws IOException {
+        return splitEachLine(new BufferedReader(new InputStreamReader(stream, charset)), regex, closure);
+    }
+
+    /**
+     * Iterates through the given InputStream line by line using the specified
+     * encoding, splitting each line using the given separator Pattern.  The list of tokens
+     * for each line is then passed to the given closure. Finally, the stream
+     * is closed.
+     *
+     * @param stream  an InputStream
+     * @param pattern the regular expression Pattern for the delimiter
+     * @param charset opens the stream with a specified charset
+     * @param closure a closure
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #splitEachLine(java.io.Reader, java.util.regex.Pattern, groovy.lang.Closure)
+     * @since 1.6.8
+     */
+    public static <T> T splitEachLine(InputStream stream, Pattern pattern, String charset, @ClosureParams(value=FromString.class,options={"List<String>","String[]"},conflictResolutionStrategy=PickFirstResolver.class) Closure<T> closure) throws IOException {
+        return splitEachLine(new BufferedReader(new InputStreamReader(stream, charset)), pattern, closure);
+    }
+
+    /**
+     * Iterates through the given InputStream line by line, splitting each line using
+     * the given separator.  The list of tokens for each line is then passed to
+     * the given closure. The stream is closed before the method returns.
+     *
+     * @param stream  an InputStream
+     * @param regex   the delimiting regular expression
+     * @param closure a closure
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @throws java.util.regex.PatternSyntaxException
+     *                     if the regular expression's syntax is invalid
+     * @see #splitEachLine(java.io.Reader, java.lang.String, groovy.lang.Closure)
+     * @since 1.5.6
+     */
+    public static <T> T splitEachLine(InputStream stream, String regex, @ClosureParams(value=FromString.class,options={"List<String>","String[]"},conflictResolutionStrategy=PickFirstResolver.class) Closure<T> closure) throws IOException {
+        return splitEachLine(new BufferedReader(new InputStreamReader(stream)), regex, closure);
+    }
+
+    /**
+     * Iterates through the given InputStream line by line, splitting each line using
+     * the given separator Pattern.  The list of tokens for each line is then passed to
+     * the given closure. The stream is closed before the method returns.
+     *
+     * @param stream  an InputStream
+     * @param pattern the regular expression Pattern for the delimiter
+     * @param closure a closure
+     * @return the last value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #splitEachLine(java.io.Reader, java.util.regex.Pattern, groovy.lang.Closure)
+     * @since 1.6.8
+     */
+    public static <T> T splitEachLine(InputStream stream, Pattern pattern, @ClosureParams(value=FromString.class,options={"List<String>","String[]"},conflictResolutionStrategy=PickFirstResolver.class) Closure<T> closure) throws IOException {
+        return splitEachLine(new BufferedReader(new InputStreamReader(stream)), pattern, closure);
+    }
+
+    /**
+     * Read a single, whole line from the given Reader.
+     *
+     * @param self a Reader
+     * @return a line
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static String readLine(Reader self) throws IOException {
+        if (self instanceof BufferedReader) {
+            BufferedReader br = (BufferedReader) self;
+            return br.readLine();
+        }
+        if (self.markSupported()) {
+            return readLineFromReaderWithMark(self);
+        }
+        return readLineFromReaderWithoutMark(self);
+    }
+
+    private static int charBufferSize = 4096;     // half the default stream buffer size
+    private static int expectedLineLength = 160;  // double the default line length
+    private static int EOF = -1;                  // End Of File
+
+    /*
+    * This method tries to read subsequent buffers from the reader using a mark
+    */
+    private static String readLineFromReaderWithMark(final Reader input)
+            throws IOException {
+        char[] cbuf = new char[charBufferSize];
+        try {
+            input.mark(charBufferSize);
+        } catch (IOException e) {
+            // this should never happen
+            LOG.warning("Caught exception setting mark on supporting reader: " + e);
+            // fallback
+            return readLineFromReaderWithoutMark(input);
+        }
+
+        // could be changed into do..while, but then
+        // we might create an additional StringBuilder
+        // instance at the end of the stream
+        int count = input.read(cbuf);
+        if (count == EOF) // we are at the end of the input data
+            return null;
+
+        StringBuilder line = new StringBuilder(expectedLineLength);
+        // now work on the buffer(s)
+        int ls = lineSeparatorIndex(cbuf, count);
+        while (ls == -1) {
+            line.append(cbuf, 0, count);
+            count = input.read(cbuf);
+            if (count == EOF) {
+                // we are at the end of the input data
+                return line.toString();
+            }
+            ls = lineSeparatorIndex(cbuf, count);
+        }
+        line.append(cbuf, 0, ls);
+
+        // correct ls if we have \r\n
+        int skipLS = 1;
+        if (ls + 1 < count) {
+            // we are not at the end of the buffer
+            if (cbuf[ls] == '\r' && cbuf[ls + 1] == '\n') {
+                skipLS++;
+            }
+        } else {
+            if (cbuf[ls] == '\r' && input.read() == '\n') {
+                skipLS++;
+            }
+        }
+
+        //reset() and skip over last linesep
+        input.reset();
+        input.skip(line.length() + skipLS);
+        return line.toString();
+    }
+
+    /*
+    * This method reads without a buffer.
+    * It returns too many empty lines if \r\n combinations
+    * are used. Nothing can be done because we can't push
+    * back the character we have just read.
+    */
+    private static String readLineFromReaderWithoutMark(Reader input)
+            throws IOException {
+
+        int c = input.read();
+        if (c == -1)
+            return null;
+        StringBuilder line = new StringBuilder(expectedLineLength);
+
+        while (c != EOF && c != '\n' && c != '\r') {
+            char ch = (char) c;
+            line.append(ch);
+            c = input.read();
+        }
+        return line.toString();
+    }
+
+    /*
+     * searches for \n or \r
+     * Returns -1 if not found.
+     */
+    private static int lineSeparatorIndex(char[] array, int length) {
+        for (int k = 0; k < length; k++) {
+            if (isLineSeparator(array[k])) {
+                return k;
+            }
+        }
+        return -1;
+    }
+
+    /*
+    * true if either \n or \r
+    */
+    private static boolean isLineSeparator(char c) {
+        return c == '\n' || c == '\r';
+    }
+
+    /**
+     * Reads the stream into a list, with one element for each line.
+     *
+     * @param stream a stream
+     * @return a List of lines
+     * @throws IOException if an IOException occurs.
+     * @see #readLines(java.io.Reader)
+     * @since 1.0
+     */
+    public static List<String> readLines(InputStream stream) throws IOException {
+        return readLines(newReader(stream));
+    }
+
+    /**
+     * Reads the stream into a list, with one element for each line.
+     *
+     * @param stream  a stream
+     * @param charset opens the stream with a specified charset
+     * @return a List of lines
+     * @throws IOException if an IOException occurs.
+     * @see #readLines(java.io.Reader)
+     * @since 1.6.8
+     */
+    public static List<String> readLines(InputStream stream, String charset) throws IOException {
+        return readLines(newReader(stream, charset));
+    }
+
+    /**
+     * Reads the reader into a list of Strings, with one entry for each line.
+     * The reader is closed before this method returns.
+     *
+     * @param reader a Reader
+     * @return a List of lines
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static List<String> readLines(Reader reader) throws IOException {
+        IteratorClosureAdapter<String> closure = new IteratorClosureAdapter<String>(reader);
+        eachLine(reader, closure);
+        return closure.asList();
+    }
+
+    /**
+     * Read the content of this InputStream and return it as a String.
+     * The stream is closed before this method returns.
+     *
+     * @param is an input stream
+     * @return the text from that URL
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static String getText(InputStream is) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+        return getText(reader);
+    }
+
+    /**
+     * Read the content of this InputStream using specified charset and return
+     * it as a String.  The stream is closed before this method returns.
+     *
+     * @param is      an input stream
+     * @param charset opens the stream with a specified charset
+     * @return the text from that URL
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static String getText(InputStream is, String charset) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset));
+        return getText(reader);
+    }
+
+    /**
+     * Read the content of the Reader and return it as a String.  The reader
+     * is closed before this method returns.
+     *
+     * @param reader a Reader whose content we want to read
+     * @return a String containing the content of the buffered reader
+     * @throws IOException if an IOException occurs.
+     * @see #getText(java.io.BufferedReader)
+     * @since 1.0
+     */
+    public static String getText(Reader reader) throws IOException {
+        BufferedReader bufferedReader = new BufferedReader(reader);
+        return getText(bufferedReader);
+    }
+
+    /**
+     * Read the content of the BufferedReader and return it as a String.
+     * The BufferedReader is closed afterwards.
+     *
+     * @param reader a BufferedReader whose content we want to read
+     * @return a String containing the content of the buffered reader
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static String getText(BufferedReader reader) throws IOException {
+        StringBuilder answer = new StringBuilder();
+        // reading the content of the file within a char buffer
+        // allow to keep the correct line endings
+        char[] charBuffer = new char[8192];
+        int nbCharRead /* = 0*/;
+        try {
+            while ((nbCharRead = reader.read(charBuffer)) != -1) {
+                // appends buffer
+                answer.append(charBuffer, 0, nbCharRead);
+            }
+            Reader temp = reader;
+            reader = null;
+            temp.close();
+        } finally {
+            closeWithWarning(reader);
+        }
+        return answer.toString();
+    }
+
+    /**
+     * Read the content of this InputStream and return it as a byte[].
+     * The stream is closed before this method returns.
+     *
+     * @param is an input stream
+     * @return the byte[] from that InputStream
+     * @throws IOException if an IOException occurs.
+     * @since 1.7.1
+     */
+    public static byte[] getBytes(InputStream is) throws IOException {
+        ByteArrayOutputStream answer = new ByteArrayOutputStream();
+        // reading the content of the file within a byte buffer
+        byte[] byteBuffer = new byte[8192];
+        int nbByteRead /* = 0*/;
+        try {
+            while ((nbByteRead = is.read(byteBuffer)) != -1) {
+                // appends buffer
+                answer.write(byteBuffer, 0, nbByteRead);
+            }
+        } finally {
+            closeWithWarning(is);
+        }
+        return answer.toByteArray();
+    }
+
+    /**
+     * Write the byte[] to the output stream.
+     * The stream is closed before this method returns.
+     *
+     * @param os    an output stream
+     * @param bytes the byte[] to write to the output stream
+     * @throws IOException if an IOException occurs.
+     * @since 1.7.1
+     */
+    public static void setBytes(OutputStream os, byte[] bytes) throws IOException {
+        try {
+            os.write(bytes);
+        } finally {
+            closeWithWarning(os);
+        }
+    }
+
+    /**
+     * Write the text and append a newline (using the platform's line-ending).
+     *
+     * @param writer a BufferedWriter
+     * @param line   the line to write
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static void writeLine(BufferedWriter writer, String line) throws IOException {
+        writer.write(line);
+        writer.newLine();
+    }
+
+    /**
+     * Creates an iterator which will traverse through the reader a line at a time.
+     *
+     * @param self a Reader object
+     * @return an Iterator for the Reader
+     * @see java.io.BufferedReader#readLine()
+     * @since 1.5.0
+     */
+    public static Iterator<String> iterator(Reader self) {
+        final BufferedReader bufferedReader;
+        if (self instanceof BufferedReader)
+            bufferedReader = (BufferedReader) self;
+        else
+            bufferedReader = new BufferedReader(self);
+        return new Iterator<String>() {
+            String nextVal /* = null */;
+            boolean nextMustRead = true;
+            boolean hasNext = true;
+
+            public boolean hasNext() {
+                if (nextMustRead && hasNext) {
+                    try {
+                        nextVal = readNext();
+                        nextMustRead = false;
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                }
+                return hasNext;
+            }
+
+            public String next() {
+                String retval = null;
+                if (nextMustRead) {
+                    try {
+                        retval = readNext();
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                } else
+                    retval = nextVal;
+                nextMustRead = true;
+                return retval;
+            }
+
+            private String readNext() throws IOException {
+                String nv = bufferedReader.readLine();
+                if (nv == null)
+                    hasNext = false;
+                return nv;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("Cannot remove() from a Reader Iterator");
+            }
+        };
+    }
+
+    /**
+     * Standard iterator for a input stream which iterates through the stream
+     * content in a byte-based fashion.
+     *
+     * @param self an InputStream object
+     * @return an Iterator for the InputStream
+     * @since 1.5.0
+     */
+    public static Iterator<Byte> iterator(InputStream self) {
+        return iterator(new DataInputStream(self));
+    }
+
+    /**
+     * Standard iterator for a data input stream which iterates through the
+     * stream content a Byte at a time.
+     *
+     * @param self a DataInputStream object
+     * @return an Iterator for the DataInputStream
+     * @since 1.5.0
+     */
+    public static Iterator<Byte> iterator(final DataInputStream self) {
+        return new Iterator<Byte>() {
+            Byte nextVal;
+            boolean nextMustRead = true;
+            boolean hasNext = true;
+
+            public boolean hasNext() {
+                if (nextMustRead && hasNext) {
+                    try {
+                        nextVal = self.readByte();
+                        nextMustRead = false;
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                }
+                return hasNext;
+            }
+
+            public Byte next() {
+                Byte retval = null;
+                if (nextMustRead) {
+                    try {
+                        retval = self.readByte();
+                    } catch (IOException e) {
+                        hasNext = false;
+                    }
+                } else
+                    retval = nextVal;
+                nextMustRead = true;
+                return retval;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("Cannot remove() from a DataInputStream Iterator");
+            }
+        };
+    }
+
+    /**
+     * Creates a reader for this input stream.
+     *
+     * @param self an input stream
+     * @return a reader
+     * @since 1.0
+     */
+    public static BufferedReader newReader(InputStream self) {
+        return new BufferedReader(new InputStreamReader(self));
+    }
+
+    /**
+     * Creates a reader for this input stream, using the specified
+     * charset as the encoding.
+     *
+     * @param self    an input stream
+     * @param charset the charset for this input stream
+     * @return a reader
+     * @throws UnsupportedEncodingException if the encoding specified is not supported
+     * @since 1.6.0
+     */
+    public static BufferedReader newReader(InputStream self, String charset) throws UnsupportedEncodingException {
+        return new BufferedReader(new InputStreamReader(self, charset));
+    }
+
+    /**
+     * Create a new PrintWriter for this Writer.
+     *
+     * @param writer a Writer
+     * @return a PrintWriter
+     * @since 1.6.0
+     */
+    public static PrintWriter newPrintWriter(Writer writer) {
+        return new GroovyPrintWriter(writer);
+    }
+
+    /**
+     * Create a new PrintWriter for this OutputStream.
+     *
+     * @param stream an OutputStream
+     * @return a PrintWriter
+     * @since 2.2.0
+     */
+    public static PrintWriter newPrintWriter(OutputStream stream) {
+        return new GroovyPrintWriter(stream);
+    }
+
+    /**
+     * Create a new PrintWriter for this Writer.  The writer is passed to the
+     * closure, and will be closed before this method returns.
+     *
+     * @param writer  a writer
+     * @param closure the closure to invoke with the PrintWriter
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 1.6.0
+     */
+    public static <T> T withPrintWriter(Writer writer, @ClosureParams(value=SimpleType.class, options="java.io.PrintWriter") Closure<T> closure) throws IOException {
+        return withWriter(newPrintWriter(writer), closure);
+    }
+
+    /**
+     * Create a new PrintWriter for this OutputStream.  The writer is passed to the
+     * closure, and will be closed before this method returns.
+     *
+     * @param stream  an OutputStream
+     * @param closure the closure to invoke with the PrintWriter
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 2.2.0
+     */
+    public static <T> T withPrintWriter(OutputStream stream, @ClosureParams(value=SimpleType.class, options="java.io.PrintWriter") Closure<T> closure) throws IOException {
+        return withWriter(newPrintWriter(stream), closure);
+    }
+
+    /**
+     * Allows this writer to be used within the closure, ensuring that it
+     * is flushed and closed before this method returns.
+     *
+     * @param writer  the writer which is used and then closed
+     * @param closure the closure that the writer is passed into
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.2
+     */
+    public static <T> T withWriter(Writer writer, @ClosureParams(FirstParam.class) Closure<T> closure) throws IOException {
+        try {
+            T result = closure.call(writer);
+
+            try {
+                writer.flush();
+            } catch (IOException e) {
+                // try to continue even in case of error
+            }
+            Writer temp = writer;
+            writer = null;
+            temp.close();
+            return result;
+        } finally {
+            closeWithWarning(writer);
+        }
+    }
+
+    /**
+     * Allows this reader to be used within the closure, ensuring that it
+     * is closed before this method returns.
+     *
+     * @param reader  the reader which is used and then closed
+     * @param closure the closure that the writer is passed into
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.2
+     */
+    public static <T> T withReader(Reader reader, @ClosureParams(FirstParam.class) Closure<T> closure) throws IOException {
+        try {
+            T result = closure.call(reader);
+
+            Reader temp = reader;
+            reader = null;
+            temp.close();
+
+            return result;
+        } finally {
+            closeWithWarning(reader);
+        }
+    }
+
+    /**
+     * Allows this input stream to be used within the closure, ensuring that it
+     * is flushed and closed before this method returns.
+     *
+     * @param stream  the stream which is used and then closed
+     * @param closure the closure that the stream is passed into
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.2
+     */
+    public static <T, U extends InputStream> T withStream(U stream, @ClosureParams(value=FirstParam.class) Closure<T> closure) throws IOException {
+        try {
+            T result = closure.call(stream);
+
+            InputStream temp = stream;
+            stream = null;
+            temp.close();
+
+            return result;
+        } finally {
+            closeWithWarning(stream);
+        }
+    }
+
+    /**
+     * Helper method to create a new Reader for a stream and then
+     * passes it into the closure.  The reader (and this stream) is closed after
+     * the closure returns.
+     *
+     * @param in      a stream
+     * @param closure the closure to invoke with the InputStream
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see java.io.InputStreamReader
+     * @since 1.5.2
+     */
+    public static <T> T withReader(InputStream in, @ClosureParams(value=SimpleType.class, options="java.io.Reader") Closure<T> closure) throws IOException {
+        return withReader(new InputStreamReader(in), closure);
+    }
+
+    /**
+     * Helper method to create a new Reader for a stream and then
+     * passes it into the closure.  The reader (and this stream) is closed after
+     * the closure returns.
+     *
+     * @param in      a stream
+     * @param charset the charset used to decode the stream
+     * @param closure the closure to invoke with the reader
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see java.io.InputStreamReader
+     * @since 1.5.6
+     */
+    public static <T> T withReader(InputStream in, String charset, @ClosureParams(value=SimpleType.class, options="java.io.Reader") Closure<T> closure) throws IOException {
+        return withReader(new InputStreamReader(in, charset), closure);
+    }
+
+    /**
+     * Creates a writer from this stream, passing it to the given closure.
+     * This method ensures the stream is closed after the closure returns.
+     *
+     * @param stream  the stream which is used and then closed
+     * @param closure the closure that the writer is passed into
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #withWriter(java.io.Writer, groovy.lang.Closure)
+     * @since 1.5.2
+     */
+    public static <T> T withWriter(OutputStream stream, @ClosureParams(value=SimpleType.class, options="java.io.Writer") Closure<T> closure) throws IOException {
+        return withWriter(new OutputStreamWriter(stream), closure);
+    }
+
+    /**
+     * Creates a writer for this stream.
+     *
+     * @param stream the stream which is used and then closed
+     * @return the newly created Writer
+     * @since 2.2.0
+     */
+    public static Writer newWriter(OutputStream stream) {
+        return new OutputStreamWriter(stream);
+    }
+
+    /**
+     * Creates a writer from this stream, passing it to the given closure.
+     * This method ensures the stream is closed after the closure returns.
+     *
+     * @param stream  the stream which is used and then closed
+     * @param charset the charset used
+     * @param closure the closure that the writer is passed into
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @see #withWriter(java.io.Writer, groovy.lang.Closure)
+     * @since 1.5.2
+     */
+    public static <T> T withWriter(OutputStream stream, String charset, @ClosureParams(value=SimpleType.class, options="java.io.Writer") Closure<T> closure) throws IOException {
+        return withWriter(new OutputStreamWriter(stream, charset), closure);
+    }
+
+    /**
+     * Creates a writer for this stream using the given charset.
+     *
+     * @param stream the stream which is used and then closed
+     * @param charset the charset used
+     * @return the newly created Writer
+     * @throws UnsupportedEncodingException if an encoding exception occurs.
+     * @since 2.2.0
+     */
+    public static Writer newWriter(OutputStream stream, String charset) throws UnsupportedEncodingException {
+        return new OutputStreamWriter(stream, charset);
+    }
+
+    /**
+     * Passes this OutputStream to the closure, ensuring that the stream
+     * is closed after the closure returns, regardless of errors.
+     *
+     * @param os      the stream which is used and then closed
+     * @param closure the closure that the stream is passed into
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.2
+     */
+    public static <T, U extends OutputStream> T withStream(U os, @ClosureParams(value=FirstParam.class) Closure<T> closure) throws IOException {
+        try {
+            T result = closure.call(os);
+            os.flush();
+
+            OutputStream temp = os;
+            os = null;
+            temp.close();
+
+            return result;
+        } finally {
+            closeWithWarning(os);
+        }
+    }
+
+    /**
+     * Traverse through each byte of the specified stream. The
+     * stream is closed after the closure returns.
+     *
+     * @param is      stream to iterate over, closed after the method call
+     * @param closure closure to apply to each byte
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static void eachByte(InputStream is, @ClosureParams(value=SimpleType.class, options="byte") Closure closure) throws IOException {
+        try {
+            while (true) {
+                int b = is.read();
+                if (b == -1) {
+                    break;
+                } else {
+                    closure.call((byte) b);
+                }
+            }
+
+            InputStream temp = is;
+            is = null;
+            temp.close();
+        } finally {
+            closeWithWarning(is);
+        }
+    }
+
+    /**
+     * Traverse through each the specified stream reading bytes into a buffer
+     * and calling the 2 parameter closure with this buffer and the number of bytes.
+     *
+     * @param is        stream to iterate over, closed after the method call.
+     * @param bufferLen the length of the buffer to use.
+     * @param closure   a 2 parameter closure which is passed the byte[] and a number of bytes successfully read.
+     * @throws IOException if an IOException occurs.
+     * @since 1.8
+     */
+    public static void eachByte(InputStream is, int bufferLen, @ClosureParams(value=FromString.class, options="byte[],Integer") Closure closure) throws IOException {
+        byte[] buffer = new byte[bufferLen];
+        int bytesRead;
+        try {
+            while ((bytesRead = is.read(buffer, 0, bufferLen)) > 0) {
+                closure.call(buffer, bytesRead);
+            }
+
+            InputStream temp = is;
+            is = null;
+            temp.close();
+        } finally {
+            closeWithWarning(is);
+        }
+    }
+
+    /**
+     * Transforms each character from this reader by passing it to the given
+     * closure.  The Closure should return each transformed character, which
+     * will be passed to the Writer.  The reader and writer will both be
+     * closed before this method returns.
+     *
+     * @param self    a Reader object
+     * @param writer  a Writer to receive the transformed characters
+     * @param closure a closure that performs the required transformation
+     * @throws IOException if an IOException occurs.
+     * @since 1.5.0
+     */
+    public static void transformChar(Reader self, Writer writer, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure closure) throws IOException {
+        int c;
+        try {
+            char[] chars = new char[1];
+            while ((c = self.read()) != -1) {
+                chars[0] = (char) c;
+                Object o = closure.call(new String(chars));
+                if (o != null) {
+                    writer.write(o.toString());
+                }
+            }
+            writer.flush();
+
+            Writer temp2 = writer;
+            writer = null;
+            temp2.close();
+            Reader temp1 = self;
+            self = null;
+            temp1.close();
+        } finally {
+            closeWithWarning(self);
+            closeWithWarning(writer);
+        }
+    }
+
+    /**
+     * Transforms the lines from a reader with a Closure and
+     * write them to a writer. Both Reader and Writer are
+     * closed after the operation.
+     *
+     * @param reader  Lines of text to be transformed. Reader is closed afterwards.
+     * @param writer  Where transformed lines are written. Writer is closed afterwards.
+     * @param closure Single parameter closure that is called to transform each line of
+     *                text from the reader, before writing it to the writer.
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static void transformLine(Reader reader, Writer writer, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure closure) throws IOException {
+        BufferedReader br = new BufferedReader(reader);
+        BufferedWriter bw = new BufferedWriter(writer);
+        String line;
+        try {
+            while ((line = br.readLine()) != null) {
+                Object o = closure.call(line);
+                if (o != null) {
+                    bw.write(o.toString());
+                    bw.newLine();
+                }
+            }
+            bw.flush();
+
+            Writer temp2 = writer;
+            writer = null;
+            temp2.close();
+            Reader temp1 = reader;
+            reader = null;
+            temp1.close();
+        } finally {
+            closeWithWarning(br);
+            closeWithWarning(reader);
+            closeWithWarning(bw);
+            closeWithWarning(writer);
+        }
+    }
+
+    /**
+     * Filter the lines from a reader and write them on the writer,
+     * according to a closure which returns true if the line should be included.
+     * Both Reader and Writer are closed after the operation.
+     *
+     * @param reader  a reader, closed after the call
+     * @param writer  a writer, closed after the call
+     * @param closure the closure which returns booleans
+     * @throws IOException if an IOException occurs.
+     * @since 1.0
+     */
+    public static void filterLine(Reader reader, Writer writer, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure closure) throws IOException {
+        BufferedReader br = new BufferedReader(reader);
+        BufferedWriter bw = new BufferedWriter(writer);
+        String line;
+        try {
+            BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
+            while ((line = br.readLine()) != null) {
+                if (bcw.call(line)) {
+                    bw.write(line);
+                    bw.newLine();
+                }
+            }
+            bw.flush();
+
+            Writer temp2 = writer;
+            writer = null;
+            temp2.close();
+            Reader temp1 = reader;
+            reader = null;
+            temp1.close();
+        } finally {
+            closeWithWarning(br);
+            closeWithWarning(reader);
+            closeWithWarning(bw);
+            closeWithWarning(writer);
+        }
+
+    }
+
+    /**
+     * Filter the lines from this Reader, and return a Writable which can be
+     * used to stream the filtered lines to a destination.  The closure should
+     * return <code>true</code> if the line should be passed to the writer.
+     *
+     * @param reader  this reader
+     * @param closure a closure used for filtering
+     * @return a Writable which will use the closure to filter each line
+     *         from the reader when the Writable#writeTo(Writer) is called.
+     * @since 1.0
+     */
+    public static Writable filterLine(Reader reader, @ClosureParams(value=SimpleType.class, options="java.lang.String") final Closure closure) {
+        final BufferedReader br = new BufferedReader(reader);
+        return new Writable() {
+            public Writer writeTo(Writer out) throws IOException {
+                BufferedWriter bw = new BufferedWriter(out);
+                String line;
+                BooleanClosureWrapper bcw = new BooleanClosureWrapper(closure);
+                while ((line = br.readLine()) != null) {
+                    if (bcw.call(line)) {
+                        bw.write(line);
+                        bw.newLine();
+                    }
+                }
+                bw.flush();
+                return out;
+            }
+
+            public String toString() {
+                StringWriter buffer = new StringWriter();
+                try {
+                    writeTo(buffer);
+                } catch (IOException e) {
+                    throw new StringWriterIOException(e);
+                }
+                return buffer.toString();
+            }
+        };
+    }
+
+    /**
+     * Filter lines from an input stream using a closure predicate.  The closure
+     * will be passed each line as a String, and it should return
+     * <code>true</code> if the line should be passed to the writer.
+     *
+     * @param self      an input stream
+     * @param predicate a closure which returns boolean and takes a line
+     * @return a writable which writes out the filtered lines
+     * @see #filterLine(java.io.Reader, groovy.lang.Closure)
+     * @since 1.0
+     */
+    public static Writable filterLine(InputStream self, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure predicate) {
+        return filterLine(newReader(self), predicate);
+    }
+
+    /**
+     * Filter lines from an input stream using a closure predicate.  The closure
+     * will be passed each line as a String, and it should return
+     * <code>true</code> if the line should be passed to the writer.
+     *
+     * @param self      an input stream
+     * @param charset   opens the stream with a specified charset
+     * @param predicate a closure which returns boolean and takes a line
+     * @return a writable which writes out the filtered lines
+     * @throws UnsupportedEncodingException if the encoding specified is not supported
+     * @see #filterLine(java.io.Reader, groovy.lang.Closure)
+     * @since 1.6.8
+     */
+    public static Writable filterLine(InputStream self, String charset, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure predicate)
+            throws UnsupportedEncodingException {
+        return filterLine(newReader(self, charset), predicate);
+    }
+
+    /**
+     * Uses a closure to filter lines from this InputStream and pass them to
+     * the given writer. The closure will be passed each line as a String, and
+     * it should return <code>true</code> if the line should be passed to the
+     * writer.
+     *
+     * @param self      the InputStream
+     * @param writer    a writer to write output to
+     * @param predicate a closure which returns true if a line should be accepted
+     * @throws IOException if an IOException occurs.
+     * @see #filterLine(java.io.Reader, java.io.Writer, groovy.lang.Closure)
+     * @since 1.0
+     */
+    public static void filterLine(InputStream self, Writer writer, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure predicate)
+            throws IOException {
+        filterLine(newReader(self), writer, predicate);
+    }
+
+    /**
+     * Uses a closure to filter lines from this InputStream and pass them to
+     * the given writer. The closure will be passed each line as a String, and
+     * it should return <code>true</code> if the line should be passed to the
+     * writer.
+     *
+     * @param self      the InputStream
+     * @param writer    a writer to write output to
+     * @param charset   opens the stream with a specified charset
+     * @param predicate a closure which returns true if a line should be accepted
+     * @throws IOException if an IOException occurs.
+     * @see #filterLine(java.io.Reader, java.io.Writer, groovy.lang.Closure)
+     * @since 1.6.8
+     */
+    public static void filterLine(InputStream self, Writer writer, String charset, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure predicate)
+            throws IOException {
+        filterLine(newReader(self, charset), writer, predicate);
+    }
+
+    /**
+     * Allows this closeable to be used within the closure, ensuring that it
+     * is closed once the closure has been executed and before this method returns.
+     * <p>
+     * As with the try-with-resources statement, if multiple exceptions are thrown
+     * the exception from the closure will be returned and the exception from closing
+     * will be added as a suppressed exception.
+     *
+     * @param self the Closeable
+     * @param action the closure taking the Closeable as parameter
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 2.4.0
+     */
+    public static <T, U extends Closeable> T withCloseable(U self, @ClosureParams(value=FirstParam.class) Closure<T> action) throws IOException {
+        Throwable thrown = null;
+        try {
+            return action.call(self);
+        } catch (Throwable e) {
+            thrown = e;
+            throw e;
+        } finally {
+            if (thrown != null) {
+                Throwable suppressed = tryClose(self, true);
+                if (suppressed != null) {
+                    thrown.addSuppressed(suppressed);
+                }
+            } else {
+                self.close();
+            }
+        }
+    }
+
+    /**
+     * Allows this AutoCloseable to be used within the closure, ensuring that it
+     * is closed once the closure has been executed and before this method returns.
+     * <p>
+     * As with the try-with-resources statement, if multiple exceptions are thrown
+     * the exception from the closure will be returned and the exception from closing
+     * will be added as a suppressed exception.
+     *
+     * @param self the AutoCloseable
+     * @param action the closure taking the AutoCloseable as parameter
+     * @return the value returned by the closure
+     * @throws Exception if an Exception occurs.
+     * @since 2.5.0
+     */
+    public static <T, U extends AutoCloseable> T withCloseable(U self, @ClosureParams(value=FirstParam.class) Closure<T> action) throws Exception {
+        Throwable thrown = null;
+        try {
+            return action.call(self);
+        } catch (Throwable e) {
+            thrown = e;
+            throw e;
+        } finally {
+            if (thrown != null) {
+                Throwable suppressed = tryClose(self, true);
+                if (suppressed != null) {
+                    thrown.addSuppressed(suppressed);
+                }
+            } else {
+                self.close();
+            }
+        }
+    }
+
+    static void writeUTF16BomIfRequired(final Writer writer, final String charset) throws IOException {
+        writeUTF16BomIfRequired(writer, Charset.forName(charset));
+    }
+
+    static void writeUTF16BomIfRequired(final Writer writer, final Charset charset) throws IOException {
+        if ("UTF-16BE".equals(charset.name())) {
+            writeUtf16Bom(writer, true);
+        } else if ("UTF-16LE".equals(charset.name())) {
+            writeUtf16Bom(writer, false);
+        }
+    }
+
+    static void writeUTF16BomIfRequired(final OutputStream stream, final String charset) throws IOException {
+        writeUTF16BomIfRequired(stream, Charset.forName(charset));
+    }
+
+    static void writeUTF16BomIfRequired(final OutputStream stream, final Charset charset) throws IOException {
+        if ("UTF-16BE".equals(charset.name())) {
+            writeUtf16Bom(stream, true);
+        } else if ("UTF-16LE".equals(charset.name())) {
+            writeUtf16Bom(stream, false);
+        }
+    }
+
+    private static void writeUtf16Bom(OutputStream stream, boolean bigEndian) throws IOException {
+        if (bigEndian) {
+            stream.write(-2);  // FE
+            stream.write(-1);  // FF
+        } else {
+            stream.write(-1);  // FF
+            stream.write(-2);  // FE
+        }
+    }
+
+    private static void writeUtf16Bom(Writer writer, boolean bigEndian) throws IOException {
+        if (bigEndian) {
+            writer.write(-2);  // FE
+            writer.write(-1);  // FF
+        } else {
+            writer.write(-1);  // FF
+            writer.write(-2);  // FE
+        }
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java
new file mode 100644
index 0000000..91857ee
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPluginFactory.java
@@ -0,0 +1,31 @@
+/*
+ *  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.antlr;
+
+import org.codehaus.groovy.control.ParserPlugin;
+import org.codehaus.groovy.control.ParserPluginFactory;
+
+/**
+ */
+public class AntlrParserPluginFactory extends ParserPluginFactory {
+
+    public ParserPlugin createParserPlugin() {
+        return new AntlrParserPlugin();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java b/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java
new file mode 100644
index 0000000..6f5fc3e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/EnumHelper.java
@@ -0,0 +1,68 @@
+/*
+ *  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.antlr;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MixinNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.objectweb.asm.Opcodes;
+
+public class EnumHelper {
+    private static final int FS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC;
+    private static final int PUBLIC_FS = Opcodes.ACC_PUBLIC | FS; 
+    
+    public static ClassNode makeEnumNode(String name, int modifiers, ClassNode[] interfaces, ClassNode outerClass) {
+        modifiers = modifiers | Opcodes.ACC_FINAL | Opcodes.ACC_ENUM;
+        ClassNode enumClass;
+        if (outerClass==null) {
+            enumClass = new ClassNode(name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY);
+        } else {
+            name = outerClass.getName() + "$" + name;
+            modifiers |= Opcodes.ACC_STATIC;
+            enumClass = new InnerClassNode(outerClass,name,modifiers,null,interfaces,MixinNode.EMPTY_ARRAY);
+        }
+        
+        // set super class and generics info
+        // "enum X" -> class X extends Enum<X>
+        GenericsType gt = new GenericsType(enumClass);
+        ClassNode superClass = ClassHelper.makeWithoutCaching("java.lang.Enum");
+        superClass.setGenericsTypes(new GenericsType[]{gt});
+        enumClass.setSuperClass(superClass);
+        superClass.setRedirect(ClassHelper.Enum_Type);
+        
+        return enumClass;
+    }
+
+    public static FieldNode addEnumConstant(ClassNode enumClass, String name, Expression init) {
+        int modifiers = PUBLIC_FS | Opcodes.ACC_ENUM;
+        if (init != null && !(init instanceof ListExpression)) {
+            ListExpression list = new ListExpression();
+            list.addExpression(init);
+            init = list;
+        }
+        FieldNode fn = new FieldNode(name, modifiers, enumClass.getPlainNodeReference(), enumClass, init);
+        enumClass.addField(fn);
+        return fn;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java b/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java
new file mode 100644
index 0000000..d256e73
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/GroovySourceAST.java
@@ -0,0 +1,177 @@
+/*
+ *  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.antlr;
+
+import antlr.CommonAST;
+import antlr.Token;
+import antlr.collections.AST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * We have an AST subclass so we can track source information.
+ * Very odd that ANTLR doesn't do this by default.
+ *
+ * @author Mike Spille
+ * @author Jeremy Rayner <gr...@ross-rayner.com>
+ */
+public class GroovySourceAST extends CommonAST implements Comparable, SourceInfo {
+    private int line;
+    private int col;
+    private int lineLast;
+    private int colLast;
+    private String snippet;
+
+    public GroovySourceAST() {
+    }
+
+    public GroovySourceAST(Token t) {
+        super(t);
+    }
+
+    public void initialize(AST ast) {
+        super.initialize(ast);
+        line = ast.getLine();
+        col = ast.getColumn();
+        if (ast instanceof GroovySourceAST) {
+            GroovySourceAST node = (GroovySourceAST)ast;
+            lineLast = node.getLineLast();
+            colLast = node.getColumnLast();
+        }
+    }
+
+    public void initialize(Token t) {
+        super.initialize(t);
+        line = t.getLine();
+        col = t.getColumn();
+        if (t instanceof SourceInfo) {
+            SourceInfo info = (SourceInfo) t;
+            lineLast = info.getLineLast();
+            colLast  = info.getColumnLast(); 
+        }
+    }
+
+    public void setLast(Token last) {
+        lineLast = last.getLine();
+        colLast = last.getColumn();
+    }
+
+    public int getLineLast() {
+        return lineLast;
+    }
+
+    public void setLineLast(int lineLast) {
+        this.lineLast = lineLast;
+    }
+
+    public int getColumnLast() {
+        return colLast;
+    }
+
+    public void setColumnLast(int colLast) {
+        this.colLast = colLast;
+    }
+
+    public void setLine(int line) {
+        this.line = line;
+    }
+
+    public int getLine() {
+        return (line);
+    }
+
+    public void setColumn(int column) {
+        this.col = column;
+    }
+
+    public int getColumn() {
+        return (col);
+    }
+
+    public void setSnippet(String snippet) {
+        this.snippet = snippet;
+    }
+
+    public String getSnippet() {
+        return snippet;
+    }
+
+    public int compareTo(Object object) {
+        if (object == null) {
+            return 0;
+        }
+        if (!(object instanceof AST)) {
+            return 0;
+        }
+        AST that = (AST) object;
+
+        // todo - possibly check for line/col with values of 0 or less...
+
+        if (this.getLine() < that.getLine()) {
+            return -1;
+        }
+        if (this.getLine() > that.getLine()) {
+            return 1;
+        }
+
+        if (this.getColumn() < that.getColumn()) {
+            return -1;
+        }
+        if (this.getColumn() > that.getColumn()) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    public GroovySourceAST childAt(int position) {
+        List list = new ArrayList();
+        AST child = this.getFirstChild();
+        while (child != null) {
+            list.add(child);
+            child = child.getNextSibling();
+        }
+        try {
+            return (GroovySourceAST)list.get(position);
+        } catch (IndexOutOfBoundsException e) {
+            return null;
+        }
+    }
+
+    public GroovySourceAST childOfType(int type) {
+        AST child = this.getFirstChild();
+        while (child != null) {
+            if (child.getType() == type) { return (GroovySourceAST)child; }
+            child = child.getNextSibling();
+        }
+        return null;
+    }
+
+    public List<GroovySourceAST> childrenOfType(int type) {
+        List<GroovySourceAST> result = new ArrayList<GroovySourceAST>();
+        AST child = this.getFirstChild();
+        while (child != null) {
+            if (child.getType() == type) { result.add((GroovySourceAST) child); }
+            child = child.getNextSibling();
+        }
+        return result;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java b/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java
new file mode 100644
index 0000000..38ffba0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/GroovySourceToken.java
@@ -0,0 +1,100 @@
+/*
+ *  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.antlr;
+
+import antlr.Token;
+
+/**
+ * This is a Token sub class to track line information 
+ * 
+ * @author Jochen Theodorou
+ */
+public class GroovySourceToken extends Token implements SourceInfo{
+    protected int line;
+    protected String text = "";
+    protected int col;
+    protected int lineLast;
+    protected int colLast;
+
+    
+    /**
+     * Constructor using a token type
+     * 
+     * @param t the type
+     */
+    public GroovySourceToken(int t) {
+        super(t);
+    }
+    
+    public int getLine() {
+        return line;
+    }
+
+    /**
+     * get the source token text
+     * @return the source token text
+     */
+    public String getText() {
+        return text;
+    }
+
+    public void setLine(int l) {
+        line = l;
+    }
+
+    /**
+     * set the source token text
+     * @param s the text
+     */
+    public void setText(String s) {
+        text = s;
+    }
+
+    public String toString() {
+        return 
+            "[\"" + getText() + "\",<" + type + ">,"+
+            "line=" + line + ",col=" + col + 
+            ",lineLast=" + lineLast + ",colLast=" + colLast +
+            "]";
+    }
+
+    public int getColumn() {
+        return col;
+    }
+
+    public void setColumn(int c) {
+        col = c;
+    }
+    
+    public int getLineLast() {
+        return lineLast;
+    }
+
+    public void setLineLast(int lineLast) {
+        this.lineLast = lineLast;
+    }
+
+    public int getColumnLast() {
+        return colLast;
+    }
+
+    public void setColumnLast(int colLast) {
+        this.colLast = colLast;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java b/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java
new file mode 100644
index 0000000..046fd17
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/LexerFrame.java
@@ -0,0 +1,279 @@
+/*
+ *  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.antlr;
+
+import antlr.CharScanner;
+import antlr.Token;
+import org.codehaus.groovy.antlr.java.JavaLexer;
+import org.codehaus.groovy.antlr.java.JavaTokenTypes;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.runtime.IOGroovyMethods;
+import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+
+import javax.swing.*;
+import javax.swing.border.Border;
+import javax.swing.text.BadLocationException;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.FileReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.Hashtable;
+
+/**
+ * Swing application to graphically display the tokens produced by the lexer.
+ */
+public class LexerFrame extends JFrame implements ActionListener {
+    private final JSplitPane jSplitPane1 = new JSplitPane();
+    private final JScrollPane jScrollPane1 = new JScrollPane();
+    private final JScrollPane jScrollPane2 = new JScrollPane();
+    private final JTextPane tokenPane = new HScrollableTextPane();
+    private final JButton jbutton = new JButton("open");
+    private final JPanel mainPanel = new JPanel(new BorderLayout());
+    private final JTextArea scriptPane = new JTextArea();
+    private final Class lexerClass;
+    private final Hashtable tokens = new Hashtable();
+
+    /**
+     * Constructor used when invoking as a standalone application
+     *
+     * @param lexerClass      the lexer class to use
+     * @param tokenTypesClass the lexer token types class
+     */
+    public LexerFrame(Class lexerClass, Class tokenTypesClass) {
+        this(lexerClass, tokenTypesClass, null);
+    }
+
+    /**
+     * Constructor used when invoking for a specific file
+     *
+     * @param lexerClass      the lexer class to use
+     * @param tokenTypesClass the lexer token types class
+     */
+    public LexerFrame(Class lexerClass, Class tokenTypesClass, Reader reader) {
+        super("Token Steam Viewer");
+        this.lexerClass = lexerClass;
+        try {
+            jbInit(reader);
+            setSize(500, 500);
+            listTokens(tokenTypesClass);
+
+            if (reader == null) {
+                final JPopupMenu popup = new JPopupMenu();
+                popup.add(loadFileAction);
+                jbutton.setSize(30, 30);
+                jbutton.addMouseListener(new MouseAdapter() {
+                    public void mouseReleased(MouseEvent e) {
+                        //if(e.isPopupTrigger())
+                        popup.show(scriptPane, e.getX(), e.getY());
+                    }
+                });
+            } else {
+                safeScanScript(reader);
+            }
+
+            setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Creates a Groovy language LexerFrame for the given script text
+     *
+     * @param scriptText the Groovy source file to parse/render
+     * @return the new frame rending the parsed tokens
+     */
+    public static LexerFrame groovyScriptFactory(String scriptText) {
+        return new LexerFrame(GroovyLexer.class, GroovyTokenTypes.class, new StringReader(scriptText));
+    }
+
+    private void listTokens(Class tokenTypes) throws Exception {
+        for (Field field : tokenTypes.getDeclaredFields()) {
+            tokens.put(field.get(null), field.getName());
+        }
+    }
+
+    public void actionPerformed(ActionEvent ae) {
+        Token token = (Token) ((JComponent) ae.getSource()).getClientProperty("token");
+        if (token.getType() == Token.EOF_TYPE) {
+            scriptPane.select(0, 0);
+            return;
+        }
+        try {
+            int start = scriptPane.getLineStartOffset(token.getLine() - 1) + token.getColumn() - 1;
+            scriptPane.select(start, start + token.getText().length());
+            scriptPane.requestFocus();
+        } catch (BadLocationException ex) {
+            // IGNORE
+        }
+    }
+
+    private final Action loadFileAction = new AbstractAction("Open File...") {
+        public void actionPerformed(ActionEvent ae) {
+            final JFileChooser jfc = new JFileChooser();
+            final int response = jfc.showOpenDialog(LexerFrame.this);
+            if (response != JFileChooser.APPROVE_OPTION) {
+                return;
+            }
+            safeScanScript(jfc.getSelectedFile());
+        }
+    };
+
+    private void safeScanScript(File file) {
+        try {
+            scanScript(new StringReader(ResourceGroovyMethods.getText(file)));
+        } catch (final Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    private void safeScanScript(Reader reader) {
+        try {
+            scanScript(reader instanceof StringReader ? (StringReader) reader : new StringReader(IOGroovyMethods.getText(reader)));
+        } catch (final Exception ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    private void scanScript(final StringReader reader) throws Exception {
+        scriptPane.read(reader, null);
+        reader.reset();
+
+        // create lexer
+        final Constructor constructor = lexerClass.getConstructor(Reader.class);
+        final CharScanner lexer = (CharScanner) constructor.newInstance(reader);
+
+        tokenPane.setEditable(true);
+        tokenPane.setText("");
+
+        int line = 1;
+        final ButtonGroup bg = new ButtonGroup();
+        Token token;
+
+        while (true) {
+            token = lexer.nextToken();
+            JToggleButton tokenButton = new JToggleButton((String) tokens.get(Integer.valueOf(token.getType())));
+            bg.add(tokenButton);
+            tokenButton.addActionListener(this);
+            tokenButton.setToolTipText(token.getText());
+            tokenButton.putClientProperty("token", token);
+            tokenButton.setMargin(new Insets(0, 1, 0, 1));
+            tokenButton.setFocusPainted(false);
+            if (token.getLine() > line) {
+                tokenPane.getDocument().insertString(tokenPane.getDocument().getLength(), "\n", null);
+                line = token.getLine();
+            }
+            insertComponent(tokenButton);
+            if (token.getType() == Token.EOF_TYPE) {
+                break;
+            }
+        }
+
+        tokenPane.setEditable(false);
+        tokenPane.setCaretPosition(0);
+        reader.close();
+    }
+
+    private void insertComponent(JComponent comp) {
+        try {
+            tokenPane.getDocument().insertString(tokenPane.getDocument().getLength(), " ", null);
+        } catch (BadLocationException ex1) {
+            // Ignore
+        }
+        try {
+            tokenPane.setCaretPosition(tokenPane.getDocument().getLength() - 1);
+        } catch (Exception ex) {
+            tokenPane.setCaretPosition(0);
+        }
+        tokenPane.insertComponent(comp);
+    }
+
+    private void jbInit(Reader reader) throws Exception {
+        final Border border = BorderFactory.createEmptyBorder();
+        jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
+        tokenPane.setEditable(false);
+        tokenPane.setText("");
+        scriptPane.setFont(new java.awt.Font("DialogInput", 0, 12));
+        scriptPane.setEditable(false);
+        scriptPane.setMargin(new Insets(5, 5, 5, 5));
+        scriptPane.setText("");
+        jScrollPane1.setBorder(border);
+        jScrollPane2.setBorder(border);
+        jSplitPane1.setMinimumSize(new Dimension(800, 600));
+        mainPanel.add(jSplitPane1, BorderLayout.CENTER);
+        if (reader == null) {
+            mainPanel.add(jbutton, BorderLayout.NORTH);
+        }
+        this.getContentPane().add(mainPanel);
+        jSplitPane1.add(jScrollPane1, JSplitPane.LEFT);
+        jScrollPane1.getViewport().add(tokenPane, null);
+        jSplitPane1.add(jScrollPane2, JSplitPane.RIGHT);
+        jScrollPane2.getViewport().add(scriptPane, null);
+
+        jScrollPane1.setColumnHeaderView(new JLabel(" Token Stream:"));
+        jScrollPane2.setColumnHeaderView(new JLabel(" Input Script:"));
+        jSplitPane1.setResizeWeight(0.5);
+    }
+
+    public static void main(String[] args) throws Exception {
+        try {
+            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        } catch (Exception ignore) {
+            // Ignore
+        }
+        LexerFrame lexerFrame = null;
+        if (args.length == 0) {
+            lexerFrame = new LexerFrame(GroovyLexer.class, GroovyTokenTypes.class);
+        } else if (args.length > 1) {
+            System.err.println("usage: java LexerFrame [filename.ext]");
+            System.exit(1);
+        } else {
+            String filename = args[0];
+            if (filename.endsWith(".java")) {
+                lexerFrame = new LexerFrame(JavaLexer.class, JavaTokenTypes.class, new FileReader(filename));
+            } else {
+                lexerFrame = new LexerFrame(GroovyLexer.class, GroovyTokenTypes.class, new FileReader(filename));
+            }
+        }
+        lexerFrame.setVisible(true);
+    }
+
+    private static class HScrollableTextPane extends JTextPane {
+        @Override
+        public boolean getScrollableTracksViewportWidth() {
+            return (getSize().width < getParent().getSize().width);
+        }
+
+        @Override
+        public void setSize(final Dimension d) {
+            if (d.width < getParent().getSize().width) {
+                d.width = getParent().getSize().width;
+            }
+            super.setSize(d);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/LineColumn.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/LineColumn.java b/src/main/java/org/codehaus/groovy/antlr/LineColumn.java
new file mode 100644
index 0000000..c7e11b6
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/LineColumn.java
@@ -0,0 +1,65 @@
+/*
+ *  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.antlr;
+
+/**
+ * An object representing a line and column position
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+public class LineColumn {
+    private int line;
+    private int column;
+
+    public LineColumn(int line, int column) {
+        this.line = line;
+        this.column = column;
+    }
+
+    public int getLine() {
+        return line;
+    }
+
+    public int getColumn() {
+        return column;
+    }
+
+    public boolean equals(Object that) {
+        if (this == that) return true;
+        if (that == null || getClass() != that.getClass()) return false;
+
+        final LineColumn lineColumn = (LineColumn) that;
+
+        if (column != lineColumn.column) return false;
+        if (line != lineColumn.line) return false;
+
+        return true;
+    }
+
+    public int hashCode() {
+        int result;
+        result = line;
+        result = 29 * result + column;
+        return result;
+    }
+
+    public String toString() {
+        return "[" + line + "," + column + "]";
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/Main.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/Main.java b/src/main/java/org/codehaus/groovy/antlr/Main.java
new file mode 100644
index 0000000..ae3bb5f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/Main.java
@@ -0,0 +1,194 @@
+/*
+ *  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.antlr;
+
+import antlr.ASTFactory;
+import antlr.CommonAST;
+import antlr.Token;
+import antlr.collections.AST;
+import antlr.debug.misc.ASTFrame;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileReader;
+
+class Main {
+
+    static boolean whitespaceIncluded = false;
+
+    static boolean showTree = false;
+    //static boolean xml = false;
+    static boolean verbose = false;
+    public static void main(String[] args) {
+        // Use a try/catch block for parser exceptions
+        try {
+            // if we have at least one command-line argument
+            if (args.length > 0 ) {
+                System.err.println("Parsing...");
+
+                // for each directory/file specified on the command line
+                for(int i=0; i< args.length;i++) {
+                    if ( args[i].equals("-showtree") ) {
+                        showTree = true;
+                    }
+                    //else if ( args[i].equals("-xml") ) {
+                    //    xml = true;
+                    //}
+                    else if ( args[i].equals("-verbose") ) {
+                        verbose = true;
+                    }
+                    else if ( args[i].equals("-trace") ) {
+                        GroovyRecognizer.tracing = true;
+                        GroovyLexer.tracing = true;
+                    }
+                    else if ( args[i].equals("-traceParser") ) {
+                        GroovyRecognizer.tracing = true;
+                    }
+                    else if ( args[i].equals("-traceLexer") ) {
+                        GroovyLexer.tracing = true;
+                    }
+                                        else if ( args[i].equals("-whitespaceIncluded") ) {
+                                            whitespaceIncluded = true;
+                                        }
+                                        else {
+                        doFile(new File(args[i])); // parse it
+                    }
+                } }
+            else
+                System.err.println("Usage: java -jar groovyc.jar [-showtree] [-verbose] [-trace{,Lexer,Parser}]"+
+                                   "<directory or file name>");
+        }
+        catch(Exception e) {
+            System.err.println("exception: "+e);
+            e.printStackTrace(System.err);   // so we can get stack trace
+        }
+    }
+
+
+    // This method decides what action to take based on the type of
+    //   file we are looking at
+    public static void doFile(File f)
+                              throws Exception {
+        // If this is a directory, walk each file/dir in that directory
+        if (f.isDirectory()) {
+            String files[] = f.list();
+            for(int i=0; i < files.length; i++)
+                doFile(new File(f, files[i]));
+        }
+
+        // otherwise, if this is a groovy file, parse it!
+        else if (f.getName().endsWith(".groovy")) {
+            System.err.println(" --- "+f.getAbsolutePath());
+            // parseFile(f.getName(), new FileInputStream(f));
+            SourceBuffer sourceBuffer = new SourceBuffer();
+            UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new FileReader(f),sourceBuffer);
+            GroovyLexer lexer = new GroovyLexer(unicodeReader);
+            unicodeReader.setLexer(lexer);
+            parseFile(f.getName(),lexer,sourceBuffer);
+        }
+    }
+
+    // Here's where we do the real work...
+    public static void parseFile(String f, GroovyLexer l, SourceBuffer sourceBuffer)
+                                 throws Exception {
+        try {
+            // Create a parser that reads from the scanner
+            GroovyRecognizer parser = GroovyRecognizer.make(l);
+            parser.setSourceBuffer(sourceBuffer);
+            parser.setFilename(f);
+                        
+                        if (whitespaceIncluded) {
+                            GroovyLexer lexer = parser.getLexer();
+                            lexer.setWhitespaceIncluded(true);
+                            while (true) {
+                                Token t = lexer.nextToken();
+                                System.out.println(t);
+                                if (t == null || t.getType() == Token.EOF_TYPE)  break;
+                            }
+                            return;
+                        }
+
+            // start parsing at the compilationUnit rule
+            parser.compilationUnit();
+            
+            System.out.println("parseFile "+f+" => "+parser.getAST());
+
+            // do something with the tree
+            doTreeAction(f, parser.getAST(), parser.getTokenNames());
+        }
+        catch (Exception e) {
+            System.err.println("parser exception: "+e);
+            e.printStackTrace();   // so we can get stack trace        
+        }
+    }
+    
+    public static void doTreeAction(String f, AST t, String[] tokenNames) {
+        if ( t==null ) return;
+        if ( showTree ) {
+            CommonAST.setVerboseStringConversion(true, tokenNames);
+            ASTFactory factory = new ASTFactory();
+            AST r = factory.create(0,"AST ROOT");
+            r.setFirstChild(t);
+            final ASTFrame frame = new ASTFrame("Groovy AST", r);
+            frame.setVisible(true);
+            frame.addWindowListener(
+                new WindowAdapter() {
+                   public void windowClosing (WindowEvent e) {
+                       frame.setVisible(false); // hide the Frame
+                       frame.dispose();
+                       System.exit(0);
+                   }
+                }
+            );
+            if (verbose)  System.out.println(t.toStringList());
+        }
+        /*if ( xml ) {
+            ((CommonAST)t).setVerboseStringConversion(true, tokenNames);
+            ASTFactory factory = new ASTFactory();
+            AST r = factory.create(0,"AST ROOT");
+            r.setFirstChild(t);
+            XStream xstream = new XStream();
+            xstream.alias("ast", CommonAST.class);
+            try {
+                xstream.toXML(r,new FileWriter(f + ".xml"));
+                System.out.println("Written AST to " + f + ".xml");
+            } catch (Exception e) {
+                System.out.println("couldn't write to " + f + ".xml");
+                e.printStackTrace();
+            }
+            //if (verbose)  System.out.println(t.toStringList());
+        }*/
+    /*@todo
+        GroovyTreeParser tparse = new GroovyTreeParser();
+        try {
+            tparse.compilationUnit(t);
+            if (verbose)  System.out.println("successful walk of result AST for "+f);
+        }
+        catch (RecognitionException e) {
+            System.err.println(e.getMessage());
+            e.printStackTrace();
+        }
+    @todo*/
+
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java b/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java
new file mode 100644
index 0000000..6b45e50
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/SourceBuffer.java
@@ -0,0 +1,111 @@
+/*
+ *  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.antlr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A simple buffer that provides line/col access to chunks of source code
+ * held within itself.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+public class SourceBuffer {
+    private final List lines;
+    private StringBuffer current;
+
+    public SourceBuffer() {
+        lines = new ArrayList();
+        //lines.add(new StringBuffer()); // dummy row for position [0] in the List
+
+        current = new StringBuffer();
+        lines.add(current);
+    }
+
+    /**
+     * Obtains a snippet of the source code within the bounds specified
+     * @param start (inclusive line/ inclusive column)
+     * @param end (inclusive line / exclusive column)
+     * @return specified snippet of source code as a String, or null if no source available
+     */
+    public String getSnippet(LineColumn start, LineColumn end) {
+        // preconditions
+        if (start == null || end == null) { return null; } // no text to return
+        if (start.equals(end)) { return null; } // no text to return
+        if (lines.size() == 1 && current.length() == 0) { return null; } // buffer hasn't been filled yet
+
+        // working variables
+        int startLine = start.getLine();
+        int startColumn = start.getColumn();
+        int endLine = end.getLine();
+        int endColumn = end.getColumn();
+
+        // reset any out of bounds requests
+        if (startLine < 1) { startLine = 1;}
+        if (endLine < 1) { endLine = 1;}
+        if (startColumn < 1) { startColumn = 1;}
+        if (endColumn < 1) { endColumn = 1;}
+        if (startLine > lines.size()) { startLine = lines.size(); }
+        if (endLine > lines.size()) { endLine = lines.size(); }
+
+        // obtain the snippet from the buffer within specified bounds
+        StringBuffer snippet = new StringBuffer();
+        for (int i = startLine - 1; i < endLine;i++) {
+            String line = ((StringBuffer)lines.get(i)).toString();
+            if (startLine == endLine) {
+                // reset any out of bounds requests (again)
+                if (startColumn > line.length()) { startColumn = line.length();}
+                if (startColumn < 1) { startColumn = 1;}
+                if (endColumn > line.length()) { endColumn = line.length() + 1;}
+                if (endColumn < 1) { endColumn = 1;}
+                if (endColumn < startColumn) { endColumn = startColumn;}
+
+                line = line.substring(startColumn - 1, endColumn - 1);
+            } else {
+                if (i == startLine - 1) {
+                    if (startColumn - 1 < line.length()) {
+                        line = line.substring(startColumn - 1);
+                    }
+                }
+                if (i == endLine - 1) {
+                    if (endColumn - 1 < line.length()) {
+                        line = line.substring(0,endColumn - 1);
+                    }
+                }
+            }
+            snippet.append(line);
+        }
+        return snippet.toString();
+    }
+
+    /**
+     * Writes the specified character into the buffer
+     * @param c
+     */
+    public void write(int c) {
+        if (c != -1) {
+            current.append((char)c);
+        }
+        if (c == '\n') {
+            current = new StringBuffer();
+            lines.add(current);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java b/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java
new file mode 100644
index 0000000..90126f0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/SourceInfo.java
@@ -0,0 +1,77 @@
+/*
+ *  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.antlr;
+
+public interface SourceInfo {
+    /**
+     * get start line
+     *
+     * @return the starting line
+     */
+    int getLine();
+
+    /**
+     * set start line
+     *
+     * @param l the line
+     */
+    void setLine(int l);
+
+    /**
+     * get starting column
+     *
+     * @return the starting column
+     */
+    int getColumn();
+
+    /**
+     * set start column
+     *
+     * @param c the column
+     */
+    void setColumn(int c);
+
+    /**
+     * get ending line
+     *
+     * @return the ending line
+     */
+    int getLineLast();
+
+    /**
+     * set ending line
+     *
+     * @param lineLast the line
+     */
+    void setLineLast(int lineLast);
+
+    /**
+     * get ending column
+     *
+     * @return the ending column
+     */
+    int getColumnLast();
+
+    /**
+     * set ending column
+     *
+     * @param colLast the column
+     */
+    void setColumnLast(int colLast);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java b/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java
new file mode 100644
index 0000000..aef7e7a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/UnicodeEscapingReader.java
@@ -0,0 +1,190 @@
+/*
+ *  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.antlr;
+
+import antlr.CharScanner;
+import antlr.Token;
+import antlr.TokenStreamException;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Translates GLS-defined unicode escapes into characters. Throws an exception
+ * in the event of an invalid unicode escape being detected.
+ * <p>
+ * No attempt has been made to optimize this class for speed or space.
+ */
+public class UnicodeEscapingReader extends Reader {
+
+    private final Reader reader;
+    private CharScanner lexer;
+    private boolean hasNextChar = false;
+    private int nextChar;
+    private final SourceBuffer sourceBuffer;
+    private int previousLine;
+    private int numUnicodeEscapesFound = 0;
+    private int numUnicodeEscapesFoundOnCurrentLine = 0;
+
+    private static class DummyLexer extends CharScanner {
+        private final Token t = new Token();
+        public Token nextToken() throws TokenStreamException {
+            return t;
+        }
+        @Override
+        public int getColumn() {
+            return 0;
+        }
+        @Override
+        public int getLine() {
+            return 0;
+        }
+    }
+    
+    /**
+     * Constructor.
+     * @param reader The reader that this reader will filter over.
+     */
+    public UnicodeEscapingReader(Reader reader,SourceBuffer sourceBuffer) {
+        this.reader = reader;
+        this.sourceBuffer = sourceBuffer;
+        this.lexer = new DummyLexer();
+    }
+
+    /**
+     * Sets the lexer that is using this reader. Must be called before the
+     * lexer is used.
+     */
+    public void setLexer(CharScanner lexer) {
+        this.lexer = lexer;
+    }
+
+    /**
+     * Reads characters from the underlying reader.
+     * @see java.io.Reader#read(char[],int,int)
+     */
+    public int read(char cbuf[], int off, int len) throws IOException {
+        int c = 0;
+        int count = 0;
+        while (count < len && (c = read())!= -1) {
+            cbuf[off + count] = (char) c;
+            count++;
+        }
+        return (count == 0 && c == -1) ? -1 : count;
+    }
+
+    /**
+     * Gets the next character from the underlying reader,
+     * translating escapes as required.
+     * @see java.io.Reader#close()
+     */
+    public int read() throws IOException {
+        if (hasNextChar) {
+            hasNextChar = false;
+            write(nextChar);
+            return nextChar;
+        }
+
+        if (previousLine != lexer.getLine()) {
+            // new line, so reset unicode escapes
+            numUnicodeEscapesFoundOnCurrentLine = 0;
+            previousLine = lexer.getLine();
+        }
+        
+        int c = reader.read();
+        if (c != '\\') {
+            write(c);
+            return c;
+        }
+
+        // Have one backslash, continue if next char is 'u'
+        c = reader.read();
+        if (c != 'u') {
+            hasNextChar = true;
+            nextChar = c;
+            write('\\');
+            return '\\';
+        }
+
+        // Swallow multiple 'u's
+        int numberOfUChars = 0;
+        do {
+            numberOfUChars++;
+            c = reader.read();
+        } while (c == 'u');
+
+        // Get first hex digit
+        checkHexDigit(c);
+        StringBuilder charNum = new StringBuilder();
+        charNum.append((char) c);
+
+        // Must now be three more hex digits
+        for (int i = 0; i < 3; i++) {
+            c = reader.read();
+            checkHexDigit(c);
+            charNum.append((char) c);
+        }
+        int rv = Integer.parseInt(charNum.toString(), 16);
+        write(rv);
+        
+        numUnicodeEscapesFound += 4 + numberOfUChars;
+        numUnicodeEscapesFoundOnCurrentLine += 4 + numberOfUChars;
+
+        return rv;
+    }
+    private void write(int c) {
+        if (sourceBuffer != null) {sourceBuffer.write(c);}
+    }
+    /**
+     * Checks that the given character is indeed a hex digit.
+     */
+    private void checkHexDigit(int c) throws IOException {
+        if (c >= '0' && c <= '9') {
+            return;
+        }
+        if (c >= 'a' && c <= 'f') {
+            return;
+        }
+        if (c >= 'A' && c <= 'F') {
+            return;
+        }
+        // Causes the invalid escape to be skipped
+        hasNextChar = true;
+        nextChar = c;
+        throw new IOException("Did not find four digit hex character code."
+                + " line: " + lexer.getLine() + " col:" + lexer.getColumn());
+    }
+
+    public int getUnescapedUnicodeColumnCount() {
+        return numUnicodeEscapesFoundOnCurrentLine;
+    }
+
+    public int getUnescapedUnicodeOffsetCount() {
+        return numUnicodeEscapesFound;
+    }
+
+    /**
+     * Closes this reader by calling close on the underlying reader.
+     *
+     * @see java.io.Reader#close()
+     */
+    public void close() throws IOException {
+        reader.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java b/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java
new file mode 100644
index 0000000..2e90b2e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/UnicodeLexerSharedInputState.java
@@ -0,0 +1,51 @@
+/*
+ *  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.antlr;
+
+import antlr.LexerSharedInputState;
+
+/**
+ * GRECLIPSE-805 Support for unicode escape sequences
+ * @author Andrew Eisenberg
+ */
+public class UnicodeLexerSharedInputState extends LexerSharedInputState {
+    private final UnicodeEscapingReader escapingReader;
+
+    private int prevUnescape;
+
+    public UnicodeLexerSharedInputState(UnicodeEscapingReader in) {
+        super(in);
+        escapingReader = in; 
+    }
+
+    @Override
+    public int getColumn() {
+        prevUnescape = escapingReader.getUnescapedUnicodeColumnCount();
+        return super.getColumn() + prevUnescape;
+    }
+
+    @Override
+    public int getTokenStartColumn() {
+        if (line == tokenStartLine) {
+            return super.getTokenStartColumn() + escapingReader.getUnescapedUnicodeColumnCount();
+        } else {
+            return super.getTokenStartColumn() + prevUnescape;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java b/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java
new file mode 100644
index 0000000..cc551fb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/java/Groovifier.java
@@ -0,0 +1,74 @@
+/*
+ *  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.antlr.java;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.antlr.treewalker.VisitorAdapter;
+
+public class Groovifier extends VisitorAdapter implements GroovyTokenTypes {
+    private String currentClassName = "";
+    private final boolean cleanRedundantPublic;
+
+    public Groovifier(String[] tokenNames) {
+        this(tokenNames, true);
+    }
+
+    public Groovifier(String[] tokenNames, boolean cleanRedundantPublic) {
+        this.cleanRedundantPublic = cleanRedundantPublic;
+    }
+
+    public void visitClassDef(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            currentClassName = t.childOfType(GroovyTokenTypes.IDENT).getText();
+        }
+    }
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            // only want to do this once per node...
+
+            // remove 'public' when implied already if requested
+            if (t.getType() == LITERAL_public && cleanRedundantPublic) {
+                t.setType(EXPR);
+            }
+
+            // constructors are not distinguished from methods in java ast
+            if (t.getType() == METHOD_DEF) {
+                String methodName = t.childOfType(IDENT).getText();
+                if (methodName != null && methodName.length() > 0) {
+                    if (methodName.equals(currentClassName)) {
+                        t.setType(CTOR_IDENT);
+                    }
+                }
+            }
+
+
+/*          if (t.getType() == MODIFIERS) {
+                GroovySourceAST publicNode = t.childOfType(LITERAL_public);
+                if (t.getNumberOfChildren() > 1 && publicNode != null) {
+                    // has more than one modifier, and one of them is public
+
+                    // delete 'public' node
+                    publicNode.setType(EXPR); // near enough the same as delete for now...
+                }
+            }*/
+            // ----
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java
new file mode 100644
index 0000000..d200a99
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyConverter.java
@@ -0,0 +1,232 @@
+/*
+ *  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.antlr.java;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.antlr.treewalker.VisitorAdapter;
+
+public class Java2GroovyConverter extends VisitorAdapter{
+    private final int[] typeMapping;
+
+    public Java2GroovyConverter(String[] tokenNames) {
+        typeMapping = new int[400]; // magic number, much greater than current number of java tokens
+        typeMapping[JavaTokenTypes.ABSTRACT] = GroovyTokenTypes.ABSTRACT;
+
+        typeMapping[JavaTokenTypes.EOF] = GroovyTokenTypes.EOF;
+        typeMapping[JavaTokenTypes.NULL_TREE_LOOKAHEAD] = GroovyTokenTypes.NULL_TREE_LOOKAHEAD;
+        typeMapping[JavaTokenTypes.BLOCK] = GroovyTokenTypes.BLOCK;
+        typeMapping[JavaTokenTypes.MODIFIERS] = GroovyTokenTypes.MODIFIERS;
+        typeMapping[JavaTokenTypes.OBJBLOCK] = GroovyTokenTypes.OBJBLOCK;
+        typeMapping[JavaTokenTypes.SLIST] = GroovyTokenTypes.SLIST;
+        typeMapping[JavaTokenTypes.METHOD_DEF] = GroovyTokenTypes.METHOD_DEF;
+        typeMapping[JavaTokenTypes.VARIABLE_DEF] = GroovyTokenTypes.VARIABLE_DEF;
+        typeMapping[JavaTokenTypes.INSTANCE_INIT] = GroovyTokenTypes.INSTANCE_INIT;
+        typeMapping[JavaTokenTypes.STATIC_INIT] = GroovyTokenTypes.STATIC_INIT;
+        typeMapping[JavaTokenTypes.TYPE] = GroovyTokenTypes.TYPE;
+        typeMapping[JavaTokenTypes.CLASS_DEF] = GroovyTokenTypes.CLASS_DEF;
+        typeMapping[JavaTokenTypes.INTERFACE_DEF] = GroovyTokenTypes.INTERFACE_DEF;
+        typeMapping[JavaTokenTypes.PACKAGE_DEF] = GroovyTokenTypes.PACKAGE_DEF;
+        typeMapping[JavaTokenTypes.ARRAY_DECLARATOR] = GroovyTokenTypes.ARRAY_DECLARATOR;
+        typeMapping[JavaTokenTypes.EXTENDS_CLAUSE] = GroovyTokenTypes.EXTENDS_CLAUSE;
+        typeMapping[JavaTokenTypes.IMPLEMENTS_CLAUSE] = GroovyTokenTypes.IMPLEMENTS_CLAUSE;
+        typeMapping[JavaTokenTypes.PARAMETERS] = GroovyTokenTypes.PARAMETERS;
+        typeMapping[JavaTokenTypes.PARAMETER_DEF] = GroovyTokenTypes.PARAMETER_DEF;
+        typeMapping[JavaTokenTypes.LABELED_STAT] = GroovyTokenTypes.LABELED_STAT;
+        typeMapping[JavaTokenTypes.TYPECAST] = GroovyTokenTypes.TYPECAST;
+        typeMapping[JavaTokenTypes.INDEX_OP] = GroovyTokenTypes.INDEX_OP;
+        typeMapping[JavaTokenTypes.POST_INC] = GroovyTokenTypes.POST_INC;
+        typeMapping[JavaTokenTypes.POST_DEC] = GroovyTokenTypes.POST_DEC;
+        typeMapping[JavaTokenTypes.METHOD_CALL] = GroovyTokenTypes.METHOD_CALL;
+        typeMapping[JavaTokenTypes.EXPR] = GroovyTokenTypes.EXPR;
+        typeMapping[JavaTokenTypes.ARRAY_INIT] = GroovyTokenTypes.LIST_CONSTRUCTOR; // this assumes LIST_CONSTRUCTOR set by PreJava2GroovyConvertor
+        typeMapping[JavaTokenTypes.IMPORT] = GroovyTokenTypes.IMPORT;
+        typeMapping[JavaTokenTypes.UNARY_MINUS] = GroovyTokenTypes.UNARY_MINUS;
+        typeMapping[JavaTokenTypes.UNARY_PLUS] = GroovyTokenTypes.UNARY_PLUS;
+        typeMapping[JavaTokenTypes.CASE_GROUP] = GroovyTokenTypes.CASE_GROUP;
+        typeMapping[JavaTokenTypes.ELIST] = GroovyTokenTypes.ELIST;
+        typeMapping[JavaTokenTypes.FOR_INIT] = GroovyTokenTypes.FOR_INIT;
+        typeMapping[JavaTokenTypes.FOR_CONDITION] = GroovyTokenTypes.FOR_CONDITION;
+        typeMapping[JavaTokenTypes.FOR_ITERATOR] = GroovyTokenTypes.FOR_ITERATOR;
+        typeMapping[JavaTokenTypes.EMPTY_STAT] = GroovyTokenTypes.EMPTY_STAT;
+        typeMapping[JavaTokenTypes.FINAL] = GroovyTokenTypes.FINAL;
+        typeMapping[JavaTokenTypes.ABSTRACT] = GroovyTokenTypes.ABSTRACT;
+        typeMapping[JavaTokenTypes.STRICTFP] = GroovyTokenTypes.STRICTFP;
+        typeMapping[JavaTokenTypes.SUPER_CTOR_CALL] = GroovyTokenTypes.SUPER_CTOR_CALL;
+        typeMapping[JavaTokenTypes.CTOR_CALL] = GroovyTokenTypes.CTOR_CALL;
+        typeMapping[JavaTokenTypes.VARIABLE_PARAMETER_DEF] = GroovyTokenTypes.VARIABLE_PARAMETER_DEF;
+        typeMapping[JavaTokenTypes.STATIC_IMPORT] = GroovyTokenTypes.STATIC_IMPORT;
+        typeMapping[JavaTokenTypes.ENUM_DEF] = GroovyTokenTypes.ENUM_DEF;
+        typeMapping[JavaTokenTypes.ENUM_CONSTANT_DEF] = GroovyTokenTypes.ENUM_CONSTANT_DEF;
+        typeMapping[JavaTokenTypes.FOR_EACH_CLAUSE] = GroovyTokenTypes.FOR_EACH_CLAUSE;
+        typeMapping[JavaTokenTypes.ANNOTATION_DEF] = GroovyTokenTypes.ANNOTATION_DEF;
+        typeMapping[JavaTokenTypes.ANNOTATIONS] = GroovyTokenTypes.ANNOTATIONS;
+        typeMapping[JavaTokenTypes.ANNOTATION] = GroovyTokenTypes.ANNOTATION;
+        typeMapping[JavaTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR] = GroovyTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR;
+        typeMapping[JavaTokenTypes.ANNOTATION_FIELD_DEF] = GroovyTokenTypes.ANNOTATION_FIELD_DEF;
+        typeMapping[JavaTokenTypes.ANNOTATION_ARRAY_INIT] = GroovyTokenTypes.ANNOTATION_ARRAY_INIT;
+        typeMapping[JavaTokenTypes.TYPE_ARGUMENTS] = GroovyTokenTypes.TYPE_ARGUMENTS;
+        typeMapping[JavaTokenTypes.TYPE_ARGUMENT] = GroovyTokenTypes.TYPE_ARGUMENT;
+        typeMapping[JavaTokenTypes.TYPE_PARAMETERS] = GroovyTokenTypes.TYPE_PARAMETERS;
+        typeMapping[JavaTokenTypes.TYPE_PARAMETER] = GroovyTokenTypes.TYPE_PARAMETER;
+        typeMapping[JavaTokenTypes.WILDCARD_TYPE] = GroovyTokenTypes.WILDCARD_TYPE;
+        typeMapping[JavaTokenTypes.TYPE_UPPER_BOUNDS] = GroovyTokenTypes.TYPE_UPPER_BOUNDS;
+        typeMapping[JavaTokenTypes.TYPE_LOWER_BOUNDS] = GroovyTokenTypes.TYPE_LOWER_BOUNDS;
+        typeMapping[JavaTokenTypes.LITERAL_package] = GroovyTokenTypes.LITERAL_package;
+        typeMapping[JavaTokenTypes.SEMI] = GroovyTokenTypes.SEMI;
+        typeMapping[JavaTokenTypes.LITERAL_import] = GroovyTokenTypes.LITERAL_import;
+        typeMapping[JavaTokenTypes.LITERAL_static] = GroovyTokenTypes.LITERAL_static;
+        typeMapping[JavaTokenTypes.LBRACK] = GroovyTokenTypes.LBRACK;
+        typeMapping[JavaTokenTypes.RBRACK] = GroovyTokenTypes.RBRACK;
+        typeMapping[JavaTokenTypes.IDENT] = GroovyTokenTypes.IDENT;
+        typeMapping[JavaTokenTypes.DOT] = GroovyTokenTypes.DOT;
+        typeMapping[JavaTokenTypes.QUESTION] = GroovyTokenTypes.QUESTION;
+        typeMapping[JavaTokenTypes.LITERAL_extends] = GroovyTokenTypes.LITERAL_extends;
+        typeMapping[JavaTokenTypes.LITERAL_super] = GroovyTokenTypes.LITERAL_super;
+        typeMapping[JavaTokenTypes.LT] = GroovyTokenTypes.LT;
+        typeMapping[JavaTokenTypes.COMMA] = GroovyTokenTypes.COMMA;
+        typeMapping[JavaTokenTypes.GT] = GroovyTokenTypes.GT;
+        typeMapping[JavaTokenTypes.SR] = GroovyTokenTypes.SR;
+        typeMapping[JavaTokenTypes.BSR] = GroovyTokenTypes.BSR;
+        typeMapping[JavaTokenTypes.LITERAL_void] = GroovyTokenTypes.LITERAL_void;
+        typeMapping[JavaTokenTypes.LITERAL_boolean] = GroovyTokenTypes.LITERAL_boolean;
+        typeMapping[JavaTokenTypes.LITERAL_byte] = GroovyTokenTypes.LITERAL_byte;
+        typeMapping[JavaTokenTypes.LITERAL_char] = GroovyTokenTypes.LITERAL_char;
+        typeMapping[JavaTokenTypes.LITERAL_short] = GroovyTokenTypes.LITERAL_short;
+        typeMapping[JavaTokenTypes.LITERAL_int] = GroovyTokenTypes.LITERAL_int;
+        typeMapping[JavaTokenTypes.LITERAL_float] = GroovyTokenTypes.LITERAL_float;
+        typeMapping[JavaTokenTypes.LITERAL_long] = GroovyTokenTypes.LITERAL_long;
+        typeMapping[JavaTokenTypes.LITERAL_double] = GroovyTokenTypes.LITERAL_double;
+        typeMapping[JavaTokenTypes.STAR] = GroovyTokenTypes.STAR;
+        typeMapping[JavaTokenTypes.LITERAL_private] = GroovyTokenTypes.LITERAL_private;
+        typeMapping[JavaTokenTypes.LITERAL_public] = GroovyTokenTypes.LITERAL_public;
+        typeMapping[JavaTokenTypes.LITERAL_protected] = GroovyTokenTypes.LITERAL_protected;
+        typeMapping[JavaTokenTypes.LITERAL_transient] = GroovyTokenTypes.LITERAL_transient;
+        typeMapping[JavaTokenTypes.LITERAL_native] = GroovyTokenTypes.LITERAL_native;
+        typeMapping[JavaTokenTypes.LITERAL_threadsafe] = GroovyTokenTypes.LITERAL_threadsafe;
+        typeMapping[JavaTokenTypes.LITERAL_synchronized] = GroovyTokenTypes.LITERAL_synchronized;
+        typeMapping[JavaTokenTypes.LITERAL_volatile] = GroovyTokenTypes.LITERAL_volatile;
+        typeMapping[JavaTokenTypes.AT] = GroovyTokenTypes.AT;
+        typeMapping[JavaTokenTypes.LPAREN] = GroovyTokenTypes.LPAREN;
+        typeMapping[JavaTokenTypes.RPAREN] = GroovyTokenTypes.RPAREN;
+        typeMapping[JavaTokenTypes.ASSIGN] = GroovyTokenTypes.ASSIGN;
+        typeMapping[JavaTokenTypes.LCURLY] = GroovyTokenTypes.LCURLY;
+        typeMapping[JavaTokenTypes.RCURLY] = GroovyTokenTypes.RCURLY;
+        typeMapping[JavaTokenTypes.LITERAL_class] = GroovyTokenTypes.LITERAL_class;
+        typeMapping[JavaTokenTypes.LITERAL_interface] = GroovyTokenTypes.LITERAL_interface;
+        typeMapping[JavaTokenTypes.LITERAL_enum] = GroovyTokenTypes.LITERAL_enum;
+        typeMapping[JavaTokenTypes.BAND] = GroovyTokenTypes.BAND;
+        typeMapping[JavaTokenTypes.LITERAL_default] = GroovyTokenTypes.LITERAL_default;
+        typeMapping[JavaTokenTypes.LITERAL_implements] = GroovyTokenTypes.LITERAL_implements;
+        typeMapping[JavaTokenTypes.LITERAL_this] = GroovyTokenTypes.LITERAL_this;
+        typeMapping[JavaTokenTypes.LITERAL_throws] = GroovyTokenTypes.LITERAL_throws;
+        typeMapping[JavaTokenTypes.TRIPLE_DOT] = GroovyTokenTypes.TRIPLE_DOT;
+        typeMapping[JavaTokenTypes.COLON] = GroovyTokenTypes.COLON;
+        typeMapping[JavaTokenTypes.LITERAL_if] = GroovyTokenTypes.LITERAL_if;
+        typeMapping[JavaTokenTypes.LITERAL_else] = GroovyTokenTypes.LITERAL_else;
+        typeMapping[JavaTokenTypes.LITERAL_while] = GroovyTokenTypes.LITERAL_while;
+        typeMapping[JavaTokenTypes.LITERAL_do] = GroovyTokenTypes.LITERAL_while; // warning - do...while... ignored
+        typeMapping[JavaTokenTypes.LITERAL_break] = GroovyTokenTypes.LITERAL_break;
+        typeMapping[JavaTokenTypes.LITERAL_continue] = GroovyTokenTypes.LITERAL_continue;
+        typeMapping[JavaTokenTypes.LITERAL_return] = GroovyTokenTypes.LITERAL_return;
+        typeMapping[JavaTokenTypes.LITERAL_switch] = GroovyTokenTypes.LITERAL_switch;
+        typeMapping[JavaTokenTypes.LITERAL_throw] = GroovyTokenTypes.LITERAL_throw;
+        typeMapping[JavaTokenTypes.LITERAL_assert] = GroovyTokenTypes.LITERAL_assert;
+        typeMapping[JavaTokenTypes.LITERAL_for] = GroovyTokenTypes.LITERAL_for;
+        typeMapping[JavaTokenTypes.LITERAL_case] = GroovyTokenTypes.LITERAL_case;
+        typeMapping[JavaTokenTypes.LITERAL_try] = GroovyTokenTypes.LITERAL_try;
+        typeMapping[JavaTokenTypes.LITERAL_finally] = GroovyTokenTypes.LITERAL_finally;
+        typeMapping[JavaTokenTypes.LITERAL_catch] = GroovyTokenTypes.LITERAL_catch;
+        typeMapping[JavaTokenTypes.PLUS_ASSIGN] = GroovyTokenTypes.PLUS_ASSIGN;
+        typeMapping[JavaTokenTypes.MINUS_ASSIGN] = GroovyTokenTypes.MINUS_ASSIGN;
+        typeMapping[JavaTokenTypes.STAR_ASSIGN] = GroovyTokenTypes.STAR_ASSIGN;
+        typeMapping[JavaTokenTypes.DIV_ASSIGN] = GroovyTokenTypes.DIV_ASSIGN;
+        typeMapping[JavaTokenTypes.MOD_ASSIGN] = GroovyTokenTypes.MOD_ASSIGN;
+        typeMapping[JavaTokenTypes.SR_ASSIGN] = GroovyTokenTypes.SR_ASSIGN;
+        typeMapping[JavaTokenTypes.BSR_ASSIGN] = GroovyTokenTypes.BSR_ASSIGN;
+        typeMapping[JavaTokenTypes.SL_ASSIGN] = GroovyTokenTypes.SL_ASSIGN;
+        typeMapping[JavaTokenTypes.BAND_ASSIGN] = GroovyTokenTypes.BAND_ASSIGN;
+        typeMapping[JavaTokenTypes.BXOR_ASSIGN] = GroovyTokenTypes.BXOR_ASSIGN;
+        typeMapping[JavaTokenTypes.BOR_ASSIGN] = GroovyTokenTypes.BOR_ASSIGN;
+        typeMapping[JavaTokenTypes.LOR] = GroovyTokenTypes.LOR;
+        typeMapping[JavaTokenTypes.LAND] = GroovyTokenTypes.LAND;
+        typeMapping[JavaTokenTypes.BOR] = GroovyTokenTypes.BOR;
+        typeMapping[JavaTokenTypes.BXOR] = GroovyTokenTypes.BXOR;
+        typeMapping[JavaTokenTypes.NOT_EQUAL] = GroovyTokenTypes.NOT_EQUAL;
+        typeMapping[JavaTokenTypes.EQUAL] = GroovyTokenTypes.EQUAL;
+        typeMapping[JavaTokenTypes.LE] = GroovyTokenTypes.LE;
+        typeMapping[JavaTokenTypes.GE] = GroovyTokenTypes.GE;
+        typeMapping[JavaTokenTypes.LITERAL_instanceof] = GroovyTokenTypes.LITERAL_instanceof;
+        typeMapping[JavaTokenTypes.SL] = GroovyTokenTypes.SL;
+        typeMapping[JavaTokenTypes.PLUS] = GroovyTokenTypes.PLUS;
+        typeMapping[JavaTokenTypes.MINUS] = GroovyTokenTypes.MINUS;
+        typeMapping[JavaTokenTypes.DIV] = GroovyTokenTypes.DIV;
+        typeMapping[JavaTokenTypes.MOD] = GroovyTokenTypes.MOD;
+        typeMapping[JavaTokenTypes.INC] = GroovyTokenTypes.INC;
+        typeMapping[JavaTokenTypes.DEC] = GroovyTokenTypes.DEC;
+        typeMapping[JavaTokenTypes.BNOT] = GroovyTokenTypes.BNOT;
+        typeMapping[JavaTokenTypes.LNOT] = GroovyTokenTypes.LNOT;
+        typeMapping[JavaTokenTypes.LITERAL_true] = GroovyTokenTypes.LITERAL_true;
+        typeMapping[JavaTokenTypes.LITERAL_false] = GroovyTokenTypes.LITERAL_false;
+        typeMapping[JavaTokenTypes.LITERAL_null] = GroovyTokenTypes.LITERAL_null;
+        typeMapping[JavaTokenTypes.LITERAL_new] = GroovyTokenTypes.LITERAL_new;
+        typeMapping[JavaTokenTypes.NUM_INT] = GroovyTokenTypes.NUM_INT;
+        typeMapping[JavaTokenTypes.CHAR_LITERAL] = GroovyTokenTypes.STRING_LITERAL; // warning: treating Java chars as "String" in Groovy
+        typeMapping[JavaTokenTypes.STRING_LITERAL] = GroovyTokenTypes.STRING_LITERAL;
+        typeMapping[JavaTokenTypes.NUM_FLOAT] = GroovyTokenTypes.NUM_FLOAT;
+        typeMapping[JavaTokenTypes.NUM_LONG] = GroovyTokenTypes.NUM_LONG;
+        typeMapping[JavaTokenTypes.NUM_DOUBLE] = GroovyTokenTypes.NUM_DOUBLE;
+        typeMapping[JavaTokenTypes.WS] = GroovyTokenTypes.WS;
+        typeMapping[JavaTokenTypes.SL_COMMENT] = GroovyTokenTypes.SL_COMMENT;
+        typeMapping[JavaTokenTypes.ML_COMMENT] = GroovyTokenTypes.ML_COMMENT;
+        typeMapping[JavaTokenTypes.ESC] = GroovyTokenTypes.ESC;
+        typeMapping[JavaTokenTypes.HEX_DIGIT] = GroovyTokenTypes.HEX_DIGIT;
+        typeMapping[JavaTokenTypes.VOCAB] = GroovyTokenTypes.VOCAB;
+        typeMapping[JavaTokenTypes.EXPONENT] = GroovyTokenTypes.EXPONENT;
+        typeMapping[JavaTokenTypes.FLOAT_SUFFIX] = GroovyTokenTypes.FLOAT_SUFFIX;
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            // only want to do this once per node...
+            t.setType(typeMapping[t.getType()]);
+            // ----
+
+            // need to remove double quotes in string literals
+            // as groovy AST doesn't expect to have them
+            if (t.getType() == GroovyTokenTypes.STRING_LITERAL) {
+                String text = t.getText();
+                if (isSingleQuoted(text) || isDoubleQuoted(text)) {
+                    t.setText(text.substring(1, text.length() - 1)); // chop off the single quotes at start and end
+                }
+            }
+        }
+    }
+
+    private static boolean isSingleQuoted(String text) {
+        return text != null && text.length() > 2
+                && text.charAt(0) == '\''
+                && text.charAt(text.length() - 1) == '\'';
+    }
+    private static boolean isDoubleQuoted(String text) {
+        return text != null && text.length() > 2
+                && text.charAt(0) == '"'
+                && text.charAt(text.length() - 1) == '"';
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
new file mode 100644
index 0000000..d7384e0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
@@ -0,0 +1,44 @@
+/*
+ *  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.antlr.java;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+
+import java.util.Arrays;
+
+public class Java2GroovyMain {
+
+    public static void main(String[] args) {
+        try {
+            Options options = new Options();
+            CommandLineParser cliParser = new DefaultParser();
+            CommandLine cli = cliParser.parse(options, args);
+            String[] filenames = cli.getArgs();
+            if (filenames.length == 0) {
+                System.err.println("Needs at least one filename");
+            }
+            Java2GroovyProcessor.processFiles(Arrays.asList(filenames));
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java
new file mode 100644
index 0000000..d6b47dd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java
@@ -0,0 +1,187 @@
+/*
+ *  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.antlr.java;
+
+import antlr.collections.AST;
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.SourceBuffer;
+import org.codehaus.groovy.antlr.UnicodeEscapingReader;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+import org.codehaus.groovy.antlr.treewalker.MindMapPrinter;
+import org.codehaus.groovy.antlr.treewalker.NodePrinter;
+import org.codehaus.groovy.antlr.treewalker.PreOrderTraversal;
+import org.codehaus.groovy.antlr.treewalker.SourceCodeTraversal;
+import org.codehaus.groovy.antlr.treewalker.SourcePrinter;
+import org.codehaus.groovy.antlr.treewalker.Visitor;
+import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.util.Iterator;
+import java.util.List;
+
+public class Java2GroovyProcessor {
+
+    public static void processFiles(List<String> fileNames) throws Exception {
+        Iterator i = fileNames.iterator();
+        while (i.hasNext()) {
+            String filename = (String) i.next();
+            File f = new File(filename);
+            String text = ResourceGroovyMethods.getText(f);
+            System.out.println(convert(filename, text, true, true));
+        }
+    }
+
+    public static String convert(String filename, String input) throws Exception {
+        return convert(filename, input, false, false);
+    }
+
+    public static String convert(String filename, String input, boolean withHeader, boolean withNewLines) throws Exception {
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+
+        // output AST in format suitable for opening in http://freemind.sourceforge.net
+        // which is a really nice way of seeing the AST, folding nodes etc
+        if ("mindmap".equals(System.getProperty("ANTLR.AST".toLowerCase()))) { // uppercase to hide from jarjar
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(filename + ".mm"));
+                Visitor visitor = new MindMapPrinter(out, tokenNames);
+                AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + filename + ".mm");
+            }
+        }
+
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new SourcePrinter(new PrintStream(baos), groovyTokenNames, withNewLines);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+
+        String header = "";
+        if (withHeader) {
+            header = "/*\n" +
+                    "  Automatically Converted from Java Source \n" +
+                    "  \n" +
+                    "  by java2groovy v0.0.1   Copyright Jeremy Rayner 2007\n" +
+                    "  \n" +
+                    "  !! NOT FIT FOR ANY PURPOSE !! \n" +
+                    "  'java2groovy' cannot be used to convert one working program into another" +
+                    "  */\n\n";
+        }
+        return header + new String(baos.toByteArray());
+    }
+
+    private static void groovifyFatJavaLikeGroovyAST(AST ast, String[] groovyTokenNames) {
+        Visitor groovifier = new Groovifier(groovyTokenNames);
+        AntlrASTProcessor groovifierTraverser = new PreOrderTraversal(groovifier);
+        groovifierTraverser.process(ast);
+    }
+
+    private static void modifyJavaASTintoGroovyAST(String[] tokenNames, AST ast) {
+        // mutate the tree when in Javaland
+        Visitor preJava2groovyConverter = new PreJava2GroovyConverter(tokenNames);
+        AntlrASTProcessor preJava2groovyTraverser = new PreOrderTraversal(preJava2groovyConverter);
+        preJava2groovyTraverser.process(ast);
+
+        // map the nodes to Groovy types
+        Visitor java2groovyConverter = new Java2GroovyConverter(tokenNames);
+        AntlrASTProcessor java2groovyTraverser = new PreOrderTraversal(java2groovyConverter);
+        java2groovyTraverser.process(ast);
+    }
+
+    private static JavaRecognizer getJavaParser(String input) {
+        JavaRecognizer parser = null;
+        SourceBuffer sourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new StringReader(input), sourceBuffer);
+        JavaLexer lexer = new JavaLexer(unicodeReader);
+        unicodeReader.setLexer(lexer);
+        parser = JavaRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+        return parser;
+    }
+
+    public static String mindmap(String input) throws Exception {
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new MindMapPrinter(new PrintStream(baos), groovyTokenNames);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+
+        return new String(baos.toByteArray());
+    }
+
+    public static String nodePrinter(String input) throws Exception {
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new NodePrinter(new PrintStream(baos), groovyTokenNames);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+
+        return new String(baos.toByteArray());
+    }
+
+    private static String[] getGroovyTokenNames(String input) {
+        GroovyRecognizer groovyParser = null;
+        SourceBuffer groovySourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader groovyUnicodeReader = new UnicodeEscapingReader(new StringReader(input), groovySourceBuffer);
+        GroovyLexer groovyLexer = new GroovyLexer(groovyUnicodeReader);
+        groovyUnicodeReader.setLexer(groovyLexer);
+        groovyParser = GroovyRecognizer.make(groovyLexer);
+        return groovyParser.getTokenNames();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java b/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java
new file mode 100644
index 0000000..6c5c1e2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/java/PreJava2GroovyConverter.java
@@ -0,0 +1,147 @@
+/*
+ *  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.antlr.java;
+
+import org.codehaus.groovy.antlr.GroovySourceAST;
+import org.codehaus.groovy.antlr.treewalker.VisitorAdapter;
+
+import java.util.Stack;
+
+/** This class mutates the Java AST, whilst it is still a Java AST, in readiness for conversion to Groovy, yippee-ky-a ! */
+public class PreJava2GroovyConverter extends VisitorAdapter{
+    private final Stack stack;
+
+    public PreJava2GroovyConverter(String[] tokenNames) {
+        this.stack = new Stack();
+    }
+
+    public void visitDefault(GroovySourceAST t,int visit) {
+        if (visit == OPENING_VISIT) {
+            if (t.getType() == JavaTokenTypes.LITERAL_do) {
+                visitJavaLiteralDo(t);
+            } else if (t.getType() == JavaTokenTypes.ARRAY_INIT) {
+                visitJavaArrayInit(t);
+            }
+        }
+    }
+
+    private void visitJavaLiteralDo(GroovySourceAST t) {
+        // todo - incomplete, as body of do...while... should be executed at least once, which this doesn't provide.
+        swapTwoChildren(t);
+    }
+
+    /**
+     * Handle Arrays. Examples:
+     *
+     * <pre>
+     * String[] myArray = new String[] {"a","b","c"};
+     *
+     * becomes
+     *
+     * String[] myArray = ["a", "b", "c"]
+     *
+     * ---
+     *
+     * To convert node (t) and surrounding nodes into the right structure for List Constructor
+     *
+     * (a) java/EXPR
+     *  |
+     *  +- (b) java/new
+     *      |
+     *      + (t) java/ARRAY_INIT
+     *
+     *  becomes
+     *
+     * (a) groovy/LIST_CONSTRUCTOR (via ARRAY_INIT as temporary marker type)
+     *  |
+     *  +- (t) groovy/ELIST
+     *
+     *  * note: node (b) is thrown away...
+     * </pre>
+     */
+    private void visitJavaArrayInit(GroovySourceAST t) {
+        // given that we might have a grandParent...
+        if (stack.size() > 2) {
+            GroovySourceAST grandParent = getGrandParentNode();
+            if (grandParent.getType() == JavaTokenTypes.EXPR) {
+                grandParent.setType(JavaTokenTypes.ARRAY_INIT); //set type as indicator for Java2GroovyConvertor to turn into LIST_CONSTRUCTOR
+                grandParent.setFirstChild(t);
+                t.setType(JavaTokenTypes.ELIST);
+            }
+        }
+    }
+
+    /** To swap two children of node t...
+     *
+     *<pre>
+     *   (t)
+     *    |
+     *    |
+     *   (a) -- (b)
+     *
+     * t.down = firstNode
+     * a.right = b
+     * b.right = null
+     *</pre>
+     * becomes
+     *<pre>
+     *   (t)
+     *    |
+     *    |
+     *   (b) -- (a)
+     *
+     * t.down = b
+     * a.right = null
+     * b.right = a
+     *</pre>
+     *
+     * todo - build API of basic tree mutations like this method.
+     */
+    public void swapTwoChildren(GroovySourceAST t) {
+        // this swaps the two child nodes, see javadoc above for explanation of implementation
+        GroovySourceAST a = (GroovySourceAST) t.getFirstChild();
+        GroovySourceAST b = (GroovySourceAST) a.getNextSibling();
+
+        t.setFirstChild(b);
+        a.setNextSibling(null);
+        b.setNextSibling(a);
+    }
+
+
+
+
+    public void push(GroovySourceAST t) {
+        stack.push(t);
+    }
+    public GroovySourceAST pop() {
+        if (!stack.empty()) {
+            return (GroovySourceAST) stack.pop();
+        }
+        return null;
+    }
+
+    private GroovySourceAST getGrandParentNode() {
+        Object currentNode = stack.pop();
+        Object parentNode = stack.pop();
+        Object grandParentNode = stack.peek();
+        stack.push(parentNode);
+        stack.push(currentNode);
+        return (GroovySourceAST) grandParentNode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/package.html b/src/main/java/org/codehaus/groovy/antlr/package.html
new file mode 100644
index 0000000..0ecf3f6
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/package.html
@@ -0,0 +1,28 @@
+<!--
+
+     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.
+
+-->
+<html>
+  <head>
+    <title>package org.codehaus.groovy.antlr.*</title>
+  </head>
+  <body>
+    <p>Parser related classes.</p>
+  </body>
+</html>


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
new file mode 100644
index 0000000..890abf2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
@@ -0,0 +1,1079 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Binding;
+import groovy.lang.Closure;
+import groovy.lang.GString;
+import groovy.lang.GroovyInterceptable;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+import groovy.lang.MetaClass;
+import groovy.lang.MetaClassRegistry;
+import groovy.lang.MissingMethodException;
+import groovy.lang.MissingPropertyException;
+import groovy.lang.Range;
+import groovy.lang.Script;
+import groovy.lang.SpreadMap;
+import groovy.lang.SpreadMapEvaluatingException;
+import groovy.lang.Tuple;
+import groovy.lang.Writable;
+import org.codehaus.groovy.control.ResolveVisitor;
+import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
+import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed;
+import org.codehaus.groovy.runtime.powerassert.PowerAssertionError;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.codehaus.groovy.runtime.wrappers.PojoWrapper;
+import org.w3c.dom.Element;
+
+import java.beans.Introspector;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A static helper class to make bytecode generation easier and act as a facade over the Invoker
+ */
+public class InvokerHelper {
+    private static final Object[] EMPTY_MAIN_ARGS = new Object[]{new String[0]};
+
+    public static final Object[] EMPTY_ARGS = {};
+    protected static final Object[] EMPTY_ARGUMENTS = EMPTY_ARGS;
+    protected static final Class[] EMPTY_TYPES = {};
+
+    // heuristic size to pre-alocate stringbuffers for collections of items
+    private static final int ITEM_ALLOCATE_SIZE = 5;
+
+    public static final MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry();
+    public static final String MAIN_METHOD_NAME = "main";
+
+    public static void removeClass(Class clazz) {
+        metaRegistry.removeMetaClass(clazz);
+        ClassInfo.remove(clazz);
+        Introspector.flushFromCaches(clazz);
+    }
+
+    public static Object invokeMethodSafe(Object object, String methodName, Object arguments) {
+        if (object != null) {
+            return invokeMethod(object, methodName, arguments);
+        }
+        return null;
+    }
+
+    public static Object invokeStaticMethod(String klass, String methodName, Object arguments) throws ClassNotFoundException {
+        Class type = Class.forName(klass);
+        return invokeStaticMethod(type, methodName, arguments);
+    }
+
+
+    public static Object invokeStaticNoArgumentsMethod(Class type, String methodName) {
+        return invokeStaticMethod(type, methodName, EMPTY_ARGS);
+    }
+
+    public static Object invokeConstructorOf(String klass, Object arguments) throws ClassNotFoundException {
+        Class type = Class.forName(klass);
+        return invokeConstructorOf(type, arguments);
+    }
+
+    public static Object invokeNoArgumentsConstructorOf(Class type) {
+        return invokeConstructorOf(type, EMPTY_ARGS);
+    }
+
+    public static Object invokeClosure(Object closure, Object arguments) {
+        return invokeMethod(closure, "doCall", arguments);
+    }
+
+    public static List asList(Object value) {
+        if (value == null) {
+            return Collections.EMPTY_LIST;
+        }
+        if (value instanceof List) {
+            return (List) value;
+        }
+        if (value.getClass().isArray()) {
+            return Arrays.asList((Object[]) value);
+        }
+        if (value instanceof Enumeration) {
+            Enumeration e = (Enumeration) value;
+            List answer = new ArrayList();
+            while (e.hasMoreElements()) {
+                answer.add(e.nextElement());
+            }
+            return answer;
+        }
+        // let's assume its a collection of 1
+        return Collections.singletonList(value);
+    }
+
+    public static String toString(Object arguments) {
+        return format(arguments, false, -1, false);
+    }
+
+    public static String inspect(Object self) {
+        return format(self, true);
+    }
+
+    public static Object getAttribute(Object object, String attribute) {
+        if (object == null) {
+            object = NullObject.getNullObject();
+        }
+
+        if (object instanceof Class) {
+            return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute);
+        } else if (object instanceof GroovyObject) {
+            return ((GroovyObject) object).getMetaClass().getAttribute(object, attribute);
+        } else {
+            return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
+        }
+    }
+
+    public static void setAttribute(Object object, String attribute, Object newValue) {
+        if (object == null) {
+            object = NullObject.getNullObject();
+        }
+
+        if (object instanceof Class) {
+            metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue);
+        } else if (object instanceof GroovyObject) {
+            ((GroovyObject) object).getMetaClass().setAttribute(object, attribute, newValue);
+        } else {
+            metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
+        }
+    }
+
+    public static Object getProperty(Object object, String property) {
+        if (object == null) {
+            object = NullObject.getNullObject();
+        }
+
+        if (object instanceof GroovyObject) {
+            GroovyObject pogo = (GroovyObject) object;
+            return pogo.getProperty(property);
+        } else if (object instanceof Class) {
+            Class c = (Class) object;
+            return metaRegistry.getMetaClass(c).getProperty(object, property);
+        } else {
+            return ((MetaClassRegistryImpl) metaRegistry).getMetaClass(object).getProperty(object, property);
+        }
+    }
+
+    public static Object getPropertySafe(Object object, String property) {
+        if (object != null) {
+            return getProperty(object, property);
+        }
+        return null;
+    }
+
+    public static void setProperty(Object object, String property, Object newValue) {
+        if (object == null) {
+            object = NullObject.getNullObject();
+        }
+
+        if (object instanceof GroovyObject) {
+            GroovyObject pogo = (GroovyObject) object;
+            pogo.setProperty(property, newValue);
+        } else if (object instanceof Class) {
+            metaRegistry.getMetaClass((Class) object).setProperty((Class) object, property, newValue);
+        } else {
+            ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object).setProperty(object, property, newValue);
+        }
+    }
+
+    /**
+     * This is so we don't have to reorder the stack when we call this method.
+     * At some point a better name might be in order.
+     */
+    public static void setProperty2(Object newValue, Object object, String property) {
+        setProperty(object, property, newValue);
+    }
+
+
+    /**
+     * This is so we don't have to reorder the stack when we call this method.
+     * At some point a better name might be in order.
+     */
+    public static void setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
+        object.setProperty(property, newValue);
+    }
+
+    public static Object getGroovyObjectProperty(GroovyObject object, String property) {
+        return object.getProperty(property);
+    }
+
+
+    /**
+     * This is so we don't have to reorder the stack when we call this method.
+     * At some point a better name might be in order.
+     */
+    public static void setPropertySafe2(Object newValue, Object object, String property) {
+        if (object != null) {
+            setProperty2(newValue, object, property);
+        }
+    }
+
+    /**
+     * Returns the method pointer for the given object name
+     */
+    public static Closure getMethodPointer(Object object, String methodName) {
+        if (object == null) {
+            throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
+        }
+        return new MethodClosure(object, methodName);
+    }
+
+    public static Object unaryMinus(Object value) {
+        if (value instanceof Integer) {
+            Integer number = (Integer) value;
+            return Integer.valueOf(-number.intValue());
+        }
+        if (value instanceof Long) {
+            Long number = (Long) value;
+            return -number;
+        }
+        if (value instanceof BigInteger) {
+            return ((BigInteger) value).negate();
+        }
+        if (value instanceof BigDecimal) {
+            return ((BigDecimal) value).negate();
+        }
+        if (value instanceof Double) {
+            Double number = (Double) value;
+            return -number;
+        }
+        if (value instanceof Float) {
+            Float number = (Float) value;
+            return -number;
+        }
+        if (value instanceof Short) {
+            Short number = (Short) value;
+            return Short.valueOf((short) -number.shortValue());
+        }
+        if (value instanceof Byte) {
+            Byte number = (Byte) value;
+            return Byte.valueOf((byte) -number.byteValue());
+        }
+        if (value instanceof ArrayList) {
+            // value is a list.
+            List newlist = new ArrayList();
+            for (Object o : ((ArrayList) value)) {
+                newlist.add(unaryMinus(o));
+            }
+            return newlist;
+        }
+        return invokeMethod(value, "negative", EMPTY_ARGS);
+    }
+
+    public static Object unaryPlus(Object value) {
+        if (value instanceof Integer ||
+                value instanceof Long ||
+                value instanceof BigInteger ||
+                value instanceof BigDecimal ||
+                value instanceof Double ||
+                value instanceof Float ||
+                value instanceof Short ||
+                value instanceof Byte) {
+            return value;
+        }
+        if (value instanceof ArrayList) {
+            // value is a list.
+            List newlist = new ArrayList();
+            for (Object o : ((ArrayList) value)) {
+                newlist.add(unaryPlus(o));
+            }
+            return newlist;
+        }
+        return invokeMethod(value, "positive", EMPTY_ARGS);
+    }
+
+    /**
+     * Find the right hand regex within the left hand string and return a matcher.
+     *
+     * @param left  string to compare
+     * @param right regular expression to compare the string to
+     */
+    public static Matcher findRegex(Object left, Object right) {
+        String stringToCompare;
+        if (left instanceof String) {
+            stringToCompare = (String) left;
+        } else {
+            stringToCompare = toString(left);
+        }
+        String regexToCompareTo;
+        if (right instanceof String) {
+            regexToCompareTo = (String) right;
+        } else if (right instanceof Pattern) {
+            Pattern pattern = (Pattern) right;
+            return pattern.matcher(stringToCompare);
+        } else {
+            regexToCompareTo = toString(right);
+        }
+        return Pattern.compile(regexToCompareTo).matcher(stringToCompare);
+    }
+
+    /**
+     * Find the right hand regex within the left hand string and return a matcher.
+     *
+     * @param left  string to compare
+     * @param right regular expression to compare the string to
+     */
+    public static boolean matchRegex(Object left, Object right) {
+        if (left == null || right == null) return false;
+        Pattern pattern;
+        if (right instanceof Pattern) {
+            pattern = (Pattern) right;
+        } else {
+            pattern = Pattern.compile(toString(right));
+        }
+        String stringToCompare = toString(left);
+        Matcher matcher = pattern.matcher(stringToCompare);
+        RegexSupport.setLastMatcher(matcher);
+        return matcher.matches();
+    }
+
+    public static Tuple createTuple(Object[] array) {
+        return new Tuple(array);
+    }
+
+    public static SpreadMap spreadMap(Object value) {
+        if (value instanceof Map) {
+            Object[] values = new Object[((Map) value).keySet().size() * 2];
+            int index = 0;
+            for (Object key : ((Map) value).keySet()) {
+                values[index++] = key;
+                values[index++] = ((Map) value).get(key);
+            }
+            return new SpreadMap(values);
+        }
+        throw new SpreadMapEvaluatingException("Cannot spread the map " + typeName(value) + ", value " + value);
+    }
+
+    public static List createList(Object[] values) {
+        List answer = new ArrayList(values.length);
+        answer.addAll(Arrays.asList(values));
+        return answer;
+    }
+
+    public static Map createMap(Object[] values) {
+        Map answer = new LinkedHashMap(values.length / 2);
+        int i = 0;
+        while (i < values.length - 1) {
+            if ((values[i] instanceof SpreadMap) && (values[i + 1] instanceof Map)) {
+                Map smap = (Map) values[i + 1];
+                for (Object e : smap.entrySet()) {
+                    Map.Entry entry = (Map.Entry) e;
+                    answer.put(entry.getKey(), entry.getValue());
+                }
+                i += 2;
+            } else {
+                answer.put(values[i++], values[i++]);
+            }
+        }
+        return answer;
+    }
+
+    public static void assertFailed(Object expression, Object message) {
+        if (message == null || "".equals(message)) {
+            throw new PowerAssertionError(expression.toString());
+        }
+        throw new AssertionError(String.valueOf(message) + ". Expression: " + expression);
+    }
+
+    public static Object runScript(Class scriptClass, String[] args) {
+        Binding context = new Binding(args);
+        Script script = createScript(scriptClass, context);
+        return invokeMethod(script, "run", EMPTY_ARGS);
+    }
+
+    static class NullScript extends Script {
+        public NullScript() { this(new Binding()); }
+        public NullScript(Binding context) { super(context); }
+        public Object run() { return null; }
+    }
+
+    public static Script createScript(Class scriptClass, Binding context) {
+        Script script;
+
+        if (scriptClass == null) {
+            script = new NullScript(context);
+        } else {
+            try {
+                if (Script.class.isAssignableFrom(scriptClass)) {
+                    script = newScript(scriptClass, context);
+                } else {
+                    final GroovyObject object = (GroovyObject) scriptClass.newInstance();
+                    // it could just be a class, so let's wrap it in a Script
+                    // wrapper; though the bindings will be ignored
+                    script = new Script(context) {
+                        public Object run() {
+                            Object argsToPass = EMPTY_MAIN_ARGS;
+                            try {
+                                Object args = getProperty("args");
+                                if (args instanceof String[]) {
+                                    argsToPass = args;
+                                }
+                            } catch (MissingPropertyException e) {
+                                // They'll get empty args since none exist in the context.
+                            }
+                            object.invokeMethod(MAIN_METHOD_NAME, argsToPass);
+                            return null;
+                        }
+                    };
+                    Map variables = context.getVariables();
+                    MetaClass mc = getMetaClass(object);
+                    for (Object o : variables.entrySet()) {
+                        Map.Entry entry = (Map.Entry) o;
+                        String key = entry.getKey().toString();
+                        // assume underscore variables are for the wrapper script
+                        setPropertySafe(key.startsWith("_") ? script : object, mc, key, entry.getValue());
+                    }
+                }
+            } catch (Exception e) {
+                throw new GroovyRuntimeException(
+                        "Failed to create Script instance for class: "
+                                + scriptClass + ". Reason: " + e, e);
+            }
+        }
+        return script;
+    }
+
+    public static Script newScript(Class<?> scriptClass, Binding context) throws InstantiationException, IllegalAccessException, InvocationTargetException {
+        Script script;
+        try {
+            Constructor constructor = scriptClass.getConstructor(Binding.class);
+            script = (Script) constructor.newInstance(context);
+        } catch (NoSuchMethodException e) {
+            // Fallback for non-standard "Script" classes.
+            script = (Script) scriptClass.newInstance();
+            script.setBinding(context);
+        }
+        return script;
+    }
+
+    /**
+     * Sets the properties on the given object
+     */
+    public static void setProperties(Object object, Map map) {
+        MetaClass mc = getMetaClass(object);
+        for (Object o : map.entrySet()) {
+            Map.Entry entry = (Map.Entry) o;
+            String key = entry.getKey().toString();
+            Object value = entry.getValue();
+            setPropertySafe(object, mc, key, value);
+        }
+    }
+
+    private static void setPropertySafe(Object object, MetaClass mc, String key, Object value) {
+        try {
+            mc.setProperty(object, key, value);
+        } catch (MissingPropertyException mpe) {
+            // Ignore
+        } catch (InvokerInvocationException iie) {
+            // GROOVY-5802 IAE for missing properties with classes that extend List
+            Throwable cause = iie.getCause();
+            if (cause == null || !(cause instanceof IllegalArgumentException)) throw iie;
+        }
+    }
+
+    /**
+     * Writes an object to a Writer using Groovy's default representation for the object.
+     */
+    public static void write(Writer out, Object object) throws IOException {
+        if (object instanceof String) {
+            out.write((String) object);
+        } else if (object instanceof Object[]) {
+            out.write(toArrayString((Object[]) object));
+        } else if (object instanceof Map) {
+            out.write(toMapString((Map) object));
+        } else if (object instanceof Collection) {
+            out.write(toListString((Collection) object));
+        } else if (object instanceof Writable) {
+            Writable writable = (Writable) object;
+            writable.writeTo(out);
+        } else if (object instanceof InputStream || object instanceof Reader) {
+            // Copy stream to stream
+            Reader reader;
+            if (object instanceof InputStream) {
+                reader = new InputStreamReader((InputStream) object);
+            } else {
+                reader = (Reader) object;
+            }
+            char[] chars = new char[8192];
+            int i;
+            while ((i = reader.read(chars)) != -1) {
+                out.write(chars, 0, i);
+            }
+            reader.close();
+        } else {
+            out.write(toString(object));
+        }
+    }
+
+    /**
+     * Appends an object to an Appendable using Groovy's default representation for the object.
+     */
+    public static void append(Appendable out, Object object) throws IOException {
+        if (object instanceof String) {
+            out.append((String) object);
+        } else if (object instanceof Object[]) {
+            out.append(toArrayString((Object[]) object));
+        } else if (object instanceof Map) {
+            out.append(toMapString((Map) object));
+        } else if (object instanceof Collection) {
+            out.append(toListString((Collection) object));
+        } else if (object instanceof Writable) {
+            Writable writable = (Writable) object;
+            StringWriter stringWriter = new StringWriter();
+            writable.writeTo(stringWriter);
+            out.append(stringWriter.toString());
+        } else if (object instanceof InputStream || object instanceof Reader) {
+            // Copy stream to stream
+            Reader reader;
+            if (object instanceof InputStream) {
+                reader = new InputStreamReader((InputStream) object);
+            } else {
+                reader = (Reader) object;
+            }
+            char[] chars = new char[8192];
+            int i;
+            while ((i = reader.read(chars)) != -1) {
+                for (int j = 0; j < i; j++) {
+                    out.append(chars[j]);
+                }
+            }
+            reader.close();
+        } else {
+            out.append(toString(object));
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public static Iterator<Object> asIterator(Object o) {
+        return (Iterator) invokeMethod(o, "iterator", EMPTY_ARGS);
+    }
+
+    protected static String format(Object arguments, boolean verbose) {
+        return format(arguments, verbose, -1);
+    }
+
+    public static String format(Object arguments, boolean verbose, int maxSize) {
+        return format(arguments, verbose, maxSize, false);
+    }
+
+    public static String format(Object arguments, boolean verbose, int maxSize, boolean safe) {
+        if (arguments == null) {
+            final NullObject nullObject = NullObject.getNullObject();
+            return (String) nullObject.getMetaClass().invokeMethod(nullObject, "toString", EMPTY_ARGS);
+        }
+        if (arguments.getClass().isArray()) {
+            if (arguments instanceof Object[]) {
+                return toArrayString((Object[]) arguments, verbose, maxSize, safe);
+            }
+            if (arguments instanceof char[]) {
+                return new String((char[]) arguments);
+            }
+            // other primitives
+            return formatCollection(DefaultTypeTransformation.arrayAsCollection(arguments), verbose, maxSize, safe);
+        }
+        if (arguments instanceof Range) {
+            Range range = (Range) arguments;
+            try {
+                if (verbose) {
+                    return range.inspect();
+                } else {
+                    return range.toString();
+                }
+            } catch (RuntimeException ex) {
+                if (!safe) throw ex;
+                return handleFormattingException(arguments, ex);
+            } catch (Exception ex) {
+                if (!safe) throw new GroovyRuntimeException(ex);
+                return handleFormattingException(arguments, ex);
+            }
+        }
+        if (arguments instanceof Collection) {
+            return formatCollection((Collection) arguments, verbose, maxSize, safe);
+        }
+        if (arguments instanceof Map) {
+            return formatMap((Map) arguments, verbose, maxSize, safe);
+        }
+        if (arguments instanceof Element) {
+            try {
+                Method serialize = Class.forName("groovy.xml.XmlUtil").getMethod("serialize", Element.class);
+                return (String) serialize.invoke(null, arguments);
+            } catch (ClassNotFoundException e) {
+                throw new RuntimeException(e);
+            } catch (NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        if (arguments instanceof String) {
+            if (verbose) {
+                String arg = escapeBackslashes((String) arguments)
+                        .replaceAll("'", "\\\\'");    // single quotation mark
+                return "\'" + arg + "\'";
+            } else {
+                return (String) arguments;
+            }
+        }
+        try {
+            // TODO: For GROOVY-2599 do we need something like below but it breaks other things
+//            return (String) invokeMethod(arguments, "toString", EMPTY_ARGS);
+            return arguments.toString();
+        } catch (RuntimeException ex) {
+            if (!safe) throw ex;
+            return handleFormattingException(arguments, ex);
+        } catch (Exception ex) {
+            if (!safe) throw new GroovyRuntimeException(ex);
+            return handleFormattingException(arguments, ex);
+        }
+    }
+
+    public static String escapeBackslashes(String orig) {
+        // must replace backslashes first, as the other replacements add backslashes not to be escaped
+        return orig
+                .replace("\\", "\\\\")           // backslash
+                .replace("\n", "\\n")            // line feed
+                .replaceAll("\\r", "\\\\r")      // carriage return
+                .replaceAll("\\t", "\\\\t")      // tab
+                .replaceAll("\\f", "\\\\f");     // form feed
+    }
+
+    private static String handleFormattingException(Object item, Exception ex) {
+
+        String hash;
+        try {
+            hash = Integer.toHexString(item.hashCode());
+        } catch (Exception ignored) {
+            hash = "????";
+        }
+        return "<" + typeName(item) + "@" + hash + ">";
+    }
+
+    private static String formatMap(Map map, boolean verbose, int maxSize, boolean safe) {
+        if (map.isEmpty()) {
+            return "[:]";
+        }
+        StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * map.size() * 2);
+        buffer.append('[');
+        boolean first = true;
+        for (Object o : map.entrySet()) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(", ");
+            }
+            if (maxSize != -1 && buffer.length() > maxSize) {
+                buffer.append("...");
+                break;
+            }
+            Map.Entry entry = (Map.Entry) o;
+            if (entry.getKey() == map) {
+                buffer.append("(this Map)");
+            } else {
+                buffer.append(format(entry.getKey(), verbose, sizeLeft(maxSize, buffer), safe));
+            }
+            buffer.append(":");
+            if (entry.getValue() == map) {
+                buffer.append("(this Map)");
+            } else {
+                buffer.append(format(entry.getValue(), verbose, sizeLeft(maxSize, buffer), safe));
+            }
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
+    private static int sizeLeft(int maxSize, StringBuilder buffer) {
+        return maxSize == -1 ? maxSize : Math.max(0, maxSize - buffer.length());
+    }
+
+    private static String formatCollection(Collection collection, boolean verbose, int maxSize, boolean safe) {
+        StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * collection.size());
+        buffer.append('[');
+        boolean first = true;
+        for (Object item : collection) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(", ");
+            }
+            if (maxSize != -1 && buffer.length() > maxSize) {
+                buffer.append("...");
+                break;
+            }
+            if (item == collection) {
+                buffer.append("(this Collection)");
+            } else {
+                buffer.append(format(item, verbose, sizeLeft(maxSize, buffer), safe));
+            }
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
+    /**
+     * A helper method to format the arguments types as a comma-separated list.
+     *
+     * @param arguments the type to process
+     * @return the string representation of the type
+     */
+    public static String toTypeString(Object[] arguments) {
+        return toTypeString(arguments, -1);
+    }
+
+    /**
+     * A helper method to format the arguments types as a comma-separated list.
+     *
+     * @param arguments the type to process
+     * @param maxSize   stop after approximately this many characters and append '...', -1 means don't stop
+     * @return the string representation of the type
+     */
+    public static String toTypeString(Object[] arguments, int maxSize) {
+        if (arguments == null) {
+            return "null";
+        }
+        StringBuilder argBuf = new StringBuilder();
+        for (int i = 0; i < arguments.length; i++) {
+            if (maxSize != -1 && argBuf.length() > maxSize) {
+                argBuf.append("...");
+                break;
+            } else {
+                if (i > 0) {
+                    argBuf.append(", ");
+                }
+                argBuf.append(arguments[i] != null ? typeName(arguments[i]) : "null");
+            }
+        }
+        return argBuf.toString();
+    }
+
+    private static Set<String> DEFAULT_IMPORT_PKGS = new HashSet<String>();
+    private static Set<String> DEFAULT_IMPORT_CLASSES = new HashSet<String>();
+    static {
+        for (String pkgName : ResolveVisitor.DEFAULT_IMPORTS) {
+            DEFAULT_IMPORT_PKGS.add(pkgName.substring(0, pkgName.length() - 1));
+        }
+        DEFAULT_IMPORT_CLASSES.add("java.math.BigDecimal");
+        DEFAULT_IMPORT_CLASSES.add("java.math.BigInteger");
+    }
+    /**
+     * Gets the type name
+     *
+     * @param argument the object to find the type for
+     * @return the type name (slightly pretty format taking into account default imports)
+     */
+    private static String typeName(Object argument) {
+        Class<?> aClass = argument.getClass();
+        String pkgName = aClass.getPackage() == null ? "" : aClass.getPackage().getName();
+        boolean useShort = DEFAULT_IMPORT_PKGS.contains(pkgName) || DEFAULT_IMPORT_CLASSES.contains(aClass.getName());
+        return useShort ? aClass.getSimpleName() : aClass.getName();
+    }
+
+    /**
+     * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
+     *
+     * @param arg the map to process
+     * @return the string representation of the map
+     */
+    public static String toMapString(Map arg) {
+        return toMapString(arg, -1);
+    }
+
+    /**
+     * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
+     *
+     * @param arg     the map to process
+     * @param maxSize stop after approximately this many characters and append '...', -1 means don't stop
+     * @return the string representation of the map
+     */
+    public static String toMapString(Map arg, int maxSize) {
+        return formatMap(arg, false, maxSize, false);
+    }
+
+    /**
+     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
+     *
+     * @param arg the collection to process
+     * @return the string representation of the collection
+     */
+    public static String toListString(Collection arg) {
+        return toListString(arg, -1);
+    }
+
+    /**
+     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
+     *
+     * @param arg     the collection to process
+     * @param maxSize stop after approximately this many characters and append '...'
+     * @return the string representation of the collection
+     */
+    public static String toListString(Collection arg, int maxSize) {
+        return toListString(arg, maxSize, false);
+    }
+
+    /**
+     * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
+     *
+     * @param arg     the collection to process
+     * @param maxSize stop after approximately this many characters and append '...', -1 means don't stop
+     * @param safe    whether to use a default object representation for any item in the collection if an exception occurs when generating its toString
+     * @return the string representation of the collection
+     */
+    public static String toListString(Collection arg, int maxSize, boolean safe) {
+        return formatCollection(arg, false, maxSize, safe);
+    }
+
+    /**
+     * A helper method to return the string representation of an array of objects
+     * with brace boundaries "[" and "]".
+     *
+     * @param arguments the array to process
+     * @return the string representation of the array
+     */
+    public static String toArrayString(Object[] arguments) {
+        return toArrayString(arguments, false, -1, false);
+    }
+
+    private static String toArrayString(Object[] array, boolean verbose, int maxSize, boolean safe) {
+        if (array == null) {
+            return "null";
+        }
+        boolean first = true;
+        StringBuilder argBuf = new StringBuilder(array.length);
+        argBuf.append('[');
+
+        for (Object item : array) {
+            if (first) {
+                first = false;
+            } else {
+                argBuf.append(", ");
+            }
+            if (maxSize != -1 && argBuf.length() > maxSize) {
+                argBuf.append("...");
+                break;
+            }
+            if (item == array) {
+                argBuf.append("(this array)");
+            } else {
+                argBuf.append(format(item, verbose, sizeLeft(maxSize, argBuf), safe));
+            }
+        }
+        argBuf.append(']');
+        return argBuf.toString();
+    }
+
+    /**
+     * A helper method to return the string representation of an array of objects
+     * with brace boundaries "[" and "]".
+     *
+     * @param arguments the array to process
+     * @param maxSize   stop after approximately this many characters and append '...'
+     * @param safe      whether to use a default object representation for any item in the array if an exception occurs when generating its toString
+     * @return the string representation of the array
+     */
+    public static String toArrayString(Object[] arguments, int maxSize, boolean safe) {
+        return toArrayString(arguments, false, maxSize, safe);
+    }
+
+    public static List createRange(Object from, Object to, boolean inclusive) {
+        try {
+            return ScriptBytecodeAdapter.createRange(from, to, inclusive);
+        } catch (RuntimeException re) {
+            throw re;
+        } catch (Error e) {
+            throw e;
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    public static Object bitwiseNegate(Object value) {
+        if (value instanceof Integer) {
+            Integer number = (Integer) value;
+            return ~number;
+        }
+        if (value instanceof Long) {
+            Long number = (Long) value;
+            return ~number;
+        }
+        if (value instanceof BigInteger) {
+            return ((BigInteger) value).not();
+        }
+        if (value instanceof String) {
+            // value is a regular expression.
+            return StringGroovyMethods.bitwiseNegate(value.toString());
+        }
+        if (value instanceof GString) {
+            // value is a regular expression.
+            return StringGroovyMethods.bitwiseNegate(value.toString());
+        }
+        if (value instanceof ArrayList) {
+            // value is a list.
+            List newlist = new ArrayList();
+            for (Object o : ((ArrayList) value)) {
+                newlist.add(bitwiseNegate(o));
+            }
+            return newlist;
+        }
+        return invokeMethod(value, "bitwiseNegate", EMPTY_ARGS);
+    }
+
+    public static MetaClassRegistry getMetaRegistry() {
+        return metaRegistry;
+    }
+
+    public static MetaClass getMetaClass(Object object) {
+        if (object instanceof GroovyObject)
+            return ((GroovyObject) object).getMetaClass();
+        else
+            return ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object);
+    }
+
+    public static MetaClass getMetaClass(Class cls) {
+        return metaRegistry.getMetaClass(cls);
+    }
+
+    /**
+     * Invokes the given method on the object.
+     */
+    public static Object invokeMethod(Object object, String methodName, Object arguments) {
+        if (object == null) {
+            object = NullObject.getNullObject();
+            //throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
+        }
+
+        // if the object is a Class, call a static method from that class
+        if (object instanceof Class) {
+            Class theClass = (Class) object;
+            MetaClass metaClass = metaRegistry.getMetaClass(theClass);
+            return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
+        }
+
+        // it's an instance; check if it's a Java one
+        if (!(object instanceof GroovyObject)) {
+            return invokePojoMethod(object, methodName, arguments);
+        }
+
+        // a groovy instance (including builder, closure, ...)
+        return invokePogoMethod(object, methodName, arguments);
+    }
+
+    static Object invokePojoMethod(Object object, String methodName, Object arguments) {
+        MetaClass metaClass = InvokerHelper.getMetaClass(object);
+        return metaClass.invokeMethod(object, methodName, asArray(arguments));
+    }
+
+    static Object invokePogoMethod(Object object, String methodName, Object arguments) {
+        GroovyObject groovy = (GroovyObject) object;
+        boolean intercepting = groovy instanceof GroovyInterceptable;
+        try {
+            // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
+            if (intercepting) {
+                return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
+            }
+            //else try a statically typed method or a GDK method
+            return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments));
+        } catch (MissingMethodException e) {
+            if (e instanceof MissingMethodExecutionFailed) {
+                throw (MissingMethodException) e.getCause();
+            } else if (!intercepting && e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
+                // in case there's nothing else, invoke the object's own invokeMethod()
+                return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    public static Object invokeSuperMethod(Object object, String methodName, Object arguments) {
+        if (object == null) {
+            throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
+        }
+
+        Class theClass = object.getClass();
+
+        MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
+        return metaClass.invokeMethod(object, methodName, asArray(arguments));
+    }
+
+    public static Object invokeStaticMethod(Class type, String method, Object arguments) {
+        MetaClass metaClass = metaRegistry.getMetaClass(type);
+        return metaClass.invokeStaticMethod(type, method, asArray(arguments));
+    }
+
+    public static Object invokeConstructorOf(Class type, Object arguments) {
+        MetaClass metaClass = metaRegistry.getMetaClass(type);
+        return metaClass.invokeConstructor(asArray(arguments));
+    }
+
+    /**
+     * Converts the given object into an array; if its an array then just
+     * cast otherwise wrap it in an array
+     */
+    public static Object[] asArray(Object arguments) {
+
+        if (arguments == null) {
+            return EMPTY_ARGUMENTS;
+        }
+        if (arguments instanceof Object[]) {
+            return (Object[]) arguments;
+        }
+        return new Object[]{arguments};
+    }
+
+    public static Object[] asUnwrappedArray(Object arguments) {
+
+        Object[] args = asArray(arguments);
+
+        for (int i = 0; i < args.length; i++) {
+            if (args[i] instanceof PojoWrapper) {
+                args[i] = ((PojoWrapper) args[i]).unwrap();
+            }
+        }
+
+        return args;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java b/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java
new file mode 100644
index 0000000..2f03126
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/InvokerInvocationException.java
@@ -0,0 +1,44 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.GroovyRuntimeException;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * An exception thrown if a method is called and an exception occurred
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class InvokerInvocationException extends GroovyRuntimeException {
+
+    public InvokerInvocationException(InvocationTargetException e) {
+        super(e.getTargetException());
+    }
+
+    public InvokerInvocationException(Throwable cause) {
+        super(cause);
+    }
+
+    public String getMessage() {
+        Throwable cause = getCause();
+        return (cause==null)?"java.lang.NullPointerException":cause.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java b/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
new file mode 100644
index 0000000..24d74f6
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/IteratorClosureAdapter.java
@@ -0,0 +1,58 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.MetaClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A closure which stores calls in a List so that method calls 
+ * can be iterated over in a 'yield' style way
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class IteratorClosureAdapter<T> extends Closure {
+
+    private final List<T> list = new ArrayList<T>();
+    private MetaClass metaClass = InvokerHelper.getMetaClass(getClass());
+    
+    public IteratorClosureAdapter(Object delegate) {
+        super(delegate);
+    }
+
+    public MetaClass getMetaClass() {
+        return metaClass;
+    }
+
+    public void setMetaClass(MetaClass metaClass) {
+        this.metaClass = metaClass;
+    }
+    
+    public List<T> asList() {
+        return list;
+    }
+
+    protected Object doCall(T argument) {
+        list.add(argument);
+        return null;
+    }
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java b/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java
new file mode 100644
index 0000000..ca8030f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/BytecodeExpression.java
@@ -0,0 +1,55 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * Represents some custom bytecode generation by the compiler
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public abstract class BytecodeExpression extends Expression {
+    public static final BytecodeExpression NOP = new BytecodeExpression() {
+        public void visit(MethodVisitor visitor) {
+            //do nothing             
+        }
+    };
+
+    public BytecodeExpression() {
+    }
+    
+    public BytecodeExpression(ClassNode type) {
+        super.setType(type);
+    }
+    
+    public void visit(GroovyCodeVisitor visitor) {
+        visitor.visitBytecodeExpression(this);
+    }
+
+    public abstract void visit(MethodVisitor mv);
+
+    public Expression transformExpression(ExpressionTransformer transformer) {
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java b/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java
new file mode 100644
index 0000000..e390654
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/BytecodeInstruction.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * Helper class used by the class generator. Usually
+ * an inner class is produced, that contains bytecode
+ * creation code in the visit method.
+ *
+ * @author Jochen Theodorou
+ */
+public abstract class BytecodeInstruction {
+    public abstract void visit(MethodVisitor mv);
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java b/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java
new file mode 100644
index 0000000..c5a6645
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/BytecodeSequence.java
@@ -0,0 +1,81 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.stmt.Statement;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This class represents a sequence of BytecodeInstructions
+ * or ASTNodes. The evaluation is depending on the type of 
+ * the visitor.
+ * 
+ * @see BytecodeInstruction
+ * @see ASTNode
+ */
+
+public class BytecodeSequence extends Statement {
+    private final List<BytecodeInstruction> instructions;
+
+    public BytecodeSequence(List instructions) {
+        this.instructions = instructions;
+    }
+    
+    public BytecodeSequence(BytecodeInstruction instruction) {
+        this.instructions = new ArrayList(1);
+        this.instructions.add(instruction);
+    }
+
+    /**
+     * Delegates to the visit method used for this class.
+     * If the visitor is a ClassGenerator, then 
+     * {@link ClassGenerator#visitBytecodeSequence(BytecodeSequence)}
+     * is called with this instance. If the visitor is no 
+     * ClassGenerator, then this method will call visit on
+     * each ASTNode element sorted by this class. If one
+     * element is a BytecodeInstruction, then it will be skipped
+     * as it is no ASTNode. 
+     * 
+     * @param visitor the visitor
+     * @see ClassGenerator
+     */
+    public void visit(GroovyCodeVisitor visitor) {
+        if (visitor instanceof ClassGenerator) {
+            ClassGenerator gen = (ClassGenerator) visitor;
+            gen.visitBytecodeSequence(this);
+            return;
+        }
+        for (Iterator iterator = instructions.iterator(); iterator.hasNext();) {
+            Object part = (Object) iterator.next();
+            if (part instanceof ASTNode) {
+                ((ASTNode)part).visit(visitor);
+            }
+        }
+    }
+
+    public List getInstructions() {
+        return instructions;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
new file mode 100644
index 0000000..b05f6bd
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -0,0 +1,746 @@
+/*
+ *  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.classgen;
+
+import org.apache.groovy.ast.tools.ClassNodeUtils;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.Variable;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.MapEntryExpression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.trait.Traits;
+
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+import static java.lang.reflect.Modifier.isAbstract;
+import static java.lang.reflect.Modifier.isFinal;
+import static java.lang.reflect.Modifier.isInterface;
+import static java.lang.reflect.Modifier.isNative;
+import static java.lang.reflect.Modifier.isPrivate;
+import static java.lang.reflect.Modifier.isStatic;
+import static java.lang.reflect.Modifier.isStrict;
+import static java.lang.reflect.Modifier.isSynchronized;
+import static java.lang.reflect.Modifier.isTransient;
+import static java.lang.reflect.Modifier.isVolatile;
+import static org.codehaus.groovy.ast.ClassHelper.VOID_TYPE;
+import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
+import static org.objectweb.asm.Opcodes.ACC_FINAL;
+import static org.objectweb.asm.Opcodes.ACC_INTERFACE;
+import static org.objectweb.asm.Opcodes.ACC_NATIVE;
+import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
+import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_STATIC;
+import static org.objectweb.asm.Opcodes.ACC_STRICT;
+import static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED;
+import static org.objectweb.asm.Opcodes.ACC_TRANSIENT;
+import static org.objectweb.asm.Opcodes.ACC_VOLATILE;
+/**
+ * Checks that a class satisfies various conditions including:
+ * <ul>
+ *     <li>Incorrect class or method access modifiers</li>
+ *     <li>No abstract methods appear in a non-abstract class</li>
+ *     <li>Existence and correct visibility for inherited members</li>
+ *     <li>Invalid attempts to override final members</li>
+ * </ul>
+ */
+public class ClassCompletionVerifier extends ClassCodeVisitorSupport {
+    private static final String[] INVALID_NAME_CHARS = {".", ":", "/", ";", "[", "<", ">"};
+    // the groovy.compiler.strictNames system property is experimental and may change default value or be removed in a future version of Groovy
+    private final boolean strictNames = Boolean.parseBoolean(System.getProperty("groovy.compiler.strictNames", "false"));
+    private ClassNode currentClass;
+    private final SourceUnit source;
+    private boolean inConstructor = false;
+    private boolean inStaticConstructor = false;
+
+    public ClassCompletionVerifier(SourceUnit source) {
+        this.source = source;
+    }
+
+    public ClassNode getClassNode() {
+        return currentClass;
+    }
+
+    public void visitClass(ClassNode node) {
+        ClassNode oldClass = currentClass;
+        currentClass = node;
+        checkImplementsAndExtends(node);
+        if (source != null && !source.getErrorCollector().hasErrors()) {
+            checkClassForIncorrectModifiers(node);
+            checkInterfaceMethodVisibility(node);
+            checkAbstractMethodVisibility(node);
+            checkClassForOverwritingFinal(node);
+            checkMethodsForIncorrectModifiers(node);
+            checkMethodsForIncorrectName(node);
+            checkMethodsForWeakerAccess(node);
+            checkMethodsForOverridingFinal(node);
+            checkNoAbstractMethodsNonabstractClass(node);
+            checkClassExtendsAllSelfTypes(node);
+            checkNoStaticMethodWithSameSignatureAsNonStatic(node);
+            checkGenericsUsage(node, node.getUnresolvedInterfaces());
+            checkGenericsUsage(node, node.getUnresolvedSuperClass());
+        }
+        super.visitClass(node);
+        currentClass = oldClass;
+    }
+
+    private void checkNoStaticMethodWithSameSignatureAsNonStatic(final ClassNode node) {
+        ClassNode parent = node.getSuperClass();
+        Map<String, MethodNode> result;
+        // start with methods from the parent if any
+        if (parent != null) {
+            result = parent.getDeclaredMethodsMap();
+        } else {
+            result = new HashMap<String, MethodNode>();
+        }
+        // add in unimplemented abstract methods from the interfaces
+        ClassNodeUtils.addDeclaredMethodsFromInterfaces(node, result);
+        for (MethodNode methodNode : node.getMethods()) {
+            MethodNode mn = result.get(methodNode.getTypeDescriptor());
+            if (mn != null && (mn.isStatic() ^ methodNode.isStatic()) && !methodNode.isStaticConstructor()) {
+                if (!mn.isAbstract()) continue;
+                ClassNode declaringClass = mn.getDeclaringClass();
+                ClassNode cn = declaringClass.getOuterClass();
+                if (cn == null && declaringClass.isResolved()) {
+                    // in case of a precompiled class, the outerclass is unknown
+                    Class typeClass = declaringClass.getTypeClass();
+                    typeClass = typeClass.getEnclosingClass();
+                    if (typeClass != null) {
+                        cn = ClassHelper.make(typeClass);
+                    }
+                }
+                if (cn == null || !Traits.isTrait(cn)) {
+                    ASTNode errorNode = methodNode;
+                    String name = mn.getName();
+                    if (errorNode.getLineNumber() == -1) {
+                        // try to get a better error message location based on the property
+                        for (PropertyNode propertyNode : node.getProperties()) {
+                            if (name.startsWith("set") || name.startsWith("get") || name.startsWith("is")) {
+                                String propName = Verifier.capitalize(propertyNode.getField().getName());
+                                String shortName = name.substring(name.startsWith("is") ? 2 : 3);
+                                if (propName.equals(shortName)) {
+                                    errorNode = propertyNode;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    addError("The " + getDescription(methodNode) + " is already defined in " + getDescription(node) +
+                            ". You cannot have both a static and an instance method with the same signature", errorNode);
+                }
+            }
+            result.put(methodNode.getTypeDescriptor(), methodNode);
+        }
+    }
+
+    private void checkInterfaceMethodVisibility(ClassNode node) {
+        if (!node.isInterface()) return;
+        for (MethodNode method : node.getMethods()) {
+            if (method.isPrivate()) {
+                addError("Method '" + method.getName() + "' is private but should be public in " + getDescription(currentClass) + ".", method);
+            } else if (method.isProtected()) {
+                addError("Method '" + method.getName() + "' is protected but should be public in " + getDescription(currentClass) + ".", method);
+            }
+        }
+    }
+
+    private void checkAbstractMethodVisibility(ClassNode node) {
+        // we only do check abstract classes (including enums), no interfaces or non-abstract classes
+        if (!isAbstract(node.getModifiers()) || isInterface(node.getModifiers())) return;
+
+        List<MethodNode> abstractMethods = node.getAbstractMethods();
+        if (abstractMethods == null || abstractMethods.isEmpty()) return;
+
+        for (MethodNode method : abstractMethods) {
+            if (method.isPrivate()) {
+                addError("Method '" + method.getName() + "' from " + getDescription(node) +
+                        " must not be private as it is declared as an abstract method.", method);
+            }
+        }
+    }
+
+    private void checkNoAbstractMethodsNonabstractClass(ClassNode node) {
+        if (isAbstract(node.getModifiers())) return;
+        List<MethodNode> abstractMethods = node.getAbstractMethods();
+        if (abstractMethods == null) return;
+        for (MethodNode method : abstractMethods) {
+            MethodNode sameArgsMethod = node.getMethod(method.getName(), method.getParameters());
+            if (sameArgsMethod==null || method.getReturnType().equals(sameArgsMethod.getReturnType())) {
+                addError("Can't have an abstract method in a non-abstract class." +
+                        " The " + getDescription(node) + " must be declared abstract or" +
+                        " the " + getDescription(method) + " must be implemented.", node);
+            } else {
+                addError("Abstract "+getDescription(method)+" is not implemented but a " +
+                                "method of the same name but different return type is defined: "+
+                                (sameArgsMethod.isStatic()?"static ":"")+
+                                getDescription(sameArgsMethod), method
+                );
+            }
+        }
+    }
+
+    private void checkClassExtendsAllSelfTypes(ClassNode node) {
+        int modifiers = node.getModifiers();
+        if (!isInterface(modifiers)) {
+            for (ClassNode anInterface : GeneralUtils.getInterfacesAndSuperInterfaces(node)) {
+                if (Traits.isTrait(anInterface)) {
+                    LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<ClassNode>();
+                    for (ClassNode type : Traits.collectSelfTypes(anInterface, selfTypes, true, false)) {
+                        if (type.isInterface() && !node.implementsInterface(type)) {
+                            addError(getDescription(node)
+                                    + " implements " + getDescription(anInterface)
+                                    + " but does not implement self type " + getDescription(type),
+                                    anInterface);
+                        } else if (!type.isInterface() && !node.isDerivedFrom(type)) {
+                            addError(getDescription(node)
+                                            + " implements " + getDescription(anInterface)
+                                            + " but does not extend self type " + getDescription(type),
+                                    anInterface);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void checkClassForIncorrectModifiers(ClassNode node) {
+        checkClassForAbstractAndFinal(node);
+        checkClassForOtherModifiers(node);
+    }
+
+    private void checkClassForAbstractAndFinal(ClassNode node) {
+        if (!isAbstract(node.getModifiers())) return;
+        if (!isFinal(node.getModifiers())) return;
+        if (node.isInterface()) {
+            addError("The " + getDescription(node) + " must not be final. It is by definition abstract.", node);
+        } else {
+            addError("The " + getDescription(node) + " must not be both final and abstract.", node);
+        }
+    }
+
+    private void checkClassForOtherModifiers(ClassNode node) {
+        checkClassForModifier(node, isTransient(node.getModifiers()), "transient");
+        checkClassForModifier(node, isVolatile(node.getModifiers()), "volatile");
+        checkClassForModifier(node, isNative(node.getModifiers()), "native");
+        if (!(node instanceof InnerClassNode)) {
+            checkClassForModifier(node, isStatic(node.getModifiers()), "static");
+            checkClassForModifier(node, isPrivate(node.getModifiers()), "private");
+        }
+        // don't check synchronized here as it overlaps with ACC_SUPER
+    }
+
+    private void checkMethodForModifier(MethodNode node, boolean condition, String modifierName) {
+        if (!condition) return;
+        addError("The " + getDescription(node) + " has an incorrect modifier " + modifierName + ".", node);
+    }
+
+    private void checkClassForModifier(ClassNode node, boolean condition, String modifierName) {
+        if (!condition) return;
+        addError("The " + getDescription(node) + " has an incorrect modifier " + modifierName + ".", node);
+    }
+
+    private static String getDescription(ClassNode node) {
+        return (node.isInterface() ? (Traits.isTrait(node)?"trait":"interface") : "class") + " '" + node.getName() + "'";
+    }
+
+    private static String getDescription(MethodNode node) {
+        return "method '" + node.getTypeDescriptor() + "'";
+    }
+
+    private static String getDescription(FieldNode node) {
+        return "field '" + node.getName() + "'";
+    }
+
+    private static String getDescription(Parameter node) {
+        return "parameter '" + node.getName() + "'";
+    }
+
+    private void checkAbstractDeclaration(MethodNode methodNode) {
+        if (!methodNode.isAbstract()) return;
+        if (isAbstract(currentClass.getModifiers())) return;
+        addError("Can't have an abstract method in a non-abstract class." +
+                " The " + getDescription(currentClass) + " must be declared abstract or the method '" +
+                methodNode.getTypeDescriptor() + "' must not be abstract.", methodNode);
+    }
+
+    private void checkClassForOverwritingFinal(ClassNode cn) {
+        ClassNode superCN = cn.getSuperClass();
+        if (superCN == null) return;
+        if (!isFinal(superCN.getModifiers())) return;
+        String msg = "You are not allowed to overwrite the final " + getDescription(superCN) + ".";
+        addError(msg, cn);
+    }
+
+    private void checkImplementsAndExtends(ClassNode node) {
+        ClassNode cn = node.getSuperClass();
+        if (cn.isInterface() && !node.isInterface()) {
+            addError("You are not allowed to extend the " + getDescription(cn) + ", use implements instead.", node);
+        }
+        for (ClassNode anInterface : node.getInterfaces()) {
+            cn = anInterface;
+            if (!cn.isInterface()) {
+                addError("You are not allowed to implement the " + getDescription(cn) + ", use extends instead.", node);
+            }
+        }
+    }
+
+    private void checkMethodsForIncorrectName(ClassNode cn) {
+        if (!strictNames) return;
+        List<MethodNode> methods = cn.getAllDeclaredMethods();
+        for (MethodNode mNode : methods) {
+            String name = mNode.getName();
+            if (name.equals("<init>") || name.equals("<clinit>")) continue;
+            // Groovy allows more characters than Character.isValidJavaIdentifier() would allow
+            // if we find a good way to encode special chars we could remove (some of) these checks
+            for (String ch : INVALID_NAME_CHARS) {
+                if (name.contains(ch)) {
+                    addError("You are not allowed to have '" + ch + "' in a method name", mNode);
+                }
+            }
+        }
+    }
+
+    private void checkMethodsForIncorrectModifiers(ClassNode cn) {
+        if (!cn.isInterface()) return;
+        for (MethodNode method : cn.getMethods()) {
+            if (method.isFinal()) {
+                addError("The " + getDescription(method) + " from " + getDescription(cn) +
+                        " must not be final. It is by definition abstract.", method);
+            }
+            if (method.isStatic() && !isConstructor(method)) {
+                addError("The " + getDescription(method) + " from " + getDescription(cn) +
+                        " must not be static. Only fields may be static in an interface.", method);
+            }
+        }
+    }
+
+    private void checkMethodsForWeakerAccess(ClassNode cn) {
+        for (MethodNode method : cn.getMethods()) {
+            checkMethodForWeakerAccessPrivileges(method, cn);
+        }
+    }
+
+    private static boolean isConstructor(MethodNode method) {
+        return method.getName().equals("<clinit>");
+    }
+
+    private void checkMethodsForOverridingFinal(ClassNode cn) {
+        for (MethodNode method : cn.getMethods()) {
+            Parameter[] params = method.getParameters();
+            for (MethodNode superMethod : cn.getSuperClass().getMethods(method.getName())) {
+                Parameter[] superParams = superMethod.getParameters();
+                if (!hasEqualParameterTypes(params, superParams)) continue;
+                if (!superMethod.isFinal()) break;
+                addInvalidUseOfFinalError(method, params, superMethod.getDeclaringClass());
+                return;
+            }
+        }
+    }
+
+    private void addInvalidUseOfFinalError(MethodNode method, Parameter[] parameters, ClassNode superCN) {
+        StringBuilder msg = new StringBuilder();
+        msg.append("You are not allowed to override the final method ").append(method.getName());
+        appendParamsDescription(parameters, msg);
+        msg.append(" from ").append(getDescription(superCN));
+        msg.append(".");
+        addError(msg.toString(), method);
+    }
+
+    private void appendParamsDescription(Parameter[] parameters, StringBuilder msg) {
+        msg.append("(");
+        boolean needsComma = false;
+        for (Parameter parameter : parameters) {
+            if (needsComma) {
+                msg.append(",");
+            } else {
+                needsComma = true;
+            }
+            msg.append(parameter.getType());
+        }
+        msg.append(")");
+    }
+
+    private void addWeakerAccessError(ClassNode cn, MethodNode method, Parameter[] parameters, MethodNode superMethod) {
+        StringBuilder msg = new StringBuilder();
+        msg.append(method.getName());
+        appendParamsDescription(parameters, msg);
+        msg.append(" in ");
+        msg.append(cn.getName());
+        msg.append(" cannot override ");
+        msg.append(superMethod.getName());
+        msg.append(" in ");
+        msg.append(superMethod.getDeclaringClass().getName());
+        msg.append("; attempting to assign weaker access privileges; was ");
+        msg.append(superMethod.isPublic() ? "public" : "protected");
+        addError(msg.toString(), method);
+    }
+
+    private static boolean hasEqualParameterTypes(Parameter[] first, Parameter[] second) {
+        if (first.length != second.length) return false;
+        for (int i = 0; i < first.length; i++) {
+            String ft = first[i].getType().getName();
+            String st = second[i].getType().getName();
+            if (ft.equals(st)) continue;
+            return false;
+        }
+        return true;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return source;
+    }
+
+    public void visitMethod(MethodNode node) {
+        inConstructor = false;
+        inStaticConstructor = node.isStaticConstructor();
+        checkAbstractDeclaration(node);
+        checkRepetitiveMethod(node);
+        checkOverloadingPrivateAndPublic(node);
+        checkMethodModifiers(node);
+        checkGenericsUsage(node, node.getParameters());
+        checkGenericsUsage(node, node.getReturnType());
+        for (Parameter param : node.getParameters()) {
+            if (param.getType().equals(VOID_TYPE)) {
+                addError("The " + getDescription(param) + " in " +  getDescription(node) + " has invalid type void", param);
+            }
+        }
+        super.visitMethod(node);
+    }
+
+    private void checkMethodModifiers(MethodNode node) {
+        // don't check volatile here as it overlaps with ACC_BRIDGE
+        // additional modifiers not allowed for interfaces
+        if ((this.currentClass.getModifiers() & ACC_INTERFACE) != 0) {
+            checkMethodForModifier(node, isStrict(node.getModifiers()), "strictfp");
+            checkMethodForModifier(node, isSynchronized(node.getModifiers()), "synchronized");
+            checkMethodForModifier(node, isNative(node.getModifiers()), "native");
+        }
+    }
+
+    private void checkMethodForWeakerAccessPrivileges(MethodNode mn, ClassNode cn) {
+        if (mn.isPublic()) return;
+        Parameter[] params = mn.getParameters();
+        for (MethodNode superMethod : cn.getSuperClass().getMethods(mn.getName())) {
+            Parameter[] superParams = superMethod.getParameters();
+            if (!hasEqualParameterTypes(params, superParams)) continue;
+            if ((mn.isPrivate() && !superMethod.isPrivate()) ||
+                    (mn.isProtected() && superMethod.isPublic())) {
+                addWeakerAccessError(cn, mn, params, superMethod);
+                return;
+            }
+        }
+    }
+
+    private void checkOverloadingPrivateAndPublic(MethodNode node) {
+        if (isConstructor(node)) return;
+        boolean hasPrivate = node.isPrivate();
+        boolean hasPublic = node.isPublic();
+        for (MethodNode method : currentClass.getMethods(node.getName())) {
+            if (method == node) continue;
+            if (!method.getDeclaringClass().equals(node.getDeclaringClass())) continue;
+            if (method.isPublic() || method.isProtected()) {
+                hasPublic = true;
+            } else {
+                hasPrivate = true;
+            }
+            if (hasPrivate && hasPublic) break;
+        }
+        if (hasPrivate && hasPublic) {
+            addError("Mixing private and public/protected methods of the same name causes multimethods to be disabled and is forbidden to avoid surprising behaviour. Renaming the private methods will solve the problem.", node);
+        }
+    }
+
+    private void checkRepetitiveMethod(MethodNode node) {
+        if (isConstructor(node)) return;
+        for (MethodNode method : currentClass.getMethods(node.getName())) {
+            if (method == node) continue;
+            if (!method.getDeclaringClass().equals(node.getDeclaringClass())) continue;
+            Parameter[] p1 = node.getParameters();
+            Parameter[] p2 = method.getParameters();
+            if (p1.length != p2.length) continue;
+            addErrorIfParamsAndReturnTypeEqual(p2, p1, node, method);
+        }
+    }
+
+    private void addErrorIfParamsAndReturnTypeEqual(Parameter[] p2, Parameter[] p1,
+                                                    MethodNode node, MethodNode element) {
+        boolean isEqual = true;
+        for (int i = 0; i < p2.length; i++) {
+            isEqual &= p1[i].getType().equals(p2[i].getType());
+            if (!isEqual) break;
+        }
+        isEqual &= node.getReturnType().equals(element.getReturnType());
+        if (isEqual) {
+            addError("Repetitive method name/signature for " + getDescription(node) +
+                    " in " + getDescription(currentClass) + ".", node);
+        }
+    }
+
+    public void visitField(FieldNode node) {
+        if (currentClass.getDeclaredField(node.getName()) != node) {
+            addError("The " + getDescription(node) + " is declared multiple times.", node);
+        }
+        checkInterfaceFieldModifiers(node);
+        checkGenericsUsage(node, node.getType());
+        if (node.getType().equals(VOID_TYPE)) {
+            addError("The " + getDescription(node) + " has invalid type void", node);
+        }
+        super.visitField(node);
+    }
+
+    public void visitProperty(PropertyNode node) {
+        checkDuplicateProperties(node);
+        checkGenericsUsage(node, node.getType());
+        super.visitProperty(node);
+    }
+
+    private void checkDuplicateProperties(PropertyNode node) {
+        ClassNode cn = node.getDeclaringClass();
+        String name = node.getName();
+        String getterName = "get" + MetaClassHelper.capitalize(name);
+        if (Character.isUpperCase(name.charAt(0))) {
+            for (PropertyNode propNode : cn.getProperties()) {
+                String otherName = propNode.getField().getName();
+                String otherGetterName = "get" + MetaClassHelper.capitalize(otherName);
+                if (node != propNode && getterName.equals(otherGetterName)) {
+                    String msg = "The field " + name + " and " + otherName + " on the class " +
+                            cn.getName() + " will result in duplicate JavaBean properties, which is not allowed";
+                    addError(msg, node);
+                }
+            }
+        }
+    }
+
+    private void checkInterfaceFieldModifiers(FieldNode node) {
+        if (!currentClass.isInterface()) return;
+        if ((node.getModifiers() & (ACC_PUBLIC | ACC_STATIC | ACC_FINAL)) == 0 ||
+                (node.getModifiers() & (ACC_PRIVATE | ACC_PROTECTED)) != 0) {
+            addError("The " + getDescription(node) + " is not 'public static final' but is defined in " +
+                    getDescription(currentClass) + ".", node);
+        }
+    }
+
+    public void visitBinaryExpression(BinaryExpression expression) {
+        if (expression.getOperation().getType() == Types.LEFT_SQUARE_BRACKET &&
+                expression.getRightExpression() instanceof MapEntryExpression) {
+            addError("You tried to use a map entry for an index operation, this is not allowed. " +
+                    "Maybe something should be set in parentheses or a comma is missing?",
+                    expression.getRightExpression());
+        }
+        super.visitBinaryExpression(expression);
+
+        if (Types.isAssignment(expression.getOperation().getType())) {
+            checkFinalFieldAccess(expression.getLeftExpression());
+            checkSuperOrThisOnLHS(expression.getLeftExpression());
+        }
+    }
+
+    private void checkSuperOrThisOnLHS(Expression expression) {
+        if (!(expression instanceof VariableExpression)) return;
+        VariableExpression ve = (VariableExpression) expression;
+        if (ve.isThisExpression()) {
+            addError("cannot have 'this' as LHS of an assignment", expression);
+        } else if (ve.isSuperExpression()) {
+            addError("cannot have 'super' as LHS of an assignment", expression);
+        }
+    }
+
+    private void checkFinalFieldAccess(Expression expression) {
+        if (!(expression instanceof VariableExpression) && !(expression instanceof PropertyExpression)) return;
+        Variable v = null;
+        if (expression instanceof VariableExpression) {
+            VariableExpression ve = (VariableExpression) expression;
+            v = ve.getAccessedVariable();
+        } else {
+            PropertyExpression propExp = ((PropertyExpression) expression);
+            Expression objectExpression = propExp.getObjectExpression();
+            if (objectExpression instanceof VariableExpression) {
+                VariableExpression varExp = (VariableExpression) objectExpression;
+                if (varExp.isThisExpression()) {
+                    v = currentClass.getDeclaredField(propExp.getPropertyAsString());
+                }
+            }
+        }
+        if (v instanceof FieldNode) {
+            FieldNode fn = (FieldNode) v;
+
+            /*
+             *  if it is static final but not accessed inside a static constructor, or,
+             *  if it is an instance final but not accessed inside a instance constructor, it is an error
+             */
+            boolean isFinal = fn.isFinal();
+            boolean isStatic = fn.isStatic();
+            boolean error = isFinal && ((isStatic && !inStaticConstructor) || (!isStatic && !inConstructor));
+
+            if (error) addError("cannot modify" + (isStatic ? " static" : "") + " final field '" + fn.getName() +
+                    "' outside of " + (isStatic ? "static initialization block." : "constructor."), expression);
+        }
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+        inConstructor = true;
+        inStaticConstructor = node.isStaticConstructor();
+        checkGenericsUsage(node, node.getParameters());
+        super.visitConstructor(node);
+    }
+
+    public void visitCatchStatement(CatchStatement cs) {
+        if (!(cs.getExceptionType().isDerivedFrom(ClassHelper.make(Throwable.class)))) {
+            addError("Catch statement parameter type is not a subclass of Throwable.", cs);
+        }
+        super.visitCatchStatement(cs);
+    }
+
+    public void visitMethodCallExpression(MethodCallExpression mce) {
+        super.visitMethodCallExpression(mce);
+        Expression aexp = mce.getArguments();
+        if (aexp instanceof TupleExpression) {
+            TupleExpression arguments = (TupleExpression) aexp;
+            for (Expression e : arguments.getExpressions()) {
+                checkForInvalidDeclaration(e);
+            }
+        } else {
+            checkForInvalidDeclaration(aexp);
+        }
+    }
+
+    @Override
+    public void visitDeclarationExpression(DeclarationExpression expression) {
+        super.visitDeclarationExpression(expression);
+        if (expression.isMultipleAssignmentDeclaration()) return;
+        checkInvalidDeclarationModifier(expression, ACC_ABSTRACT, "abstract");
+        checkInvalidDeclarationModifier(expression, ACC_NATIVE, "native");
+        checkInvalidDeclarationModifier(expression, ACC_PRIVATE, "private");
+        checkInvalidDeclarationModifier(expression, ACC_PROTECTED, "protected");
+        checkInvalidDeclarationModifier(expression, ACC_PUBLIC, "public");
+        checkInvalidDeclarationModifier(expression, ACC_STATIC, "static");
+        checkInvalidDeclarationModifier(expression, ACC_STRICT, "strictfp");
+        checkInvalidDeclarationModifier(expression, ACC_SYNCHRONIZED, "synchronized");
+        checkInvalidDeclarationModifier(expression, ACC_TRANSIENT, "transient");
+        checkInvalidDeclarationModifier(expression, ACC_VOLATILE, "volatile");
+        if (expression.getVariableExpression().getOriginType().equals(VOID_TYPE)) {
+            addError("The variable '" + expression.getVariableExpression().getName() + "' has invalid type void", expression);
+        }
+    }
+
+    private void checkInvalidDeclarationModifier(DeclarationExpression expression, int modifier, String modName) {
+        if ((expression.getVariableExpression().getModifiers() & modifier) != 0) {
+            addError("Modifier '" + modName + "' not allowed here.", expression);
+        }
+    }
+
+    private void checkForInvalidDeclaration(Expression exp) {
+        if (!(exp instanceof DeclarationExpression)) return;
+        addError("Invalid use of declaration inside method call.", exp);
+    }
+
+    public void visitConstantExpression(ConstantExpression expression) {
+        super.visitConstantExpression(expression);
+        checkStringExceedingMaximumLength(expression);
+    }
+
+    public void visitGStringExpression(GStringExpression expression) {
+        super.visitGStringExpression(expression);
+        for (ConstantExpression ce : expression.getStrings()) {
+            checkStringExceedingMaximumLength(ce);
+        }
+    }
+
+    private void checkStringExceedingMaximumLength(ConstantExpression expression) {
+        Object value = expression.getValue();
+        if (value instanceof String) {
+            String s = (String) value;
+            if (s.length() > 65535) {
+                addError("String too long. The given string is " + s.length() + " Unicode code units long, but only a maximum of 65535 is allowed.", expression);
+            }
+        }
+    }
+
+    private void checkGenericsUsage(ASTNode ref, ClassNode[] nodes) {
+        for (ClassNode node : nodes) {
+            checkGenericsUsage(ref, node);
+        }
+    }
+    
+    private void checkGenericsUsage(ASTNode ref, Parameter[] params) {
+        for (Parameter p : params) {
+            checkGenericsUsage(ref, p.getType());
+        }
+    }
+    
+    private void checkGenericsUsage(ASTNode ref, ClassNode node) {
+        if (node.isArray()) {
+            checkGenericsUsage(ref, node.getComponentType());
+        } else if (!node.isRedirectNode() && node.isUsingGenerics()) {
+            addError(   
+                    "A transform used a generics containing ClassNode "+ node + " " +
+                    "for "+getRefDescriptor(ref) + 
+                    "directly. You are not supposed to do this. " +
+                    "Please create a new ClassNode referring to the old ClassNode " +
+                    "and use the new ClassNode instead of the old one. Otherwise " +
+                    "the compiler will create wrong descriptors and a potential " +
+                    "NullPointerException in TypeResolver in the OpenJDK. If this is " +
+                    "not your own doing, please report this bug to the writer of the " +
+                    "transform.",
+                    ref);
+        }
+    }
+
+    private static String getRefDescriptor(ASTNode ref) {
+        if (ref instanceof FieldNode) {
+            FieldNode f = (FieldNode) ref;
+            return "the field "+f.getName()+" ";
+        } else if (ref instanceof PropertyNode) {
+            PropertyNode p = (PropertyNode) ref;
+            return "the property "+p.getName()+" ";
+        } else if (ref instanceof ConstructorNode) {
+            return "the constructor "+ref.getText()+" ";
+        } else if (ref instanceof MethodNode) {
+            return "the method "+ref.getText()+" ";
+        } else if (ref instanceof ClassNode) {
+            return "the super class "+ref+" ";
+        }
+        return "<unknown with class "+ref.getClass()+"> ";
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java
new file mode 100644
index 0000000..2ed8661
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassGenerator.java
@@ -0,0 +1,48 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.control.SourceUnit;
+import org.objectweb.asm.Opcodes;
+
+import java.util.LinkedList;
+
+/**
+ * Abstract base class for generator of Java class versions of Groovy AST classes
+ *
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ * @author Russel Winder
+ */
+public abstract class ClassGenerator extends ClassCodeVisitorSupport implements Opcodes {
+    // inner classes created while generating bytecode
+    protected LinkedList<ClassNode> innerClasses = new LinkedList<ClassNode>();
+
+    public LinkedList<ClassNode> getInnerClasses() {
+        return innerClasses;
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return null;
+    }
+
+    public void visitBytecodeSequence(BytecodeSequence bytecodeSequence) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java b/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java
new file mode 100644
index 0000000..bce3448
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/ClassGeneratorException.java
@@ -0,0 +1,36 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.classgen;
+
+/**
+ * An exception thrown by the class generator
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ClassGeneratorException extends RuntimeException {
+
+    public ClassGeneratorException(String message) {
+        super(message);
+    }
+
+    public ClassGeneratorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java
new file mode 100644
index 0000000..15ade40
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/DummyClassGenerator.java
@@ -0,0 +1,180 @@
+/*
+ *  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.classgen;
+
+import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.Iterator;
+
+/**
+ * To generate a class that has all the fields and methods, except that fields are not initialized
+ * and methods are empty. It's intended for being used as a place holder during code generation
+ * of reference to the "this" class itself.
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ * @author <a href="mailto:b55r@sina.com">Bing Ran</a>
+ */
+public class DummyClassGenerator extends ClassGenerator {
+
+    private final ClassVisitor cv;
+    private MethodVisitor mv;
+    private final GeneratorContext context;
+
+    // current class details
+    private ClassNode classNode;
+    private String internalClassName;
+    private String internalBaseClassName;
+
+
+    public DummyClassGenerator(
+            GeneratorContext context,
+            ClassVisitor classVisitor,
+            ClassLoader classLoader,
+            String sourceFile) {
+        this.context = context;
+        this.cv = classVisitor;
+    }
+
+    // GroovyClassVisitor interface
+    //-------------------------------------------------------------------------
+    public void visitClass(ClassNode classNode) {
+        try {
+            this.classNode = classNode;
+            this.internalClassName = BytecodeHelper.getClassInternalName(classNode);
+
+            //System.out.println("Generating class: " + classNode.getName());
+
+            this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
+
+            cv.visit(
+                    Opcodes.V1_3,
+                    classNode.getModifiers(),
+                    internalClassName,
+                    (String) null,
+                    internalBaseClassName,
+                    BytecodeHelper.getClassInternalNames(classNode.getInterfaces())
+            );
+
+            classNode.visitContents(this);
+
+            for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
+                ClassNode innerClass = (ClassNode) iter.next();
+                ClassNode innerClassType = innerClass;
+                String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassType);
+                String outerClassName = internalClassName; // default for inner classes
+                MethodNode enclosingMethod = innerClass.getEnclosingMethod();
+                if (enclosingMethod != null) {
+                    // local inner classes do not specify the outer class name
+                    outerClassName = null;
+                }
+                cv.visitInnerClass(
+                        innerClassInternalName,
+                        outerClassName,
+                        innerClassType.getName(),
+                        innerClass.getModifiers());
+            }
+            cv.visitEnd();
+        }
+        catch (GroovyRuntimeException e) {
+            e.setModule(classNode.getModule());
+            throw e;
+        }
+    }
+
+    public void visitConstructor(ConstructorNode node) {
+
+        visitParameters(node, node.getParameters());
+
+        String methodType = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, node.getParameters());
+        mv = cv.visitMethod(node.getModifiers(), "<init>", methodType, null, null);
+        mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+        mv.visitInsn(DUP);
+        mv.visitLdcInsn("not intended for execution");
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V", false);
+        mv.visitInsn(ATHROW);
+        mv.visitMaxs(0, 0);
+    }
+
+    public void visitMethod(MethodNode node) {
+
+        visitParameters(node, node.getParameters());
+
+        String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
+        mv = cv.visitMethod(node.getModifiers(), node.getName(), methodType, null, null);
+
+        mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+        mv.visitInsn(DUP);
+        mv.visitLdcInsn("not intended for execution");
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V", false);
+        mv.visitInsn(ATHROW);
+
+        mv.visitMaxs(0, 0);
+    }
+
+    public void visitField(FieldNode fieldNode) {
+
+        cv.visitField(
+                fieldNode.getModifiers(),
+                fieldNode.getName(),
+                BytecodeHelper.getTypeDescription(fieldNode.getType()),
+                null, //fieldValue,  //br  all the sudden that one cannot init the field here. init is done in static initializer and instance initializer.
+                null);
+    }
+
+    /**
+     * Creates a getter, setter and field
+     */
+    public void visitProperty(PropertyNode statement) {
+    }
+
+    protected CompileUnit getCompileUnit() {
+        CompileUnit answer = classNode.getCompileUnit();
+        if (answer == null) {
+            answer = context.getCompileUnit();
+        }
+        return answer;
+    }
+
+    protected void visitParameters(ASTNode node, Parameter[] parameters) {
+        for (int i = 0, size = parameters.length; i < size; i++) {
+            visitParameter(node, parameters[i]);
+        }
+    }
+
+    protected void visitParameter(ASTNode node, Parameter parameter) {
+    }
+
+
+    public void visitAnnotations(AnnotatedNode node) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java b/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java
new file mode 100644
index 0000000..30c6fab
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/EnumCompletionVisitor.java
@@ -0,0 +1,169 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.CodeVisitorSupport;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.EnumConstantClassNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+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.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.transform.TupleConstructorASTTransformation;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Enums have a parent constructor with two arguments from java.lang.Enum.
+ * This visitor adds those two arguments into manually created constructors
+ * and performs the necessary super call.
+ */
+public class EnumCompletionVisitor extends ClassCodeVisitorSupport {
+    private final SourceUnit sourceUnit;
+
+    public EnumCompletionVisitor(CompilationUnit cu, SourceUnit su) {
+        sourceUnit = su;
+    }
+
+    public void visitClass(ClassNode node) {
+        if (!node.isEnum()) return;
+        completeEnum(node);
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
+    }
+
+    private void completeEnum(ClassNode enumClass) {
+        boolean isAic = isAnonymousInnerClass(enumClass);
+        if (enumClass.getDeclaredConstructors().isEmpty()) {
+            addImplicitConstructors(enumClass, isAic);
+        }
+
+        for (ConstructorNode ctor : enumClass.getDeclaredConstructors()) {
+            transformConstructor(ctor, isAic);
+        }
+    }
+
+    /**
+     * Add map and no-arg constructor or mirror those of the superclass (i.e. base enum).
+     */
+    private static void addImplicitConstructors(ClassNode enumClass, boolean aic) {
+        if (aic) {
+            ClassNode sn = enumClass.getSuperClass();
+            List<ConstructorNode> sctors = new ArrayList<ConstructorNode>(sn.getDeclaredConstructors());
+            if (sctors.isEmpty()) {
+                addMapConstructors(enumClass, false);
+            } else {
+                for (ConstructorNode constructorNode : sctors) {
+                    ConstructorNode init = new ConstructorNode(Opcodes.ACC_PUBLIC, constructorNode.getParameters(), ClassNode.EMPTY_ARRAY, new BlockStatement());
+                    enumClass.addConstructor(init);
+                }
+            }
+        } else {
+            addMapConstructors(enumClass, false);
+        }
+    }
+
+    /**
+     * If constructor does not define a call to super, then transform constructor
+     * to get String,int parameters at beginning and add call super(String,int).
+     */
+    private void transformConstructor(ConstructorNode ctor, boolean isAic) {
+        boolean chainedThisConstructorCall = false;
+        ConstructorCallExpression cce = null;
+        if (ctor.firstStatementIsSpecialConstructorCall()) {
+            Statement code = ctor.getFirstStatement();
+            cce = (ConstructorCallExpression) ((ExpressionStatement) code).getExpression();
+            if (cce.isSuperCall()) return;
+            // must be call to this(...)
+            chainedThisConstructorCall = true;
+        }
+        // we need to add parameters
+        Parameter[] oldP = ctor.getParameters();
+        Parameter[] newP = new Parameter[oldP.length + 2];
+        String stringParameterName = getUniqueVariableName("__str", ctor.getCode());
+        newP[0] = new Parameter(ClassHelper.STRING_TYPE, stringParameterName);
+        String intParameterName = getUniqueVariableName("__int", ctor.getCode());
+        newP[1] = new Parameter(ClassHelper.int_TYPE, intParameterName);
+        System.arraycopy(oldP, 0, newP, 2, oldP.length);
+        ctor.setParameters(newP);
+        VariableExpression stringVariable = new VariableExpression(newP[0]);
+        VariableExpression intVariable = new VariableExpression(newP[1]);
+        if (chainedThisConstructorCall) {
+            TupleExpression args = (TupleExpression) cce.getArguments();
+            List<Expression> argsExprs = args.getExpressions();
+            argsExprs.add(0, stringVariable);
+            argsExprs.add(1, intVariable);
+        } else {
+            // add a super call
+            List<Expression> args = new ArrayList<Expression>();
+            args.add(stringVariable);
+            args.add(intVariable);
+            if (isAic) {
+                for (Parameter parameter : oldP) {
+                    args.add(new VariableExpression(parameter.getName()));
+                }
+            }
+            cce = new ConstructorCallExpression(ClassNode.SUPER, new ArgumentListExpression(args));
+            BlockStatement code = new BlockStatement();
+            code.addStatement(new ExpressionStatement(cce));
+            Statement oldCode = ctor.getCode();
+            if (oldCode != null) code.addStatement(oldCode);
+            ctor.setCode(code);
+        }
+    }
+
+    public static void addMapConstructors(ClassNode enumClass, boolean hasNoArg) {
+        TupleConstructorASTTransformation.addMapConstructors(enumClass, hasNoArg, "One of the enum constants for enum " + enumClass.getName() +
+                " was initialized with null. Please use a non-null value or define your own constructor.");
+    }
+
+    private String getUniqueVariableName(final String name, Statement code) {
+        if (code == null) return name;
+        final Object[] found = new Object[1];
+        CodeVisitorSupport cv = new CodeVisitorSupport() {
+            public void visitVariableExpression(VariableExpression expression) {
+                if (expression.getName().equals(name)) found[0] = Boolean.TRUE;
+            }
+        };
+        code.visit(cv);
+        if (found[0] != null) return getUniqueVariableName("_" + name, code);
+        return name;
+    }
+
+    private static boolean isAnonymousInnerClass(ClassNode enumClass) {
+        if (!(enumClass instanceof EnumConstantClassNode)) return false;
+        InnerClassNode ic = (InnerClassNode) enumClass;
+        return ic.getVariableScope() == null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
new file mode 100644
index 0000000..743801f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/EnumVisitor.java
@@ -0,0 +1,444 @@
+/*
+ *  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.classgen;
+
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.EnumConstantClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.FieldExpression;
+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.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.SpreadExpression;
+import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.IfStatement;
+import org.codehaus.groovy.ast.stmt.ReturnStatement;
+import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
+import org.objectweb.asm.Opcodes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EnumVisitor extends ClassCodeVisitorSupport {
+    // some constants for modifiers
+    private static final int FS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC;
+    private static final int PS = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
+    private static final int PUBLIC_FS = Opcodes.ACC_PUBLIC | FS;
+    private static final int PRIVATE_FS = Opcodes.ACC_PRIVATE | FS;
+
+    private final SourceUnit sourceUnit;
+
+
+    public EnumVisitor(CompilationUnit cu, SourceUnit su) {
+        sourceUnit = su;
+    }
+
+    public void visitClass(ClassNode node) {
+        if (!node.isEnum()) return;
+        completeEnum(node);
+    }
+
+    protected SourceUnit getSourceUnit() {
+        return sourceUnit;
+    }
+
+    private void completeEnum(ClassNode enumClass) {
+        boolean isAic = isAnonymousInnerClass(enumClass);
+        // create MIN_VALUE and MAX_VALUE fields
+        FieldNode minValue = null, maxValue = null, values = null;
+
+        if (!isAic) {
+            ClassNode enumRef = enumClass.getPlainNodeReference();
+
+            // create values field
+            values = new FieldNode("$VALUES", PRIVATE_FS | Opcodes.ACC_SYNTHETIC, enumRef.makeArray(), enumClass, null);
+            values.setSynthetic(true);
+
+            addMethods(enumClass, values);
+            checkForAbstractMethods(enumClass);
+
+            // create MIN_VALUE and MAX_VALUE fields
+            minValue = new FieldNode("MIN_VALUE", PUBLIC_FS, enumRef, enumClass, null);
+            maxValue = new FieldNode("MAX_VALUE", PUBLIC_FS, enumRef, enumClass, null);
+        }
+        addInit(enumClass, minValue, maxValue, values, isAic);
+    }
+
+    private static void checkForAbstractMethods(ClassNode enumClass) {
+        List<MethodNode> methods = enumClass.getMethods();
+        for (MethodNode m : methods) {
+            if (m.isAbstract()) {
+                // make the class abstract also see Effective Java p.152
+                enumClass.setModifiers(enumClass.getModifiers() | Opcodes.ACC_ABSTRACT);
+                break;
+            }
+        }
+    }
+
+    private static void addMethods(ClassNode enumClass, FieldNode values) {
+        List<MethodNode> methods = enumClass.getMethods();
+
+        boolean hasNext = false;
+        boolean hasPrevious = false;
+        for (MethodNode m : methods) {
+            if (m.getName().equals("next") && m.getParameters().length == 0) hasNext = true;
+            if (m.getName().equals("previous") && m.getParameters().length == 0) hasPrevious = true;
+            if (hasNext && hasPrevious) break;
+        }
+
+        ClassNode enumRef = enumClass.getPlainNodeReference();
+
+        {
+            // create values() method
+            MethodNode valuesMethod = new MethodNode("values", PUBLIC_FS, enumRef.makeArray(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
+            valuesMethod.setSynthetic(true);
+            BlockStatement code = new BlockStatement();
+            MethodCallExpression cloneCall = new MethodCallExpression(new FieldExpression(values), "clone", MethodCallExpression.NO_ARGUMENTS);
+            cloneCall.setMethodTarget(values.getType().getMethod("clone", Parameter.EMPTY_ARRAY));
+            code.addStatement(new ReturnStatement(cloneCall));
+            valuesMethod.setCode(code);
+            enumClass.addMethod(valuesMethod);
+        }
+
+        if (!hasNext) {
+            // create next() method, code:
+            //     Day next() {
+            //        int ordinal = ordinal().next()
+            //        if (ordinal >= values().size()) ordinal = 0
+            //        return values()[ordinal]
+            //     }
+            Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
+            Token ge = Token.newSymbol(Types.COMPARE_GREATER_THAN_EQUAL, -1, -1);
+            MethodNode nextMethod = new MethodNode("next", Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, enumRef, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
+            nextMethod.setSynthetic(true);
+            BlockStatement code = new BlockStatement();
+            BlockStatement ifStatement = new BlockStatement();
+            ifStatement.addStatement(
+                    new ExpressionStatement(
+                            new BinaryExpression(new VariableExpression("ordinal"), assign, new ConstantExpression(0))
+                    )
+            );
+
+            code.addStatement(
+                    new ExpressionStatement(
+                            new DeclarationExpression(
+                                    new VariableExpression("ordinal"),
+                                    assign,
+                                    new MethodCallExpression(
+                                            new MethodCallExpression(
+                                                    VariableExpression.THIS_EXPRESSION,
+                                                    "ordinal",
+                                                    MethodCallExpression.NO_ARGUMENTS),
+                                            "next",
+                                            MethodCallExpression.NO_ARGUMENTS
+                                    )
+                            )
+                    )
+            );
+            code.addStatement(
+                    new IfStatement(
+                            new BooleanExpression(new BinaryExpression(
+                                    new VariableExpression("ordinal"),
+                                    ge,
+                                    new MethodCallExpression(
+                                            new FieldExpression(values),
+                                            "size",
+                                            MethodCallExpression.NO_ARGUMENTS
+                                    )
+                            )),
+                            ifStatement,
+                            EmptyStatement.INSTANCE
+                    )
+            );
+            code.addStatement(
+                    new ReturnStatement(
+                            new MethodCallExpression(new FieldExpression(values), "getAt", new VariableExpression("ordinal"))
+                    )
+            );
+            nextMethod.setCode(code);
+            enumClass.addMethod(nextMethod);
+        }
+
+        if (!hasPrevious) {
+            // create previous() method, code:
+            //    Day previous() {
+            //        int ordinal = ordinal().previous()
+            //        if (ordinal < 0) ordinal = values().size() - 1
+            //        return values()[ordinal]
+            //    }
+            Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
+            Token lt = Token.newSymbol(Types.COMPARE_LESS_THAN, -1, -1);
+            MethodNode nextMethod = new MethodNode("previous", Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, enumRef, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
+            nextMethod.setSynthetic(true);
+            BlockStatement code = new BlockStatement();
+            BlockStatement ifStatement = new BlockStatement();
+            ifStatement.addStatement(
+                    new ExpressionStatement(
+                            new BinaryExpression(new VariableExpression("ordinal"), assign,
+                                    new MethodCallExpression(
+                                            new MethodCallExpression(
+                                                    new FieldExpression(values),
+                                                    "size",
+                                                    MethodCallExpression.NO_ARGUMENTS
+                                            ),
+                                            "minus",
+                                            new ConstantExpression(1)
+                                    )
+                            )
+                    )
+            );
+
+            code.addStatement(
+                    new ExpressionStatement(
+                            new DeclarationExpression(
+                                    new VariableExpression("ordinal"),
+                                    assign,
+                                    new MethodCallExpression(
+                                            new MethodCallExpression(
+                                                    VariableExpression.THIS_EXPRESSION,
+                                                    "ordinal",
+                                                    MethodCallExpression.NO_ARGUMENTS),
+                                            "previous",
+                                            MethodCallExpression.NO_ARGUMENTS
+                                    )
+                            )
+                    )
+            );
+            code.addStatement(
+                    new IfStatement(
+                            new BooleanExpression(new BinaryExpression(
+                                    new VariableExpression("ordinal"),
+                                    lt,
+                                    new ConstantExpression(0)
+                            )),
+                            ifStatement,
+                            EmptyStatement.INSTANCE
+                    )
+            );
+            code.addStatement(
+                    new ReturnStatement(
+                            new MethodCallExpression(new FieldExpression(values), "getAt", new VariableExpression("ordinal"))
+                    )
+            );
+            nextMethod.setCode(code);
+            enumClass.addMethod(nextMethod);
+        }
+
+        {
+            // create valueOf
+            Parameter stringParameter = new Parameter(ClassHelper.STRING_TYPE, "name");
+            MethodNode valueOfMethod = new MethodNode("valueOf", PS, enumRef, new Parameter[]{stringParameter}, ClassNode.EMPTY_ARRAY, null);
+            ArgumentListExpression callArguments = new ArgumentListExpression();
+            callArguments.addExpression(new ClassExpression(enumClass));
+            callArguments.addExpression(new VariableExpression("name"));
+
+            BlockStatement code = new BlockStatement();
+            code.addStatement(
+                    new ReturnStatement(
+                            new MethodCallExpression(new ClassExpression(ClassHelper.Enum_Type), "valueOf", callArguments)
+                    )
+            );
+            valueOfMethod.setCode(code);
+            valueOfMethod.setSynthetic(true);
+            enumClass.addMethod(valueOfMethod);
+        }
+    }
+
+    private void addInit(ClassNode enumClass, FieldNode minValue,
+                         FieldNode maxValue, FieldNode values,
+                         boolean isAic) {
+        // constructor helper
+        // This method is used instead of calling the constructor as
+        // calling the constructor may require a table with MetaClass
+        // selecting the constructor for each enum value. So instead we
+        // use this method to have a central point for constructor selection
+        // and only one table. The whole construction is needed because 
+        // Reflection forbids access to the enum constructor.
+        // code:
+        // def $INIT(Object[] para) {
+        //  return this(*para)
+        // }
+        ClassNode enumRef = enumClass.getPlainNodeReference();
+        Parameter[] parameter = new Parameter[]{new Parameter(ClassHelper.OBJECT_TYPE.makeArray(), "para")};
+        MethodNode initMethod = new MethodNode("$INIT", PUBLIC_FS | Opcodes.ACC_SYNTHETIC, enumRef, parameter, ClassNode.EMPTY_ARRAY, null);
+        initMethod.setSynthetic(true);
+        ConstructorCallExpression cce = new ConstructorCallExpression(
+                ClassNode.THIS,
+                new ArgumentListExpression(
+                        new SpreadExpression(new VariableExpression("para"))
+                )
+        );
+        BlockStatement code = new BlockStatement();
+        code.addStatement(new ReturnStatement(cce));
+        initMethod.setCode(code);
+        enumClass.addMethod(initMethod);
+
+        // static init
+        List<FieldNode> fields = enumClass.getFields();
+        List<Expression> arrayInit = new ArrayList<Expression>();
+        int value = -1;
+        Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
+        List<Statement> block = new ArrayList<Statement>();
+        FieldNode tempMin = null;
+        FieldNode tempMax = null;
+        for (FieldNode field : fields) {
+            if ((field.getModifiers() & Opcodes.ACC_ENUM) == 0) continue;
+            value++;
+            if (tempMin == null) tempMin = field;
+            tempMax = field;
+
+            ClassNode enumBase = enumClass;
+            ArgumentListExpression args = new ArgumentListExpression();
+            args.addExpression(new ConstantExpression(field.getName()));
+            args.addExpression(new ConstantExpression(value));
+            if (field.getInitialExpression() == null) {
+                if ((enumClass.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
+                    addError(field, "The enum constant " + field.getName() + " must override abstract methods from " + enumBase.getName() + ".");
+                    continue;
+                }
+            } else {
+                ListExpression oldArgs = (ListExpression) field.getInitialExpression();
+                List<MapEntryExpression> savedMapEntries = new ArrayList<MapEntryExpression>();
+                for (Expression exp : oldArgs.getExpressions()) {
+                    if (exp instanceof MapEntryExpression) {
+                        savedMapEntries.add((MapEntryExpression) exp);
+                        continue;
+                    }
+
+                    InnerClassNode inner = null;
+                    if (exp instanceof ClassExpression) {
+                        ClassExpression clazzExp = (ClassExpression) exp;
+                        ClassNode ref = clazzExp.getType();
+                        if (ref instanceof EnumConstantClassNode) {
+                            inner = (InnerClassNode) ref;
+                        }
+                    }
+                    if (inner != null) {
+                        List<MethodNode> baseMethods = enumBase.getMethods();
+                        for (MethodNode methodNode : baseMethods) {
+                            if (!methodNode.isAbstract()) continue;
+                            MethodNode enumConstMethod = inner.getMethod(methodNode.getName(), methodNode.getParameters());
+                            if (enumConstMethod == null || (enumConstMethod.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
+                                addError(field, "Can't have an abstract method in enum constant " + field.getName() + ". Implement method '" + methodNode.getTypeDescriptor() + "'.");
+                            }
+                        }
+                        if (inner.getVariableScope() == null) {
+                            enumBase = inner;
+                            /*
+                             * GROOVY-3985: Remove the final modifier from $INIT method in this case
+                             * so that subclasses of enum generated for enum constants (aic) can provide
+                             * their own $INIT method
+                             */
+                            initMethod.setModifiers(initMethod.getModifiers() & ~Opcodes.ACC_FINAL);
+                            continue;
+                        }
+                    }
+                    args.addExpression(exp);
+                }
+                if (!savedMapEntries.isEmpty()) {
+                    args.getExpressions().add(2, new MapExpression(savedMapEntries));
+                }
+            }
+            field.setInitialValueExpression(null);
+            block.add(
+                    new ExpressionStatement(
+                            new BinaryExpression(
+                                    new FieldExpression(field),
+                                    assign,
+                                    new StaticMethodCallExpression(enumBase, "$INIT", args)
+                            )
+                    )
+            );
+            arrayInit.add(new FieldExpression(field));
+        }
+
+        if (!isAic) {
+            if (tempMin != null) {
+                block.add(
+                        new ExpressionStatement(
+                                new BinaryExpression(
+                                        new FieldExpression(minValue),
+                                        assign,
+                                        new FieldExpression(tempMin)
+                                )
+                        )
+                );
+                block.add(
+                        new ExpressionStatement(
+                                new BinaryExpression(
+                                        new FieldExpression(maxValue),
+                                        assign,
+                                        new FieldExpression(tempMax)
+                                )
+                        )
+                );
+                enumClass.addField(minValue);
+                enumClass.addField(maxValue);
+            }
+
+            block.add(
+                    new ExpressionStatement(
+                            new BinaryExpression(new FieldExpression(values), assign, new ArrayExpression(enumClass, arrayInit))
+                    )
+            );
+            enumClass.addField(values);
+        }
+        enumClass.addStaticInitializerStatements(block, true);
+    }
+
+    private void addError(AnnotatedNode exp, String msg) {
+        sourceUnit.getErrorCollector().addErrorAndContinue(
+                new SyntaxErrorMessage(
+                        new SyntaxException(msg + '\n', exp.getLineNumber(), exp.getColumnNumber(), exp.getLastLineNumber(), exp.getLastColumnNumber()), sourceUnit)
+        );
+    }
+
+    private static boolean isAnonymousInnerClass(ClassNode enumClass) {
+        if (!(enumClass instanceof EnumConstantClassNode)) return false;
+        InnerClassNode ic = (InnerClassNode) enumClass;
+        return ic.getVariableScope() == null;
+    }
+
+}


[61/62] [abbrv] groovy git commit: Build grooid jar using the new jarjar task

Posted by cc...@apache.org.
Build grooid jar using the new jarjar task


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/c37615bb
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/c37615bb
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/c37615bb

Branch: refs/heads/GROOVY_2_6_X
Commit: c37615bb4177a41b310de5d41be6d9dfeeb930f1
Parents: 044b787
Author: Cedric Champeau <cc...@apache.org>
Authored: Sat Dec 16 21:54:00 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:54:01 2017 +0100

----------------------------------------------------------------------
 .../codehaus/groovy/gradle/JarJarTask.groovy    | 68 ++++++++++++++------
 gradle/assemble.gradle                          | 67 +++++++++----------
 gradle/upload.gradle                            |  2 +-
 3 files changed, 82 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/c37615bb/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy
index 4a3c4ca..37fb67c 100644
--- a/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy
+++ b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy
@@ -19,14 +19,14 @@
 package org.codehaus.groovy.gradle
 
 import groovy.transform.CompileStatic
+import org.gradle.api.Action
 import org.gradle.api.DefaultTask
 import org.gradle.api.file.FileCollection
+import org.gradle.api.java.archives.Manifest
 import org.gradle.api.tasks.CacheableTask
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.OutputFile
 import org.gradle.api.tasks.TaskAction
-import org.gradle.api.Action
-import org.gradle.api.java.archives.Manifest
 
 @CacheableTask
 class JarJarTask extends DefaultTask {
@@ -46,20 +46,35 @@ class JarJarTask extends DefaultTask {
     FileCollection jarjarToolClasspath
 
     @Input
-    List<String> untouchedFiles
+    @org.gradle.api.tasks.Optional
+    List<String> untouchedFiles = []
+
+    @Input
+    @org.gradle.api.tasks.Optional
+    List<String> excludes = []
 
     @Input
     Map<String, String> patterns
 
     @Input
-    Map<String, List<String>> excludesPerLibrary
+    @org.gradle.api.tasks.Optional
+    Map<String, List<String>> excludesPerLibrary = [:]
 
     @Input
-    Map<String, List<String>> includesPerLibrary
+    @org.gradle.api.tasks.Optional
+    Map<String, List<String>> includesPerLibrary = [:]
+
+    @Input
+    @org.gradle.api.tasks.Optional
+    Map<String, String> includedResources = [:]
 
     @OutputFile
     File outputFile
 
+    @Input
+    @org.gradle.api.tasks.Optional
+    boolean createManifest = true
+
     void withManifest(Action<? super Manifest> action) {
         manifestTweaks << action
     }
@@ -82,8 +97,12 @@ class JarJarTask extends DefaultTask {
                 jarjar(jarfile: tmpJar, filesonly: true) {
                     zipfileset(
                             src: originalJar,
-                            excludes: untouchedFiles.join(','))
-
+                            excludes: (untouchedFiles+excludes).join(','))
+                    includedResources.each { String resource, String path ->
+                        String dir = resource.substring(0, resource.lastIndexOf('/') + 1)
+                        String filename = resource.substring(resource.lastIndexOf('/') + 1)
+                        zipfileset(dir: dir, includes: filename, fullpath: path)
+                    }
                     repackagedLibraries.files.each { File library ->
                         def libraryName = JarJarTask.baseName(library)
                         def includes = includesPerLibrary[libraryName]
@@ -102,19 +121,24 @@ class JarJarTask extends DefaultTask {
                 }
             }
 
-            // next step is to generate an OSGI manifest using the newly repackaged classes
-            def mf = project.rootProject.convention.plugins.osgi.osgiManifest {
-                symbolicName = project.name
-                instruction 'Import-Package', '*;resolution:=optional'
-                classesDir = tmpJar
-            }
+            if (createManifest) {
+                // next step is to generate an OSGI manifest using the newly repackaged classes
+                def mf = project.rootProject.convention.plugins.osgi.osgiManifest {
+                    symbolicName = project.name
+                    instruction 'Import-Package', '*;resolution:=optional'
+                    classesDir = tmpJar
+                }
 
-            manifestTweaks.each {
-                it.execute(mf)
-            }
+                manifestTweaks.each {
+                    it.execute(mf)
+                }
 
-            // then we need to generate the manifest file
-            mf.writeTo(manifestFile)
+                // then we need to generate the manifest file
+                mf.writeTo(manifestFile)
+
+            } else {
+                manifestFile << ''
+            }
 
             // so that we can put it into the final jar
             project.ant.copy(file: tmpJar, tofile: outputFile)
@@ -124,9 +148,11 @@ class JarJarTask extends DefaultTask {
                     // introduce cache misses
                     attribute(name:'Created-By', value:'Gradle')
                 }
-                zipfileset(
-                        src: originalJar,
-                        includes: untouchedFiles.join(','))
+                if (untouchedFiles) {
+                    zipfileset(
+                            src: originalJar,
+                            includes: untouchedFiles.join(','))
+                }
             }
         } finally {
             manifestFile.delete()

http://git-wip-us.apache.org/repos/asf/groovy/blob/c37615bb/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index 212c0c2..4443dcb 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -211,13 +211,13 @@ allprojects {
                     'org/codehaus/groovy/tools/shell/util/HelpFormatter*.class'
             ]
             patterns = [
-                    'antlr.**': 'groovyjarjarantlr.@1', // antlr2
-                    'org.antlr.**': 'groovyjarjarantlr4.@1', // antlr4
-                    'org.objectweb.**': 'groovyjarjarasm.@1',
+                    'antlr.**'                 : 'groovyjarjarantlr.@1', // antlr2
+                    'org.antlr.**'             : 'groovyjarjarantlr4.@1', // antlr4
+                    'org.objectweb.**'         : 'groovyjarjarasm.@1',
                     'org.apache.commons.cli.**': 'groovyjarjarcommonscli.@1'
             ]
             excludesPerLibrary = [
-                    '*': ['META-INF/maven/**','META-INF/*','META-INF/services/javax.annotation.processing.Processor','module-info.class']
+                    '*': ['META-INF/maven/**', 'META-INF/*', 'META-INF/services/javax.annotation.processing.Processor', 'module-info.class']
             ]
             includesPerLibrary = [
                     'asm-util': ['org/objectweb/asm/util/Printer.class',
@@ -225,7 +225,7 @@ allprojects {
                                  'org/objectweb/asm/util/ASMifier.class',
                                  'org/objectweb/asm/util/Trace*']
             ]
-            outputFile = file("$buildDir/libs/${arch.baseName}-${arch.version}${arch.classifier?'-'+arch.classifier:''}.jar")
+            outputFile = file("$buildDir/libs/${arch.baseName}-${arch.version}${arch.classifier ? '-' + arch.classifier : ''}.jar")
 
             withManifest {
                 def moduleName = "org.codehaus.${project.name.replace('-', '.')}"
@@ -244,36 +244,36 @@ allprojects {
     }
 
     if (project.name in ['groovy', 'groovy-test']) {
-        task grooidjar(type: Jar) {
-            destinationDir = jar.destinationDir
-            baseName = jar.baseName
-            classifier = jar.classifier ? "${jar.classifier}grooid" : 'grooid'
-            includeEmptyDirs = false
-            def target = new File("${archivePath}.tmp")
-            boolean isRootProject = project == rootProject
-
-            doFirst {
-                from zipTree(target)
-                ant {
-                    taskdef name: 'jarjar', classname: jarjarTaskClassName, classpath: rootProject.configurations.tools.asPath
-                    jarjar(jarfile: target) {
-                        zipfileset(dir: "$rootProject.projectDir/notices/", includes: isRootProject ? 'NOTICE-GROOIDJARJAR' : 'NOTICE-GROOID', fullpath: 'META-INF/NOTICE')
-                        zipfileset(src: jarjar.outputFile, excludes: 'META-INF/NOTICE')
-                        if (isRootProject) {
-                            zipfileset(src: rootProject.configurations.runtime.files.find {
-                                it.name.startsWith('openbeans')
-                            }, excludes: 'META-INF/*')
+        task grooidjar(type: JarJarTask) {
+            dependsOn jarjar
+            from = file(jarjar.outputFile)
+            if (isRoot) {
+                repackagedLibraries = files(configurations.runtime.incoming.artifactView {
+                    componentFilter { component ->
+                        if (component instanceof ModuleComponentIdentifier) {
+                            return component.module in ['openbeans']
                         }
-                        rule pattern: 'com.googlecode.openbeans.**', result: 'groovyjarjaropenbeans.@1'
-                        rule pattern: 'org.apache.harmony.beans.**', result: 'groovyjarjarharmonybeans.@1'
-                        rule pattern: 'java.beans.**', result: 'groovyjarjaropenbeans.@1'
+                        return false
                     }
-                }
-
-            }
-            doLast {
-                target.delete()
+                }.files)
+            } else {
+                repackagedLibraries = files()
             }
+            jarjarToolClasspath = rootProject.configurations.tools
+            patterns = [
+                    'com.googlecode.openbeans.**': 'groovyjarjaropenbeans.@1',
+                    'org.apache.harmony.beans.**': 'groovyjarjarharmonybeans.@1',
+                    'java.beans.**'              : 'groovyjarjaropenbeans.@1'
+            ]
+            excludesPerLibrary = [
+                    '*': ['META-INF/NOTICE']
+            ]
+            excludes = ['META-INF/NOTICE']
+            createManifest = false
+            includedResources = [
+                    ("$rootProject.projectDir/notices/${isRoot ? 'NOTICE-GROOIDJARJAR' : 'NOTICE-GROOID'}".toString()): 'META-INF/NOTICE'
+            ]
+            outputFile = file("$buildDir/libs/${jar.baseName}-${jar.version}-grooid.jar")
         }
     }
 }
@@ -349,7 +349,8 @@ ext.distSpec = copySpec {
         from jarjar
         from modules()*.jarjar
         from(configurations.runtime) {
-            exclude {   it.file.name.startsWith('openbeans-') ||
+            exclude {
+                it.file.name.startsWith('openbeans-') ||
                         it.file.name.startsWith('asm-') ||
                         it.file.name.startsWith('antlr-') ||
                         it.file.name.startsWith('antlr4-')

http://git-wip-us.apache.org/repos/asf/groovy/blob/c37615bb/gradle/upload.gradle
----------------------------------------------------------------------
diff --git a/gradle/upload.gradle b/gradle/upload.gradle
index c06cad6..8d21a75 100644
--- a/gradle/upload.gradle
+++ b/gradle/upload.gradle
@@ -115,7 +115,7 @@ allprojects {
                 }
                 def grooidJar = rootProject.ext.deriveFile(jar.archivePath, 'grooid')
                 if (grooidJar.exists()) {
-                    project.artifacts.add('archives', grooidJar)
+                    project.artifacts.add('archives', grooidJar.outputFile)
                 }
             }
         }


[60/62] [abbrv] groovy git commit: Turn `jarjar` into a cacheable task

Posted by cc...@apache.org.
Turn `jarjar` into a cacheable task

This commit moves the logic of creating a jarjar archive into its own class. This
makes it possible to cache it, unlike the traditional `Jar` task from Gradle.


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/044b7874
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/044b7874
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/044b7874

Branch: refs/heads/GROOVY_2_6_X
Commit: 044b7874e6616cccc209cb9c6fda6dcfb5a43e50
Parents: e7ee1f2
Author: Cedric Champeau <cc...@apache.org>
Authored: Sat Dec 16 20:49:34 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:53:29 2017 +0100

----------------------------------------------------------------------
 .../codehaus/groovy/gradle/CacheableJar.groovy  |  29 ----
 .../codehaus/groovy/gradle/JarJarTask.groovy    | 142 +++++++++++++++++++
 gradle/assemble.gradle                          | 132 +++++++----------
 gradle/upload.gradle                            |   6 +-
 4 files changed, 200 insertions(+), 109 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/044b7874/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy
deleted file mode 100644
index fa4b5f2..0000000
--- a/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/CacheableJar.groovy
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.codehaus.groovy.gradle
-
-import groovy.transform.CompileStatic
-import org.gradle.api.tasks.CacheableTask
-import org.gradle.api.tasks.bundling.Jar
-
-@CompileStatic
-@CacheableTask
-class CacheableJar extends Jar {
-
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/044b7874/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy
----------------------------------------------------------------------
diff --git a/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy
new file mode 100644
index 0000000..4a3c4ca
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/codehaus/groovy/gradle/JarJarTask.groovy
@@ -0,0 +1,142 @@
+/*
+ *  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.gradle
+
+import groovy.transform.CompileStatic
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.FileCollection
+import org.gradle.api.tasks.CacheableTask
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.OutputFile
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.Action
+import org.gradle.api.java.archives.Manifest
+
+@CacheableTask
+class JarJarTask extends DefaultTask {
+    private final static String JARJAR_CLASS_NAME = 'org.pantsbuild.jarjar.JarJarTask'
+
+    String description = "Repackages dependencies into a shaded jar"
+
+    private List<Action<? super Manifest>> manifestTweaks = []
+
+    @Input
+    File from
+
+    @Input
+    FileCollection repackagedLibraries
+
+    @Input
+    FileCollection jarjarToolClasspath
+
+    @Input
+    List<String> untouchedFiles
+
+    @Input
+    Map<String, String> patterns
+
+    @Input
+    Map<String, List<String>> excludesPerLibrary
+
+    @Input
+    Map<String, List<String>> includesPerLibrary
+
+    @OutputFile
+    File outputFile
+
+    void withManifest(Action<? super Manifest> action) {
+        manifestTweaks << action
+    }
+
+    String getArchiveName() {
+        outputFile.name
+    }
+
+    @TaskAction
+    void generateDescriptor() {
+        def originalJar = from
+        def tmpJar = new File(temporaryDir, "${outputFile.name}.${Integer.toHexString(UUID.randomUUID().hashCode())}.tmp")
+        def manifestFile = new File(temporaryDir, 'MANIFEST.MF')
+
+        // First step is to create a repackaged jar
+        outputFile.parentFile.mkdirs()
+        try {
+            project.ant {
+                taskdef name: 'jarjar', classname: JARJAR_CLASS_NAME, classpath: jarjarToolClasspath.asPath
+                jarjar(jarfile: tmpJar, filesonly: true) {
+                    zipfileset(
+                            src: originalJar,
+                            excludes: untouchedFiles.join(','))
+
+                    repackagedLibraries.files.each { File library ->
+                        def libraryName = JarJarTask.baseName(library)
+                        def includes = includesPerLibrary[libraryName]
+                        def excludes = excludesPerLibrary[libraryName]
+                        if (includes) {
+                            zipfileset(src: library, includes: includes.join(','))
+                        } else if (excludes) {
+                            zipfileset(src: library, excludes: excludes.join(','))
+                        } else {
+                            zipfileset(src: library, excludes: excludesPerLibrary['*'].join(','))
+                        }
+                    }
+                    patterns.each { pattern, result ->
+                        rule pattern: pattern, result: result
+                    }
+                }
+            }
+
+            // next step is to generate an OSGI manifest using the newly repackaged classes
+            def mf = project.rootProject.convention.plugins.osgi.osgiManifest {
+                symbolicName = project.name
+                instruction 'Import-Package', '*;resolution:=optional'
+                classesDir = tmpJar
+            }
+
+            manifestTweaks.each {
+                it.execute(mf)
+            }
+
+            // then we need to generate the manifest file
+            mf.writeTo(manifestFile)
+
+            // so that we can put it into the final jar
+            project.ant.copy(file: tmpJar, tofile: outputFile)
+            project.ant.jar(destfile: outputFile, update: true, manifest: manifestFile) {
+                manifest {
+                    // because we don't want to use JDK 1.8.0_91, we don't care and it will
+                    // introduce cache misses
+                    attribute(name:'Created-By', value:'Gradle')
+                }
+                zipfileset(
+                        src: originalJar,
+                        includes: untouchedFiles.join(','))
+            }
+        } finally {
+            manifestFile.delete()
+            project.ant.delete(file: tmpJar, quiet: true, deleteonexit: true)
+        }
+    }
+
+    @CompileStatic
+    private static String baseName(File file) {
+        file.name.substring(0, file.name.lastIndexOf('-'))
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/groovy/blob/044b7874/gradle/assemble.gradle
----------------------------------------------------------------------
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index c02659c..212c0c2 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -17,6 +17,8 @@
  *  under the License.
  */
 import org.apache.tools.ant.filters.ReplaceTokens
+import org.codehaus.groovy.gradle.JarJarTask
+import org.gradle.api.artifacts.component.ModuleComponentIdentifier
 
 apply plugin: 'osgi'
 
@@ -84,6 +86,7 @@ task copy(type: Copy) {
 
 // unnecessary entries which in addition may trigger unnecessary rebuilds
 def excludedFromManifest = [
+        'Ant-Version',
         'Originally-Created-By',
         'Bnd-LastModified',
         'Created-By'
@@ -140,6 +143,8 @@ ext.subprojectOsgiManifest = {
 }
 
 allprojects {
+    boolean isRoot = project == rootProject
+
     def producedJars = [jar]
     jar {
         appendix = 'raw'
@@ -180,87 +185,60 @@ allprojects {
         }
         arch.exclude '**/package-info.class'
 
-        task "jar${arch.name}"(type: Jar, dependsOn: arch) {
-            outputs.cacheIf {
-                // caching JarJar because it's quite expensive to create
-                true
+        task "jar${arch.name}"(type: JarJarTask) {
+            dependsOn arch
+            from = file(arch.archivePath)
+            if (project == rootProject) {
+                repackagedLibraries = files(configurations.runtime.incoming.artifactView {
+                    componentFilter { component ->
+                        if (component instanceof ModuleComponentIdentifier) {
+                            return component.module in [
+                                    'antlr', 'antlr-runtime', 'antlr4', 'antlr4-runtime', 'antlr4-annotations',
+                                    'asm', 'asm-commons', 'asm-tree', 'asm-util',
+                                    'commons-cli']
+                        }
+                        return false
+                    }
+                }.files)
+            } else {
+                repackagedLibraries = files()
             }
-            destinationDir = arch.destinationDir
-            baseName = arch.baseName
-            classifier = arch.classifier
-            includeEmptyDirs = false
-            def target = new File("${archivePath}.tmp")
-            def targetTmp = new File("${archivePath}.tmp.1.tmp")
-            inputs.file(arch.archivePath)
-
-            doFirst {
-                from zipTree(target)
-
-                def keepUntouched = [
-                        'org/codehaus/groovy/cli/GroovyPosixParser*.class',
-                        'groovy/util/CliBuilder*.class',
-                        'groovy/util/OptionAccessor*.class',
-                        'org/codehaus/groovy/tools/shell/util/HelpFormatter*.class'
-                ].join(',')
-                boolean isRoot = project == rootProject
-                def gradleProject = project
-                ant {
-                    taskdef name: 'jarjar', classname: jarjarTaskClassName, classpath: rootProject.configurations.tools.asPath
-                    jarjar(jarfile: targetTmp) {
-                        zipfileset(
-                                src: arch.archivePath,
-                                excludes: keepUntouched)
-
-                        // only groovy core will include the dependencies repackaged
-                        if (isRoot) {
-                            configurations.runtime.files.findAll { file ->
-                                ['antlr', 'asm', 'commons-cli'].any {
-                                    file.name.startsWith(it)
-                                } && ['asm-attr', 'asm-util', 'asm-analysis'].every { !file.name.startsWith(it) }
-                            }.each { jarjarFile ->
-                                // explanation of excludes:
-                                // GROOVY-7386: stop copy of incorrect maven meta info
-                                // GROOVY-8332: stop copy of annotation processor which is for some reason included in antlr runtime artifact
-                                // GROOVY-8387: we don't want module-info.class from any dependencies
-                                zipfileset(src: jarjarFile,
-                                        excludes: 'META-INF/maven/**,META-INF/*,META-INF/services/javax.annotation.processing.Processor,module-info.class')
-                            }
-
-                            zipfileset(src: configurations.runtime.files.find { file -> file.name.startsWith('asm-util') },
-                                    includes: 'org/objectweb/asm/util/Printer.class,org/objectweb/asm/util/Textifier.class,org/objectweb/asm/util/ASMifier.class,org/objectweb/asm/util/Trace*')
+            jarjarToolClasspath = rootProject.configurations.tools
+            untouchedFiles = [
+                    'org/codehaus/groovy/cli/GroovyPosixParser*.class',
+                    'groovy/util/CliBuilder*.class',
+                    'groovy/util/OptionAccessor*.class',
+                    'org/codehaus/groovy/tools/shell/util/HelpFormatter*.class'
+            ]
+            patterns = [
+                    'antlr.**': 'groovyjarjarantlr.@1', // antlr2
+                    'org.antlr.**': 'groovyjarjarantlr4.@1', // antlr4
+                    'org.objectweb.**': 'groovyjarjarasm.@1',
+                    'org.apache.commons.cli.**': 'groovyjarjarcommonscli.@1'
+            ]
+            excludesPerLibrary = [
+                    '*': ['META-INF/maven/**','META-INF/*','META-INF/services/javax.annotation.processing.Processor','module-info.class']
+            ]
+            includesPerLibrary = [
+                    'asm-util': ['org/objectweb/asm/util/Printer.class',
+                                 'org/objectweb/asm/util/Textifier.class',
+                                 'org/objectweb/asm/util/ASMifier.class',
+                                 'org/objectweb/asm/util/Trace*']
+            ]
+            outputFile = file("$buildDir/libs/${arch.baseName}-${arch.version}${arch.classifier?'-'+arch.classifier:''}.jar")
+
+            withManifest {
+                def moduleName = "org.codehaus.${project.name.replace('-', '.')}"
+                attributes('Automatic-Module-Name': moduleName)
+                from(allManifest) {
+                    eachEntry { details ->
+                        if (excludedFromManifest.any { it == details.key }) {
+                            details.exclude()
                         }
-                        rule pattern: 'antlr.**', result: 'groovyjarjarantlr.@1' // antlr2
-                        rule pattern: 'org.antlr.**', result: 'groovyjarjarantlr4.@1' // antlr4
-                        rule pattern: 'org.objectweb.**', result: 'groovyjarjarasm.@1'
-                        rule pattern: 'org.apache.commons.cli.**', result: 'groovyjarjarcommonscli.@1'
                     }
                 }
-
-                def manifestSpec = isRoot ? groovyOsgiManifest : subprojectOsgiManifest
-                manifest = osgiManifest {
-                    symbolicName = gradleProject.name
-                    instruction 'Import-Package', '*;resolution:=optional'
-                    classesDir = targetTmp
-                    def moduleName = "org.codehaus.${gradleProject.name.replace('-', '.')}"
-                    attributes('Automatic-Module-Name': moduleName)
-                }
-                manifest(manifestSpec)
-
-                def manifestPath = "${temporaryDir}/META-INF/MANIFEST.MF"
-                manifest.writeTo(manifestPath)
-
-                ant.copy(file: targetTmp, tofile: target)
-                ant.jar(destfile: target, update: true, manifest: manifestPath) {
-                    zipfileset(
-                            src: arch.archivePath,
-                            includes: keepUntouched)
-                }
-
-            }
-            doLast {
-                target.delete()
-                ant.delete(file: targetTmp, quiet: true, deleteonexit: true)
             }
+            withManifest(isRoot ? groovyOsgiManifest : subprojectOsgiManifest)
         }
 
     }
@@ -280,7 +258,7 @@ allprojects {
                     taskdef name: 'jarjar', classname: jarjarTaskClassName, classpath: rootProject.configurations.tools.asPath
                     jarjar(jarfile: target) {
                         zipfileset(dir: "$rootProject.projectDir/notices/", includes: isRootProject ? 'NOTICE-GROOIDJARJAR' : 'NOTICE-GROOID', fullpath: 'META-INF/NOTICE')
-                        zipfileset(src: jarjar.archivePath, excludes: 'META-INF/NOTICE')
+                        zipfileset(src: jarjar.outputFile, excludes: 'META-INF/NOTICE')
                         if (isRootProject) {
                             zipfileset(src: rootProject.configurations.runtime.files.find {
                                 it.name.startsWith('openbeans')

http://git-wip-us.apache.org/repos/asf/groovy/blob/044b7874/gradle/upload.gradle
----------------------------------------------------------------------
diff --git a/gradle/upload.gradle b/gradle/upload.gradle
index 8588346..c06cad6 100644
--- a/gradle/upload.gradle
+++ b/gradle/upload.gradle
@@ -94,7 +94,7 @@ allprojects {
         }
 
         artifacts {
-            archives jarjar
+            archives jarjar.outputFile
             archives sourceJar
             archives javadocJar
             archives groovydocJar
@@ -105,13 +105,13 @@ allprojects {
         }
 
         [uploadArchives, install]*.with {
-            dependsOn([jar, sourceJar, javadocJar, groovydocJar])
+            dependsOn([grooidjar, jarjar, sourceJar, javadocJar, groovydocJar])
             if (rootProject.indyCapable()) {
                 dependsOn jarjarWithIndy
             }
             doFirst {
                 if (rootProject.indyCapable()) {
-                    project.artifacts.add('archives', jarjarWithIndy)
+                    project.artifacts.add('archives', jarjarWithIndy.outputFile)
                 }
                 def grooidJar = rootProject.ext.deriveFile(jar.archivePath, 'grooid')
                 if (grooidJar.exists()) {


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
new file mode 100644
index 0000000..1e434cb
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -0,0 +1,764 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.InnerClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.decompiled.DecompiledClassNode;
+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.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.TupleExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.classgen.asm.CallSiteWriter;
+import org.codehaus.groovy.classgen.asm.CompileStack;
+import org.codehaus.groovy.classgen.asm.ExpressionAsVariableSlot;
+import org.codehaus.groovy.classgen.asm.InvocationWriter;
+import org.codehaus.groovy.classgen.asm.MethodCallerMultiAdapter;
+import org.codehaus.groovy.classgen.asm.OperandStack;
+import org.codehaus.groovy.classgen.asm.TypeChooser;
+import org.codehaus.groovy.classgen.asm.VariableSlotLoader;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.sc.StaticCompilationVisitor;
+import org.codehaus.groovy.transform.sc.TemporaryVariableExpression;
+import org.codehaus.groovy.transform.stc.ExtensionMethodNode;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
+import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.PRIVATE_BRIDGE_METHODS;
+import static org.objectweb.asm.Opcodes.ACONST_NULL;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.CHECKCAST;
+import static org.objectweb.asm.Opcodes.GOTO;
+import static org.objectweb.asm.Opcodes.IFNULL;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+
+public class StaticInvocationWriter extends InvocationWriter {
+    private static final ClassNode INVOKERHELPER_CLASSNODE = ClassHelper.make(InvokerHelper.class);
+    private static final Expression INVOKERHELER_RECEIVER = new ClassExpression(INVOKERHELPER_CLASSNODE);
+    private static final MethodNode INVOKERHELPER_INVOKEMETHOD = INVOKERHELPER_CLASSNODE.getMethod(
+            "invokeMethodSafe",
+            new Parameter[]{
+                    new Parameter(ClassHelper.OBJECT_TYPE, "object"),
+                    new Parameter(ClassHelper.STRING_TYPE, "name"),
+                    new Parameter(ClassHelper.OBJECT_TYPE, "args")
+            }
+    );
+
+    private static final MethodNode INVOKERHELPER_INVOKESTATICMETHOD = INVOKERHELPER_CLASSNODE.getMethod(
+            "invokeStaticMethod",
+            new Parameter[]{
+                    new Parameter(ClassHelper.CLASS_Type, "clazz"),
+                    new Parameter(ClassHelper.STRING_TYPE, "name"),
+                    new Parameter(ClassHelper.OBJECT_TYPE, "args")
+            }
+    );
+
+    private final AtomicInteger labelCounter = new AtomicInteger();
+
+    final WriterController controller;
+
+    private MethodCallExpression currentCall;
+
+    public StaticInvocationWriter(WriterController wc) {
+        super(wc);
+        controller = wc;
+    }
+
+    @Override
+    protected boolean makeDirectCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean implicitThis, final boolean containsSpreadExpression) {
+        if (origin instanceof MethodCallExpression &&
+                receiver instanceof VariableExpression &&
+                ((VariableExpression) receiver).isSuperExpression()) {
+            ClassNode superClass = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
+            if (superClass!=null && !controller.getCompileStack().isLHS()) {
+                // GROOVY-7300
+                MethodCallExpression mce = (MethodCallExpression) origin;
+                MethodNode node = superClass.getDeclaredMethod(mce.getMethodAsString(), Parameter.EMPTY_ARRAY);
+                mce.setMethodTarget(node);
+            }
+        }
+        return super.makeDirectCall(origin, receiver, message, arguments, adapter, implicitThis, containsSpreadExpression);
+    }
+
+    @Override
+    public void writeInvokeMethod(final MethodCallExpression call) {
+        MethodCallExpression old = currentCall;
+        currentCall = call;
+        super.writeInvokeMethod(call);
+        currentCall = old;
+    }
+
+    @Override
+    public void writeInvokeConstructor(final ConstructorCallExpression call) {
+        MethodNode mn = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+        if (mn == null) {
+            super.writeInvokeConstructor(call);
+            return;
+        }
+        if (writeAICCall(call)) return;
+        ConstructorNode cn;
+        if (mn instanceof ConstructorNode) {
+            cn = (ConstructorNode) mn;
+        } else {
+            cn = new ConstructorNode(mn.getModifiers(), mn.getParameters(), mn.getExceptions(), mn.getCode());
+            cn.setDeclaringClass(mn.getDeclaringClass());
+        }
+        TupleExpression args = makeArgumentList(call.getArguments());
+        if (cn.isPrivate()) {
+            ClassNode classNode = controller.getClassNode();
+            ClassNode declaringClass = cn.getDeclaringClass();
+            if (declaringClass != classNode) {
+                MethodNode bridge = null;
+                if (call.getNodeMetaData(StaticTypesMarker.PV_METHODS_ACCESS) != null) {
+                    Map<MethodNode, MethodNode> bridgeMethods = declaringClass.getNodeMetaData(StaticCompilationMetadataKeys.PRIVATE_BRIDGE_METHODS);
+                    bridge = bridgeMethods != null ? bridgeMethods.get(cn) : null;
+                }
+                if (bridge != null && bridge instanceof ConstructorNode) {
+                    ArgumentListExpression newArgs = new ArgumentListExpression(new ConstantExpression(null));
+                    for (Expression arg: args) {
+                        newArgs.addExpression(arg);
+                    }
+                    cn = (ConstructorNode) bridge;
+                    args = newArgs;
+                } else {
+                    controller.getSourceUnit().addError(new SyntaxException("Cannot call private constructor for " + declaringClass.toString(false) +
+                            " from class " + classNode.toString(false), call.getLineNumber(), call.getColumnNumber(), mn.getLastLineNumber(), call.getLastColumnNumber()));
+                }
+            }
+        }
+
+        String ownerDescriptor = prepareConstructorCall(cn);
+        int before = controller.getOperandStack().getStackLength();
+        loadArguments(args.getExpressions(), cn.getParameters());
+        finnishConstructorCall(cn, ownerDescriptor, controller.getOperandStack().getStackLength() - before);
+    }
+
+    @Override
+    public void writeSpecialConstructorCall(final ConstructorCallExpression call) {
+        MethodNode mn = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+        if (mn==null) {
+            super.writeSpecialConstructorCall(call);
+            return;
+        }
+        controller.getCompileStack().pushInSpecialConstructorCall();
+        ConstructorNode cn;
+        if (mn instanceof ConstructorNode) {
+            cn = (ConstructorNode) mn;
+        } else {
+            cn = new ConstructorNode(mn.getModifiers(), mn.getParameters(), mn.getExceptions(), mn.getCode());
+            cn.setDeclaringClass(mn.getDeclaringClass());
+        }
+        // load "this"
+        controller.getMethodVisitor().visitVarInsn(ALOAD, 0);
+        String ownerDescriptor = BytecodeHelper.getClassInternalName(cn.getDeclaringClass());
+        TupleExpression args = makeArgumentList(call.getArguments());
+        int before = controller.getOperandStack().getStackLength();
+        loadArguments(args.getExpressions(), cn.getParameters());
+        finnishConstructorCall(cn, ownerDescriptor, controller.getOperandStack().getStackLength() - before);
+        // on a special call, there's no object on stack
+        controller.getOperandStack().remove(1);
+        controller.getCompileStack().pop();
+    }
+
+    /**
+     * Attempts to make a direct method call on a bridge method, if it exists.
+     */
+    @Deprecated
+    protected boolean tryBridgeMethod(MethodNode target, Expression receiver, boolean implicitThis, TupleExpression args) {
+        return tryBridgeMethod(target, receiver, implicitThis, args, null);
+    }
+
+    /**
+     * Attempts to make a direct method call on a bridge method, if it exists.
+     */
+    protected boolean tryBridgeMethod(MethodNode target, Expression receiver, boolean implicitThis,
+                                      TupleExpression args, ClassNode thisClass) {
+        ClassNode lookupClassNode;
+        if (target.isProtected()) {
+            lookupClassNode = controller.getClassNode();
+            while (lookupClassNode != null && !lookupClassNode.isDerivedFrom(target.getDeclaringClass())) {
+                lookupClassNode = lookupClassNode.getOuterClass();
+            }
+            if (lookupClassNode == null) {
+                return false;
+            }
+        } else {
+            lookupClassNode = target.getDeclaringClass().redirect();
+        }
+        Map<MethodNode, MethodNode> bridges = lookupClassNode.getNodeMetaData(PRIVATE_BRIDGE_METHODS);
+        MethodNode bridge = bridges==null?null:bridges.get(target);
+        if (bridge != null) {
+            Expression fixedReceiver = receiver;
+            if (implicitThis) {
+                if (!controller.isInClosure()) {
+                    fixedReceiver = new PropertyExpression(new ClassExpression(lookupClassNode), "this");
+                } else if (thisClass != null) {
+                    ClassNode current = thisClass.getOuterClass();
+                    fixedReceiver = new VariableExpression("thisObject", current);
+                    // adjust for multiple levels of nesting if needed
+                    while (current != null && current instanceof InnerClassNode && !lookupClassNode.equals(current)) {
+                        FieldNode thisField = current.getField("this$0");
+                        current = current.getOuterClass();
+                        if (thisField != null) {
+                            fixedReceiver = new PropertyExpression(fixedReceiver, "this$0");
+                            fixedReceiver.setType(current);
+                        }
+                    }
+                }
+            }
+            ArgumentListExpression newArgs = new ArgumentListExpression(target.isStatic()?new ConstantExpression(null):fixedReceiver);
+            for (Expression expression : args.getExpressions()) {
+                newArgs.addExpression(expression);
+            }
+            return writeDirectMethodCall(bridge, implicitThis, fixedReceiver, newArgs);
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean writeDirectMethodCall(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args) {
+        if (target==null) return false;
+
+        if (target instanceof ExtensionMethodNode) {
+            ExtensionMethodNode emn = (ExtensionMethodNode) target;
+            MethodNode node = emn.getExtensionMethodNode();
+            String methodName = target.getName();
+
+            MethodVisitor mv = controller.getMethodVisitor();
+            int argumentsToRemove = 0;
+            List<Expression> argumentList = new LinkedList<Expression>(args.getExpressions());
+
+            if (emn.isStaticExtension()) {
+                // it's a static extension method
+                argumentList.add(0, ConstantExpression.NULL);
+            } else {
+                argumentList.add(0, receiver);
+            }
+
+            Parameter[] parameters = node.getParameters();
+            loadArguments(argumentList, parameters);
+
+            String owner = BytecodeHelper.getClassInternalName(node.getDeclaringClass());
+            String desc = BytecodeHelper.getMethodDescriptor(target.getReturnType(), parameters);
+            mv.visitMethodInsn(INVOKESTATIC, owner, methodName, desc, false);
+            ClassNode ret = target.getReturnType().redirect();
+            if (ret == ClassHelper.VOID_TYPE) {
+                ret = ClassHelper.OBJECT_TYPE;
+                mv.visitInsn(ACONST_NULL);
+            }
+            argumentsToRemove += argumentList.size();
+            controller.getOperandStack().remove(argumentsToRemove);
+            controller.getOperandStack().push(ret);
+            return true;
+        } else {
+            if (target == StaticTypeCheckingVisitor.CLOSURE_CALL_VARGS) {
+                // wrap arguments into an array
+                ArrayExpression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
+                return super.writeDirectMethodCall(target, implicitThis, receiver, new ArgumentListExpression(arr));
+            }
+            ClassNode classNode = controller.getClassNode();
+            if (classNode.isDerivedFrom(ClassHelper.CLOSURE_TYPE)
+                    && controller.isInClosure()
+                    && !target.isPublic()
+                    && target.getDeclaringClass() != classNode) {
+                if (!tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
+                    // replace call with an invoker helper call
+                    ArrayExpression arr = new ArrayExpression(ClassHelper.OBJECT_TYPE, args.getExpressions());
+                    MethodCallExpression mce = new MethodCallExpression(
+                            INVOKERHELER_RECEIVER,
+                            target.isStatic() ? "invokeStaticMethod" : "invokeMethodSafe",
+                            new ArgumentListExpression(
+                                    target.isStatic() ?
+                                            new ClassExpression(target.getDeclaringClass()) :
+                                            receiver,
+                                    new ConstantExpression(target.getName()),
+                                    arr
+                            )
+                    );
+                    mce.setMethodTarget(target.isStatic() ? INVOKERHELPER_INVOKESTATICMETHOD : INVOKERHELPER_INVOKEMETHOD);
+                    mce.visit(controller.getAcg());
+                    return true;
+                }
+                return true;
+            }
+            Expression fixedReceiver = null;
+            boolean fixedImplicitThis = implicitThis;
+            if (target.isPrivate()) {
+                if (tryPrivateMethod(target, implicitThis, receiver, args, classNode)) return true;
+            } else if (target.isProtected()) {
+                ClassNode node = receiver==null?ClassHelper.OBJECT_TYPE:controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
+                boolean isThisOrSuper = false;
+                if (receiver instanceof VariableExpression) {
+                    isThisOrSuper = ((VariableExpression) receiver).isThisExpression() || ((VariableExpression) receiver).isSuperExpression();
+                }
+                if (!implicitThis && !isThisOrSuper
+                        && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(node,target.getDeclaringClass())) {
+                    ASTNode src = receiver==null?args:receiver;
+                    controller.getSourceUnit().addError(
+                            new SyntaxException("Method " + target.getName() + " is protected in " + target.getDeclaringClass().toString(false),
+                                    src.getLineNumber(), src.getColumnNumber(), src.getLastLineNumber(), src.getLastColumnNumber()));
+                } else if (!node.isDerivedFrom(target.getDeclaringClass()) && tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
+                    return true;
+                }
+            } else if (target.isPublic() && receiver != null) {
+                if (implicitThis
+                        && !classNode.isDerivedFrom(target.getDeclaringClass())
+                        && !classNode.implementsInterface(target.getDeclaringClass())
+                        && classNode instanceof InnerClassNode && controller.isInClosure()) {
+                    ClassNode current = classNode.getOuterClass();
+                    fixedReceiver = new VariableExpression("thisObject", current);
+                    // adjust for multiple levels of nesting if needed
+                    while (current != null && current instanceof InnerClassNode && !classNode.equals(current)) {
+                        FieldNode thisField = current.getField("this$0");
+                        current = current.getOuterClass();
+                        if (thisField != null) {
+                            fixedReceiver = new PropertyExpression(fixedReceiver, "this$0");
+                            fixedReceiver.setType(current);
+                            fixedImplicitThis = false;
+                        }
+                    }
+                }
+            }
+            if (receiver != null) {
+                boolean callToSuper = receiver instanceof VariableExpression && ((VariableExpression) receiver).isSuperExpression();
+                if (!callToSuper) {
+                    fixedReceiver = fixedReceiver == null ? receiver : fixedReceiver;
+                    // in order to avoid calls to castToType, which is the dynamic behaviour, we make sure that we call CHECKCAST instead
+                    // then replace the top operand type
+                    Expression checkCastReceiver = new CheckcastReceiverExpression(fixedReceiver, target);
+                    return super.writeDirectMethodCall(target, fixedImplicitThis, checkCastReceiver, args);
+                }
+            }
+            return super.writeDirectMethodCall(target, implicitThis, receiver, args);
+        }
+    }
+
+    private boolean tryPrivateMethod(final MethodNode target, final boolean implicitThis, final Expression receiver, final TupleExpression args, final ClassNode classNode) {
+        ClassNode declaringClass = target.getDeclaringClass();
+        if ((isPrivateBridgeMethodsCallAllowed(declaringClass, classNode) || isPrivateBridgeMethodsCallAllowed(classNode, declaringClass))
+                && declaringClass.getNodeMetaData(PRIVATE_BRIDGE_METHODS) != null
+                && !declaringClass.equals(classNode)) {
+            if (tryBridgeMethod(target, receiver, implicitThis, args, classNode)) {
+                return true;
+            } else if (declaringClass != classNode) {
+                controller.getSourceUnit().addError(new SyntaxException("Cannot call private method " + (target.isStatic() ? "static " : "") +
+                        declaringClass.toString(false) + "#" + target.getName() + " from class " + classNode.toString(false), receiver.getLineNumber(), receiver.getColumnNumber(), receiver.getLastLineNumber(), receiver.getLastColumnNumber()));
+            }
+        }
+        if (declaringClass != classNode) {
+            controller.getSourceUnit().addError(new SyntaxException("Cannot call private method " + (target.isStatic() ? "static " : "") +
+                                                declaringClass.toString(false) + "#" + target.getName() + " from class " + classNode.toString(false), receiver.getLineNumber(), receiver.getColumnNumber(), receiver.getLastLineNumber(), receiver.getLastColumnNumber()));
+        }
+        return false;
+    }
+
+    protected static boolean isPrivateBridgeMethodsCallAllowed(ClassNode receiver, ClassNode caller) {
+        if (receiver == null) return false;
+        if (receiver.redirect() == caller) return true;
+        if (caller.redirect() instanceof InnerClassNode) return
+                isPrivateBridgeMethodsCallAllowed(receiver, caller.redirect().getOuterClass()) ||
+                        isPrivateBridgeMethodsCallAllowed(receiver.getOuterClass(), caller);
+        return false;
+    }
+
+    protected void loadArguments(List<Expression> argumentList, Parameter[] para) {
+        if (para.length == 0) return;
+        ClassNode lastParaType = para[para.length - 1].getOriginType();
+        AsmClassGenerator acg = controller.getAcg();
+        TypeChooser typeChooser = controller.getTypeChooser();
+        OperandStack operandStack = controller.getOperandStack();
+        ClassNode lastArgType = !argumentList.isEmpty() ?
+                typeChooser.resolveType(argumentList.get(argumentList.size()-1), controller.getClassNode()):null;
+        if (lastParaType.isArray()
+                && ((argumentList.size() > para.length)
+                || ((argumentList.size() == (para.length - 1)) && !lastParaType.equals(lastArgType))
+                || ((argumentList.size() == para.length && lastArgType!=null && !lastArgType.isArray())
+                    && (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(lastArgType,lastParaType.getComponentType())))
+                        || ClassHelper.GSTRING_TYPE.equals(lastArgType) && ClassHelper.STRING_TYPE.equals(lastParaType.getComponentType()))
+                ) {
+            int stackLen = operandStack.getStackLength() + argumentList.size();
+            MethodVisitor mv = controller.getMethodVisitor();
+            //mv = new org.objectweb.asm.util.TraceMethodVisitor(mv);
+            controller.setMethodVisitor(mv);
+            // varg call
+            // first parameters as usual
+            for (int i = 0; i < para.length - 1; i++) {
+                Expression expression = argumentList.get(i);
+                expression.visit(acg);
+                if (!isNullConstant(expression)) {
+                    operandStack.doGroovyCast(para[i].getType());
+                }
+            }
+            // last parameters wrapped in an array
+            List<Expression> lastParams = new LinkedList<Expression>();
+            for (int i = para.length - 1; i < argumentList.size(); i++) {
+                lastParams.add(argumentList.get(i));
+            }
+            ArrayExpression array = new ArrayExpression(
+                    lastParaType.getComponentType(),
+                    lastParams
+            );
+            array.visit(acg);
+            // adjust stack length
+            while (operandStack.getStackLength() < stackLen) {
+                operandStack.push(ClassHelper.OBJECT_TYPE);
+            }
+            if (argumentList.size() == para.length - 1) {
+                operandStack.remove(1);
+            }
+        } else if (argumentList.size() == para.length) {
+            for (int i = 0; i < argumentList.size(); i++) {
+                Expression expression = argumentList.get(i);
+                expression.visit(acg);
+                if (!isNullConstant(expression)) {
+                    operandStack.doGroovyCast(para[i].getType());
+                }
+            }
+        } else {
+            // method call with default arguments
+            ClassNode classNode = controller.getClassNode();
+            Expression[] arguments = new Expression[para.length];
+            for (int i = 0, j = 0; i < para.length; i++) {
+                Parameter curParam = para[i];
+                ClassNode curParamType = curParam.getType();
+                Expression curArg = j < argumentList.size() ? argumentList.get(j) : null;
+                Expression initialExpression = curParam.getNodeMetaData(StaticTypesMarker.INITIAL_EXPRESSION);
+                if (initialExpression == null && curParam.hasInitialExpression())
+                    initialExpression = curParam.getInitialExpression();
+                if (initialExpression == null && curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION)!=null) {
+                    initialExpression = curParam.getNodeMetaData(Verifier.INITIAL_EXPRESSION);
+                }
+                ClassNode curArgType = curArg == null ? null : typeChooser.resolveType(curArg, classNode);
+
+                if (initialExpression != null && !compatibleArgumentType(curArgType, curParamType)) {
+                    // use default expression
+                    arguments[i] = initialExpression;
+                } else {
+                    arguments[i] = curArg;
+                    j++;
+                }
+            }
+            for (int i = 0; i < arguments.length; i++) {
+                Expression expression = arguments[i];
+                expression.visit(acg);
+                if (!isNullConstant(expression)) {
+                    operandStack.doGroovyCast(para[i].getType());
+                }
+            }
+        }
+    }
+
+    private static boolean isNullConstant(final Expression expression) {
+        return (expression instanceof ConstantExpression && ((ConstantExpression) expression).getValue() == null);
+    }
+
+    private boolean compatibleArgumentType(ClassNode argumentType, ClassNode paramType) {
+        if (argumentType == null) return false;
+        if (ClassHelper.getWrapper(argumentType).equals(ClassHelper.getWrapper(paramType))) return true;
+        if (paramType.isInterface()) return argumentType.implementsInterface(paramType);
+        if (paramType.isArray() && argumentType.isArray())
+            return compatibleArgumentType(argumentType.getComponentType(), paramType.getComponentType());
+        return ClassHelper.getWrapper(argumentType).isDerivedFrom(ClassHelper.getWrapper(paramType));
+    }
+
+    @Override
+    public void makeCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
+        ClassNode dynamicCallReturnType = origin.getNodeMetaData(StaticTypesMarker.DYNAMIC_RESOLUTION);
+        if (dynamicCallReturnType !=null) {
+            StaticTypesWriterController staticController = (StaticTypesWriterController) controller;
+            if (origin instanceof MethodCallExpression) {
+                ((MethodCallExpression) origin).setMethodTarget(null);
+            }
+            InvocationWriter dynamicInvocationWriter = staticController.getRegularInvocationWriter();
+            dynamicInvocationWriter.
+                    makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
+            return;
+        }
+        if (tryImplicitReceiver(origin, message, arguments, adapter, safe, spreadSafe, implicitThis)) {
+            return;
+        }
+        // if call is spread safe, replace it with a for in loop
+        if (spreadSafe && origin instanceof MethodCallExpression) {
+            // receiver expressions with side effects should not be visited twice, avoid by using a temporary variable
+            Expression tmpReceiver = receiver;
+            if (!(receiver instanceof VariableExpression) && !(receiver instanceof ConstantExpression)) {
+                tmpReceiver = new TemporaryVariableExpression(receiver);
+            }
+            MethodVisitor mv = controller.getMethodVisitor();
+            CompileStack compileStack = controller.getCompileStack();
+            TypeChooser typeChooser = controller.getTypeChooser();
+            OperandStack operandStack = controller.getOperandStack();
+            ClassNode classNode = controller.getClassNode();
+            int counter = labelCounter.incrementAndGet();
+
+            // use a temporary variable for the arraylist in which the results of the spread call will be stored
+            ConstructorCallExpression cce = new ConstructorCallExpression(StaticCompilationVisitor.ARRAYLIST_CLASSNODE, ArgumentListExpression.EMPTY_ARGUMENTS);
+            cce.setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, StaticCompilationVisitor.ARRAYLIST_CONSTRUCTOR);
+            TemporaryVariableExpression result = new TemporaryVariableExpression(cce);
+            result.visit(controller.getAcg());
+            operandStack.pop();
+            // if (receiver != null)
+            tmpReceiver.visit(controller.getAcg());
+            Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
+            mv.visitJumpInsn(IFNULL, ifnull);
+            operandStack.remove(1); // receiver consumed by if()
+            Label nonull = compileStack.createLocalLabel("nonull_" + counter);
+            mv.visitLabel(nonull);
+            ClassNode componentType = StaticTypeCheckingVisitor.inferLoopElementType(typeChooser.resolveType(tmpReceiver, classNode));
+            Parameter iterator = new Parameter(componentType, "for$it$" + counter);
+            VariableExpression iteratorAsVar = new VariableExpression(iterator);
+            MethodCallExpression origMCE = (MethodCallExpression) origin;
+            MethodCallExpression newMCE = new MethodCallExpression(
+                    iteratorAsVar,
+                    origMCE.getMethodAsString(),
+                    origMCE.getArguments()
+            );
+            newMCE.setImplicitThis(false);
+            newMCE.setMethodTarget(origMCE.getMethodTarget());
+            newMCE.setSafe(true);
+            MethodCallExpression add = new MethodCallExpression(
+                    result,
+                    "add",
+                    newMCE
+            );
+            add.setImplicitThis(false);
+            add.setMethodTarget(StaticCompilationVisitor.ARRAYLIST_ADD_METHOD);
+            // for (e in receiver) { result.add(e?.method(arguments) }
+            ForStatement stmt = new ForStatement(
+                    iterator,
+                    tmpReceiver,
+                    new ExpressionStatement(add)
+            );
+            stmt.visit(controller.getAcg());
+            // else { empty list }
+            mv.visitLabel(ifnull);
+
+            // end of if/else
+            // return result list
+            result.visit(controller.getAcg());
+
+            // cleanup temporary variables
+            if (tmpReceiver instanceof TemporaryVariableExpression) {
+                ((TemporaryVariableExpression) tmpReceiver).remove(controller);
+            }
+            result.remove(controller);
+        } else if (safe && origin instanceof MethodCallExpression) {
+            // wrap call in an IFNULL check
+            MethodVisitor mv = controller.getMethodVisitor();
+            CompileStack compileStack = controller.getCompileStack();
+            OperandStack operandStack = controller.getOperandStack();
+            int counter = labelCounter.incrementAndGet();
+            // if (receiver != null)
+            ExpressionAsVariableSlot slot = new ExpressionAsVariableSlot(controller, receiver);
+            slot.visit(controller.getAcg());
+            operandStack.box();
+            Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
+            mv.visitJumpInsn(IFNULL, ifnull);
+            operandStack.remove(1); // receiver consumed by if()
+            Label nonull = compileStack.createLocalLabel("nonull_" + counter);
+            mv.visitLabel(nonull);
+            MethodCallExpression origMCE = (MethodCallExpression) origin;
+            MethodCallExpression newMCE = new MethodCallExpression(
+                    new VariableSlotLoader(slot.getType(), slot.getIndex(), controller.getOperandStack()),
+                    origMCE.getMethodAsString(),
+                    origMCE.getArguments()
+            );
+            MethodNode methodTarget = origMCE.getMethodTarget();
+            newMCE.setMethodTarget(methodTarget);
+            newMCE.setSafe(false);
+            newMCE.setImplicitThis(origMCE.isImplicitThis());
+            newMCE.setSourcePosition(origMCE);
+            newMCE.visit(controller.getAcg());
+            compileStack.removeVar(slot.getIndex());
+            ClassNode returnType = operandStack.getTopOperand();
+            if (ClassHelper.isPrimitiveType(returnType) && !ClassHelper.VOID_TYPE.equals(returnType)) {
+                operandStack.box();
+            }
+            Label endof = compileStack.createLocalLabel("endof_" + counter);
+            mv.visitJumpInsn(GOTO, endof);
+            mv.visitLabel(ifnull);
+            // else { null }
+            mv.visitInsn(ACONST_NULL);
+            mv.visitLabel(endof);
+        } else {
+            if ((adapter == AsmClassGenerator.getGroovyObjectField
+                    || adapter == AsmClassGenerator.getField ) && origin instanceof AttributeExpression) {
+                String pname = ((PropertyExpression) origin).getPropertyAsString();
+                CallSiteWriter callSiteWriter = controller.getCallSiteWriter();
+                if (pname!=null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
+                    StaticTypesCallSiteWriter stcsw = (StaticTypesCallSiteWriter) callSiteWriter;
+                    TypeChooser typeChooser = controller.getTypeChooser();
+                    if (stcsw.makeGetField(receiver, typeChooser.resolveType(receiver, controller.getClassNode()), pname, safe, false, true)) {
+                        return;
+                    }
+                }
+            }
+            super.makeCall(origin, receiver, message, arguments, adapter, safe, spreadSafe, implicitThis);
+        }
+    }
+
+    boolean tryImplicitReceiver(final Expression origin, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
+        Object implicitReceiver = origin.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+        if (implicitThis && implicitReceiver==null && origin instanceof MethodCallExpression) {
+            implicitReceiver = ((MethodCallExpression) origin).getObjectExpression().getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+        }
+        if (implicitReceiver !=null && implicitThis) {
+            String[] propertyPath = ((String) implicitReceiver).split("\\.");
+            // GROOVY-6021
+            PropertyExpression pexp = new PropertyExpression(new VariableExpression("this", CLOSURE_TYPE), propertyPath[0]);
+            pexp.setImplicitThis(true);
+            for (int i=1; i<propertyPath.length;i++) {
+                pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, CLOSURE_TYPE);
+                pexp = new PropertyExpression(pexp, propertyPath[i]);
+            }
+            pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, implicitReceiver);
+            origin.removeNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
+            if (origin instanceof PropertyExpression) {
+                PropertyExpression rewritten = new PropertyExpression(
+                        pexp,
+                        ((PropertyExpression) origin).getProperty(),
+                        ((PropertyExpression) origin).isSafe()
+                );
+                rewritten.setSpreadSafe(((PropertyExpression) origin).isSpreadSafe());
+                rewritten.setImplicitThis(false);
+                rewritten.visit(controller.getAcg());
+                rewritten.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, origin.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE));
+                return true;
+            }
+            makeCall(origin, pexp, message, arguments, adapter, safe, spreadSafe, false);
+            return true;
+        }
+        return false;
+    }
+
+    private class CheckcastReceiverExpression extends Expression {
+        private final Expression receiver;
+        private final MethodNode target;
+
+        private ClassNode resolvedType;
+
+        public CheckcastReceiverExpression(final Expression receiver, final MethodNode target) {
+            this.receiver = receiver;
+            this.target = target;
+        }
+
+        @Override
+        public Expression transformExpression(final ExpressionTransformer transformer) {
+            return this;
+        }
+
+        @Override
+        public void visit(final GroovyCodeVisitor visitor) {
+            receiver.visit(visitor);
+            if (visitor instanceof AsmClassGenerator) {
+                ClassNode topOperand = controller.getOperandStack().getTopOperand();
+                ClassNode type = getType();
+                if (ClassHelper.GSTRING_TYPE.equals(topOperand) && ClassHelper.STRING_TYPE.equals(type)) {
+                    // perform regular type conversion
+                    controller.getOperandStack().doGroovyCast(type);
+                    return;
+                }
+                if (ClassHelper.isPrimitiveType(topOperand) && !ClassHelper.isPrimitiveType(type)) {
+                    controller.getOperandStack().box();
+                } else if (!ClassHelper.isPrimitiveType(topOperand) && ClassHelper.isPrimitiveType(type)) {
+                    controller.getOperandStack().doGroovyCast(type);
+                }
+                if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(topOperand, type)) return;
+                controller.getMethodVisitor().visitTypeInsn(CHECKCAST, type.isArray() ?
+                        BytecodeHelper.getTypeDescription(type) :
+                        BytecodeHelper.getClassInternalName(type.getName()));
+                controller.getOperandStack().replace(type);
+            }
+        }
+
+        @Override
+        public ClassNode getType() {
+            if (resolvedType!=null) {
+                return resolvedType;
+            }
+            ClassNode type;
+            if (target instanceof ExtensionMethodNode) {
+                type = ((ExtensionMethodNode) target).getExtensionMethodNode().getDeclaringClass();
+            } else {
+                type = getWrapper(controller.getTypeChooser().resolveType(receiver, controller.getClassNode()));
+                ClassNode declaringClass = target.getDeclaringClass();
+                if (type.getClass() != ClassNode.class
+                        && type.getClass() != InnerClassNode.class
+                        && type.getClass() != DecompiledClassNode.class) {
+                    type = declaringClass; // ex: LUB type
+                }
+                if (OBJECT_TYPE.equals(type) && !OBJECT_TYPE.equals(declaringClass)) {
+                    // can happen for compiler rewritten code, where type information is missing
+                    type = declaringClass;
+                }
+                if (OBJECT_TYPE.equals(declaringClass)) {
+                    // check cast not necessary because Object never evolves
+                    // and it prevents a potential ClassCastException if the delegate of a closure
+                    // is changed in a statically compiled closure
+                    type = OBJECT_TYPE;
+                }
+            }
+            resolvedType = type;
+            return type;
+        }
+    }
+
+    public MethodCallExpression getCurrentCall() {
+        return currentCall;
+    }
+
+    @Override
+    protected boolean makeCachedCall(Expression origin, ClassExpression sender, Expression receiver, Expression message, Expression arguments, MethodCallerMultiAdapter adapter, boolean safe, boolean spreadSafe, boolean implicitThis, boolean containsSpreadExpression) {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
new file mode 100644
index 0000000..6027a0c
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
@@ -0,0 +1,133 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.transform.sc.ListOfExpressionsExpression;
+import org.codehaus.groovy.transform.sc.TemporaryVariableExpression;
+
+import java.util.Arrays;
+
+/**
+ * Contains helper methods aimed at facilitating the generation of statically compiled bytecode for property access.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public abstract class StaticPropertyAccessHelper {
+    public static Expression transformToSetterCall(
+            Expression receiver,
+            MethodNode setterMethod,
+            final Expression arguments,
+            boolean implicitThis,
+            boolean safe,
+            boolean spreadSafe,
+            boolean requiresReturnValue,
+            Expression location) {
+        if (requiresReturnValue) {
+            TemporaryVariableExpression tmp = new TemporaryVariableExpression(arguments);
+            PoppingMethodCallExpression call = new PoppingMethodCallExpression(receiver, setterMethod, tmp);
+            call.setImplicitThis(implicitThis);
+            call.setSafe(safe);
+            call.setSpreadSafe(spreadSafe);
+            call.setSourcePosition(location);
+            PoppingListOfExpressionsExpression result = new PoppingListOfExpressionsExpression(tmp, call);
+            result.setSourcePosition(location);
+            return result;
+        } else {
+            MethodCallExpression call = new MethodCallExpression(
+                    receiver,
+                    setterMethod.getName(),
+                    arguments
+            );
+            call.setImplicitThis(implicitThis);
+            call.setSafe(safe);
+            call.setSpreadSafe(spreadSafe);
+            call.setMethodTarget(setterMethod);
+            call.setSourcePosition(location);
+            return call;
+        }
+    }
+
+    private static class PoppingListOfExpressionsExpression extends ListOfExpressionsExpression {
+        private final TemporaryVariableExpression tmp;
+        private final PoppingMethodCallExpression call;
+
+        public PoppingListOfExpressionsExpression(final TemporaryVariableExpression tmp, final PoppingMethodCallExpression call) {
+            super(Arrays.asList(
+                    tmp,
+                    call
+            ));
+            this.tmp = tmp;
+            this.call = call;
+        }
+
+        @Override
+        public Expression transformExpression(final ExpressionTransformer transformer) {
+            PoppingMethodCallExpression tcall = (PoppingMethodCallExpression) call.transformExpression(transformer);
+            return new PoppingListOfExpressionsExpression(tcall.tmp, tcall);
+        }
+
+        @Override
+        public void visit(final GroovyCodeVisitor visitor) {
+            super.visit(visitor);
+            if (visitor instanceof AsmClassGenerator) {
+                tmp.remove(((AsmClassGenerator) visitor).getController());
+            }
+        }
+    }
+
+    private static class PoppingMethodCallExpression extends MethodCallExpression {
+        private final Expression receiver;
+        private final MethodNode setter;
+        private final TemporaryVariableExpression tmp;
+
+        public PoppingMethodCallExpression(final Expression receiver, final MethodNode setterMethod, final TemporaryVariableExpression tmp) {
+            super(receiver, setterMethod.getName(), tmp);
+            this.receiver = receiver;
+            this.setter = setterMethod;
+            this.tmp = tmp;
+            setMethodTarget(setterMethod);
+        }
+
+        @Override
+        public Expression transformExpression(final ExpressionTransformer transformer) {
+            PoppingMethodCallExpression trn = new PoppingMethodCallExpression(receiver.transformExpression(transformer), setter, (TemporaryVariableExpression) tmp.transformExpression(transformer));
+            trn.copyNodeMetaData(this);
+            trn.setImplicitThis(isImplicitThis());
+            trn.setSafe(isSafe());
+            trn.setSpreadSafe(isSpreadSafe());
+            return trn;
+        }
+
+        @Override
+        public void visit(final GroovyCodeVisitor visitor) {
+            super.visit(visitor);
+            if (visitor instanceof AsmClassGenerator) {
+                // ignore the return of the call
+                ((AsmClassGenerator) visitor).getController().getOperandStack().pop();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
new file mode 100644
index 0000000..116fd16
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
@@ -0,0 +1,426 @@
+/*
+ *  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.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.AttributeExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
+import org.codehaus.groovy.ast.expr.DeclarationExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.stmt.ExpressionStatement;
+import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.tools.WideningCategories;
+import org.codehaus.groovy.classgen.asm.BinaryExpressionMultiTypeDispatcher;
+import org.codehaus.groovy.classgen.asm.BinaryExpressionWriter;
+import org.codehaus.groovy.classgen.asm.BytecodeHelper;
+import org.codehaus.groovy.classgen.asm.CompileStack;
+import org.codehaus.groovy.classgen.asm.OperandStack;
+import org.codehaus.groovy.classgen.asm.TypeChooser;
+import org.codehaus.groovy.classgen.asm.VariableSlotLoader;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
+import org.codehaus.groovy.transform.sc.StaticCompilationVisitor;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.Modifier;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.char_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.double_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.float_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.long_TYPE;
+import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.ARRAYLIST_ADD_METHOD;
+import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.ARRAYLIST_CLASSNODE;
+import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.ARRAYLIST_CONSTRUCTOR;
+
+/**
+ * A specialized version of the multi type binary expression dispatcher which is aware of static compilation.
+ * It is able to generate optimized bytecode for some operations using JVM instructions when available.
+ *
+ * @author Cedric Champeau
+ * @author Jochen Theodorou
+ */
+public class StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpressionMultiTypeDispatcher implements Opcodes {
+
+    private final AtomicInteger labelCounter = new AtomicInteger();
+    private static final MethodNode CLOSURE_GETTHISOBJECT_METHOD = CLOSURE_TYPE.getMethod("getThisObject", new Parameter[0]);
+
+
+    public StaticTypesBinaryExpressionMultiTypeDispatcher(WriterController wc) {
+        super(wc);
+    }
+
+    @Override
+    protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
+        MethodNode mn = orig.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+        WriterController controller = getController();
+        OperandStack operandStack = controller.getOperandStack();
+        if (mn!=null) {
+            operandStack.pop();
+            MethodCallExpression call = new MethodCallExpression(
+                    expression,
+                    method,
+                    ArgumentListExpression.EMPTY_ARGUMENTS
+            );
+            call.setMethodTarget(mn);
+            call.visit(controller.getAcg());
+            return;
+        }
+
+        ClassNode top = operandStack.getTopOperand();
+        if (ClassHelper.isPrimitiveType(top) && (ClassHelper.isNumberType(top)||char_TYPE.equals(top))) {
+            MethodVisitor mv = controller.getMethodVisitor();
+            if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
+                mv.visitInsn(ICONST_1);
+            } else if (long_TYPE.equals(top)) {
+                mv.visitInsn(LCONST_1);
+            } else if (float_TYPE.equals(top)) {
+                mv.visitInsn(FCONST_1);
+            } else if (double_TYPE.equals(top)) {
+                mv.visitInsn(DCONST_1);
+            }
+            if ("next".equals(method)) {
+                if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
+                    mv.visitInsn(IADD);
+                } else if (long_TYPE.equals(top)) {
+                    mv.visitInsn(LADD);
+                } else if (float_TYPE.equals(top)) {
+                    mv.visitInsn(FADD);
+                } else if (double_TYPE.equals(top)) {
+                    mv.visitInsn(DADD);
+                }
+            } else {
+                if (WideningCategories.isIntCategory(top) || char_TYPE.equals(top)) {
+                    mv.visitInsn(ISUB);
+                } else if (long_TYPE.equals(top)) {
+                    mv.visitInsn(LSUB);
+                } else if (float_TYPE.equals(top)) {
+                    mv.visitInsn(FSUB);
+                } else if (double_TYPE.equals(top)) {
+                    mv.visitInsn(DSUB);
+                }
+            }
+            return;
+        }
+        super.writePostOrPrefixMethod(op, method, expression, orig);
+    }
+
+    @Override
+    public void evaluateEqual(final BinaryExpression expression, final boolean defineVariable) {
+        if (!defineVariable) {
+            Expression leftExpression = expression.getLeftExpression();
+            if (leftExpression instanceof PropertyExpression) {
+                PropertyExpression pexp = (PropertyExpression) leftExpression;
+                if (makeSetProperty(
+                        pexp.getObjectExpression(),
+                        pexp.getProperty(),
+                        expression.getRightExpression(),
+                        pexp.isSafe(),
+                        pexp.isSpreadSafe(),
+                        pexp.isImplicitThis(),
+                        pexp instanceof AttributeExpression)) return;
+            }
+        }
+        // GROOVY-5620: Spread safe/Null safe operator on LHS is not supported
+        if (expression.getLeftExpression() instanceof PropertyExpression
+                && ((PropertyExpression) expression.getLeftExpression()).isSpreadSafe()
+                && StaticTypeCheckingSupport.isAssignment(expression.getOperation().getType())) {
+            // rewrite it so that it can be statically compiled
+            transformSpreadOnLHS(expression);
+            return;
+        }
+        super.evaluateEqual(expression, defineVariable);
+    }
+
+    private void transformSpreadOnLHS(BinaryExpression origin) {
+        PropertyExpression spreadExpression = (PropertyExpression) origin.getLeftExpression();
+        Expression value = origin.getRightExpression();
+        WriterController controller = getController();
+        MethodVisitor mv = controller.getMethodVisitor();
+        CompileStack compileStack = controller.getCompileStack();
+        TypeChooser typeChooser = controller.getTypeChooser();
+        OperandStack operandStack = controller.getOperandStack();
+        ClassNode classNode = controller.getClassNode();
+        int counter = labelCounter.incrementAndGet();
+        Expression receiver = spreadExpression.getObjectExpression();
+
+        // create an empty arraylist
+        VariableExpression result = new VariableExpression(
+                this.getClass().getSimpleName()+"$spreadresult" + counter,
+                ARRAYLIST_CLASSNODE
+        );
+        ConstructorCallExpression cce = new ConstructorCallExpression(ARRAYLIST_CLASSNODE, ArgumentListExpression.EMPTY_ARGUMENTS);
+        cce.setNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, ARRAYLIST_CONSTRUCTOR);
+        DeclarationExpression declr = new DeclarationExpression(
+                result,
+                Token.newSymbol("=", spreadExpression.getLineNumber(), spreadExpression.getColumnNumber()),
+                cce
+        );
+        declr.visit(controller.getAcg());
+        // if (receiver != null)
+        receiver.visit(controller.getAcg());
+        Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
+        mv.visitJumpInsn(IFNULL, ifnull);
+        operandStack.remove(1); // receiver consumed by if()
+        Label nonull = compileStack.createLocalLabel("nonull_" + counter);
+        mv.visitLabel(nonull);
+        ClassNode componentType = StaticTypeCheckingVisitor.inferLoopElementType(typeChooser.resolveType(receiver, classNode));
+        Parameter iterator = new Parameter(componentType, "for$it$" + counter);
+        VariableExpression iteratorAsVar = new VariableExpression(iterator);
+        PropertyExpression pexp = spreadExpression instanceof AttributeExpression ?
+                new AttributeExpression(iteratorAsVar, spreadExpression.getProperty(), true):
+                new PropertyExpression(iteratorAsVar, spreadExpression.getProperty(), true);
+        pexp.setImplicitThis(spreadExpression.isImplicitThis());
+        pexp.setSourcePosition(spreadExpression);
+        BinaryExpression assignment = new BinaryExpression(
+                pexp,
+                origin.getOperation(),
+                value
+        );
+        MethodCallExpression add = new MethodCallExpression(
+                result,
+                "add",
+                assignment
+        );
+        add.setMethodTarget(ARRAYLIST_ADD_METHOD);
+        // for (e in receiver) { result.add(e?.method(arguments) }
+        ForStatement stmt = new ForStatement(
+                iterator,
+                receiver,
+                new ExpressionStatement(add)
+        );
+        stmt.visit(controller.getAcg());
+        // else { empty list }
+        mv.visitLabel(ifnull);
+
+        // end of if/else
+        // return result list
+        result.visit(controller.getAcg());
+
+    }
+
+    private boolean makeSetProperty(final Expression receiver, final Expression message, final Expression arguments, final boolean safe, final boolean spreadSafe, final boolean implicitThis, final boolean isAttribute) {
+        WriterController controller = getController();
+        TypeChooser typeChooser = controller.getTypeChooser();
+        ClassNode receiverType = typeChooser.resolveType(receiver, controller.getClassNode());
+        String property = message.getText();
+        boolean isThisExpression = receiver instanceof VariableExpression && ((VariableExpression) receiver).isThisExpression();
+        if (isAttribute
+                || (isThisExpression &&
+                    receiverType.getDeclaredField(property)!=null)) {
+            ClassNode current = receiverType;
+            FieldNode fn = null;
+            while (fn==null && current!=null) {
+                fn = current.getDeclaredField(property);
+                if (fn==null){
+                    current = current.getSuperClass();
+                }
+            }
+            if (fn!=null && receiverType!=current && !fn.isPublic()) {
+                // check that direct access is allowed
+                if (!fn.isProtected()) {
+                    return false;
+                }
+                String pkg1 = receiverType.getPackageName();
+                String pkg2 = current.getPackageName();
+                if (pkg1!=pkg2 && !pkg1.equals(pkg2)) {
+                    return false;
+                }
+                OperandStack operandStack = controller.getOperandStack();
+                MethodVisitor mv = controller.getMethodVisitor();
+                if (!fn.isStatic()) {
+                    receiver.visit(controller.getAcg());
+                }
+                arguments.visit(controller.getAcg());
+                operandStack.doGroovyCast(fn.getOriginType());
+                mv.visitFieldInsn(fn.isStatic() ? PUTSTATIC : PUTFIELD,
+                        BytecodeHelper.getClassInternalName(fn.getOwner()),
+                        property,
+                        BytecodeHelper.getTypeDescription(fn.getOriginType()));
+                operandStack.remove(fn.isStatic()?1:2);
+                return true;
+            }
+        }
+        if (!isAttribute) {
+            String setter = "set" + MetaClassHelper.capitalize(property);
+            MethodNode setterMethod = receiverType.getSetterMethod(setter, false);
+            ClassNode declaringClass = setterMethod!=null?setterMethod.getDeclaringClass():null;
+            if (isThisExpression && declaringClass!=null && declaringClass.equals(controller.getClassNode())) {
+                // this.x = ... shouldn't use a setter if in the same class
+                setterMethod = null;
+            } else if (setterMethod == null) {
+                PropertyNode propertyNode = receiverType.getProperty(property);
+                if (propertyNode != null) {
+                    int mods = propertyNode.getModifiers();
+                    if (!Modifier.isFinal(mods)) {
+                        setterMethod = new MethodNode(
+                                setter,
+                                ACC_PUBLIC,
+                                ClassHelper.VOID_TYPE,
+                                new Parameter[]{new Parameter(propertyNode.getOriginType(), "value")},
+                                ClassNode.EMPTY_ARRAY,
+                                EmptyStatement.INSTANCE
+                        );
+                        setterMethod.setDeclaringClass(receiverType);
+                    }
+                }
+            }
+            if (setterMethod != null) {
+                Expression call = StaticPropertyAccessHelper.transformToSetterCall(
+                        receiver,
+                        setterMethod,
+                        arguments,
+                        implicitThis,
+                        safe,
+                        spreadSafe,
+                        true, // to be replaced with a proper test whether a return value should be used or not
+                        message
+                );
+                call.visit(controller.getAcg());
+                return true;
+            }
+            if (isThisExpression && !controller.isInClosure()) {
+                receiverType = controller.getClassNode();
+            }
+            if (makeSetPrivateFieldWithBridgeMethod(receiver, receiverType, property, arguments, safe, spreadSafe, implicitThis)) return true;
+        }
+        return false;
+    }
+
+    @SuppressWarnings("unchecked")
+    private boolean makeSetPrivateFieldWithBridgeMethod(final Expression receiver, final ClassNode receiverType, final String fieldName, final Expression arguments, final boolean safe, final boolean spreadSafe, final boolean implicitThis) {
+        WriterController controller = getController();
+        FieldNode field = receiverType.getField(fieldName);
+        ClassNode outerClass = receiverType.getOuterClass();
+        if (field == null && implicitThis && outerClass != null && !receiverType.isStaticClass()) {
+            Expression pexp;
+            if (controller.isInClosure()) {
+                MethodCallExpression mce = new MethodCallExpression(
+                    new VariableExpression("this"),
+                    "getThisObject",
+                    ArgumentListExpression.EMPTY_ARGUMENTS
+                );
+                mce.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, controller.getOutermostClass());
+                mce.setImplicitThis(true);
+                mce.setMethodTarget(CLOSURE_GETTHISOBJECT_METHOD);
+                pexp = new CastExpression(controller.getOutermostClass(),mce);
+            } else {
+                pexp = new PropertyExpression(
+                    new ClassExpression(outerClass),
+                    "this"
+                );
+                ((PropertyExpression)pexp).setImplicitThis(true);
+            }
+            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, outerClass);
+            pexp.setSourcePosition(receiver);
+            return makeSetPrivateFieldWithBridgeMethod(pexp, outerClass, fieldName, arguments, safe, spreadSafe, true);
+        }
+        ClassNode classNode = controller.getClassNode();
+        if (field != null && Modifier.isPrivate(field.getModifiers())
+            && (StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, classNode) || StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode,receiverType))
+            && !receiverType.equals(classNode)) {
+            Map<String, MethodNode> mutators = receiverType.redirect().getNodeMetaData(StaticCompilationMetadataKeys.PRIVATE_FIELDS_MUTATORS);
+            if (mutators != null) {
+                MethodNode methodNode = mutators.get(fieldName);
+                if (methodNode != null) {
+                    MethodCallExpression mce = new MethodCallExpression(receiver, methodNode.getName(),
+                        new ArgumentListExpression(field.isStatic()?new ConstantExpression(null):receiver, arguments));
+                        mce.setMethodTarget(methodNode);
+                        mce.setSafe(safe);
+                        mce.setSpreadSafe(spreadSafe);
+                    mce.setImplicitThis(implicitThis);
+                    mce.visit(controller.getAcg());
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void assignToArray(Expression parent, Expression receiver, Expression index, Expression rhsValueLoader, boolean safe) {
+        ClassNode current = getController().getClassNode();
+        ClassNode arrayType = getController().getTypeChooser().resolveType(receiver, current);
+        ClassNode arrayComponentType = arrayType.getComponentType();
+        int operationType = getOperandType(arrayComponentType);
+        BinaryExpressionWriter bew = binExpWriter[operationType];
+
+        if (bew.arraySet(true) && arrayType.isArray() && !safe) {
+            super.assignToArray(parent, receiver, index, rhsValueLoader, safe);
+        } else {
+            /******
+            / This code path is needed because ACG creates array access expressions
+            *******/
+
+            WriterController controller = getController();
+            StaticTypeCheckingVisitor visitor = new StaticCompilationVisitor(controller.getSourceUnit(), controller.getClassNode());
+            // let's replace this assignment to a subscript operator with a
+            // method call
+            // e.g. x[5] = 10
+            // -> (x, [], 5), =, 10
+            // -> methodCall(x, "putAt", [5, 10])
+            ArgumentListExpression ae = new ArgumentListExpression(index, rhsValueLoader);
+            if (rhsValueLoader instanceof VariableSlotLoader && parent instanceof BinaryExpression) {
+                // GROOVY-6061
+                rhsValueLoader.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE,
+                        controller.getTypeChooser().resolveType(parent, controller.getClassNode()));
+            }
+            MethodCallExpression mce = new MethodCallExpression(
+                    receiver,
+                    "putAt",
+                    ae
+            );
+
+            mce.setSafe(safe);
+            mce.setSourcePosition(parent);
+            visitor.visitMethodCallExpression(mce);
+            OperandStack operandStack = controller.getOperandStack();
+            int height = operandStack.getStackLength();
+            mce.visit(controller.getAcg());
+            operandStack.pop();
+            operandStack.remove(operandStack.getStackLength()-height);
+            // return value of assignment
+            rhsValueLoader.visit(controller.getAcg());
+        }
+    }
+
+}


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/BytecodeInterface8.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/BytecodeInterface8.java b/src/main/java/org/codehaus/groovy/runtime/BytecodeInterface8.java
new file mode 100644
index 0000000..79fae05
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/BytecodeInterface8.java
@@ -0,0 +1,377 @@
+/*
+ *  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.runtime;
+
+import org.codehaus.groovy.runtime.metaclass.DefaultMetaClassInfo;
+
+/**
+ * This class contains methods special to optimizations used directly from bytecode in Groovy 1.8
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen "blackdrag" Theodorou</a>
+ */
+public class BytecodeInterface8 {
+    
+    public static boolean disabledStandardMetaClass() {
+        return DefaultMetaClassInfo.disabledStandardMetaClass();
+    }
+    
+    // ------------------ int ------------------
+    
+    /**
+     * @return true if integer has its default MetaClass
+     */
+    public static boolean isOrigInt(){
+       return DefaultMetaClassInfo.isOrigInt(); 
+    }
+
+    // ------------------ int[] ------------------
+    
+    /**
+     * @return true if integer array has its default MetaClass
+     */
+    public static boolean isOrigIntArray(){
+       return DefaultMetaClassInfo.isOrigIntArray(); 
+    }
+    
+    
+    /**
+     * get value from int[] using normalized index
+     */
+    public static int intArrayGet(int[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from int[] using normalized index
+     */
+    public static void intArraySet(int[] a, int i, int v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ byte ------------------
+    
+    /**
+     * @return true if byte has its default MetaClass
+     */
+    public static boolean isOrigB(){
+       return DefaultMetaClassInfo.isOrigByte(); 
+    }
+
+    // ------------------ byte[] ------------------
+    
+    /**
+     * @return true if byte array has its default MetaClass
+     */
+    public static boolean isOrigBArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from byte[] using normalized index
+     */
+    public static byte bArrayGet(byte[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from byte[] using normalized index
+     */
+    public static void bArraySet(byte[] a, int i, byte v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ short ------------------
+    
+    /**
+     * @return true if short has its default MetaClass
+     */
+    public static boolean isOrigS(){
+       return DefaultMetaClassInfo.isOrigShort(); 
+    }
+
+    // ------------------ short[] ------------------
+    
+    /**
+     * @return true if short array has its default MetaClass
+     */
+    public static boolean isOrigSArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from short[] using normalized index
+     */
+    public static short sArrayGet(short[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from short[] using normalized index
+     */
+    public static void sArraySet(short[] a, int i, short v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ char ------------------
+    
+    /**
+     * @return true if char has its default MetaClass
+     */
+    public static boolean isOrigC(){
+       return DefaultMetaClassInfo.isOrigChar(); 
+    }
+
+    // ------------------ char[] ------------------
+    
+    /**
+     * @return true if char array has its default MetaClass
+     */
+    public static boolean isOrigCArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from char[] using normalized index
+     */
+    public static char cArrayGet(char[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from char[] using normalized index
+     */
+    public static void cArraySet(char[] a, int i, char v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ long ------------------
+    
+    /**
+     * @return true if long has its default MetaClass
+     */
+    public static boolean isOrigL(){
+       return DefaultMetaClassInfo.isOrigLong(); 
+    }
+
+    // ------------------ long[] ------------------
+    
+    /**
+     * @return true if long array has its default MetaClass
+     */
+    public static boolean isOrigLArray(){
+       return false; 
+    }
+    
+    
+    /**
+     * get value from long[] using normalized index
+     */
+    public static long lArrayGet(long[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from long[] using normalized index
+     */
+    public static void lArraySet(long[] a, int i, long v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ boolean ------------------
+    
+    /**
+     * @return true if boolean has its default MetaClass
+     */
+    public static boolean isOrigZ(){
+       return DefaultMetaClassInfo.isOrigBool(); 
+    }
+
+    // ------------------ boolean[] ------------------
+    
+    /**
+     * @return true if boolean array has its default MetaClass
+     */
+    public static boolean isOrigZArray(){
+       return false; 
+    }
+    
+    /**
+     * get value from boolean[] using normalized index
+     */
+    public static boolean zArrayGet(boolean[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from boolean[] using normalized index
+     */
+    public static void zArraySet(boolean[] a, int i, boolean v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ float ------------------
+    
+    /**
+     * @return true if float has its default MetaClass
+     */
+    public static boolean isOrigF(){
+       return DefaultMetaClassInfo.isOrigFloat(); 
+    }
+
+    // ------------------ float[] ------------------
+    
+    /**
+     * @return true if float array has its default MetaClass
+     */
+    public static boolean isOrigFArray(){
+       return false; 
+    }
+    
+    /**
+     * get value from float[] using normalized index
+     */
+    public static float fArrayGet(float[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from float[] using normalized index
+     */
+    public static void fArraySet(float[] a, int i, float v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ double ------------------
+    
+    /**
+     * @return true if double has its default MetaClass
+     */
+    public static boolean isOrigD(){
+       return DefaultMetaClassInfo.isOrigDouble(); 
+    }
+
+    // ------------------ double[] ------------------
+    
+    /**
+     * @return true if double array has its default MetaClass
+     */
+    public static boolean isOrigDArray(){
+       return false; 
+    }
+    
+    /**
+     * get value from double[] using normalized index
+     */
+    public static double dArrayGet(double[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from double[] using normalized index
+     */
+    public static void dArraySet(double[] a, int i, double v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+    
+    // ------------------ Object[] ------------------
+    public static Object objectArrayGet(Object[] a, int i) {
+        try {
+            return a[i];
+        } catch (Throwable t) {
+            return a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)];
+        }
+    }
+    
+    /**
+     * set value from double[] using normalized index
+     */
+    public static void objectArraySet(Object[] a, int i, Object v) {
+        try {
+            a[i]=v;
+        } catch (Throwable t) {
+            a[DefaultGroovyMethodsSupport.normaliseIndex(i,a.length)]=v;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java b/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java
new file mode 100644
index 0000000..6e5d371
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ClassExtender.java
@@ -0,0 +1,89 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * A helper class used by the runtime to allow Groovy classes to be extended at runtime
+ * 
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class ClassExtender {
+    private Map variables;
+    private Map methods;
+
+    public synchronized Object get(String name) {
+        if (variables != null) {
+            return variables.get(name);
+        }
+        return null;
+    }
+
+    public synchronized void set(String name, Object value) {
+        if (variables == null) {
+            variables = createMap();
+        }
+        variables.put(name, value);
+    }
+
+    public synchronized void remove(String name) {
+        if (variables != null) {
+            variables.remove(name);
+        }
+    }
+
+    public void call(String name, Object params) {
+        Closure closure = null;
+        synchronized (this) {
+            if (methods != null) {
+                closure = (Closure) methods.get(name);
+            }
+        }
+        if (closure != null) {
+            closure.call(params);
+        }
+        /*
+        else {
+            throw DoesNotUnderstandException();
+        }
+        */
+    }
+
+    public synchronized void addMethod(String name, Closure closure) {
+        if (methods == null) {
+            methods = createMap();
+        }
+        methods.put(name, methods);
+    }
+
+    public synchronized void removeMethod(String name) {
+        if (methods != null) {
+            methods.remove(name);
+        }
+    }
+
+    protected Map createMap() {
+        return new HashMap();
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java b/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java
new file mode 100644
index 0000000..63e0406
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ComposedClosure.java
@@ -0,0 +1,108 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+
+import java.util.List;
+
+/**
+ * A wrapper for Closure to support composition.
+ * Normally used only internally through the <code>rightShift()</code> and
+ * <code>leftShift()</code> methods on <code>Closure</code>.
+ * <p>
+ * Typical usages:
+ * <pre class="groovyTestCase">
+ * def twice = { a -> a * 2 }
+ * def inc = { b -> b + 1 }
+ * def f = { x -> twice(inc(x)) } // longhand
+ * def g = inc >> twice
+ * def h = twice << inc
+ * assert f(10) == 22
+ * assert g(10) == 22
+ * assert h(10) == 22
+ *
+ * def s2c = { it.chars[0] }
+ * def p = Integer.&toHexString >> s2c >> Character.&toUpperCase
+ * assert p(15) == 'F'
+ *
+ * def multiply = { a, b -> a * b }
+ * def identity = { a -> [a, a] }
+ * def sq = identity >> multiply
+ * assert (1..5).collect{ sq(it) } == [1, 4, 9, 16, 25]
+ *
+ * def add3 = { a, b, c -> a + b + c }
+ * def add2plus10 = add3.curry(10)
+ * def multBoth = { a, b, c -> [a*c, b*c] }
+ * def twiceBoth = multBoth.rcurry(2)
+ * def twiceBothPlus10 = twiceBoth >> add2plus10
+ * assert twiceBothPlus10(5, 10) == 40
+ * </pre>
+ *
+ * @author Paul King
+ */
+public final class ComposedClosure<V> extends Closure<V> {
+
+    private final Closure first;
+    private final Closure<V> second;
+
+    public ComposedClosure(Closure first, Closure<V> second) {
+        super(first.clone());
+        this.first = (Closure) getOwner();
+        this.second = (Closure<V>) second.clone();
+        maximumNumberOfParameters = first.getMaximumNumberOfParameters();
+    }
+
+    public void setDelegate(Object delegate) {
+        ((Closure) getOwner()).setDelegate(delegate);
+        second.setDelegate(delegate);
+    }
+
+    public Object getDelegate() {
+        return ((Closure) getOwner()).getDelegate();
+    }
+
+    public void setResolveStrategy(int resolveStrategy) {
+        ((Closure) getOwner()).setResolveStrategy(resolveStrategy);
+        second.setResolveStrategy(resolveStrategy);
+    }
+
+    public int getResolveStrategy() {
+        return ((Closure) getOwner()).getResolveStrategy();
+    }
+
+    public Object clone() {
+        return new ComposedClosure<V>(first, second);
+    }
+
+    public Class[] getParameterTypes() {
+        return first.getParameterTypes();
+    }
+
+    public Object doCall(Object... args) {
+        return call(args);
+    }
+
+    @Override
+    public V call(Object... args) {
+        Object temp = first.call(args);
+        if (temp instanceof List && second.getParameterTypes().length > 1) temp = ((List) temp).toArray();
+        return temp instanceof Object[] ? second.call((Object[]) temp) : second.call(temp);
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java b/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
new file mode 100644
index 0000000..8bf7c69
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ConversionHandler.java
@@ -0,0 +1,224 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.GroovySystem;
+import groovy.lang.MetaClass;
+import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
+import org.codehaus.groovy.vmplugin.VMPlugin;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This class is a general adapter to map a call to a Java interface
+ * to a given delegate.
+ *
+ * @author Ben Yu
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public abstract class ConversionHandler implements InvocationHandler, Serializable {
+    private final Object delegate;
+    private static final long serialVersionUID = 1162833717190835227L;
+    private final ConcurrentHashMap<Method, Object> handleCache;
+    {
+        if (VMPluginFactory.getPlugin().getVersion() >= 7) {
+            handleCache = new ConcurrentHashMap<Method, Object>(16, 0.9f, 2);
+        } else {
+            handleCache = null;
+        }
+    }
+
+    private MetaClass metaClass;
+
+    /**
+     * Creates a ConversionHandler with an delegate.
+     *
+     * @param delegate the delegate
+     * @throws IllegalArgumentException if the given delegate is null
+     */
+    public ConversionHandler(Object delegate) {
+        if (delegate == null) {
+            throw new IllegalArgumentException("delegate must not be null");
+        }
+        this.delegate = delegate;
+    }
+
+    /**
+     * Returns the delegate.
+     *
+     * @return the delegate
+     */
+    public Object getDelegate() {
+        return delegate;
+    }
+
+    /**
+     * This method is a default implementation for the invoke method given in
+     * InvocationHandler. Any call to a method with a declaring class that is
+     * not Object, excluding toString() and default methods is redirected to invokeCustom.
+     * <p>
+     * Methods like equals and hashcode are called on the class itself instead
+     * of the delegate because they are considered fundamental methods that should
+     * not be overwritten. The toString() method gets special treatment as it is
+     * deemed to be a method that you might wish to override when called from Groovy.
+     * Interface default methods from Java 8 on the other hand are considered being
+     * default implementations you don't normally want to change. So they are called
+     * directly too
+     * </p><p>
+     * In many scenarios, it is better to overwrite the invokeCustom method where
+     * the core Object related methods are filtered out.
+     *</p>
+     * @param proxy  the proxy
+     * @param method the method
+     * @param args   the arguments
+     * @return the result of the invocation by method or delegate
+     * @throws Throwable if caused by the delegate or the method
+     * @see #invokeCustom(Object, Method, Object[])
+     * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+     */
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (handleCache != null && isDefaultMethod(method)) {
+            VMPlugin plugin = VMPluginFactory.getPlugin();
+            Object handle = handleCache.get(method);
+            if (handle == null) {
+                handle = plugin.getInvokeSpecialHandle(method, proxy);
+                handleCache.put(method, handle);
+            }
+            return plugin.invokeHandle(handle, args);
+        }
+
+        if (!checkMethod(method)) {
+            try {
+                if (method.getDeclaringClass() == GroovyObject.class) {
+                    if ("getMetaClass".equals(method.getName())) {
+                        return getMetaClass(proxy);
+                    } else if ("setMetaClass".equals(method.getName())) {
+                        return setMetaClass((MetaClass) args[0]);
+                    }
+                }
+                return invokeCustom(proxy, method, args);
+            } catch (GroovyRuntimeException gre) {
+                throw ScriptBytecodeAdapter.unwrap(gre);
+            }
+        }
+
+        try {
+            return method.invoke(this, args);
+        } catch (InvocationTargetException ite) {
+            throw ite.getTargetException();
+        }
+    }
+
+    protected boolean isDefaultMethod(Method method) {
+        return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
+                Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
+    }
+
+    protected boolean checkMethod(Method method) {
+        return isCoreObjectMethod(method);
+    }
+
+    /**
+     * This method is called for all Methods not defined on Object.
+     * The delegate should be called here.
+     *
+     * @param proxy  the proxy
+     * @param method the method
+     * @param args   the arguments
+     * @return the result of the invocation of the delegate
+     * @throws Throwable any exception causes by the delegate
+     * @see #invoke(Object, Method, Object[])
+     * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
+     */
+    public abstract Object invokeCustom(Object proxy, Method method, Object[] args) throws Throwable;
+
+    /**
+     * Indicates whether some other object is "equal to" this one.
+     * The delegate is used if the class of the parameter and the
+     * current class are equal. In other cases the method will return
+     * false. The exact class is here used, if inheritance is needed,
+     * this method must be overwritten.
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Proxy) {
+            obj = Proxy.getInvocationHandler(obj);
+        }
+
+        if (obj instanceof ConversionHandler) {
+            return (((ConversionHandler) obj).getDelegate()).equals(delegate);
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a hash code value for the delegate.
+     *
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+
+    /**
+     * Returns a String version of the delegate.
+     *
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return delegate.toString();
+    }
+
+    /**
+     * Checks whether a method is a core method from java.lang.Object.
+     * Such methods often receive special treatment because they are
+     * deemed fundamental enough to not be tampered with.
+     *
+     * @param method the method to check
+     * @return true if the method is deemed to be a core method
+     */
+    public static boolean isCoreObjectMethod(Method method) {
+        return Object.class.equals(method.getDeclaringClass());
+    }
+
+    private MetaClass setMetaClass(MetaClass mc) {
+        metaClass = mc;
+        return mc;
+    }
+
+    private MetaClass getMetaClass(Object proxy) {
+        MetaClass mc = metaClass;
+        if (mc == null) {
+            mc = ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(proxy);
+            metaClass = mc;
+        }
+        return mc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java b/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
new file mode 100644
index 0000000..dfc7ea0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ConvertedClosure.java
@@ -0,0 +1,58 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+
+/**
+ * This class is a general adapter to adapt a closure to any Java interface.
+ * <p>
+ * @author Ben Yu
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ * Jul 27, 2006 3:50:51 PM
+ */
+public class ConvertedClosure extends ConversionHandler implements Serializable {
+    private final String methodName;
+    private static final long serialVersionUID = 1162833713450835227L;
+
+    /**
+     * to create a ConvertedClosure object.
+     * @param closure the closure object.
+     */
+    public ConvertedClosure(Closure closure, String method) {
+        super(closure);
+        this.methodName = method;
+    }
+    
+    public ConvertedClosure(Closure closure) {
+        this(closure,null);
+    }
+
+    @Override
+    public Object invokeCustom(Object proxy, Method method, Object[] args)
+    throws Throwable {
+        if (methodName!=null && !methodName.equals(method.getName())) return null;
+        return ((Closure) getDelegate()).call(args);
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java b/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java
new file mode 100644
index 0000000..393d55e
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/ConvertedMap.java
@@ -0,0 +1,80 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * This class is a general adapter to adapt a map of closures to
+ * any Java interface.
+ *
+ * @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
+ */
+public class ConvertedMap extends ConversionHandler {
+
+    /**
+     * to create a ConvertedMap object.
+     *
+     * @param closures the map of closures
+     */
+    protected ConvertedMap(Map closures) {
+        super(closures);
+    }
+
+    @Override
+    public Object invokeCustom(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        Map m = (Map) getDelegate();
+        Closure cl = (Closure) m.get(method.getName());
+        if(cl == null && "toString".equals(method.getName())) {
+            return m.toString();
+        }
+        if (cl == null) {
+            throw new UnsupportedOperationException();
+        }
+        return cl.call(args);
+    }
+
+    @Override
+    public String toString() {
+        return DefaultGroovyMethods.toString(getDelegate());
+    }
+
+    @Override
+    protected boolean checkMethod(Method method) {
+        return isCoreObjectMethod(method);
+    }
+
+    /**
+     * Checks whether a method is a core method from java.lang.Object.
+     * Such methods often receive special treatment because they are
+     * deemed fundamental enough to not be tampered with.
+     * call toString() is an exception to allow overriding toString() by a closure specified in the map
+     *
+     * @param method the method to check
+     * @return true if the method is deemed to be a core method
+     */
+    public static boolean isCoreObjectMethod(Method method) {
+        return ConversionHandler.isCoreObjectMethod(method) && !"toString".equals(method.getName());
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java b/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java
new file mode 100644
index 0000000..cabe230
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/CurriedClosure.java
@@ -0,0 +1,192 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+
+/**
+ * A wrapper for Closure to support currying.
+ * Normally used only internally through the <code>curry()</code>, <code>rcurry()</code> or
+ * <code>ncurry()</code> methods on <code>Closure</code>.
+ * Typical usages:
+ * <pre class="groovyTestCase">
+ * // normal usage
+ * def unitAdder = { first, second, unit -> "${first + second} $unit" }
+ * assert unitAdder(10, 15, "minutes") == "25 minutes"
+ * assert unitAdder.curry(60)(15, "minutes") == "75 minutes"
+ * def minuteAdder = unitAdder.rcurry("minutes")
+ * assert minuteAdder(15, 60) == "75 minutes"
+ *
+ * // explicit creation
+ * import org.codehaus.groovy.runtime.CurriedClosure
+ * assert new CurriedClosure(unitAdder, 45)(15, "minutes") == "60 minutes"
+ * assert new CurriedClosure(unitAdder, "six", "ty")("minutes") == "sixty minutes"
+ * </pre>
+ *
+ * Notes:
+ * <ul>
+ *     <li>Caters for Groovy's lazy (rcurry) and eager (ncurry) calculation of argument position</li>
+ * </ul>
+ */
+public final class CurriedClosure<V> extends Closure<V> {
+
+    private final Object[] curriedParams;
+    private final int minParamsExpected;
+    private int index;
+    private Class varargType = null;
+
+    /**
+     * Creates the curried closure.
+     *
+     * @param index the position where the parameters should be injected (-ve for lazy)
+     * @param uncurriedClosure the closure to be called after the curried parameters are injected
+     * @param arguments the supplied parameters
+     */
+    public CurriedClosure(int index, Closure<V> uncurriedClosure, Object... arguments) {
+        super(uncurriedClosure.clone());
+        curriedParams = arguments;
+        this.index = index;
+        final int origMaxLen = uncurriedClosure.getMaximumNumberOfParameters();
+        maximumNumberOfParameters = origMaxLen - arguments.length;
+        Class[] classes = uncurriedClosure.getParameterTypes();
+        Class lastType = classes.length == 0 ? null : classes[classes.length-1];
+        if (lastType != null && lastType.isArray()) {
+            varargType = lastType;
+        }
+
+        if (!isVararg()) {
+            // perform some early param checking for non-vararg case
+            if (index < 0) {
+                // normalise
+                this.index += origMaxLen;
+                minParamsExpected = 0;
+            } else {
+                minParamsExpected = index + arguments.length;
+            }
+            if (maximumNumberOfParameters < 0) {
+                throw new IllegalArgumentException("Can't curry " + arguments.length + " arguments for a closure with " + origMaxLen + " parameters.");
+            }
+            if (index < 0) {
+                if (index < -origMaxLen || index > -arguments.length)
+                    throw new IllegalArgumentException("To curry " + arguments.length + " argument(s) expect index range " +
+                            (-origMaxLen) + ".." + (-arguments.length) + " but found " + index);
+            } else if (index > maximumNumberOfParameters) {
+                throw new IllegalArgumentException("To curry " + arguments.length + " argument(s) expect index range 0.." +
+                        maximumNumberOfParameters + " but found " + index);
+            }
+        } else {
+            minParamsExpected = 0;
+        }
+    }
+
+    public CurriedClosure(Closure<V> uncurriedClosure, Object... arguments) {
+        this(0, uncurriedClosure, arguments);
+    }
+
+    public Object[] getUncurriedArguments(Object... arguments) {
+        if (isVararg()) {
+            int normalizedIndex = index < 0 ? index + arguments.length + curriedParams.length : index;
+            if (normalizedIndex < 0 || normalizedIndex > arguments.length) {
+                throw new IllegalArgumentException("When currying expected index range between " +
+                        (-arguments.length - curriedParams.length) + ".." + (arguments.length + curriedParams.length) + " but found " + index);
+            }
+            return createNewCurriedParams(normalizedIndex, arguments);
+        }
+        if (curriedParams.length + arguments.length < minParamsExpected) {
+            throw new IllegalArgumentException("When currying expected at least " + index + " argument(s) to be supplied before known curried arguments but found " + arguments.length);
+        }
+        int newIndex = Math.min(index, curriedParams.length + arguments.length - 1);
+        // rcurried arguments are done lazily to allow normal method selection between overloaded alternatives
+        newIndex = Math.min(newIndex, arguments.length);
+        return createNewCurriedParams(newIndex, arguments);
+    }
+
+    private Object[] createNewCurriedParams(int normalizedIndex, Object[] arguments) {
+        Object[] newCurriedParams = new Object[curriedParams.length + arguments.length];
+        System.arraycopy(arguments, 0, newCurriedParams, 0, normalizedIndex);
+        System.arraycopy(curriedParams, 0, newCurriedParams, normalizedIndex, curriedParams.length);
+        if (arguments.length - normalizedIndex > 0)
+            System.arraycopy(arguments, normalizedIndex, newCurriedParams, curriedParams.length + normalizedIndex, arguments.length - normalizedIndex);
+        return newCurriedParams;
+    }
+
+    public void setDelegate(Object delegate) {
+        ((Closure) getOwner()).setDelegate(delegate);
+    }
+
+    public Object getDelegate() {
+        return ((Closure) getOwner()).getDelegate();
+    }
+
+    public void setResolveStrategy(int resolveStrategy) {
+        ((Closure) getOwner()).setResolveStrategy(resolveStrategy);
+    }
+
+    public int getResolveStrategy() {
+        return ((Closure) getOwner()).getResolveStrategy();
+    }
+
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        Closure<V> uncurriedClosure = (Closure<V>) ((Closure) getOwner()).clone();
+        return new CurriedClosure<V>(index, uncurriedClosure, curriedParams);
+    }
+
+    public Class[] getParameterTypes() {
+        Class[] oldParams = ((Closure) getOwner()).getParameterTypes();
+        int extraParams = 0;
+        int gobbledParams = curriedParams.length;
+        if (isVararg()) {
+            int numNonVarargs = oldParams.length - 1;
+            if (index < 0) {
+                int absIndex = -index;
+                // do -ve indexes based on actual args, so can't accurately calculate type here
+                // so work out minimal type params and vararg on end will allow for other possibilities
+                if (absIndex > numNonVarargs) gobbledParams = numNonVarargs;
+                int newNumNonVarargs = numNonVarargs - gobbledParams;
+                if (absIndex - curriedParams.length > newNumNonVarargs) extraParams = absIndex - curriedParams.length - newNumNonVarargs;
+                int keptParams = Math.max(numNonVarargs - absIndex, 0);
+                Class[] newParams = new Class[keptParams + newNumNonVarargs + extraParams + 1];
+                System.arraycopy(oldParams, 0, newParams, 0, keptParams);
+                for (int i = 0; i < newNumNonVarargs; i++) newParams[keptParams + i] = Object.class;
+                for (int i = 0; i < extraParams; i++) newParams[keptParams + newNumNonVarargs + i] = varargType.getComponentType();
+                newParams[newParams.length - 1] = varargType;
+                return newParams;
+            }
+            int leadingKept = Math.min(index, numNonVarargs);
+            int trailingKept = Math.max(numNonVarargs - leadingKept - curriedParams.length, 0);
+            if (index > leadingKept) extraParams = index - leadingKept;
+            Class[] newParams = new Class[leadingKept + trailingKept + extraParams + 1];
+            System.arraycopy(oldParams, 0, newParams, 0, leadingKept);
+            if (trailingKept > 0) System.arraycopy(oldParams, leadingKept + curriedParams.length, newParams, leadingKept, trailingKept);
+            for (int i = 0; i < extraParams; i++) newParams[leadingKept + trailingKept + i] = varargType.getComponentType();
+            newParams[newParams.length - 1] = varargType;
+            return newParams;
+        }
+        Class[] newParams = new Class[oldParams.length - gobbledParams + extraParams];
+        System.arraycopy(oldParams, 0, newParams, 0, index);
+        if (newParams.length - index > 0)
+            System.arraycopy(oldParams, curriedParams.length + index, newParams, index, newParams.length - index);
+        return newParams;
+    }
+
+    private boolean isVararg() {
+        return varargType != null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
new file mode 100644
index 0000000..1c30802
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DateGroovyMethods.java
@@ -0,0 +1,775 @@
+/*
+ *  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.runtime;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyRuntimeException;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+/**
+ * This class defines new groovy methods which appear on normal JDK
+ * Date and Calendar classes inside the Groovy environment.
+ */
+public class DateGroovyMethods extends DefaultGroovyMethodsSupport {
+
+    /**
+     * Support the subscript operator for a Date.
+     *
+     * @param self  a Date
+     * @param field a Calendar field, e.g. MONTH
+     * @return the value for the given field, e.g. FEBRUARY
+     * @see java.util.Calendar
+     * @since 1.5.5
+     */
+    public static int getAt(Date self, int field) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        return cal.get(field);
+    }
+
+    /**
+     * Convert a Date to a Calendar.
+     *
+     * @param self a Date
+     * @return a Calendar corresponding to the given Date
+     * @since 1.7.6
+     */
+    public static Calendar toCalendar(Date self) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        return cal;
+    }
+
+    /**
+     * Support the subscript operator for a Calendar.
+     *
+     * @param self  a Calendar
+     * @param field a Calendar field, e.g. MONTH
+     * @return the value for the given field, e.g. FEBRUARY
+     * @see java.util.Calendar
+     * @since 1.7.3
+     */
+    public static int getAt(Calendar self, int field) {
+        return self.get(field);
+    }
+
+    /**
+     * Support the subscript operator for mutating a Calendar.
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.*
+     * def cal = Calendar.instance
+     * cal[DAY_OF_WEEK] = MONDAY
+     * cal[MONTH] = MARCH
+     * println cal.time // A Monday in March
+     * </pre>
+     *
+     * @param self  A Calendar
+     * @param field A Calendar field, e.g. MONTH
+     * @param value The value for the given field, e.g. FEBRUARY
+     * @see java.util.Calendar#set(int, int)
+     * @since 1.7.3
+     */
+    public static void putAt(Calendar self, int field, int value) {
+        self.set(field, value);
+    }
+
+    /**
+     * Support the subscript operator for mutating a Date.
+     *
+     * @param self  A Date
+     * @param field A Calendar field, e.g. MONTH
+     * @param value The value for the given field, e.g. FEBRUARY
+     * @see #putAt(java.util.Calendar, int, int)
+     * @see java.util.Calendar#set(int, int)
+     * @since 1.7.3
+     */
+    public static void putAt(Date self, int field, int value) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        putAt(cal, field, value);
+        self.setTime(cal.getTimeInMillis());
+    }
+
+    /**
+     * Support mutating a Calendar with a Map.
+     * <p>
+     * The map values are the normal values provided as the
+     * second parameter to <code>java.util.Calendar#set(int, int)</code>.
+     * The keys can either be the normal fields values provided as
+     * the first parameter to that method or one of the following Strings:
+     * <table border="1" cellpadding="4">
+     *   <caption>Calendar index values</caption>
+     *   <tr><td>year</td><td>Calendar.YEAR</td></tr>
+     *   <tr><td>month</td><td>Calendar.MONTH</td></tr>
+     *   <tr><td>date</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
+     *   <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
+     *   <tr><td>second</td><td>Calendar.SECOND</td></tr>
+     * </table>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.*
+     * def cal = Calendar.instance
+     * def m = [:]
+     * m[YEAR] = 2010
+     * m[MONTH] = DECEMBER
+     * m[DATE] = 25
+     * cal.set(m)
+     * println cal.time // Christmas 2010
+     *
+     * cal.set(year:2011, month:DECEMBER, date:25)
+     * println cal.time // Christmas 2010
+     * </pre>
+     *
+     * @param self    A Calendar
+     * @param updates A Map of Calendar keys and values
+     * @see java.util.Calendar#set(int, int)
+     * @see java.util.Calendar#set(int, int, int, int, int, int)
+     * @since 1.7.3
+     */
+    public static void set(Calendar self, Map<Object, Integer> updates) {
+        for (Map.Entry<Object, Integer> entry : updates.entrySet()) {
+            Object key = entry.getKey();
+            if (key instanceof String) key = CAL_MAP.get(key);
+            if (key instanceof Integer) self.set((Integer) key, entry.getValue());
+        }
+    }
+
+    /**
+     * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
+     *
+     * @see #copyWith(java.util.Calendar, java.util.Map)
+     * @since 1.7.3
+     */
+    public static Calendar updated(Calendar self, Map<Object, Integer> updates) {
+        Calendar result = (Calendar) self.clone();
+        set(result, updates);
+        return result;
+    }
+
+    /**
+     * Support creating a new Date having similar properties to
+     * an existing Date (which remains unaltered) but with
+     * some fields updated according to a Map of changes.
+     * <p>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.YEAR
+     * def now = Calendar.instance
+     * def nextYear = now[YEAR] + 1
+     * def oneYearFromNow = now.copyWith(year: nextYear)
+     * println now.time
+     * println oneYearFromNow.time
+     * </pre>
+     *
+     * @param self    A Calendar
+     * @param updates A Map of Calendar keys and values
+     * @return The newly created Calendar
+     * @see java.util.Calendar#set(int, int)
+     * @see java.util.Calendar#set(int, int, int, int, int, int)
+     * @see #set(java.util.Calendar, java.util.Map)
+     * @since 2.2.0
+     */
+    public static Calendar copyWith(Calendar self, Map<Object, Integer> updates) {
+        Calendar result = (Calendar) self.clone();
+        set(result, updates);
+        return result;
+    }
+
+    /**
+     * Support mutating a Date with a Map.
+     * <p>
+     * The map values are the normal values provided as the
+     * second parameter to <code>java.util.Calendar#set(int, int)</code>.
+     * The keys can either be the normal fields values provided as
+     * the first parameter to that method or one of the following Strings:
+     * <table border="1" cellpadding="4">
+     *   <caption>Calendar index values</caption>
+     *   <tr><td>year</td><td>Calendar.YEAR</td></tr>
+     *   <tr><td>month</td><td>Calendar.MONTH</td></tr>
+     *   <tr><td>date</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>dayOfMonth</td><td>Calendar.DATE</td></tr>
+     *   <tr><td>hourOfDay</td><td>Calendar.HOUR_OF_DAY</td></tr>
+     *   <tr><td>minute</td><td>Calendar.MINUTE</td></tr>
+     *   <tr><td>second</td><td>Calendar.SECOND</td></tr>
+     * </table>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.YEAR
+     * def date = new Date()
+     * def nextYear = date[YEAR] + 1
+     * date.set(year: nextYear)
+     * println date
+     * </pre>
+     *
+     * @param self    A Date
+     * @param updates A Map of Calendar keys and values
+     * @see java.util.Calendar#set(int, int)
+     * @see #set(java.util.Calendar, java.util.Map)
+     * @since 1.7.3
+     */
+    public static void set(Date self, Map<Object, Integer> updates) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        set(cal, updates);
+        self.setTime(cal.getTimeInMillis());
+    }
+
+    /**
+     * Legacy alias for copyWith. Will be deprecated and removed in future versions of Groovy.
+     *
+     * @see #copyWith(java.util.Date, java.util.Map)
+     * @since 1.7.3
+     */
+    public static Date updated(Date self, Map<Object, Integer> updates) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        set(cal, updates);
+        return cal.getTime();
+    }
+
+    /**
+     * Support creating a new Date having similar properties to
+     * an existing Date (which remains unaltered) but with
+     * some fields updated according to a Map of changes.
+     * <p>
+     * Example usage:
+     * <pre>
+     * import static java.util.Calendar.YEAR
+     * def today = new Date()
+     * def nextYear = today[YEAR] + 1
+     * def oneYearFromNow = today.copyWith(year: nextYear)
+     * println today
+     * println oneYearFromNow
+     * </pre>
+     *
+     * @param self    A Date
+     * @param updates A Map of Calendar keys and values
+     * @return The newly created Date
+     * @see java.util.Calendar#set(int, int)
+     * @see #set(java.util.Date, java.util.Map)
+     * @see #copyWith(java.util.Calendar, java.util.Map)
+     * @since 2.2.0
+     */
+    public static Date copyWith(Date self, Map<Object, Integer> updates) {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(self);
+        set(cal, updates);
+        return cal.getTime();
+    }
+
+    private static final Map<String, Integer> CAL_MAP = new HashMap<String, Integer>();
+
+    static {
+        CAL_MAP.put("year", Calendar.YEAR);
+        CAL_MAP.put("month", Calendar.MONTH);
+        CAL_MAP.put("date", Calendar.DATE);
+        CAL_MAP.put("dayOfMonth", Calendar.DATE);
+        CAL_MAP.put("hourOfDay", Calendar.HOUR_OF_DAY);
+        CAL_MAP.put("minute", Calendar.MINUTE);
+        CAL_MAP.put("second", Calendar.SECOND);
+    }
+
+    /**
+     * Increment a Date by one day.
+     *
+     * @param self a Date
+     * @return the next days date
+     * @since 1.0
+     */
+    public static Date next(Date self) {
+        return plus(self, 1);
+    }
+
+    /**
+     * Increment a Calendar by one day.
+     *
+     * @param self a Calendar
+     * @return a new Calendar set to the next day
+     * @since 1.8.7
+     */
+    public static Calendar next(Calendar self) {
+        Calendar result = (Calendar) self.clone();
+        result.add(Calendar.DAY_OF_YEAR, 1);
+        return result;
+    }
+
+    /**
+     * Decrement a Calendar by one day.
+     *
+     * @param self a Calendar
+     * @return a new Calendar set to the previous day
+     * @since 1.8.7
+     */
+    public static Calendar previous(Calendar self) {
+        Calendar result = (Calendar) self.clone();
+        result.add(Calendar.DAY_OF_YEAR, -1);
+        return result;
+    }
+
+    /**
+     * Increment a java.sql.Date by one day.
+     *
+     * @param self a java.sql.Date
+     * @return the next days date
+     * @since 1.0
+     */
+    public static java.sql.Date next(java.sql.Date self) {
+        return new java.sql.Date(next((Date) self).getTime());
+    }
+
+    /**
+     * Decrement a Date by one day.
+     *
+     * @param self a Date
+     * @return the previous days date
+     * @since 1.0
+     */
+    public static Date previous(Date self) {
+        return minus(self, 1);
+    }
+
+    /**
+     * Decrement a java.sql.Date by one day.
+     *
+     * @param self a java.sql.Date
+     * @return the previous days date
+     * @since 1.0
+     */
+    public static java.sql.Date previous(java.sql.Date self) {
+        return new java.sql.Date(previous((Date) self).getTime());
+    }
+
+    /**
+     * Add a number of days to this date and returns the new date.
+     *
+     * @param self a Date
+     * @param days the number of days to increase
+     * @return the new date
+     * @since 1.0
+     */
+    public static Date plus(Date self, int days) {
+        Calendar calendar = (Calendar) Calendar.getInstance().clone();
+        calendar.setTime(self);
+        calendar.add(Calendar.DAY_OF_YEAR, days);
+        return calendar.getTime();
+    }
+
+    /**
+     * Add a number of days to this date and returns the new date.
+     *
+     * @param self a java.sql.Date
+     * @param days the number of days to increase
+     * @return the new date
+     * @since 1.0
+     */
+    public static java.sql.Date plus(java.sql.Date self, int days) {
+        return new java.sql.Date(plus((Date) self, days).getTime());
+    }
+
+    /**
+     * Add number of days to this Timestamp and returns the new Timestamp object.
+     *
+     * @param self a Timestamp
+     * @param days the number of days to increase
+     * @return the new Timestamp
+     */
+    public static Timestamp plus(Timestamp self, int days) {
+        Calendar calendar = (Calendar) Calendar.getInstance().clone();
+        calendar.setTime(self);
+        calendar.add(Calendar.DAY_OF_YEAR, days);
+        Timestamp ts = new Timestamp(calendar.getTime().getTime());
+        ts.setNanos(self.getNanos());
+        return ts;
+    }
+
+    /**
+     * Subtract a number of days from this date and returns the new date.
+     *
+     * @param self a Date
+     * @param days the number of days to subtract
+     * @return the new date
+     * @since 1.0
+     */
+    public static Date minus(Date self, int days) {
+        return plus(self, -days);
+    }
+
+    /**
+     * Subtract a number of days from this date and returns the new date.
+     *
+     * @param self a java.sql.Date
+     * @param days the number of days to subtract
+     * @return the new date
+     * @since 1.0
+     */
+    public static java.sql.Date minus(java.sql.Date self, int days) {
+        return new java.sql.Date(minus((Date) self, days).getTime());
+    }
+
+    /**
+     * Subtract a number of days from this Timestamp and returns the new Timestamp object.
+     *
+     * @param self a Timestamp
+     * @param days the number of days to subtract
+     * @return the new Timestamp
+     */
+    public static Timestamp minus(Timestamp self, int days) {
+        return plus(self, -days);
+    }
+
+    /**
+     * Subtract another date from this one and return the number of days of the difference.
+     * <p>
+     * Date self = Date then + (Date self - Date then)
+     * <p>
+     * IOW, if self is before then the result is a negative value.
+     *
+     * @param self a Calendar
+     * @param then another Calendar
+     * @return number of days
+     * @since 1.6.0
+     */
+    public static int minus(Calendar self, Calendar then) {
+        Calendar a = self;
+        Calendar b = then;
+
+        boolean swap = a.before(b);
+
+        if (swap) {
+            Calendar t = a;
+            a = b;
+            b = t;
+        }
+
+        int days = 0;
+
+        b = (Calendar) b.clone();
+
+        while (a.get(Calendar.YEAR) > b.get(Calendar.YEAR)) {
+            days += 1 + (b.getActualMaximum(Calendar.DAY_OF_YEAR) - b.get(Calendar.DAY_OF_YEAR));
+            b.set(Calendar.DAY_OF_YEAR, 1);
+            b.add(Calendar.YEAR, 1);
+        }
+
+        days += a.get(Calendar.DAY_OF_YEAR) - b.get(Calendar.DAY_OF_YEAR);
+
+        if (swap) days = -days;
+
+        return days;
+    }
+
+    /**
+     * Subtract another Date from this one and return the number of days of the difference.
+     * <p>
+     * Date self = Date then + (Date self - Date then)
+     * <p>
+     * IOW, if self is before then the result is a negative value.
+     *
+     * @param self a Date
+     * @param then another Date
+     * @return number of days
+     * @since 1.6.0
+     */
+    public static int minus(Date self, Date then) {
+        Calendar a = (Calendar) Calendar.getInstance().clone();
+        a.setTime(self);
+        Calendar b = (Calendar) Calendar.getInstance().clone();
+        b.setTime(then);
+        return minus(a, b);
+    }
+
+    /**
+     * <p>Create a String representation of this date according to the given
+     * format pattern.
+     * <p>
+     * <p>For example, if the system timezone is GMT,
+     * <code>new Date(0).format('MM/dd/yy')</code> would return the string
+     * <code>"01/01/70"</code>. See documentation for {@link java.text.SimpleDateFormat}
+     * for format pattern use.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   a Date
+     * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
+     * @return a string representation of this date.
+     * @see java.text.SimpleDateFormat
+     * @since 1.5.7
+     */
+    public static String format(Date self, String format) {
+        return new SimpleDateFormat(format).format(self);
+    }
+
+    /**
+     * <p>Create a String representation of this date according to the given
+     * format pattern and timezone.
+     * <p>
+     * <p>For example:
+     * <code>
+     * def d = new Date(0)
+     * def tz = TimeZone.getTimeZone('GMT')
+     * println d.format('dd/MMM/yyyy', tz)
+     * </code> would return the string
+     * <code>"01/Jan/1970"</code>. See documentation for {@link java.text.SimpleDateFormat}
+     * for format pattern use.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   a Date
+     * @param format the format pattern to use according to {@link java.text.SimpleDateFormat}
+     * @param tz     the TimeZone to use
+     * @return a string representation of this date.
+     * @see java.text.SimpleDateFormat
+     * @since 1.8.3
+     */
+    public static String format(Date self, String format, TimeZone tz) {
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        sdf.setTimeZone(tz);
+        return sdf.format(self);
+    }
+
+    /**
+     * <p>Return a string representation of the 'day' portion of this date
+     * according to the locale-specific {@link java.text.DateFormat#SHORT} default format.
+     * For an "en_UK" system locale, this would be <code>dd/MM/yy</code>.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self a Date
+     * @return a string representation of this date
+     * @see java.text.DateFormat#getDateInstance(int)
+     * @see java.text.DateFormat#SHORT
+     * @since 1.5.7
+     */
+    public static String getDateString(Date self) {
+        return DateFormat.getDateInstance(DateFormat.SHORT).format(self);
+    }
+
+    /**
+     * <p>Return a string representation of the time portion of this date
+     * according to the locale-specific {@link java.text.DateFormat#MEDIUM} default format.
+     * For an "en_UK" system locale, this would be <code>HH:MM:ss</code>.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self a Date
+     * @return a string representing the time portion of this date
+     * @see java.text.DateFormat#getTimeInstance(int)
+     * @see java.text.DateFormat#MEDIUM
+     * @since 1.5.7
+     */
+    public static String getTimeString(Date self) {
+        return DateFormat.getTimeInstance(DateFormat.MEDIUM).format(self);
+    }
+
+    /**
+     * <p>Return a string representation of the date and time time portion of
+     * this Date instance, according to the locale-specific format used by
+     * {@link java.text.DateFormat}.  This method uses the {@link java.text.DateFormat#SHORT}
+     * preset for the day portion and {@link java.text.DateFormat#MEDIUM} for the time
+     * portion of the output string.
+     * <p>
+     * <p>Note that a new DateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self a Date
+     * @return a string representation of this date and time
+     * @see java.text.DateFormat#getDateTimeInstance(int, int)
+     * @since 1.5.7
+     */
+    public static String getDateTimeString(Date self) {
+        return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM).format(self);
+    }
+
+    /**
+     * Common code for {@link #clearTime(java.util.Calendar)} and {@link #clearTime(java.util.Date)}
+     * and {@link #clearTime(java.sql.Date)}
+     *
+     * @param self a Calendar to adjust
+     */
+    private static void clearTimeCommon(final Calendar self) {
+        self.set(Calendar.HOUR_OF_DAY, 0);
+        self.clear(Calendar.MINUTE);
+        self.clear(Calendar.SECOND);
+        self.clear(Calendar.MILLISECOND);
+    }
+
+    /**
+     * Clears the time portion of this Date instance; useful utility where
+     * it makes sense to compare month/day/year only portions of a Date.
+     *
+     * @param self a Date
+     * @return the Date but with the time portion cleared
+     * @since 1.6.7
+     */
+    public static Date clearTime(final Date self) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(self);
+        clearTimeCommon(calendar);
+        self.setTime(calendar.getTime().getTime());
+        return self;
+    }
+
+    /**
+     * Clears the time portion of this java.sql.Date instance; useful utility
+     * where it makes sense to compare month/day/year only portions of a Date.
+     *
+     * @param self a java.sql.Date
+     * @return the java.sql.Date but with the time portion cleared
+     * @since 1.6.7
+     */
+    public static java.sql.Date clearTime(final java.sql.Date self) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(self);
+        clearTimeCommon(calendar);
+        self.setTime(calendar.getTime().getTime());
+        return self;
+    }
+
+    /**
+     * Clears the time portion of this Calendar instance; useful utility
+     * where it makes sense to compare month/day/year only portions of a Calendar.
+     *
+     * @param self a Calendar
+     * @return the Calendar but with the time portion cleared
+     * @since 1.6.7
+     */
+    public static Calendar clearTime(final Calendar self) {
+        clearTimeCommon(self);
+        return self;
+    }
+
+    /**
+     * <p>Shortcut for {@link java.text.SimpleDateFormat} to output a String representation
+     * of this calendar instance.  This method respects the Calendar's assigned
+     * {@link java.util.TimeZone}, whereas calling <code>cal.time.format('HH:mm:ss')</code>
+     * would use the system timezone.
+     * <p>Note that Calendar equivalents of <code>date.getDateString()</code>
+     * and variants do not exist because those methods are Locale-dependent.
+     * Although a Calendar may be assigned a {@link java.util.Locale}, that information is
+     * lost and therefore cannot be used to control the default date/time formats
+     * provided by these methods.  Instead, the system Locale would always be
+     * used.  The alternative is to simply call
+     * {@link java.text.DateFormat#getDateInstance(int, java.util.Locale)} and pass the same Locale
+     * that was used for the Calendar.
+     *
+     * @param self    this calendar
+     * @param pattern format pattern
+     * @return String representation of this calendar with the given format.
+     * @see java.text.DateFormat#setTimeZone(java.util.TimeZone)
+     * @see java.text.SimpleDateFormat#format(java.util.Date)
+     * @see #format(java.util.Date, String)
+     * @since 1.6.0
+     */
+    public static String format(Calendar self, String pattern) {
+        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+        sdf.setTimeZone(self.getTimeZone());
+        return sdf.format(self.getTime());
+    }
+
+    /**
+     * Iterates from this date up to the given date, inclusive,
+     * incrementing by one day each time.
+     *
+     * @param self    a Date
+     * @param to      another Date to go up to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void upto(Date self, Date to, Closure closure) {
+        if (self.compareTo(to) <= 0) {
+            for (Date i = (Date) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to upto() cannot be earlier than the value (" + self + ") it's called on.");
+    }
+
+    /**
+     * Iterates from the date represented by this calendar up to the date represented
+     * by the given calendar, inclusive, incrementing by one day each time.
+     *
+     * @param self    a Calendar
+     * @param to      another Calendar to go up to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void upto(Calendar self, Calendar to, Closure closure) {
+        if (self.compareTo(to) <= 0) {
+            for (Calendar i = (Calendar) self.clone(); i.compareTo(to) <= 0; i = next(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to upto() cannot be earlier than the value (" + self + ") it's called on.");
+    }
+
+    /**
+     * Iterates from this date down to the given date, inclusive,
+     * decrementing by one day each time.
+     *
+     * @param self    a Date
+     * @param to      another Date to go down to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void downto(Date self, Date to, Closure closure) {
+        if (self.compareTo(to) >= 0) {
+            for (Date i = (Date) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to downto() cannot be later than the value (" + self + ") it's called on.");
+    }
+
+    /**
+     * Iterates from the date represented by this calendar up to the date represented
+     * by the given calendar, inclusive, incrementing by one day each time.
+     *
+     * @param self    a Calendar
+     * @param to      another Calendar to go down to
+     * @param closure the closure to call
+     * @since 2.2
+     */
+    public static void downto(Calendar self, Calendar to, Closure closure) {
+        if (self.compareTo(to) >= 0) {
+            for (Calendar i = (Calendar) self.clone(); i.compareTo(to) >= 0; i = previous(i)) {
+                closure.call(i);
+            }
+        } else
+            throw new GroovyRuntimeException("The argument (" + to + 
+                    ") to downto() cannot be later than the value (" + self + ") it's called on.");
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java b/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java
new file mode 100644
index 0000000..9dd8cd0
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultCachedMethodKey.java
@@ -0,0 +1,47 @@
+/*
+ *  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.runtime;
+
+import org.codehaus.groovy.reflection.CachedClass;
+
+
+/**
+ * A default implementation of MethodKey
+ *
+ * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
+ */
+public class DefaultCachedMethodKey extends MethodKey{
+
+    private final CachedClass[] parameterTypes;
+
+    public DefaultCachedMethodKey(Class sender, String name, CachedClass[] parameterTypes, boolean isCallToSuper) {
+        super(sender, name,isCallToSuper);
+        this.parameterTypes = parameterTypes;
+    }
+
+    public int getParameterCount() {
+        return parameterTypes.length;
+    }
+
+    public Class getParameterType(int index) {
+        CachedClass c = parameterTypes[index];
+        if (c==null) return Object.class;
+        return c.getTheClass();
+    }
+}


[56/62] [abbrv] groovy git commit: Avoid copying resources into docgenerator sourceset

Posted by cc...@apache.org.
Avoid copying resources into docgenerator sourceset


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/52b67fc4
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/52b67fc4
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/52b67fc4

Branch: refs/heads/GROOVY_2_6_X
Commit: 52b67fc41c1022eff0eeeed4d55d9d139bd8bceb
Parents: 41133d7
Author: Cedric Champeau <cc...@apache.org>
Authored: Thu Dec 14 22:44:08 2017 +0100
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sun Dec 17 14:52:26 2017 +0100

----------------------------------------------------------------------
 gradle/docs.gradle | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/52b67fc4/gradle/docs.gradle
----------------------------------------------------------------------
diff --git a/gradle/docs.gradle b/gradle/docs.gradle
index 483bb23..0f4c123 100644
--- a/gradle/docs.gradle
+++ b/gradle/docs.gradle
@@ -111,7 +111,7 @@ groovydocAll groovydocSpec
 // but the file is only generated by the 'jar' task, so as a workaround, we copy
 // it into the docgenerator classes
 task docProjectVersionInfo(type: Copy) {
-    destinationDir = file("${project(':groovy-docgenerator').sourceSets.main.java.outputDir}")
+    destinationDir = file("${buildDir}/docgenerator-resources")
     into('META-INF') {
         from(generateReleaseInfo)
     }
@@ -119,13 +119,13 @@ task docProjectVersionInfo(type: Copy) {
 }
 
 task docGDK {
-//    ext.extraDocGDKclasses = []
+    outputs.cacheIf { true }
     dependsOn([project(':groovy-groovydoc'), project(':groovy-docgenerator')]*.classes)
     // TODO don't hard-code these
     dependsOn([project(':groovy-nio'), project(':groovy-sql'), project(':groovy-xml'), project(':groovy-swing')]*.classes)
     dependsOn docProjectVersionInfo
     ext.destinationDir = "$buildDir/html/groovy-jdk"
-    inputs.files sourceSets.main.runtimeClasspath + configurations.tools
+    inputs.files sourceSets.main.runtimeClasspath + configurations.tools + files(docProjectVersionInfo.destinationDir)
     outputs.dir destinationDir
     def docGeneratorPath = files(project(':groovy-docgenerator').sourceSets.main.output.classesDirs)
     doLast { task ->
@@ -134,7 +134,7 @@ task docGDK {
                 java(classname: 'org.codehaus.groovy.tools.DocGenerator',
                      fork: 'true',
                      failonerror: 'true',
-                     classpath: (sourceSets.main.runtimeClasspath + configurations.tools + groovydocAll.groovyClasspath + docGeneratorPath).asPath,
+                     classpath: (sourceSets.main.runtimeClasspath + rootProject.files(docProjectVersionInfo.destinationDir) + configurations.tools + groovydocAll.groovyClasspath + docGeneratorPath).asPath,
                      errorproperty: 'edr',
                      outputproperty: 'odr') {
                     arg(value: '-title')


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

Posted by cc...@apache.org.
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/GroovyBugError.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/GroovyBugError.java b/src/main/java/org/codehaus/groovy/GroovyBugError.java
new file mode 100644
index 0000000..30ed7de
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/GroovyBugError.java
@@ -0,0 +1,111 @@
+/*
+ *  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;
+
+/**
+ * This class represents an error that is thrown when a bug is 
+ * recognized inside the runtime. Basically it is thrown when
+ * a constraint is not fulfilled that should be fulfilled.
+ * 
+ * @author Jochen Theodorou
+ */
+public class GroovyBugError extends AssertionError {
+    
+    // message string
+    private String message;
+    // optional exception
+    private final Exception exception;
+
+    /**
+     * constructs a bug error using the given text
+     * @param message the error message text
+     */
+    public GroovyBugError( String message ) {
+        this(message, null);
+    }
+    
+    /**
+     * Constructs a bug error using the given exception
+     * @param exception cause of this error
+     */
+    public GroovyBugError( Exception exception ) {
+        this(null, exception);
+    }
+    
+    /**
+     * Constructs a bug error using the given exception and
+     * a text with additional information about the cause 
+     * @param msg additional information about this error
+     * @param exception cause of this error
+     */
+    public GroovyBugError( String msg, Exception exception ) {
+        this.exception = exception;
+        this.message = msg;
+    }
+
+    /**
+     * Returns a String representation of this class by calling <code>getMessage()</code>.  
+     * @see #getMessage()
+     */
+    public String toString() {
+        return getMessage();
+    }
+    
+    /**
+     * Returns the detail message string of this error. The message 
+     * will consist of the bug text prefixed by "BUG! " if there this
+     * instance was created using a message. If this error was
+     * constructed without using a bug text the message of the cause 
+     * is used prefixed by "BUG! UNCAUGHT EXCEPTION: "
+     *  
+     * @return the detail message string of this error.
+     */
+    public String getMessage() {
+        if( message != null )
+        {
+            return "BUG! "+message;
+        }
+        else
+        {
+            return "BUG! UNCAUGHT EXCEPTION: " + exception.getMessage();
+        }
+    }
+    
+    public Throwable getCause() {
+        return this.exception;
+    }    
+    
+    /**
+     * Returns the bug text to describe this error
+     */
+    public String getBugText(){
+        if( message != null ){
+            return message;
+        } else {
+            return exception.getMessage();
+        }
+    }
+    
+    /**
+     * Sets the bug text to describe this error
+     */
+    public void setBugText(String msg) {
+        this.message = msg;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/GroovyException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/GroovyException.java b/src/main/java/org/codehaus/groovy/GroovyException.java
new file mode 100644
index 0000000..582da48
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/GroovyException.java
@@ -0,0 +1,52 @@
+/*
+ *  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;
+
+public class GroovyException extends Exception implements GroovyExceptionInterface {
+    private boolean fatal = true;
+
+    public GroovyException() {
+    }
+
+    public GroovyException(String message) {
+        super(message);
+    }
+
+    public GroovyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public GroovyException(boolean fatal) {
+        super();
+        this.fatal = fatal;
+    }
+
+    public GroovyException(String message, boolean fatal) {
+        super(message);
+        this.fatal = fatal;
+    }
+
+    public boolean isFatal() {
+        return fatal;
+    }
+
+    public void setFatal(boolean fatal) {
+        this.fatal = fatal;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/GroovyExceptionInterface.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/GroovyExceptionInterface.java b/src/main/java/org/codehaus/groovy/GroovyExceptionInterface.java
new file mode 100644
index 0000000..bfff301
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/GroovyExceptionInterface.java
@@ -0,0 +1,31 @@
+/*
+ *  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;
+
+/**
+ *  An interface for use by all Groovy compiler exceptions.
+ */
+
+public interface GroovyExceptionInterface {
+
+    boolean isFatal();
+
+    void setFatal( boolean fatal );
+    
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/ASTParserException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/ASTParserException.java b/src/main/java/org/codehaus/groovy/antlr/ASTParserException.java
new file mode 100644
index 0000000..204674b
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/ASTParserException.java
@@ -0,0 +1,54 @@
+/*
+ *  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.antlr;
+
+import antlr.collections.AST;
+import org.codehaus.groovy.syntax.ParserException;
+
+/**
+ * Thrown when trying to parse the AST
+ *
+ */
+public class ASTParserException extends ParserException {
+    private final AST ast;
+
+    public ASTParserException(ASTRuntimeException e) {
+        super(e.getMessage(), e, e.getLine(), e.getColumn(), getLineLast(e), getColumnLast(e));
+        this.ast = e.getAst();
+    }
+
+    public ASTParserException(String message, ASTRuntimeException e) {
+        super(message, e, e.getLine(), e.getColumn(), getLineLast(e), getColumnLast(e));
+        this.ast = e.getAst();
+    }
+
+    public AST getAst() {
+        return ast;
+    }
+    
+    private static int getLineLast(ASTRuntimeException e) {
+        final AST ast = e.getAst();
+        return (ast instanceof SourceInfo) ? ((SourceInfo)ast).getLineLast() : ast.getLine();
+    }
+
+    private static int getColumnLast(ASTRuntimeException e) {
+        final AST ast = e.getAst();
+        return (ast instanceof SourceInfo) ? ((SourceInfo)ast).getColumnLast() : ast.getColumn()+1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/ASTRuntimeException.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/ASTRuntimeException.java b/src/main/java/org/codehaus/groovy/antlr/ASTRuntimeException.java
new file mode 100644
index 0000000..aec85d4
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/ASTRuntimeException.java
@@ -0,0 +1,55 @@
+/*
+ *  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.antlr;
+
+import antlr.collections.AST;
+
+/**
+ * @author <a href="mailto:jstrachan@protique.com">James Strachan</a>
+ */
+public class ASTRuntimeException extends RuntimeException {
+    private final AST ast;
+
+    public ASTRuntimeException(AST ast, String message) {
+        super(message + description(ast));
+        this.ast = ast;
+    }
+
+    public ASTRuntimeException(AST ast, String message, Throwable throwable) {
+        super(message + description(ast), throwable);
+        this.ast = null;
+    }
+
+    protected static String description(AST node) {
+        return (node != null) ? " at line: " + node.getLine() + " column: " + node.getColumn() : "";
+    }
+
+    public AST getAst() {
+        return ast;
+    }
+
+    public int getLine() {
+        return ast != null ? ast.getLine() : -1;
+    }
+
+    public int getColumn() {
+        return ast != null ? ast.getColumn() : -1;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessSnippets.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessSnippets.java b/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessSnippets.java
new file mode 100644
index 0000000..94e8bf1
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessSnippets.java
@@ -0,0 +1,96 @@
+/*
+ *  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.antlr;
+
+/**
+ * Process to decorate antlr AST with ending line/col info, and if
+ * possible the snippet of source from the start/end line/col for each node.
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+
+import antlr.collections.AST;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class AntlrASTProcessSnippets implements AntlrASTProcessor{
+
+    public AntlrASTProcessSnippets() {
+    }
+
+    /**
+     * decorate antlr AST with ending line/col info, and if
+     * possible the snippet of source from the start/end line/col for each node.
+     * @param t the AST to decorate
+     * @return the decorated AST
+     */
+    public AST process(AST t) {
+        // first visit
+        List l = new ArrayList();
+        traverse((GroovySourceAST)t,l,null);
+
+        //System.out.println("l:" + l);
+        // second visit
+        Iterator itr = l.iterator();
+        if (itr.hasNext()) { itr.next(); /* discard first */ }
+        traverse((GroovySourceAST)t,null,itr);
+        return t;
+    }
+
+    /**
+     * traverse an AST node
+     * @param t the AST node to traverse
+     * @param l A list to add line/col info to
+     * @param itr An iterator over a list of line/col
+     */
+    private void traverse(GroovySourceAST t,List l,Iterator itr) {
+         while (t != null) {
+             // first visit of node
+             if (l != null) {
+                 l.add(new LineColumn(t.getLine(),t.getColumn()));
+             }
+
+             // second visit of node
+             if (itr != null && itr.hasNext()) {
+                 LineColumn lc = (LineColumn)itr.next();
+                 if (t.getLineLast() == 0) {
+                     int nextLine = lc.getLine();
+                     int nextColumn = lc.getColumn();
+                     if (nextLine < t.getLine() || (nextLine == t.getLine() && nextColumn < t.getColumn())) {
+                         nextLine = t.getLine();
+                         nextColumn = t.getColumn();
+                     }
+                     t.setLineLast(nextLine);
+                     t.setColumnLast(nextColumn);
+                     // This is a good point to call t.setSnippet(),
+                     // but it bulks up the AST too much for production code.
+                 }
+             }
+
+             GroovySourceAST child = (GroovySourceAST)t.getFirstChild();
+             if (child != null) {
+                 traverse(child,l,itr);
+             }
+
+             t = (GroovySourceAST)t.getNextSibling();
+         }
+    }
+}

http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessor.java b/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessor.java
new file mode 100644
index 0000000..924f91f
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/antlr/AntlrASTProcessor.java
@@ -0,0 +1,35 @@
+/*
+ *  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.antlr;
+
+import antlr.collections.AST;
+
+/**
+ * An interface for processing antlr AST objects
+ *
+ * @author <a href="mailto:groovy@ross-rayner.com">Jeremy Rayner</a>
+ */
+public interface AntlrASTProcessor {
+    /**
+     * performs some processing on the supplied AST node.
+     * @param t the AST node to process.
+     * @return possibly returns the AST modified or null, depends on the implementation.
+     */
+    AST process(AST t);
+}