groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From C├ędric Champeau <cedric.champ...@gmail.com>
Subject Re: groovy git commit: Support safe chain operator
Date Wed, 27 Sep 2017 14:39:17 GMT
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 <sunlan@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 <sunlan@apache.org>
> Authored: Wed Sep 27 22:25:38 2017 +0800
> Committer: sunlan <sunlan@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)
>
>

Mime
View raw message