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/13 00:24:20 UTC
[groovy] 02/02: GROOVY-8258: generate unique param name for each
invocation of lambda
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 d1f754bf8315cfb598337f970d5ebfa1053d1f02
Author: Daniel Sun <su...@apache.org>
AuthorDate: Tue Oct 13 08:23:22 2020 +0800
GROOVY-8258: generate unique param name for each invocation of lambda
---
.../linq/provider/collection/GinqAstWalker.groovy | 23 ++++++--
.../groovy/org/apache/groovy/linq/GinqTest.groovy | 64 +++++++++++-----------
2 files changed, 50 insertions(+), 37 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 e6c3850..db33cff 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
@@ -365,6 +365,11 @@ 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 ->
if (!isJoin) return expression
@@ -387,7 +392,7 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
*
* The following code shows how to construct the access path for variables
*/
- Expression prop = isGroup ? propX(new VariableExpression(__T), 'v1') : new VariableExpression(__T)
+ Expression prop = isGroup ? propX(new VariableExpression(lambdaParamName), 'v1') : new VariableExpression(lambdaParamName)
for (DataSourceExpression dse = dataSourceExpression;
null == transformedExpression && dse instanceof JoinExpression;
dse = dse.getNodeMetaData(__DATA_SOURCE_EXPRESSION)) {
@@ -414,9 +419,9 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
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 (__T != expression.text) {
+ if (lambdaParamName != expression.text) {
// replace `gk` in the groupby with `__t.v1.gk`, note: __t.v1 stores the group key
- transformedExpression = propX(propX(new VariableExpression(__T), 'v1'), expression.text)
+ transformedExpression = propX(propX(new VariableExpression(lambdaParamName), 'v1'), expression.text)
}
} else if (isJoin) {
transformedExpression = correctVarsForJoin(expression)
@@ -427,7 +432,7 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
if (expression.implicitThis) {
String methodName = expression.methodAsString
if ('count' == methodName && ((TupleExpression) expression.arguments).getExpressions().isEmpty()) {
- expression.objectExpression = propX(new VariableExpression(__T), 'v2')
+ expression.objectExpression = propX(new VariableExpression(lambdaParamName), 'v2')
transformedExpression = expression
}
}
@@ -479,15 +484,21 @@ class GinqAstWalker implements GinqVisitor<Object>, SyntaxErrorReportable {
)
}
+ private static String generateLambdaParamName() {
+ "__t_${System.nanoTime()}_${new Random().nextInt(1000)}"
+ }
+
private Tuple2<String, Expression> correctVariablesOfLambdaExpression(DataSourceExpression dataSourceExpression, Expression lambdaCode) {
boolean isGroup = isGroupByVisited()
String lambdaParamName
if (dataSourceExpression instanceof JoinExpression || isGroup) {
- lambdaParamName = __T
+ lambdaParamName = generateLambdaParamName()
+ lambdaCode.putNodeMetaData(__LAMBDA_PARAM_NAME, lambdaParamName)
lambdaCode = correctVariablesOfGinqExpression(dataSourceExpression, lambdaCode)
} else {
lambdaParamName = dataSourceExpression.aliasExpr.text
+ lambdaCode.putNodeMetaData(__LAMBDA_PARAM_NAME, lambdaParamName)
}
return Tuple.tuple(lambdaParamName, lambdaCode)
@@ -516,6 +527,6 @@ 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 __T = "__t"
private static final String __GROUP_BY = "__GROUP_BY"
+ private static final String __LAMBDA_PARAM_NAME = "__LAMBDA_PARAM_NAME"
}
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 9a22d19..86a4d9c 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
@@ -18,7 +18,6 @@
*/
package org.apache.groovy.linq
-import groovy.json.JsonSlurper
import groovy.transform.CompileDynamic
import groovy.transform.CompileStatic
import org.junit.Test
@@ -1585,36 +1584,39 @@ class GinqTest {
@CompileDynamic
@Test
void "testGinq - query json - 1"() {
- def parser = new JsonSlurper()
- def json = parser.parseText('''
- {
- "persons": [
- {"id": 1, "name": "Daniel"},
- {"id": 2, "name": "Paul"},
- {"id": 3, "name": "Eric"}
- ],
- "tasks": [
- {"id": 1, "assignee": 1, "content": "task1", "manDay": 6},
- {"id": 2, "assignee": 1, "content": "task2", "manDay": 1},
- {"id": 3, "assignee": 2, "content": "task3", "manDay": 3},
- {"id": 4, "assignee": 3, "content": "task4", "manDay": 5}
- ]
- }
- ''')
-
- def expected = [
- [taskId: 1, taskContent: 'task1', assignee: 'Daniel', manDay: 6],
- [taskId: 4, taskContent: 'task4', assignee: 'Eric', manDay: 5],
- [taskId: 3, taskContent: 'task3', assignee: 'Paul', manDay: 3]
- ]
-
- assert expected == GINQ {
- from p in json.persons
- innerjoin t in json.tasks on t.assignee == p.id
- where t.id in [1, 3, 4]
- orderby t.manDay in desc
- select (taskId: t.id, taskContent: t.content, assignee: p.name, manDay: t.manDay)
- }.toList()
+ assertScript """
+ import groovy.json.JsonSlurper
+ def parser = new JsonSlurper()
+ def json = parser.parseText('''
+ {
+ "persons": [
+ {"id": 1, "name": "Daniel"},
+ {"id": 2, "name": "Paul"},
+ {"id": 3, "name": "Eric"}
+ ],
+ "tasks": [
+ {"id": 1, "assignee": 1, "content": "task1", "manDay": 6},
+ {"id": 2, "assignee": 1, "content": "task2", "manDay": 1},
+ {"id": 3, "assignee": 2, "content": "task3", "manDay": 3},
+ {"id": 4, "assignee": 3, "content": "task4", "manDay": 5}
+ ]
+ }
+ ''')
+
+ def expected = [
+ [taskId: 1, taskContent: 'task1', assignee: 'Daniel', manDay: 6],
+ [taskId: 4, taskContent: 'task4', assignee: 'Eric', manDay: 5],
+ [taskId: 3, taskContent: 'task3', assignee: 'Paul', manDay: 3]
+ ]
+
+ assert expected == GINQ {
+ from p in json.persons
+ innerjoin t in json.tasks on t.assignee == p.id
+ where t.id in [1, 3, 4]
+ orderby t.manDay in desc
+ select (taskId: t.id, taskContent: t.content, assignee: p.name, manDay: t.manDay)
+ }.toList()
+ """
}
@CompileDynamic