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:59 UTC
[48/62] [abbrv] [partial] groovy git commit: Move Java source set
into `src/main/java`
http://git-wip-us.apache.org/repos/asf/groovy/blob/0edfcde9/src/main/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);
+
+}