You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/11/09 16:26:57 UTC

[groovy] 01/01: GROOVY-10353: `evaluateExpression` can handle simple expression directly

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

emilles pushed a commit to branch GROOVY-10353
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit b93c21319dcaa3dbde26511e2dcf92140c395948
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 9 10:18:23 2021 -0600

    GROOVY-10353: `evaluateExpression` can handle simple expression directly
---
 src/main/java/groovy/lang/GroovyClassLoader.java   |  6 ++---
 .../transform/stc/StaticTypeCheckingSupport.java   | 31 +++++++++++++++-------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/src/main/java/groovy/lang/GroovyClassLoader.java b/src/main/java/groovy/lang/GroovyClassLoader.java
index c28306e..ce76e65 100644
--- a/src/main/java/groovy/lang/GroovyClassLoader.java
+++ b/src/main/java/groovy/lang/GroovyClassLoader.java
@@ -703,10 +703,10 @@ public class GroovyClassLoader extends URLClassLoader {
     }
 
     /**
-     * open up the super class define that takes raw bytes
+     * Converts an array of bytes into an instance of {@code Class}.
      */
-    public Class defineClass(String name, byte[] b) {
-        return super.defineClass(name, b, 0, b.length);
+    public Class defineClass(final String name, final byte[] bytes) throws ClassFormatError {
+        return super.defineClass(name, bytes, 0, bytes.length);
     }
 
     /**
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 7095e54..fe91d94 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -31,6 +31,7 @@ import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.ArrayExpression;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
 import org.codehaus.groovy.ast.expr.ClosureExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.Expression;
@@ -51,7 +52,6 @@ import org.codehaus.groovy.tools.GroovyClass;
 import org.codehaus.groovy.transform.trait.Traits;
 import org.objectweb.asm.Opcodes;
 
-import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -2147,22 +2147,33 @@ public abstract class StaticTypeCheckingSupport {
      * @return the result of the expression
      */
     public static Object evaluateExpression(final Expression expr, final CompilerConfiguration config) {
+        Expression ce = expr instanceof CastExpression ? ((CastExpression) expr).getExpression() : expr;
+        if (ce instanceof ConstantExpression) {
+            if (expr.getType().equals(ce.getType()))
+                return ((ConstantExpression) ce).getValue();
+        } else if (ce instanceof ListExpression) {
+            if (expr.getType().isArray() && expr.getType().getComponentType().equals(STRING_TYPE))
+                return ((ListExpression) ce).getExpressions().stream().map(e -> evaluateExpression(e, config)).toArray(String[]::new);
+        }
+
         String className = "Expression$" + UUID.randomUUID().toString().replace('-', '$');
-        ClassNode node = new ClassNode(className, Opcodes.ACC_PUBLIC, OBJECT_TYPE);
-        ReturnStatement code = new ReturnStatement(expr);
-        addGeneratedMethod(node, "eval", Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, code);
-        CompilerConfiguration copyConf = new CompilerConfiguration(config);
-        // disable preview features so class can be inspected by this JVM
-        copyConf.setPreviewFeatures(false);
-        CompilationUnit cu = new CompilationUnit(copyConf);
+        ClassNode simpleClass = new ClassNode(className, Opcodes.ACC_PUBLIC, OBJECT_TYPE);
+        addGeneratedMethod(simpleClass, "eval", Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new ReturnStatement(expr));
+
+        // adjust configuration so class can be inspected by this JVM
+        CompilerConfiguration cc = new CompilerConfiguration(config);
+        cc.setPreviewFeatures(false); // unlikely to be required by expression
+        cc.setTargetBytecode(CompilerConfiguration.DEFAULT.getTargetBytecode());
+
+        CompilationUnit cu = new CompilationUnit(cc);
         try {
-            cu.addClassNode(node);
+            cu.addClassNode(simpleClass);
             cu.compile(Phases.CLASS_GENERATION);
             List<GroovyClass> classes = cu.getClasses();
             Class<?> aClass = cu.getClassLoader().defineClass(className, classes.get(0).getBytes());
             try {
                 return aClass.getMethod("eval").invoke(null);
-            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
+            } catch (ReflectiveOperationException e) {
                 throw new GroovyBugError(e);
             }
         } finally {