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 2020/10/22 08:08:54 UTC

[groovy] branch GROOVY-8258 updated (5d189c1 -> eead551)

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

sunlan pushed a change to branch GROOVY-8258
in repository https://gitbox.apache.org/repos/asf/groovy.git.


    from 5d189c1  GROOVY-9787: add the most powerful aggregate function `agg`
     new 3f8c06b  GROOVY-9787: avoid using method name as alias
     new eead551  GROOVY-9787: minor refactor

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../linq/provider/collection/GinqAstWalker.groovy  | 216 ++++++++++-----------
 .../groovy/org/apache/groovy/linq/GinqTest.groovy  |   4 +-
 2 files changed, 109 insertions(+), 111 deletions(-)


[groovy] 02/02: GROOVY-9787: minor refactor

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit eead551f29a3a1968d0b7c8c4e314cde43e6d676
Author: Daniel Sun <su...@apache.org>
AuthorDate: Thu Oct 22 16:08:06 2020 +0800

    GROOVY-9787: minor refactor
---
 .../linq/provider/collection/GinqAstWalker.groovy  | 218 ++++++++++-----------
 1 file changed, 108 insertions(+), 110 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy
index 3497df5..ff67699 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy
@@ -279,7 +279,7 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
 
         MethodCallExpression groupMethodCallExpression = callXWithLambda(groupMethodCallReceiver, "groupby", dataSourceExpression, namedListCtorCallExpression)
 
-        this.currentGinqExpression.putNodeMetaData(__GROUP_BY, true)
+        this.currentGinqExpression.putNodeMetaData(__GROUPBY_VISITED, true)
         return groupMethodCallExpression
     }
 
@@ -351,10 +351,7 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
                     elementExpression = e
                     nameExpression = e.property
                 }
-            } /*else if (e instanceof MethodCallExpression) {
-                elementExpression = e
-                nameExpression = new ConstantExpression(e.methodAsString)
-            }*/
+            }
             elementExpressionList << elementExpression
             nameExpressionList << nameExpression
         }
