groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cchamp...@apache.org
Subject [48/62] [abbrv] [partial] groovy git commit: Move Java source set into `src/main/java`
Date Sun, 17 Dec 2017 15:05:10 GMT
http://git-wip-us.apache.org/repos/asf/groovy/blob/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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/a188738d/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);
+
+}


Mime
View raw message