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 '''