You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/07/25 14:38:49 UTC

[groovy] branch master updated: Tweak GINQ transformation

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

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


The following commit(s) were added to refs/heads/master by this push:
     new aef68f0  Tweak GINQ transformation
aef68f0 is described below

commit aef68f078d955c98fe4056c4852e9c8334fde326
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Jul 25 22:38:20 2021 +0800

    Tweak GINQ transformation
---
 .../src/main/groovy/groovy/ginq/transform/GQ.java  |  6 +++
 .../collection/runtime/QueryableCollection.java    |  4 ++
 .../ginq/transform/GinqASTTransformation.java      | 37 +++++++++++--
 .../groovy-ginq/src/spec/doc/ginq-userguide.adoc   |  7 +++
 .../test/org/apache/groovy/ginq/GinqTest.groovy    | 63 ++++++++++++++++++++++
 5 files changed, 113 insertions(+), 4 deletions(-)

diff --git a/subprojects/groovy-ginq/src/main/groovy/groovy/ginq/transform/GQ.java b/subprojects/groovy-ginq/src/main/groovy/groovy/ginq/transform/GQ.java
index 683e857..9d706a0 100644
--- a/subprojects/groovy-ginq/src/main/groovy/groovy/ginq/transform/GQ.java
+++ b/subprojects/groovy-ginq/src/main/groovy/groovy/ginq/transform/GQ.java
@@ -18,6 +18,7 @@
  */
 package groovy.ginq.transform;
 
+import org.apache.groovy.ginq.provider.collection.runtime.Queryable;
 import org.apache.groovy.lang.annotation.Incubating;
 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
 
