You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2021/04/12 06:04:08 UTC

[groovy] 02/26: GROOVY-9649: Rework range creation to also allow left- and full-open ranges

This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch groovy9649
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 9b36007010305a133886c9dc9cd932985dc78b87
Author: Esko Toivonen <es...@tuni.fi>
AuthorDate: Tue Mar 30 11:12:26 2021 +0300

    GROOVY-9649: Rework range creation to also allow left- and full-open ranges
    
    This commit also adds a new parameter to MethodCaller which is used in
    AsmClassGenerator to access the createRange method. This new parameter is needed
    because the three-parameter version has to be left in for backwards
    compatibility, and without the additional parameter in MethodCaller the wrong
    method would be found.
---
 .../groovy/classgen/AsmClassGenerator.java         |  9 ++++---
 .../codehaus/groovy/classgen/asm/MethodCaller.java | 29 ++++++++++++++++++----
 .../org/codehaus/groovy/runtime/InvokerHelper.java |  9 +++++--
 .../groovy/runtime/ScriptBytecodeAdapter.java      |  8 +++++-
 4 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
index bfbd856..be5047d 100644
--- a/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/java/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -216,7 +216,9 @@ public class AsmClassGenerator extends ClassGenerator {
     // type conversions
     private static final MethodCaller createMapMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createMap");
     private static final MethodCaller createListMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createList");
-    private static final MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange");
+    // The 3-parameter version of createRange is kept in for backwards compatibility, so we need to specify the
+    // parameter count here
+    private static final MethodCaller createRangeMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createRange", 4);
     private static final MethodCaller createPojoWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createPojoWrapper");
     private static final MethodCaller createGroovyObjectWrapperMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "createGroovyObjectWrapper");
 
@@ -1526,10 +1528,11 @@ public class AsmClassGenerator extends ClassGenerator {
         operandStack.box();
         expression.getTo().visit(this);
         operandStack.box();
-        operandStack.pushBool(expression.isInclusive());
+        operandStack.pushBool(expression.isExclusiveLeft());
+        operandStack.pushBool(expression.isExclusiveRight());
 
         createRangeMethod.call(controller.getMethodVisitor());
-        operandStack.replace(ClassHelper.RANGE_TYPE, 3);
+        operandStack.replace(ClassHelper.RANGE_TYPE, 4);
     }
 
     @Override
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java
index 91a5988..faf3390 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/MethodCaller.java
@@ -38,11 +38,17 @@ public class MethodCaller {
     private String name;
     private Class theClass;
     private String methodDescriptor;
+    private int parameterCount;
+    private static final int ANY_PARAMETER_COUNT = -1;
 
     public static MethodCaller newStatic(Class theClass, String name) {
         return new MethodCaller(INVOKESTATIC, theClass, name);
     }
 
+    public static MethodCaller newStatic(Class theClass, String name, int parameterCount) {
+        return new MethodCaller(INVOKESTATIC, theClass, name, parameterCount);
+    }
+
     public static MethodCaller newInterface(Class theClass, String name) {
         return new MethodCaller(INVOKEINTERFACE, theClass, name);
     }
@@ -57,11 +63,15 @@ public class MethodCaller {
     protected MethodCaller() {}
 
     public MethodCaller(int opcode, Class theClass, String name) {
+        this(opcode, theClass, name, ANY_PARAMETER_COUNT);
+    }
+
+    public MethodCaller(int opcode, Class theClass, String name, int parameterCount) {
         this.opcode = opcode;
         this.internalName = Type.getInternalName(theClass);
         this.theClass = theClass;
         this.name = name;
-
+        this.parameterCount = parameterCount;
     }
 
     public void call(MethodVisitor methodVisitor) {
@@ -78,11 +88,20 @@ public class MethodCaller {
 
     protected Method getMethod() {
         Method[] methods = theClass.getMethods();
-        for (Method method : methods) {
-            if (method.getName().equals(name)) {
-                return method;
+        if (parameterCount != ANY_PARAMETER_COUNT) {
+            for (Method method : methods) {
+                if (method.getName().equals(name) && method.getParameterCount() == parameterCount) {
+                    return method;
+                }
+            }
+        } else {
+            for (Method method : methods) {
+                if (method.getName().equals(name)) {
+                    return method;
+                }
             }
         }
-        throw new ClassGeneratorException("Could not find method: " + name + " on class: " + theClass);
+        throw new ClassGeneratorException("Could not find method: " + name +
+                (parameterCount >= 0 ? " with parameter count " + parameterCount : "") + " on class: " + theClass);
     }
 }
diff --git a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
index 82a8868..6d64276 100644
--- a/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
+++ b/src/main/java/org/codehaus/groovy/runtime/InvokerHelper.java
@@ -933,9 +933,9 @@ public class InvokerHelper {
         return toArrayString(arguments, false, maxSize, safe);
     }
 
-    public static List createRange(Object from, Object to, boolean inclusive) {
+    public static List createRange(Object from, Object to, boolean exclusiveLeft, boolean exclusiveRight) {
         try {
-            return ScriptBytecodeAdapter.createRange(from, to, inclusive);
+            return ScriptBytecodeAdapter.createRange(from, to, exclusiveLeft, exclusiveRight);
         } catch (RuntimeException | Error re) {
             throw re;
         } catch (Throwable t) {
@@ -943,6 +943,11 @@ public class InvokerHelper {
         }
     }
 
+    // Kept in for backwards compatibility
+    public static List createRange(Object from, Object to, boolean inclusive) {
+        return createRange(from, to, false, !inclusive);
+    }
+
     public static Object bitwiseNegate(Object value) {
         if (value instanceof Integer) {
             Integer number = (Integer) value;
diff --git a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
index 69cd50f..e02bc62 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
@@ -635,7 +635,8 @@ public class ScriptBytecodeAdapter {
         return InvokerHelper.createMap(values);
     }
 
-    public static List createRange(Object from, Object to, boolean inclusive) throws Throwable {
+    public static List createRange(Object from, Object to, boolean exclusiveLeft, boolean exclusiveRight) throws Throwable {
+        boolean inclusive = !exclusiveRight;
         if (from instanceof Integer && to instanceof Integer) {
             int ifrom = (Integer) from;
             int ito = (Integer) to;
@@ -660,6 +661,11 @@ public class ScriptBytecodeAdapter {
         return new ObjectRange((Comparable) from, (Comparable) to);
     }
 
+    // Kept in for backwards compatibility
+    public static List createRange(Object from, Object to, boolean inclusive) throws Throwable {
+        return createRange(from, to, false, !inclusive);
+    }
+
     @SuppressWarnings("unchecked")
     private static <T extends Number & Comparable> T comparableNumber(Number n) {
         return (T) n;