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 2019/02/19 16:43:46 UTC
[groovy] branch master updated: GROOVY-8991: Difference in
behaviour with closure and lambda(closes #878)
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 66a9883 GROOVY-8991: Difference in behaviour with closure and lambda(closes #878)
66a9883 is described below
commit 66a9883a9ac6ecf28353e013a5777f82e1e33d84
Author: Daniel Sun <su...@apache.org>
AuthorDate: Wed Feb 20 00:42:09 2019 +0800
GROOVY-8991: Difference in behaviour with closure and lambda(closes #878)
---
src/antlr/GroovyParser.g4 | 17 ++++--
.../apache/groovy/parser/antlr4/AstBuilder.java | 36 ++++++++----
.../groovy/parser/antlr4/GroovyParserTest.groovy | 1 +
.../src/test/resources/bugs/BUG-GROOVY-8991.groovy | 68 ++++++++++++++++++++++
4 files changed, 105 insertions(+), 17 deletions(-)
diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index 5d3fbcf..ba238c5 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -480,6 +480,7 @@ options { baseContext = standardLambdaExpression; }
: lambdaParameters nls ARROW nls lambdaBody
;
+// JAVA STANDARD LAMBDA EXPRESSION
standardLambdaExpression
: standardLambdaParameters nls ARROW nls lambdaBody
;
@@ -503,12 +504,17 @@ lambdaBody
| statementExpression
;
-
// CLOSURE
closure
: LBRACE nls (formalParameterList? nls ARROW nls)? blockStatementsOpt RBRACE
;
+// GROOVY-8991: Difference in behaviour with closure and lambda
+closureOrLambdaExpression
+ : closure
+ | lambdaExpression
+ ;
+
blockStatementsOpt
: blockStatements?
;
@@ -872,6 +878,7 @@ expression
enhancedStatementExpression #assignmentExprAlt
;
+
castOperandExpression
options { baseContext = expression; }
: castParExpression castOperandExpression #castExprAlt
@@ -932,7 +939,8 @@ commandArgument
* (Compare to a C lvalue, or LeftHandSide in the JLS section 15.26.)
* General expressions are built up from path expressions, using operators like '+' and '='.
*
- * t 0: primary, 1: namePart, 2: arguments, 3: closure, 4: indexPropertyArgs, 5: namedPropertyArgs, 6: non-static inner class creator
+ * t 0: primary, 1: namePart, 2: arguments, 3: closureOrLambdaExpression, 4: indexPropertyArgs, 5: namedPropertyArgs,
+ * 6: non-static inner class creator
*/
pathExpression returns [int t]
: primary (pathElement { $t = $pathElement.t; })*
@@ -962,7 +970,7 @@ pathElement returns [int t]
{ $t = 2; }
// Can always append a block, as foo{bar}
- | nls closure
+ | nls closureOrLambdaExpression
{ $t = 3; }
// Element selection is always an option, too.
@@ -1032,8 +1040,7 @@ primary
| THIS #thisPrmrAlt
| SUPER #superPrmrAlt
| parExpression #parenPrmrAlt
- | closure #closurePrmrAlt
- | lambdaExpression #lambdaPrmrAlt
+ | closureOrLambdaExpression #closureOrLambdaExpressionPrmrAlt
| list #listPrmrAlt
| map #mapPrmrAlt
| builtInType #builtInTypePrmrAlt
diff --git a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 007b8e2..0e54bb9 100644
--- a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -180,7 +180,8 @@ import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassOrInterfaceT
import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassicalForControlContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClassifiedModifiersContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClosureContext;
-import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClosurePrmrAltContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClosureOrLambdaExpressionContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.ClosureOrLambdaExpressionPrmrAltContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.CommandArgumentContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.CommandExprAltContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.CommandExpressionContext;
@@ -250,7 +251,6 @@ import static org.apache.groovy.parser.antlr4.GroovyLangParser.LE;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.LT;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.LabeledStmtAltContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.LambdaBodyContext;
-import static org.apache.groovy.parser.antlr4.GroovyLangParser.LambdaPrmrAltContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.ListContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.ListPrmrAltContext;
import static org.apache.groovy.parser.antlr4.GroovyLangParser.LiteralPrmrAltContext;
@@ -2454,8 +2454,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov
// e.g. 1(), 1.1(), ((int) 1 / 2)(1, 2), {a, b -> a + b }(1, 2), m()()
return configureAST(createCallMethodCallExpression(baseExpr, argumentsExpr), ctx);
- } else if (asBoolean(ctx.closure())) {
- ClosureExpression closureExpression = this.visitClosure(ctx.closure());
+ } else if (asBoolean(ctx.closureOrLambdaExpression())) {
+ ClosureExpression closureExpression = this.visitClosureOrLambdaExpression(ctx.closureOrLambdaExpression());
if (baseExpr instanceof MethodCallExpression) {
MethodCallExpression methodCallExpression = (MethodCallExpression) baseExpr;
@@ -3160,13 +3160,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov
}
@Override
- public ClosureExpression visitClosurePrmrAlt(ClosurePrmrAltContext ctx) {
- return configureAST(this.visitClosure(ctx.closure()), ctx);
- }
-
- @Override
- public ClosureExpression visitLambdaPrmrAlt(LambdaPrmrAltContext ctx) {
- return configureAST(this.visitStandardLambdaExpression(ctx.standardLambdaExpression()), ctx);
+ public ClosureExpression visitClosureOrLambdaExpressionPrmrAlt(ClosureOrLambdaExpressionPrmrAltContext ctx) {
+ return configureAST(this.visitClosureOrLambdaExpression(ctx.closureOrLambdaExpression()), ctx);
}
@Override
@@ -3589,7 +3584,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov
.map(e -> {
Expression expression = this.visitGstringValue(e);
- if (expression instanceof ClosureExpression && !asBoolean(e.closure().ARROW())) {
+ if (expression instanceof ClosureExpression && !hasArrow(e)) {
List<Statement> statementList = ((BlockStatement) ((ClosureExpression) expression).getCode()).getStatements();
if (statementList.stream().noneMatch(DefaultGroovyMethods::asBoolean)) {
@@ -3623,6 +3618,10 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov
return configureAST(new GStringExpression(verbatimText.toString(), stringLiteralList, values), ctx);
}
+ private boolean hasArrow(GstringValueContext e) {
+ return asBoolean(e.closure().ARROW());
+ }
+
private String parseGStringEnd(GstringContext ctx, String beginQuotation) {
StringBuilder text = new StringBuilder(ctx.GStringEnd().getText());
text.insert(0, beginQuotation);
@@ -4084,6 +4083,19 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov
}
@Override
+ public ClosureExpression visitClosureOrLambdaExpression(ClosureOrLambdaExpressionContext ctx) {
+ // GROOVY-8991: Difference in behaviour with closure and lambda
+ if (asBoolean(ctx.closure())) {
+ return configureAST(this.visitClosure(ctx.closure()), ctx);
+ } else if (asBoolean(ctx.standardLambdaExpression())) {
+ return configureAST(this.visitStandardLambdaExpression(ctx.standardLambdaExpression()), ctx);
+ }
+
+ // should never reach here
+ throw createParsingFailedException("The node is not expected here" + ctx.getText(), ctx);
+ }
+
+ @Override
public BlockStatement visitBlockStatementsOpt(BlockStatementsOptContext ctx) {
if (asBoolean(ctx.blockStatements())) {
return configureAST(this.visitBlockStatements(ctx.blockStatements()), ctx);
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
index 8bb1852..b519f83 100644
--- a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
@@ -439,5 +439,6 @@ class GroovyParserTest extends GroovyTestCase {
doRunAndTestAntlr4('bugs/BUG-GROOVY-8613.groovy')
doTest('bugs/BUG-GROOVY-8641.groovy')
doTest('bugs/BUG-GROOVY-8913.groovy')
+ doRunAndTestAntlr4('bugs/BUG-GROOVY-8991.groovy')
}
}
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8991.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8991.groovy
new file mode 100644
index 0000000..44cb7a1
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-8991.groovy
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+class BarHolder {
+ def foo2(lambda) {
+ lambda()
+ }
+ def bar(lambda) {
+ lambda() + 1
+ }
+ def bar2(lambda) {
+ lambda(6) + 1
+ }
+}
+
+def foo(lambda) {
+ lambda()
+}
+
+def result =
+ foo () -> {
+ new BarHolder()
+ }
+ .bar () -> {
+ 2
+ }
+assert 3 == result
+
+def result2 =
+ foo () -> {
+ new BarHolder()
+ }
+ .bar2 (e) -> {
+ 2 + e
+ }
+assert 9 == result2
+
+def result3 =
+ foo () -> {
+ new BarHolder()
+ }
+ .foo2 () -> {
+ new BarHolder()
+ }
+ .bar () -> {
+ 2
+ }
+assert 3 == result3
+
+def foo5(c) {c()}
+def c2 = foo5 { { Integer x -> 1} }
+assert 1 == c2()