Optimize ParserListenerUtils()
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / ParserListenerUtils.java
index 49f4178731f59221fa5660efd59a1816ba210efc..a261241557e5e974060640702d0ecc9b24fa3522 100644 (file)
@@ -9,11 +9,18 @@ package org.opendaylight.yangtools.yang.parser.impl;
 
 import static com.google.common.base.Preconditions.checkState;
 
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Optional;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Stack;
 
@@ -118,8 +125,8 @@ import org.opendaylight.yangtools.yang.model.util.Uint64;
 import org.opendaylight.yangtools.yang.model.util.Uint8;
 import org.opendaylight.yangtools.yang.model.util.UnknownType;
 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
-import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
+import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
@@ -132,10 +139,12 @@ import org.opendaylight.yangtools.yang.parser.util.YangParseException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-
 public final class ParserListenerUtils {
     private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class);
+    private static final Splitter KEYDEF_SPLITTER = Splitter.on(' ').omitEmptyStrings();
+    private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
+    private static final Splitter DOT_DOT_SPLITTER = Splitter.on("..").trimResults();
+    private static final CharMatcher QUOTE_MATCHER = CharMatcher.is('"');
 
     private ParserListenerUtils() {
     }
@@ -150,31 +159,47 @@ public final class ParserListenerUtils {
     public static String stringFromNode(final ParseTree treeNode) {
         String result = "";
         for (int i = 0; i < treeNode.getChildCount(); ++i) {
-            if (treeNode.getChild(i) instanceof StringContext) {
-                final StringContext context = (StringContext) treeNode.getChild(i);
-                if (context != null) {
-                    return stringFromStringContext(context);
-
-                }
+            final ParseTree child = treeNode.getChild(i);
+            if (child instanceof StringContext) {
+                return stringFromStringContext((StringContext)child);
             }
         }
         return result;
     }
 
-    public static String stringFromStringContext(final StringContext context) {
-        StringBuilder str = new StringBuilder();
+    private static String stringFromStringContext(final StringContext context) {
+        StringBuilder sb = new StringBuilder();
         for (TerminalNode stringNode : context.STRING()) {
-            String result = stringNode.getText();
-            if(!result.contains("\"")){
-                str.append(result);
-            } else if (!(result.startsWith("\"")) && result.endsWith("\"")) {
+            final String str = stringNode.getText();
+            final int i = str.indexOf('"');
+
+            if (i == -1) {
+                sb.append(str);
+                continue;
+            }
+
+            /*
+             * The string contains quotes, so we have to tread carefully.
+             *
+             * FIXME: I think this code is broken, but proving that requires
+             *        making sense of the parser/lexer and how they tie into
+             *        this method. Especially what format 'str' can have and
+             *        how we need to handle it. The original check was:
+             *
+             *        if (!(result.startsWith("\"")) && result.endsWith("\""))
+             *
+             *        Looking at the parentheses it is hard to justify the
+             *        pair right after negation -- the intent may have been
+             *        to negate the entire expression.
+             */
+            if (i != 0 && str.endsWith("\"")) {
                 LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(context),
                         context.getStart().getLine());
             } else {
-                str.append(result.replace("\"", ""));
+                sb.append(QUOTE_MATCHER.removeFrom(str));
             }
         }
-        return str.toString();
+        return sb.toString();
     }
 
     private static String getParentModule(final ParseTree ctx) {
@@ -182,7 +207,7 @@ public final class ParserListenerUtils {
         while (current != null && !(current instanceof Module_stmtContext)) {
             current = current.getParent();
         }
-        if (current instanceof Module_stmtContext) {
+        if (current != null) {
             Module_stmtContext module = (Module_stmtContext) current;
             for (int i = 0; i < module.getChildCount(); i++) {
                 if (module.getChild(i) instanceof StringContext) {
@@ -259,15 +284,13 @@ public final class ParserListenerUtils {
      *         statement
      */
     public static String parseUnits(final ParseTree ctx) {
-        String units = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree child = ctx.getChild(i);
             if (child instanceof Units_stmtContext) {
-                units = stringFromNode(child);
-                break;
+                return stringFromNode(child);
             }
         }
-        return units;
+        return null;
     }
 
     /**
@@ -279,15 +302,13 @@ public final class ParserListenerUtils {
      *         default statement
      */
     public static String parseDefault(final ParseTree ctx) {
-        String defaultValue = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree child = ctx.getChild(i);
             if (child instanceof Default_stmtContext) {
-                defaultValue = stringFromNode(child);
-                break;
+                return stringFromNode(child);
             }
         }
-        return defaultValue;
+        return null;
     }
 
     /**
@@ -310,14 +331,7 @@ public final class ParserListenerUtils {
      */
     public static List<String> createListKey(final Key_stmtContext ctx) {
         String keyDefinition = stringFromNode(ctx);
-        List<String> keys = new ArrayList<>();
-        String[] splittedKey = keyDefinition.split(" ");
-        for (String keyElement : splittedKey) {
-            if (!keyElement.isEmpty()) {
-                keys.add(keyElement);
-            }
-        }
-        return keys;
+        return Lists.newArrayList(KEYDEF_SPLITTER.split(keyDefinition));
     }
 
     /**
@@ -541,16 +555,14 @@ public final class ParserListenerUtils {
      * @return List of RangeConstraint created from this context
      */
     private static List<RangeConstraint> getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
-        List<RangeConstraint> rangeConstraints = Collections.emptyList();
-        outer: for (int i = 0; i < ctx.getChildCount(); i++) {
+        for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree numRestrChild = ctx.getChild(i);
 
             if (numRestrChild instanceof Numerical_restrictionsContext) {
                 for (int j = 0; j < numRestrChild.getChildCount(); j++) {
                     ParseTree rangeChild = numRestrChild.getChild(j);
                     if (rangeChild instanceof Range_stmtContext) {
-                        rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
-                        break outer;
+                        return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
                     }
                 }
             }
@@ -562,16 +574,14 @@ public final class ParserListenerUtils {
                         for (int k = 0; k < decRestr.getChildCount(); k++) {
                             ParseTree rangeChild = decRestr.getChild(k);
                             if (rangeChild instanceof Range_stmtContext) {
-                                rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
-                                break outer;
+                                return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
                             }
                         }
-
                     }
                 }
             }
         }
-        return rangeConstraints;
+        return Collections.emptyList();
     }
 
     /**
@@ -585,33 +595,34 @@ public final class ParserListenerUtils {
      */
     private static List<RangeConstraint> parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) {
         final int line = ctx.getStart().getLine();
-        List<RangeConstraint> rangeConstraints = new ArrayList<>();
-        String description = null;
-        String reference = null;
+        Optional<String> description = Optional.absent();
+        Optional<String> reference = Optional.absent();
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree child = ctx.getChild(i);
             if (child instanceof Description_stmtContext) {
-                description = stringFromNode(child);
+                description = Optional.fromNullable(stringFromNode(child));
             } else if (child instanceof Reference_stmtContext) {
-                reference = stringFromNode(child);
+                reference = Optional.fromNullable(stringFromNode(child));
             }
         }
 
-        String rangeStr = stringFromNode(ctx);
-        String trimmed = rangeStr.replace(" ", "");
-        String[] splittedRange = trimmed.split("\\|");
-        for (String rangeDef : splittedRange) {
-            String[] splittedRangeDef = rangeDef.split("\\.\\.");
-            Number min;
-            Number max;
-            if (splittedRangeDef.length == 1) {
-                min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
+        List<RangeConstraint> rangeConstraints = new ArrayList<>();
+        for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) {
+            final Iterator<String> split = DOT_DOT_SPLITTER.split(def).iterator();
+            final Number min = parseNumberConstraintValue(split.next(), moduleName, line);
+
+            final Number max;
+            if (split.hasNext()) {
+                max = parseNumberConstraintValue(split.next(), moduleName, line);
+                if (split.hasNext()) {
+                    throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\".");
+                }
             } else {
-                min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
-                max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line);
+                max = min;
             }
-            RangeConstraint range = BaseConstraints.rangeConstraint(min, max, description, reference);
+
+            RangeConstraint range = BaseConstraints.newRangeConstraint(min, max, description, reference);
             rangeConstraints.add(range);
         }
 
@@ -628,20 +639,18 @@ public final class ParserListenerUtils {
      * @return List of LengthConstraint created from this context
      */
     private static List<LengthConstraint> getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
-        List<LengthConstraint> lengthConstraints = Collections.emptyList();
-        outer: for (int i = 0; i < ctx.getChildCount(); i++) {
+        for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree stringRestrChild = ctx.getChild(i);
             if (stringRestrChild instanceof String_restrictionsContext) {
                 for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
                     ParseTree lengthChild = stringRestrChild.getChild(j);
                     if (lengthChild instanceof Length_stmtContext) {
-                        lengthConstraints = parseLengthConstraints((Length_stmtContext) lengthChild, moduleName);
-                        break outer;
+                        return parseLengthConstraints((Length_stmtContext) lengthChild, moduleName);
                     }
                 }
             }
         }
-        return lengthConstraints;
+        return Collections.emptyList();
     }
 
     /**
@@ -655,33 +664,34 @@ public final class ParserListenerUtils {
      */
     private static List<LengthConstraint> parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) {
         final int line = ctx.getStart().getLine();
-        List<LengthConstraint> lengthConstraints = new ArrayList<>();
-        String description = null;
-        String reference = null;
+        Optional<String> description = Optional.absent();
+        Optional<String> reference = Optional.absent();
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree child = ctx.getChild(i);
             if (child instanceof Description_stmtContext) {
-                description = stringFromNode(child);
+                description = Optional.fromNullable(stringFromNode(child));
             } else if (child instanceof Reference_stmtContext) {
-                reference = stringFromNode(child);
+                reference = Optional.fromNullable(stringFromNode(child));
             }
         }
 
-        String lengthStr = stringFromNode(ctx);
-        String trimmed = lengthStr.replace(" ", "");
-        String[] splittedRange = trimmed.split("\\|");
-        for (String rangeDef : splittedRange) {
-            String[] splittedRangeDef = rangeDef.split("\\.\\.");
-            Number min;
-            Number max;
-            if (splittedRangeDef.length == 1) {
-                min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
+        List<LengthConstraint> lengthConstraints = new ArrayList<>();
+        for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) {
+            final Iterator<String> split = DOT_DOT_SPLITTER.split(def).iterator();
+            final Number min = parseNumberConstraintValue(split.next(), moduleName, line);
+
+            final Number max;
+            if (split.hasNext()) {
+                max = parseNumberConstraintValue(split.next(), moduleName, line);
+                if (split.hasNext()) {
+                    throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\".");
+                }
             } else {
-                min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
-                max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line);
+                max = min;
             }
-            LengthConstraint range = BaseConstraints.lengthConstraint(min, max, description, reference);
+
+            LengthConstraint range = BaseConstraints.newLengthConstraint(min, max, description, reference);
             lengthConstraints.add(range);
         }
 
