Minor refactoring
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/b2bb7229 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/b2bb7229 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/b2bb7229 Branch: refs/heads/GROOVY_2_6_X Commit: b2bb7229490a9f2031c1d221dea3585193a0162c Parents: 1c5dbda Author: sunlan <sun...@apache.org> Authored: Sat Jun 10 11:56:36 2017 +0800 Committer: paulk <pa...@asert.com.au> Committed: Tue Jun 13 15:35:34 2017 +1000 ---------------------------------------------------------------------- src/main/org/codehaus/groovy/ast/ASTNode.java | 91 ++---------- .../groovy/ast/NodeMetaDataHandler.java | 137 +++++++++++++++++++ .../apache/groovy/parser/antlr4/GroovyParser.g4 | 53 ++----- .../apache/groovy/parser/antlr4/AstBuilder.java | 48 +++---- 4 files changed, 175 insertions(+), 154 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/b2bb7229/src/main/org/codehaus/groovy/ast/ASTNode.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/ASTNode.java b/src/main/org/codehaus/groovy/ast/ASTNode.java index 058af78..a192e68 100644 --- a/src/main/org/codehaus/groovy/ast/ASTNode.java +++ b/src/main/org/codehaus/groovy/ast/ASTNode.java @@ -18,10 +18,8 @@ */ package org.codehaus.groovy.ast; -import org.codehaus.groovy.GroovyBugError; import org.codehaus.groovy.util.ListHashMap; -import java.util.Collections; import java.util.Map; /** @@ -46,13 +44,13 @@ import java.util.Map; * @author <a href="mailto:ja...@coredevelopers.net">James Strachan</a> * @author <a href="mailto:blackd...@gmx.org">Jochen "blackdrag" Theodorou</a> */ -public class ASTNode { +public class ASTNode implements NodeMetaDataHandler { private int lineNumber = -1; private int columnNumber = -1; private int lastLineNumber = -1; private int lastColumnNumber = -1; - private ListHashMap metaDataMap = null; + private Map metaDataMap = null; public void visit(GroovyCodeVisitor visitor) { throw new RuntimeException("No visit() method implemented for class: " + getClass().getName()); @@ -108,93 +106,22 @@ public class ASTNode { this.lastColumnNumber = node.getLastColumnNumber(); this.lineNumber = node.getLineNumber(); } - - /** - * Gets the node meta data. - * - * @param key - the meta data key - * @return the node meta data value for this key - */ - public <T> T getNodeMetaData(Object key) { - if (metaDataMap == null) { - return (T) null; - } - return (T) metaDataMap.get(key); - } /** * Copies all node meta data from the other node to this one * @param other - the other node */ public void copyNodeMetaData(ASTNode other) { - if (other.metaDataMap == null) { - return; - } - if (metaDataMap == null) { - metaDataMap = new ListHashMap(); - } - metaDataMap.putAll(other.metaDataMap); - } - - /** - * Sets the node meta data. - * - * @param key - the meta data key - * @param value - the meta data value - * @throws GroovyBugError if key is null or there is already meta - * data under that key - */ - public void setNodeMetaData(Object key, Object value) { - if (key==null) throw new GroovyBugError("Tried to set meta data with null key on "+this+"."); - if (metaDataMap == null) { - metaDataMap = new ListHashMap(); - } - Object old = metaDataMap.put(key,value); - if (old!=null) throw new GroovyBugError("Tried to overwrite existing meta data "+this+"."); + copyNodeMetaData((NodeMetaDataHandler) other); } - /** - * Sets the node meta data but allows overwriting values. - * - * @param key - the meta data key - * @param value - the meta data value - * @return the old node meta data value for this key - * @throws GroovyBugError if key is null - */ - public Object putNodeMetaData(Object key, Object value) { - if (key == null) throw new GroovyBugError("Tried to set meta data with null key on " + this + "."); - if (metaDataMap == null) { - metaDataMap = new ListHashMap(); - } - return metaDataMap.put(key, value); - } - - /** - * Removes a node meta data entry. - * - * @param key - the meta data key - * @throws GroovyBugError if the key is null - */ - public void removeNodeMetaData(Object key) { - if (key==null) throw new GroovyBugError("Tried to remove meta data with null key "+this+"."); - if (metaDataMap == null) { - return; - } - metaDataMap.remove(key); - } - - /** - * Returns an unmodifiable view of the current node metadata. - * @return the node metadata. Always not null. - */ - public Map<?,?> getNodeMetaData() { - if (metaDataMap==null) { - return Collections.emptyMap(); - } - return Collections.unmodifiableMap(metaDataMap); + @Override + public ListHashMap getMetaDataMap() { + return (ListHashMap) metaDataMap; } - public ListHashMap getMetaDataMap() { - return metaDataMap; + @Override + public void setMetaDataMap(Map<?, ?> metaDataMap) { + this.metaDataMap = metaDataMap; } } http://git-wip-us.apache.org/repos/asf/groovy/blob/b2bb7229/src/main/org/codehaus/groovy/ast/NodeMetaDataHandler.java ---------------------------------------------------------------------- diff --git a/src/main/org/codehaus/groovy/ast/NodeMetaDataHandler.java b/src/main/org/codehaus/groovy/ast/NodeMetaDataHandler.java new file mode 100644 index 0000000..280cd6b --- /dev/null +++ b/src/main/org/codehaus/groovy/ast/NodeMetaDataHandler.java @@ -0,0 +1,137 @@ +/* + * 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. + */ +package org.codehaus.groovy.ast; + +import org.codehaus.groovy.GroovyBugError; +import org.codehaus.groovy.util.ListHashMap; + +import java.util.Collections; +import java.util.Map; + +/** + * An interface to mark a node being able to handle metadata + */ +public interface NodeMetaDataHandler { + /** + * Gets the node meta data. + * + * @param key - the meta data key + * @return the node meta data value for this key + */ + default <T> T getNodeMetaData(Object key) { + Map<?, ?> metaDataMap = this.getMetaDataMap(); + + if (metaDataMap == null) { + return (T) null; + } + return (T) metaDataMap.get(key); + } + + /** + * Copies all node meta data from the other node to this one + * + * @param other - the other node + */ + default void copyNodeMetaData(NodeMetaDataHandler other) { + Map otherMetaDataMap = other.getMetaDataMap(); + if (otherMetaDataMap == null) { + return; + } + Map metaDataMap = this.getMetaDataMap(); + if (metaDataMap == null) { + metaDataMap = new ListHashMap(); + this.setMetaDataMap(metaDataMap); + } + + metaDataMap.putAll(otherMetaDataMap); + } + + /** + * Sets the node meta data. + * + * @param key - the meta data key + * @param value - the meta data value + * @throws GroovyBugError if key is null or there is already meta + * data under that key + */ + default void setNodeMetaData(Object key, Object value) { + if (key == null) throw new GroovyBugError("Tried to set meta data with null key on " + this + "."); + + Map metaDataMap = this.getMetaDataMap(); + if (metaDataMap == null) { + metaDataMap = new ListHashMap(); + this.setMetaDataMap(metaDataMap); + } + Object old = metaDataMap.put(key, value); + if (old != null) throw new GroovyBugError("Tried to overwrite existing meta data " + this + "."); + } + + /** + * Sets the node meta data but allows overwriting values. + * + * @param key - the meta data key + * @param value - the meta data value + * @return the old node meta data value for this key + * @throws GroovyBugError if key is null + */ + default Object putNodeMetaData(Object key, Object value) { + if (key == null) throw new GroovyBugError("Tried to set meta data with null key on " + this + "."); + + Map metaDataMap = this.getMetaDataMap(); + if (metaDataMap == null) { + metaDataMap = new ListHashMap(); + this.setMetaDataMap(metaDataMap); + } + return metaDataMap.put(key, value); + } + + /** + * Removes a node meta data entry. + * + * @param key - the meta data key + * @throws GroovyBugError if the key is null + */ + default void removeNodeMetaData(Object key) { + if (key == null) throw new GroovyBugError("Tried to remove meta data with null key " + this + "."); + + Map metaDataMap = this.getMetaDataMap(); + if (metaDataMap == null) { + return; + } + metaDataMap.remove(key); + } + + /** + * Returns an unmodifiable view of the current node metadata. + * + * @return the node metadata. Always not null. + */ + default Map<?, ?> getNodeMetaData() { + Map metaDataMap = this.getMetaDataMap(); + + if (metaDataMap == null) { + return Collections.emptyMap(); + } + return Collections.unmodifiableMap(metaDataMap); + } + + Map<?, ?> getMetaDataMap(); + + void setMetaDataMap(Map<?, ?> metaDataMap); +} http://git-wip-us.apache.org/repos/asf/groovy/blob/b2bb7229/subprojects/parser-antlr4/src/main/antlr4/org/apache/groovy/parser/antlr4/GroovyParser.g4 ---------------------------------------------------------------------- diff --git a/subprojects/parser-antlr4/src/main/antlr4/org/apache/groovy/parser/antlr4/GroovyParser.g4 b/subprojects/parser-antlr4/src/main/antlr4/org/apache/groovy/parser/antlr4/GroovyParser.g4 index 3e6bc07..1fb2c97 100644 --- a/subprojects/parser-antlr4/src/main/antlr4/org/apache/groovy/parser/antlr4/GroovyParser.g4 +++ b/subprojects/parser-antlr4/src/main/antlr4/org/apache/groovy/parser/antlr4/GroovyParser.g4 @@ -41,14 +41,13 @@ options { @header { import java.util.Map; - import org.codehaus.groovy.util.ListHashMap; + import org.codehaus.groovy.ast.NodeMetaDataHandler; import org.apache.groovy.parser.antlr4.SemanticPredicates; - import org.codehaus.groovy.GroovyBugError; } @members { - public static class GroovyParserRuleContext extends ParserRuleContext { + public static class GroovyParserRuleContext extends ParserRuleContext implements NodeMetaDataHandler { private Map metaDataMap = null; public GroovyParserRuleContext() {} @@ -57,50 +56,14 @@ options { super(parent, invokingStateNumber); } - /** - * Gets the node meta data. - * - * @param key - the meta data key - * @return the node meta data value for this key - */ - public <T> T getNodeMetaData(Object key) { - if (metaDataMap == null) { - return (T) null; - } - return (T) metaDataMap.get(key); + @Override + public Map<?, ?> getMetaDataMap() { + return this.metaDataMap; } - /** - * Sets the node meta data. - * - * @param key - the meta data key - * @param value - the meta data value - * @throws GroovyBugError if key is null or there is already meta - * data under that key - */ - public void setNodeMetaData(Object key, Object value) { - if (key==null) throw new GroovyBugError("Tried to set meta data with null key on "+this+"."); - if (metaDataMap == null) { - metaDataMap = new ListHashMap(); - } - Object old = metaDataMap.put(key,value); - if (old!=null) throw new GroovyBugError("Tried to overwrite existing meta data "+this+"."); - } - - /** - * Sets the node meta data but allows overwriting values. - * - * @param key - the meta data key - * @param value - the meta data value - * @return the old node meta data value for this key - * @throws GroovyBugError if key is null - */ - public Object putNodeMetaData(Object key, Object value) { - if (key == null) throw new GroovyBugError("Tried to set meta data with null key on " + this + "."); - if (metaDataMap == null) { - metaDataMap = new ListHashMap(); - } - return metaDataMap.put(key, value); + @Override + public void setMetaDataMap(Map<?, ?> metaDataMap) { + this.metaDataMap = metaDataMap; } } http://git-wip-us.apache.org/repos/asf/groovy/blob/b2bb7229/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 add3e6d..c8d8eae 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 @@ -48,6 +48,7 @@ import org.codehaus.groovy.ast.ImportNode; import org.codehaus.groovy.ast.InnerClassNode; import org.codehaus.groovy.ast.MethodNode; import org.codehaus.groovy.ast.ModuleNode; +import org.codehaus.groovy.ast.NodeMetaDataHandler; import org.codehaus.groovy.ast.PackageNode; import org.codehaus.groovy.ast.Parameter; import org.codehaus.groovy.ast.PropertyNode; @@ -1749,7 +1750,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov (PropertyExpression) baseExpr, arguments), arguments); - } else if (baseExpr instanceof MethodCallExpression && !isTrue(baseExpr, IS_INSIDE_PARENTHESES)) { // e.g. m {} a, b OR m(...) a, b + } else if (baseExpr instanceof MethodCallExpression && !isInsideParentheses(baseExpr)) { // e.g. m {} a, b OR m(...) a, b if (asBoolean(arguments)) { // The error should never be thrown. throw new GroovyBugError("When baseExpr is a instance of MethodCallExpression, which should follow NO argumentList"); @@ -1757,7 +1758,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov methodCallExpression = (MethodCallExpression) baseExpr; } else if ( - !isTrue(baseExpr, IS_INSIDE_PARENTHESES) + !isInsideParentheses(baseExpr) && (baseExpr instanceof VariableExpression /* e.g. m 1, 2 */ || baseExpr instanceof GStringExpression /* e.g. "$m" 1, 2 */ || (baseExpr instanceof ConstantExpression && isTrue(baseExpr, IS_STRING)) /* e.g. "m" 1, 2 */) @@ -1852,8 +1853,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov public Expression visitParExpression(ParExpressionContext ctx) { Expression expression = this.visitExpressionInPar(ctx.expressionInPar()); - expression.putNodeMetaData(IS_INSIDE_PARENTHESES, true); - Integer insideParenLevel = expression.getNodeMetaData(INSIDE_PARENTHESES_LEVEL); if (asBoolean((Object) insideParenLevel)) { insideParenLevel++; @@ -1984,7 +1983,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov Expression argumentsExpr = this.visitArguments(ctx.arguments()); this.configureAST(argumentsExpr, ctx); - if (isTrue(baseExpr, IS_INSIDE_PARENTHESES)) { // e.g. (obj.x)(), (obj.@x)() + if (isInsideParentheses(baseExpr)) { // e.g. (obj.x)(), (obj.@x)() MethodCallExpression methodCallExpression = new MethodCallExpression( baseExpr, @@ -2437,7 +2436,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov ExpressionContext expressionCtx = ctx.expression(); Expression expression = (Expression) this.visit(expressionCtx); - Boolean insidePar = isTrue(expression, IS_INSIDE_PARENTHESES); + Boolean insidePar = isInsideParentheses(expression); switch (ctx.op.getType()) { case ADD: { @@ -2629,7 +2628,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov Expression leftExpr = (Expression) this.visit(ctx.left); if (leftExpr instanceof VariableExpression - && isTrue(leftExpr, IS_INSIDE_PARENTHESES)) { // it is a special multiple assignment whose variable count is only one, e.g. (a) = [1] + && isInsideParentheses(leftExpr)) { // it is a special multiple assignment whose variable count is only one, e.g. (a) = [1] if ((Integer) leftExpr.getNodeMetaData(INSIDE_PARENTHESES_LEVEL) > 1) { throw createParsingFailedException("Nested parenthesis is not allowed in multiple assignment, e.g. ((a)) = b", ctx); @@ -2648,7 +2647,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov !( (leftExpr instanceof VariableExpression // && !(THIS_STR.equals(leftExpr.getText()) || SUPER_STR.equals(leftExpr.getText())) // commented, e.g. this = value // this will be transformed to $this - && !isTrue(leftExpr, IS_INSIDE_PARENTHESES)) // e.g. p = 123 + && !isInsideParentheses(leftExpr)) // e.g. p = 123 || leftExpr instanceof PropertyExpression // e.g. obj.p = 123 @@ -2929,7 +2928,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov Expression expression = (Expression) this.visit(ctx.primary()); // if the key is variable and not inside parentheses, convert it to a constant, e.g. [a:1, b:2] - if (expression instanceof VariableExpression && !isTrue(expression, IS_INSIDE_PARENTHESES)) { + if (expression instanceof VariableExpression && !isInsideParentheses(expression)) { expression = this.configureAST( new ConstantExpression(((VariableExpression) expression).getName()), @@ -4019,6 +4018,16 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov return moduleNode.getStatementBlock().isEmpty() && moduleNode.getMethods().isEmpty() && moduleNode.getClasses().isEmpty(); } + private boolean isInsideParentheses(NodeMetaDataHandler nodeMetaDataHandler) { + Integer insideParenLevel = nodeMetaDataHandler.getNodeMetaData(INSIDE_PARENTHESES_LEVEL); + + if (asBoolean((Object) insideParenLevel)) { + return insideParenLevel > 0; + } + + return false; + } + private void addEmptyReturnStatement() { moduleNode.addStatement(ReturnStatement.RETURN_NULL_OR_VOID); } @@ -4182,29 +4191,15 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov return astNode; } - private boolean isTrue(GroovyParserRuleContext ctx, String key) { - Object nmd = ctx.getNodeMetaData(key); - - if (null == nmd) { - return false; - } - - if (!(nmd instanceof Boolean)) { - throw new GroovyBugError(ctx + " ctx meta data[" + key + "] is not an instance of Boolean"); - } - - return (Boolean) nmd; - } - - private boolean isTrue(ASTNode node, String key) { - Object nmd = node.getNodeMetaData(key); + private boolean isTrue(NodeMetaDataHandler nodeMetaDataHandler, String key) { + Object nmd = nodeMetaDataHandler.getNodeMetaData(key); if (null == nmd) { return false; } if (!(nmd instanceof Boolean)) { - throw new GroovyBugError(node + " node meta data[" + key + "] is not an instance of Boolean"); + throw new GroovyBugError(nodeMetaDataHandler + " node meta data[" + key + "] is not an instance of Boolean"); } return (Boolean) nmd; @@ -4434,7 +4429,6 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov private static final Set<String> PRIMITIVE_TYPE_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("boolean", "char", "byte", "short", "int", "long", "float", "double"))); private static final Logger LOGGER = Logger.getLogger(AstBuilder.class.getName()); - private static final String IS_INSIDE_PARENTHESES = "_IS_INSIDE_PARENTHESES"; private static final String INSIDE_PARENTHESES_LEVEL = "_INSIDE_PARENTHESES_LEVEL"; private static final String IS_INSIDE_INSTANCEOF_EXPR = "_IS_INSIDE_INSTANCEOF_EXPR";