You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@groovy.apache.org by Cédric Champeau <ce...@gmail.com> on 2017/09/27 14:39:17 UTC
Re: groovy git commit: Support safe chain operator
Hi Daniel,
I don't think you should push this to master without further discussion. It
would be better to develop experiments on branches, and only integrate once
we got general agreement.
2017-09-27 16:25 GMT+02:00 <su...@apache.org>:
> Repository: groovy
> Updated Branches:
> refs/heads/master 4cc78440d -> ce1d251bf
>
>
> Support safe chain operator
>
>
> Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
> Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/ce1d251b
> Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/ce1d251b
> Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/ce1d251b
>
> Branch: refs/heads/master
> Commit: ce1d251bfbd67c8a3129034179e9de034149d04b
> Parents: 4cc7844
> Author: sunlan <su...@apache.org>
> Authored: Wed Sep 27 22:25:38 2017 +0800
> Committer: sunlan <su...@apache.org>
> Committed: Wed Sep 27 22:25:38 2017 +0800
>
> ----------------------------------------------------------------------
> src/antlr/GroovyLexer.g4 | 1 +
> src/antlr/GroovyParser.g4 | 1 +
> .../apache/groovy/parser/antlr4/AstBuilder.java | 42 ++++++++++++--------
> .../parser/antlr4/GroovyParserTest.groovy | 4 ++
> .../resources/core/SafeChainOperator.groovy | 30 ++++++++++++++
> 5 files changed, 62 insertions(+), 16 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/groovy/blob/ce1d251b/src/antlr/
> GroovyLexer.g4
> ----------------------------------------------------------------------
> diff --git a/src/antlr/GroovyLexer.g4 b/src/antlr/GroovyLexer.g4
> index 05fb767..bcf6f24 100644
> --- a/src/antlr/GroovyLexer.g4
> +++ b/src/antlr/GroovyLexer.g4
> @@ -768,6 +768,7 @@ RANGE_INCLUSIVE : '..';
> RANGE_EXCLUSIVE : '..<';
> SPREAD_DOT : '*.';
> SAFE_DOT : '?.';
> +SAFE_CHAIN_DOT : '??.';
> ELVIS : '?:';
> METHOD_POINTER : '.&';
> METHOD_REFERENCE : '::';
>
> http://git-wip-us.apache.org/repos/asf/groovy/blob/ce1d251b/src/antlr/
> GroovyParser.g4
> ----------------------------------------------------------------------
> diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
> index 8f8aad3..cb2c3de 100644
> --- a/src/antlr/GroovyParser.g4
> +++ b/src/antlr/GroovyParser.g4
> @@ -982,6 +982,7 @@ locals[ boolean isInsideClosure ]
> // AT: foo.@bar selects the field (or attribute), not property
> ( SPREAD_DOT nls (AT | nonWildcardTypeArguments)? // Spread
> operator: x*.y === x?.collect{it.y}
> | SAFE_DOT nls (AT | nonWildcardTypeArguments)? //
> Optional-null operator: x?.y === (x==null)?null:x.y
> + | SAFE_CHAIN_DOT nls (AT | nonWildcardTypeArguments)? //
> Optional-null chain operator: x??.y.z === x?.y?.z
> | METHOD_POINTER nls // Method
> pointer operator: foo.&y == foo.metaClass.getMethodPointer(foo, "y")
> | METHOD_REFERENCE nls // Method
> reference: System.out::println
> | DOT nls (AT | nonWildcardTypeArguments)? // The
> all-powerful dot.
>
> http://git-wip-us.apache.org/repos/asf/groovy/blob/
> ce1d251b/subprojects/parser-antlr4/src/main/java/org/
> apache/groovy/parser/antlr4/AstBuilder.java
> ----------------------------------------------------------------------
> 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 5abc847..ad632d9 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
> @@ -1959,23 +1959,16 @@ public class AstBuilder extends
> GroovyParserBaseVisitor<Object> implements Groov
>
>
> if (asBoolean(ctx.DOT())) {
> - if (asBoolean(ctx.AT())) { // e.g. obj.@a
> - return configureAST(new AttributeExpression(baseExpr,
> namePartExpr), ctx);
> - } else { // e.g. obj.p
> - PropertyExpression propertyExpression = new
> PropertyExpression(baseExpr, namePartExpr);
> - propertyExpression.putNodeMetaData(PATH_
> EXPRESSION_BASE_EXPR_GENERICS_TYPES, genericsTypes);
> + boolean isSafeChain = isTrue(baseExpr,
> PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN);
>
> - return configureAST(propertyExpression, ctx);
> - }
> + return createDotExpression(ctx, baseExpr, namePartExpr,
> genericsTypes, isSafeChain);
> } else if (asBoolean(ctx.SAFE_DOT())) {
> - if (asBoolean(ctx.AT())) { // e.g. obj?.@a
> - return configureAST(new AttributeExpression(baseExpr,
> namePartExpr, true), ctx);
> - } else { // e.g. obj?.p
> - PropertyExpression propertyExpression = new
> PropertyExpression(baseExpr, namePartExpr, true);
> - propertyExpression.putNodeMetaData(PATH_
> EXPRESSION_BASE_EXPR_GENERICS_TYPES, genericsTypes);
> + return createDotExpression(ctx, baseExpr, namePartExpr,
> genericsTypes, true);
> + } else if (asBoolean(ctx.SAFE_CHAIN_DOT())) { // e.g.
> obj??.a OR obj??.@a
> + Expression expression = createDotExpression(ctx,
> baseExpr, namePartExpr, genericsTypes, true);
> + expression.putNodeMetaData(PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN,
> true);
>
> - return configureAST(propertyExpression, ctx);
> - }
> + return expression;
> } else if (asBoolean(ctx.METHOD_POINTER())) { // e.g. obj.&m
> return configureAST(new MethodPointerExpression(baseExpr,
> namePartExpr), ctx);
> } else if (asBoolean(ctx.METHOD_REFERENCE())) { // e.g.
> obj::m
> @@ -2210,6 +2203,17 @@ public class AstBuilder extends
> GroovyParserBaseVisitor<Object> implements Groov
> throw createParsingFailedException("Unsupported path element: "
> + ctx.getText(), ctx);
> }
>
> + private Expression createDotExpression(PathElementContext ctx,
> Expression baseExpr, Expression namePartExpr, GenericsType[] genericsTypes,
> boolean safe) {
> + if (asBoolean(ctx.AT())) { // e.g. obj.@a OR obj?.@a
> + return configureAST(new AttributeExpression(baseExpr,
> namePartExpr, safe), ctx);
> + } else { // e.g. obj.p OR obj?.p
> + PropertyExpression propertyExpression = new
> PropertyExpression(baseExpr, namePartExpr, safe);
> + propertyExpression.putNodeMetaData(PATH_
> EXPRESSION_BASE_EXPR_GENERICS_TYPES, genericsTypes);
> +
> + return configureAST(propertyExpression, ctx);
> + }
> + }
> +
> private MethodCallExpression createCallMethodCallExpression(Expression
> baseExpr, Expression argumentsExpr) {
> return createCallMethodCallExpression(baseExpr, argumentsExpr,
> false);
> }
> @@ -3973,10 +3977,15 @@ public class AstBuilder extends
> GroovyParserBaseVisitor<Object> implements Groov
> .reduce(primaryExpr,
> (r, e) -> {
> PathElementContext pathElementContext =
> (PathElementContext) e;
> -
> pathElementContext.putNodeMetaData(PATH_EXPRESSION_BASE_EXPR,
> r);
> + Expression expression = this.visitPathElement(
> pathElementContext);
> +
> + boolean isSafeChain = isTrue((Expression) r,
> PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN);
> + if (isSafeChain) {
> + expression.putNodeMetaData(
> PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN, true);
> + }
>
> - return this.visitPathElement(
> pathElementContext);
> + return expression;
> }
> );
> }
> @@ -4415,6 +4424,7 @@ public class AstBuilder extends
> GroovyParserBaseVisitor<Object> implements Groov
>
> private static final String PATH_EXPRESSION_BASE_EXPR =
> "_PATH_EXPRESSION_BASE_EXPR";
> private static final String PATH_EXPRESSION_BASE_EXPR_GENERICS_TYPES
> = "_PATH_EXPRESSION_BASE_EXPR_GENERICS_TYPES";
> + private static final String PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN =
> "_PATH_EXPRESSION_BASE_EXPR_SAFE_CHAIN";
> private static final String CMD_EXPRESSION_BASE_EXPR =
> "_CMD_EXPRESSION_BASE_EXPR";
> private static final String TYPE_DECLARATION_MODIFIERS =
> "_TYPE_DECLARATION_MODIFIERS";
> private static final String CLASS_DECLARATION_CLASS_NODE =
> "_CLASS_DECLARATION_CLASS_NODE";
>
> http://git-wip-us.apache.org/repos/asf/groovy/blob/
> ce1d251b/subprojects/parser-antlr4/src/test/groovy/org/
> apache/groovy/parser/antlr4/GroovyParserTest.groovy
> ----------------------------------------------------------------------
> 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 91cd61f..fd65344 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
> @@ -369,6 +369,10 @@ class GroovyParserTest extends GroovyTestCase {
> doRunAndTest('core/Number_01x.groovy');
> }
>
> + void "test groovy core - SafeChainOperator"() {
> + doRunAndTest('core/SafeChainOperator.groovy');
> + }
> +
> void "test groovy core - BUG"() {
> doRunAndTest('bugs/BUG-GROOVY-4757.groovy');
> doRunAndTest('bugs/BUG-GROOVY-5652.groovy');
>
> http://git-wip-us.apache.org/repos/asf/groovy/blob/
> ce1d251b/subprojects/parser-antlr4/src/test/resources/
> core/SafeChainOperator.groovy
> ----------------------------------------------------------------------
> diff --git a/subprojects/parser-antlr4/src/test/resources/core/SafeChainOperator.groovy
> b/subprojects/parser-antlr4/src/test/resources/core/
> SafeChainOperator.groovy
> new file mode 100644
> index 0000000..790dbfe
> --- /dev/null
> +++ b/subprojects/parser-antlr4/src/test/resources/core/
> SafeChainOperator.groovy
> @@ -0,0 +1,30 @@
> +/*
> + * 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.
> + */
> +assert 3 == 1??.plus(2)
> +assert 6 == 1??.plus(2).plus(3)
> +assert 6 == 1??.plus(2)?.plus(3)
> +assert 6 == 1??.plus(2)??.plus(3)
> +assert 10 == 1??.plus(2)?.plus(3).plus(4)
> +assert 10 == 1?.plus(2)??.plus(3).plus(4)
> +assert 10 == 1?.plus(2)?.plus(3)??.plus(4)
> +assert 10 == 1.plus(2).plus(3)??.plus(4)
> +assert null == null??.plus(2).plus(3)
> +assert null == null??.plus(2).plus(3).plus(4)
> +assert null == null??.plus(2)??.plus(3).plus(4)
> +assert null == null??.plus(2)??.plus(3)?.plus(4)
>
>
Re: groovy git commit: Support safe chain operator
Posted by Cédric Champeau <ce...@gmail.com>.
I guess that's why official discussions should be held on MLs, so that
everybody sees them... Slack is nice but not official.
2017-09-27 16:55 GMT+02:00 Daniel Sun <re...@hotmail.com>:
> Hi Cédric,
>
> The new feature was discussed with Guillaume, Paul, Chris and other
> developers in the Slack channel(#groovy)...
>
> Cheers,
> Daniel.Sun
>
>
>
> --
> Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html
>
Re: groovy git commit: Support safe chain operator
Posted by Daniel Sun <re...@hotmail.com>.
Hi Cédric,
The new feature was discussed with Guillaume, Paul, Chris and other
developers in the Slack channel(#groovy)...
Cheers,
Daniel.Sun
--
Sent from: http://groovy.329449.n5.nabble.com/Groovy-Dev-f372993.html