@@ -704,10 +714,10 @@ public final class ParserListenerUtils {
             result = new UnknownBoundaryNumber(value);
         } else {
             try {
-                if (value.contains(".")) {
+                if (value.indexOf('.') != -1) {
                     result = new BigDecimal(value);
                 } else {
-                    result = Long.valueOf(value);
+                    result = new BigInteger(value);
                 }
             } catch (NumberFormatException e) {
                 throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
@@ -995,7 +1005,7 @@ public final class ParserListenerUtils {
 
     private static boolean getParentConfig(final Builder node) {
         Builder parent = node.getParent();
-        boolean config = false;
+        boolean config;
 
         if (parent instanceof ChoiceCaseBuilder) {
             parent = parent.getParent();
@@ -1199,13 +1209,13 @@ public final class ParserListenerUtils {
             baseType = uintType;
         } else if ("enumeration".equals(typeName)) {
             List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
-            return new EnumerationType(baseTypePath, enumConstants);
+            return EnumerationType.create(baseTypePath, enumConstants, Optional.<EnumPair> absent());
         } else if ("string".equals(typeName)) {
             StringTypeDefinition stringType = StringType.getInstance();
             constraints.addLengths(stringType.getLengthConstraints());
             baseType = stringType;
         } else if ("bits".equals(typeName)) {
-            return new BitsType(baseTypePath, getBits(typeBody, actualPath, moduleName));
+            return BitsType.create(baseTypePath, getBits(typeBody, actualPath, moduleName));
         } else if ("leafref".equals(typeName)) {
             final String path = parseLeafrefPath(typeBody);
             final boolean absolute = path.startsWith("/");
@@ -1216,8 +1226,7 @@ public final class ParserListenerUtils {
             constraints.addLengths(binaryType.getLengthConstraints());
             baseType = binaryType;
         } else if ("instance-identifier".equals(typeName)) {
-            boolean requireInstance = isRequireInstance(typeBody);
-            return new InstanceIdentifier(null, requireInstance);
+            return InstanceIdentifier.create(isRequireInstance(typeBody));
         }
 
         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
@@ -1348,7 +1357,7 @@ public final class ParserListenerUtils {
      *            Must_stmtContext
      * @return MustDefinition object based on parsed context
      */
-    public static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
+    private static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
         StringBuilder mustText = new StringBuilder();
         String description = null;
         String reference = null;