@@ -39,6 +40,11 @@ import java.lang.annotation.Target;
 @GroovyASTTransformationClass("org.apache.groovy.ginq.transform.GinqASTTransformation")
 public @interface GQ {
     /**
+     * Specify the result type
+     */
+    Class<?> value() default Queryable.class;
+
+    /**
      * Whether to optimize the GINQ AST
      */
     boolean optimize() default true;
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java
index db5900f..2ec26d1 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/provider/collection/runtime/QueryableCollection.java
@@ -712,6 +712,10 @@ class QueryableCollection<T> implements Queryable<T>, Serializable {
     }
 
     public Object asType(Class<?> clazz) {
+        if (Queryable.class == clazz || QueryableCollection.class == clazz) {
+            return this;
+        }
+
         if (List.class == clazz || Collection.class == clazz || Iterable.class == clazz) {
             return toList();
         }
diff --git a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/transform/GinqASTTransformation.java b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/transform/GinqASTTransformation.java
index ac865a4..bdf21ad 100644
--- a/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/transform/GinqASTTransformation.java
+++ b/subprojects/groovy-ginq/src/main/groovy/org/apache/groovy/ginq/transform/GinqASTTransformation.java
@@ -23,8 +23,11 @@ import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.MapExpression;
@@ -44,6 +47,7 @@ import static org.apache.groovy.ginq.GinqGroovyMethods.CONF_LIST;
 import static org.apache.groovy.ginq.GinqGroovyMethods.transformGinqCode;
 import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.mapX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
@@ -54,8 +58,6 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
  */
 @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
 public class GinqASTTransformation extends AbstractASTTransformation {
-    private static final ClassNode GQ_CLASS_NODE = make(GQ.class);
-
     @Override
     public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
         init(nodes, sourceUnit);
@@ -71,7 +73,20 @@ public class GinqASTTransformation extends AbstractASTTransformation {
             }
             BlockStatement origCode = (BlockStatement) methodNode.getCode();
             MapExpression ginqConfigurationMapExpression = makeGinqConfigurationMapExpression(annotationNode);
-            BlockStatement newCode = block(stmt(transformGinqCode(sourceUnit, ginqConfigurationMapExpression, origCode)));
+            Expression valueExpression = annotationNode.getMember(VALUE);
+
+            ClassNode targetType = DEFAULT_RESULT_TYPE;
+            if (valueExpression instanceof ClassExpression) {
+                ClassNode type = valueExpression.getType();
+                if (!targetType.equals(type)) {
+                    targetType = type;
+                }
+            }
+
+            CastExpression castExpression = castX(targetType, transformGinqCode(sourceUnit, ginqConfigurationMapExpression, origCode));
+            castExpression.setCoerce(true);
+
+            BlockStatement newCode = block(stmt(castExpression));
             newCode.setSourcePosition(origCode);
             methodNode.setCode(newCode);
             VariableScopeVisitor variableScopeVisitor = new VariableScopeVisitor(sourceUnit);
@@ -81,13 +96,27 @@ public class GinqASTTransformation extends AbstractASTTransformation {
 
     private MapExpression makeGinqConfigurationMapExpression(AnnotationNode annotationNode) {
         Map<String, Expression> resultMembers = new HashMap<>(DEFAULT_OPTION_MAP);
-        resultMembers.putAll(annotationNode.getMembers());
+        Map<String, Expression> currentMembers = new HashMap<>(annotationNode.getMembers());
+        currentMembers.remove(VALUE);
+        resultMembers.putAll(currentMembers);
 
         return mapX(resultMembers.entrySet().stream()
                     .map(e -> new MapEntryExpression(constX(e.getKey()), constX(e.getValue().getText())))
                     .collect(Collectors.toList()));
     }
 
+    private static final String VALUE = "value";
+    private static final ClassNode GQ_CLASS_NODE = make(GQ.class);
+    private static final ClassNode DEFAULT_RESULT_TYPE;
+    static {
+        Class<?> c;
+        try {
+            c = (Class<?>) GQ_CLASS_NODE.getTypeClass().getMethod(VALUE).getDefaultValue();
+        } catch (NoSuchMethodException e) {
+            throw new GroovyBugError(e);
+        }
+        DEFAULT_RESULT_TYPE = ClassHelper.make(c);
+    }
     private static final Map<String, Expression> DEFAULT_OPTION_MAP = unmodifiableMap(CONF_LIST.stream().collect(Collectors.toMap(
             c -> c,
             c -> {
diff --git a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
index ebc9de3..e505ae1 100644
--- a/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
+++ b/subprojects/groovy-ginq/src/spec/doc/ginq-userguide.adoc
@@ -100,6 +100,13 @@ For example,
 include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_method_01,indent=0]
 ----
 
+Specify the return type as `List`:
+[source, groovy]
+----
+include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_method_03,indent=0]
+----
+
+Enable parallel querying:
 [source, groovy]
 ----
 include::../test/org/apache/groovy/ginq/GinqTest.groovy[tags=ginq_method_02,indent=0]
diff --git a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
index fee5e33..04a38ed 100644
--- a/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
+++ b/subprojects/groovy-ginq/src/spec/test/org/apache/groovy/ginq/GinqTest.groovy
@@ -6343,6 +6343,69 @@ class GinqTest {
         '''
     }
 
+    @Test
+    void "testGinqMethod - GQ - 12"() {
+        assertScript '''
+            import groovy.ginq.transform.GQ
+            import groovy.transform.CompileStatic
+            import groovy.transform.CompileDynamic
+            
+            @CompileStatic
+            class GinqClass {
+                private static final int F = 6
+                private int e = 3
+                
+                List<Integer> biz(b) {
+                    (List<Integer>) ginq(b)
+                }
+                
+                @GQ(List)
+                @CompileDynamic
+                def ginq(b) {
+                    from n in [1, 2, 3]
+                    where b < n && n < e
+                    select n + F
+                }
+            }
+            
+            assert [8] == new GinqClass().ginq(1)
+        '''
+    }
+
+    @Test
+    void "testGinqMethod - GQ - 13"() {
+        assertScript '''
+// tag::ginq_method_03[]
+            import groovy.ginq.transform.GQ
+            
+            @GQ(List)
+            def ginq(b, e) {
+                from n in [1, 2, 3, 4, 5, 6]
+                where b < n && n < e
+                select n
+            }
+            
+            assert [3, 4] == ginq(2, 5)
+// end::ginq_method_03[]
+        '''
+    }
+
+    @Test
+    void "testGinqMethod - GQ - 14"() {
+        assertScript '''
+            import groovy.ginq.transform.GQ
+            
+            @GQ(value=List, parallel=true)
+            def ginq(b, e) {
+                from n in [1, 2, 3, 4, 5, 6]
+                where b < n && n < e
+                select n
+            }
+            
+            assert [3, 4] == ginq(2, 5)
+        '''
+    }
+
     @AfterClass
     static void "testGinq - shutdown - 0"() {
         assertScript '''