@@ -381,114 +378,13 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
     }
 
     private Expression correctVariablesOfGinqExpression(DataSourceExpression dataSourceExpression, Expression expr) {
-        boolean isGroup = isGroupByVisited()
-        boolean isJoin = dataSourceExpression instanceof JoinExpression
         String lambdaParamName = expr.getNodeMetaData(__LAMBDA_PARAM_NAME)
-
         if (null == lambdaParamName) {
             throw new GroovyBugError("lambdaParamName is null. dataSourceExpression:${dataSourceExpression}, expr:${expr}")
         }
 
-        def correctVarsForJoin = { Expression expression, Expression prop ->
-            if (!isJoin) return expression
-
-            Expression transformedExpression = null
-
-            /*
-                     * `n1`(`from` node) join `n2` join `n3`  will construct a join tree:
-                     *
-                     *  __t (join node)
-                     *    |__ v2 (n3)
-                     *    |__ v1 (join node)
-                     *         |__ v2 (n2)
-                     *         |__ v1 (n1) (`from` node)
-                     *
-                     * Note: `__t` is a tuple with 2 elements
-                     * so  `n3`'s access path is `__t.v2`
-                     * and `n2`'s access path is `__t.v1.v2`
-                     * and `n1`'s access path is `__t.v1.v1`
-                     *
-                     * The following code shows how to construct the access path for variables
-                     */
-            for (DataSourceExpression dse = dataSourceExpression;
-                 null == transformedExpression && dse instanceof JoinExpression;
-                 dse = dse.getNodeMetaData(__DATA_SOURCE_EXPRESSION)) {
-
-                DataSourceExpression otherDataSourceExpression = dse.getNodeMetaData(__DATA_SOURCE_EXPRESSION)
-                Expression firstAliasExpr = otherDataSourceExpression?.aliasExpr ?: EmptyExpression.INSTANCE
-                Expression secondAliasExpr = dse.aliasExpr
-
-                if (firstAliasExpr.text == expression.text && otherDataSourceExpression !instanceof JoinExpression) {
-                    transformedExpression = propX(prop, 'v1')
-                } else if (secondAliasExpr.text == expression.text) {
-                    transformedExpression = propX(prop, 'v2')
-                } else { // not found
-                    prop = propX(prop, 'v1')
-                }
-            }
-
-            return transformedExpression
-        }
-
-        def correctVars = { Expression expression ->
-            Expression transformedExpression = null
-            if (expression instanceof VariableExpression) {
-                if (expression.isThisExpression()) return expression
-                if (expression.text && Character.isUpperCase(expression.text.charAt(0))) return expression // type should be transformed
-
-                if (isGroup) { //  groupby
-                    // in #1, we will correct receiver of built-in aggregate functions
-                    // the correct receiver is `__t.v2`, so we should not replace `__t` here
-                    if (lambdaParamName != expression.text) {
-                        if (visitingAggregateFunction) {
-                            if ('_q' == expression.text) {
-                                transformedExpression = new VariableExpression(lambdaParamName)
-                            } else {
-                                transformedExpression = isJoin
-                                        ? correctVarsForJoin(expression, new VariableExpression(lambdaParamName))
-                                        : new VariableExpression(lambdaParamName)
-                            }
-                        } else {
-                            // replace `gk` in the groupby with `__t.v1.gk`, note: __t.v1 stores the group key
-                            transformedExpression = propX(propX(new VariableExpression(lambdaParamName), 'v1'), expression.text)
-                        }
-                    }
-                } else if (isJoin) {
-                    transformedExpression = correctVarsForJoin(expression, new VariableExpression(lambdaParamName))
-                }
-            } else if (expression instanceof MethodCallExpression) {
-                // #1
-                if (isGroup) { // groupby
-                    if (expression.implicitThis) {
-                        String methodName = expression.methodAsString
-                        if ('count' == methodName && ((TupleExpression) expression.arguments).getExpressions().isEmpty()) { // Similar to count(*) in SQL
-                            visitingAggregateFunction = true
-                            expression.objectExpression = propX(new VariableExpression(lambdaParamName), 'v2')
-                            transformedExpression = expression
-                            visitingAggregateFunction = false
-                        } else if (methodName in ['count', 'sum', 'agg'] && 1 == ((TupleExpression) expression.arguments).getExpressions().size()) {
-                            visitingAggregateFunction = true
-                            Expression lambdaCode = ((TupleExpression) expression.arguments).getExpression(0)
-                            lambdaCode.putNodeMetaData(__LAMBDA_PARAM_NAME, findRootObjectExpression(lambdaCode).text)
-                            transformedExpression =
-                                    callXWithLambda(
-                                            propX(new VariableExpression(lambdaParamName), 'v2'), methodName,
-                                            dataSourceExpression, lambdaCode)
-                            visitingAggregateFunction = false
-                        }
-                    }
-                }
-            }
-
-            if (null != transformedExpression) {
-                return transformedExpression
-            }
-
-            return expression
-        }
-
         // (1) correct itself
-        expr = correctVars(expr)
+        expr = correctVars(dataSourceExpression, lambdaParamName, expr)
 
         // (2) correct its children nodes
         // The synthetic lambda parameter `__t` represents the element from the result datasource of joining, e.g. `n1` innerJoin `n2`
@@ -497,7 +393,7 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
         expr = expr.transformExpression(new ExpressionTransformer() {
             @Override
             Expression transform(Expression expression) {
-                Expression transformedExpression = correctVars(expression)
+                Expression transformedExpression = correctVars(dataSourceExpression, lambdaParamName, expression)
                 if (transformedExpression !== expression) {
                     return transformedExpression
                 }
@@ -509,6 +405,107 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
         return expr
     }
 
+    private Expression correctVars(DataSourceExpression dataSourceExpression, String lambdaParamName, Expression expression) {
+        boolean isGroup = isGroupByVisited()
+        boolean isJoin = dataSourceExpression instanceof JoinExpression
+
+        Expression transformedExpression = null
+        if (expression instanceof VariableExpression) {
+            if (expression.isThisExpression()) return expression
+            if (expression.text && Character.isUpperCase(expression.text.charAt(0))) return expression // type should be transformed
+
+            if (isGroup) { //  groupby
+                // in #1, we will correct receiver of built-in aggregate functions
+                // the correct receiver is `__t.v2`, so we should not replace `__t` here
+                if (lambdaParamName != expression.text) {
+                    if (visitingAggregateFunction) {
+                        if (_Q == expression.text) {
+                            transformedExpression = new VariableExpression(lambdaParamName)
+                        } else {
+                            transformedExpression = isJoin
+                                    ? correctVarsForJoin(dataSourceExpression, expression, new VariableExpression(lambdaParamName))
+                                    : new VariableExpression(lambdaParamName)
+                        }
+                    } else {
+                        // replace `gk` in the groupby with `__t.v1.gk`, note: __t.v1 stores the group key
+                        transformedExpression = propX(propX(new VariableExpression(lambdaParamName), 'v1'), expression.text)
+                    }
+                }
+            } else if (isJoin) {
+                transformedExpression = correctVarsForJoin(dataSourceExpression, expression, new VariableExpression(lambdaParamName))
+            }
+        } else if (expression instanceof MethodCallExpression) {
+            // #1
+            if (isGroup) { // groupby
+                if (expression.implicitThis) {
+                    String methodName = expression.methodAsString
+                    if ('count' == methodName && ((TupleExpression) expression.arguments).getExpressions().isEmpty()) { // Similar to count(*) in SQL
+                        visitingAggregateFunction = true
+                        expression.objectExpression = propX(new VariableExpression(lambdaParamName), 'v2')
+                        transformedExpression = expression
+                        visitingAggregateFunction = false
+                    } else if (methodName in ['count', 'sum', 'agg'] && 1 == ((TupleExpression) expression.arguments).getExpressions().size()) {
+                        visitingAggregateFunction = true
+                        Expression lambdaCode = ((TupleExpression) expression.arguments).getExpression(0)
+                        lambdaCode.putNodeMetaData(__LAMBDA_PARAM_NAME, findRootObjectExpression(lambdaCode).text)
+                        transformedExpression =
+                                callXWithLambda(
+                                        propX(new VariableExpression(lambdaParamName), 'v2'), methodName,
+                                        dataSourceExpression, lambdaCode)
+                        visitingAggregateFunction = false
+                    }
+                }
+            }
+        }
+
+        if (null != transformedExpression) {
+            return transformedExpression
+        }
+
+        return expression
+    }
+
+    private Expression correctVarsForJoin(DataSourceExpression dataSourceExpression, Expression expression, Expression prop) {
+        boolean isJoin = dataSourceExpression instanceof JoinExpression
+        if (!isJoin) return expression
+
+        Expression transformedExpression = null
+        /*
+                 * `n1`(`from` node) join `n2` join `n3`  will construct a join tree:
+                 *
+                 *  __t (join node)
+                 *    |__ v2 (n3)
+                 *    |__ v1 (join node)
+                 *         |__ v2 (n2)
+                 *         |__ v1 (n1) (`from` node)
+                 *
+                 * Note: `__t` is a tuple with 2 elements
+                 * so  `n3`'s access path is `__t.v2`
+                 * and `n2`'s access path is `__t.v1.v2`
+                 * and `n1`'s access path is `__t.v1.v1`
+                 *
+                 * The following code shows how to construct the access path for variables
+                 */
+        for (DataSourceExpression dse = dataSourceExpression;
+             null == transformedExpression && dse instanceof JoinExpression;
+             dse = dse.getNodeMetaData(__DATA_SOURCE_EXPRESSION)) {
+
+            DataSourceExpression otherDataSourceExpression = dse.getNodeMetaData(__DATA_SOURCE_EXPRESSION)
+            Expression firstAliasExpr = otherDataSourceExpression?.aliasExpr ?: EmptyExpression.INSTANCE
+            Expression secondAliasExpr = dse.aliasExpr
+
+            if (firstAliasExpr.text == expression.text && otherDataSourceExpression !instanceof JoinExpression) {
+                transformedExpression = propX(prop, 'v1')
+            } else if (secondAliasExpr.text == expression.text) {
+                transformedExpression = propX(prop, 'v2')
+            } else { // not found
+                prop = propX(prop, 'v1')
+            }
+        }
+
+        return transformedExpression
+    }
+
     private static Expression findRootObjectExpression(Expression expression) {
         if (expression instanceof PropertyExpression) {
             Expression expr = expression
@@ -573,7 +570,7 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
     }
 
     private boolean isGroupByVisited() {
-        return currentGinqExpression.getNodeMetaData(__GROUP_BY) ?: false
+        return currentGinqExpression.getNodeMetaData(__GROUPBY_VISITED) ?: false
     }
 
     private static MethodCallExpression callXWithLambda(Expression receiver, String methodName, LambdaExpression lambdaExpression) {
@@ -595,6 +592,7 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
 
     private static final String __DATA_SOURCE_EXPRESSION = "__dataSourceExpression"
     private static final String __METHOD_CALL_RECEIVER = "__methodCallReceiver"
-    private static final String __GROUP_BY = "__GROUP_BY"
+    private static final String __GROUPBY_VISITED = "__groupByVisited"
     private static final String __LAMBDA_PARAM_NAME = "__LAMBDA_PARAM_NAME"
+    private static final String _Q = '_q' // the implicit variable representing grouped `Queryable` object
 }


[groovy] 01/02: GROOVY-9787: avoid using method name as alias

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3f8c06bc0aea41bf10f636da825c947408570d6e
Author: Daniel Sun <su...@apache.org>
AuthorDate: Thu Oct 22 15:27:03 2020 +0800

    GROOVY-9787: avoid using method name as alias
---
 .../org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy   | 4 ++--
 .../src/test/groovy/org/apache/groovy/linq/GinqTest.groovy            | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy
index 8b9436c..3497df5 100644
--- a/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy
+++ b/subprojects/groovy-linq/src/main/groovy/org/apache/groovy/linq/provider/collection/GinqAstWalker.groovy
@@ -351,10 +351,10 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
                     elementExpression = e
                     nameExpression = e.property
                 }
-            } else if (e instanceof MethodCallExpression) {
+            } /*else if (e instanceof MethodCallExpression) {
                 elementExpression = e
                 nameExpression = new ConstantExpression(e.methodAsString)
-            }
+            }*/
             elementExpressionList << elementExpression
             nameExpressionList << nameExpression
         }
diff --git a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy
index 643bee2..4cfbb5e 100644
--- a/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy
+++ b/subprojects/groovy-linq/src/test/groovy/org/apache/groovy/linq/GinqTest.groovy
@@ -812,9 +812,9 @@ class GinqTest {
             assert [[1, 1], [2, 4], [3, 9]] == GINQ {
                 from v in (
                     from n in [1, 2, 3]
-                    select n, Math.pow(n, 2)
+                    select n, Math.pow(n, 2) as powerOfN
                 )
-                select v.n, v.pow
+                select v.n, v.powerOfN
             }.toList()
         '''
     }