Added support for parsing submodules & added dependency utility parser
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / ParserListenerUtils.java
index 51d7e3120b23bed689f06163b5db9f37f41d9d86..3b3423030cef6fe2a9a2f7416285d3220f635f88 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.yangtools.yang.parser.util;
 
+import static com.google.common.base.Preconditions.checkState;
+
+import java.math.BigDecimal;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -14,7 +17,10 @@ import java.util.Date;
 import java.util.List;
 import java.util.Stack;
 
+import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.omg.CORBA.CTX_RESTRICT_SCOPE;
 import org.opendaylight.yangtools.antlrv4.code.gen.*;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
@@ -40,6 +46,7 @@ import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_elements_stmtC
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_value_argContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_value_argContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Must_stmtContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
@@ -112,13 +119,14 @@ 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.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ConstraintsBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
 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);
 
@@ -133,18 +141,52 @@ public final class ParserListenerUtils {
      * @return first string value from given tree
      */
     public static String stringFromNode(final ParseTree treeNode) {
-        final String result = "";
+        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 context.getChild(0).getText().replace("\"", "");
+                    return stringFromStringContext(context);
+                    
                 }
             }
         }
         return result;
     }
 
+    public static String stringFromStringContext(StringContext context) {
+        StringBuilder str = new StringBuilder();
+        for (TerminalNode stringNode : context.STRING()) {
+            String result = stringNode.getText();
+            if(!result.contains("\"")){
+                str.append(result);
+            } else if (!(result.startsWith("\"")) && result.endsWith("\"")) {
+                LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(context),
+                        context.getStart().getLine());
+            } else {
+                str.append(result.replace("\"", ""));
+            }
+        }
+        return str.toString();
+    }
+
+    private static String getParentModule(final ParseTree ctx) {
+        ParseTree current = ctx;
+        while (current != null && !(current instanceof Module_stmtContext)) {
+            current = current.getParent();
+        }
+        if (current instanceof Module_stmtContext) {
+            Module_stmtContext module = (Module_stmtContext) current;
+            for (int i = 0; i < module.getChildCount(); i++) {
+                if (module.getChild(i) instanceof StringContext) {
+                    final StringContext str = (StringContext) module.getChild(i);
+                    return str.getChild(0).getText();
+                }
+            }
+        }
+        return "";
+    }
+
     /**
      * Parse 'description', 'reference' and 'status' statements and fill in
      * given builder.
@@ -183,13 +225,17 @@ public final class ParserListenerUtils {
             ParseTree statusArg = ctx.getChild(i);
             if (statusArg instanceof Status_argContext) {
                 String statusArgStr = stringFromNode(statusArg);
-                if ("current".equals(statusArgStr)) {
+                switch (statusArgStr) {
+                case "current":
                     result = Status.CURRENT;
-                } else if ("deprecated".equals(statusArgStr)) {
+                    break;
+                case "deprecated":
                     result = Status.DEPRECATED;
-                } else if ("obsolete".equals(statusArgStr)) {
+                    break;
+                case "obsolete":
                     result = Status.OBSOLETE;
-                } else {
+                    break;
+                default:
                     LOG.warn("Invalid 'status' statement: " + statusArgStr);
                 }
             }
@@ -245,7 +291,7 @@ public final class ParserListenerUtils {
      * @return SchemaPath object
      */
     public static SchemaPath createActualSchemaPath(final Stack<QName> actualPath) {
-        final List<QName> path = new ArrayList<QName>(actualPath);
+        final List<QName> path = new ArrayList<>(actualPath);
         return new SchemaPath(path, true);
     }
 
@@ -265,10 +311,10 @@ public final class ParserListenerUtils {
      */
     public static List<QName> createListKey(final String keyDefinition, final URI namespace, final Date revision,
             final String prefix) {
-        List<QName> key = new ArrayList<QName>();
+        List<QName> key = new ArrayList<>();
         String[] splittedKey = keyDefinition.split(" ");
 
-        QName qname = null;
+        QName qname;
         for (String keyElement : splittedKey) {
             if (keyElement.length() != 0) {
                 qname = new QName(namespace, revision, prefix, keyElement);
@@ -291,7 +337,7 @@ public final class ParserListenerUtils {
      */
     private static List<EnumTypeDefinition.EnumPair> getEnumConstants(final Type_body_stmtsContext ctx,
             final Stack<QName> path, final String moduleName) {
-        List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<EnumTypeDefinition.EnumPair>();
+        List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<>();
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree enumSpecChild = ctx.getChild(i);
@@ -319,7 +365,7 @@ public final class ParserListenerUtils {
      *            enum statement context
      * @param highestValue
      *            current highest value in enumeration
-     * @param path
+     * @param actualPath
      *            actual position in YANG model
      * @param moduleName
      *            current module name
@@ -495,12 +541,14 @@ public final class ParserListenerUtils {
      * @param ctx
      *            type body context to parse
      * @param moduleName
+     *            name of current module
      * @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++) {
             ParseTree numRestrChild = ctx.getChild(i);
+
             if (numRestrChild instanceof Numerical_restrictionsContext) {
                 for (int j = 0; j < numRestrChild.getChildCount(); j++) {
                     ParseTree rangeChild = numRestrChild.getChild(j);
@@ -510,6 +558,22 @@ public final class ParserListenerUtils {
                     }
                 }
             }
+
+            if (numRestrChild instanceof Decimal64_specificationContext) {
+                for (int j = 0; j < numRestrChild.getChildCount(); j++) {
+                    ParseTree decRestr = numRestrChild.getChild(j);
+                    if (decRestr instanceof Numerical_restrictionsContext) {
+                        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 rangeConstraints;
     }
@@ -520,11 +584,12 @@ public final class ParserListenerUtils {
      * @param ctx
      *            range context to parse
      * @param moduleName
+     *            name of current module
      * @return List of RangeConstraints parsed from this context
      */
     private static List<RangeConstraint> parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) {
         final int line = ctx.getStart().getLine();
-        List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();
+        List<RangeConstraint> rangeConstraints = new ArrayList<>();
         String description = null;
         String reference = null;
 
@@ -563,6 +628,7 @@ public final class ParserListenerUtils {
      * @param ctx
      *            type body context to parse
      * @param moduleName
+     *            name of current module
      * @return List of LengthConstraint created from this context
      */
     private static List<LengthConstraint> getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
@@ -588,11 +654,12 @@ public final class ParserListenerUtils {
      * @param ctx
      *            length context to parse
      * @param moduleName
+     *            name of current module
      * @return List of LengthConstraints parsed from this context
      */
     private static List<LengthConstraint> parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) {
         final int line = ctx.getStart().getLine();
-        List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();
+        List<LengthConstraint> lengthConstraints = new ArrayList<>();
         String description = null;
         String reference = null;
 
@@ -628,18 +695,24 @@ public final class ParserListenerUtils {
     /**
      * @param value
      *            value to parse
-     * @param moduleName name of current module
-     * @param line current line in module
+     * @param moduleName
+     *            name of current module
+     * @param line
+     *            current line in module
      * @return wrapper object of primitive java type or UnknownBoundaryNumber if
      *         type is one of special YANG values 'min' or 'max'
      */
     private static Number parseNumberConstraintValue(final String value, final String moduleName, final int line) {
-        Number result = null;
+        Number result;
         if ("min".equals(value) || "max".equals(value)) {
             result = new UnknownBoundaryNumber(value);
         } else {
             try {
-                result = Long.valueOf(value);
+                if (value.contains(".")) {
+                    result = new BigDecimal(value);
+                } else {
+                    result = Long.valueOf(value);
+                }
             } catch (NumberFormatException e) {
                 throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
             }
@@ -655,7 +728,7 @@ public final class ParserListenerUtils {
      * @return list of pattern constraints
      */
     private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx) {
-        List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
+        List<PatternConstraint> patterns = new ArrayList<>();
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
             ParseTree stringRestrChild = ctx.getChild(i);
@@ -689,7 +762,7 @@ public final class ParserListenerUtils {
                 reference = stringFromNode(child);
             }
         }
-        String pattern = patternStringFromNode(ctx);
+        String pattern = parsePatternString(ctx);
         return BaseConstraints.patternConstraint(pattern, description, reference);
     }
 
@@ -700,7 +773,7 @@ public final class ParserListenerUtils {
      *            context to parse
      * @return pattern value as String
      */
-    public static String patternStringFromNode(final Pattern_stmtContext ctx) {
+    private static String parsePatternString(final Pattern_stmtContext ctx) {
         StringBuilder result = new StringBuilder();
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             ParseTree child = ctx.getChild(i);
@@ -777,7 +850,7 @@ public final class ParserListenerUtils {
      */
     private static List<BitsTypeDefinition.Bit> getBits(Type_body_stmtsContext ctx, Stack<QName> actualPath,
             String moduleName) {
-        final List<BitsTypeDefinition.Bit> bits = new ArrayList<BitsTypeDefinition.Bit>();
+        final List<BitsTypeDefinition.Bit> bits = new ArrayList<>();
         for (int j = 0; j < ctx.getChildCount(); j++) {
             ParseTree bitsSpecChild = ctx.getChild(j);
             if (bitsSpecChild instanceof Bits_specificationContext) {
@@ -865,11 +938,14 @@ public final class ParserListenerUtils {
             ParseTree orderArg = ctx.getChild(j);
             if (orderArg instanceof Ordered_by_argContext) {
                 String orderStr = stringFromNode(orderArg);
-                if ("system".equals(orderStr)) {
+                switch (orderStr) {
+                case "system":
                     result = false;
-                } else if ("user".equals(orderStr)) {
+                    break;
+                case "user":
                     result = true;
-                } else {
+                    break;
+                default:
                     LOG.warn("Invalid 'ordered-by' statement.");
                 }
             }
@@ -892,7 +968,7 @@ public final class ParserListenerUtils {
      * @return config statement parsed from given context
      */
     public static Boolean getConfig(final ParseTree ctx, final Builder parent, final String moduleName, final int line) {
-        Boolean result = null;
+        Boolean result;
         // parse configuration statement
         Boolean config = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
@@ -911,18 +987,6 @@ public final class ParserListenerUtils {
                 // If the parent node is a rpc input or output, it can has
                 // config set to null
                 result = parentConfig == null ? true : parentConfig;
-            } else if (parent instanceof ChoiceCaseBuilder) {
-                // If the parent node is a 'case' node, the value is the same as
-                // the 'case' node's parent 'choice' node
-                ChoiceCaseBuilder choiceCase = (ChoiceCaseBuilder) parent;
-                Builder choice = choiceCase.getParent();
-                Boolean parentConfig = null;
-                if (choice instanceof ChoiceBuilder) {
-                    parentConfig = ((ChoiceBuilder) choice).isConfiguration();
-                } else {
-                    parentConfig = true;
-                }
-                result = parentConfig;
             } else {
                 result = true;
             }
@@ -958,13 +1022,14 @@ public final class ParserListenerUtils {
                 final ParseTree configContext = ctx.getChild(i);
                 if (configContext instanceof Config_argContext) {
                     final String value = stringFromNode(configContext);
-                    if ("true".equals(value)) {
+                    switch (value) {
+                    case "true":
                         result = true;
                         break;
-                    } else if ("false".equals(value)) {
+                    case "false":
                         result = false;
                         break;
-                    } else {
+                    default:
                         throw new YangParseException(moduleName, ctx.getStart().getLine(),
                                 "Failed to parse 'config' statement value: '" + value + "'.");
                     }
@@ -982,10 +1047,15 @@ public final class ParserListenerUtils {
      * @param ctx
      *            type body
      * @param actualPath
+     *            actual path in model
      * @param namespace
+     *            module namespace
      * @param revision
+     *            module revision
      * @param prefix
+     *            module prefix
      * @param parent
+     *            current node parent
      * @return UnknownType object with constraints from parsed type body
      */
     public static TypeDefinition<?> parseUnknownTypeWithBody(final QName typedefQName,
@@ -1011,7 +1081,6 @@ public final class ParserListenerUtils {
                 return unknownType.build();
             } else {
                 TypeDefinition<?> baseType = unknownType.build();
-                TypeDefinition<?> result = null;
                 QName qname = new QName(namespace, revision, prefix, typeName);
                 SchemaPath schemaPath = createTypePath(actualPath, typeName);
 
@@ -1020,9 +1089,8 @@ public final class ParserListenerUtils {
                 typeBuilder.lengths(lengthStatements);
                 typeBuilder.patterns(patternStatements);
                 typeBuilder.fractionDigits(fractionDigits);
-                result = typeBuilder.build();
 
-                return result;
+                return typeBuilder.build();
             }
         }
 
@@ -1076,49 +1144,63 @@ public final class ParserListenerUtils {
 
         if ("decimal64".equals(typeName)) {
             if (rangeStatements.isEmpty()) {
-                return new Decimal64(baseTypePath, fractionDigits);
+                try {
+                    return new Decimal64(baseTypePath, fractionDigits);
+                } catch(Exception e) {
+                    throw new YangParseException(moduleName, line, e.getMessage());
+                }
             }
             Decimal64 decimalType = new Decimal64(extBaseTypePath, fractionDigits);
-            constraints.addRanges(decimalType.getRangeStatements());
+            constraints.addRanges(decimalType.getRangeConstraints());
             baseType = decimalType;
         } else if (typeName.startsWith("int")) {
             IntegerTypeDefinition intType = null;
-            if ("int8".equals(typeName)) {
-                intType = new Int8(extBaseTypePath);
-            } else if ("int16".equals(typeName)) {
-                intType = new Int16(extBaseTypePath);
-            } else if ("int32".equals(typeName)) {
-                intType = new Int32(extBaseTypePath);
-            } else if ("int64".equals(typeName)) {
-                intType = new Int64(extBaseTypePath);
+            switch (typeName) {
+            case "int8":
+                intType = Int8.getInstance();
+                break;
+            case "int16":
+                intType = Int16.getInstance();
+                break;
+            case "int32":
+                intType = Int32.getInstance();
+                break;
+            case "int64":
+                intType = Int64.getInstance();
+                break;
             }
             if (intType == null) {
                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
             }
-            constraints.addRanges(intType.getRangeStatements());
+            constraints.addRanges(intType.getRangeConstraints());
             baseType = intType;
         } else if (typeName.startsWith("uint")) {
             UnsignedIntegerTypeDefinition uintType = null;
-            if ("uint8".equals(typeName)) {
-                uintType = new Uint8(extBaseTypePath);
-            } else if ("uint16".equals(typeName)) {
-                uintType = new Uint16(extBaseTypePath);
-            } else if ("uint32".equals(typeName)) {
-                uintType = new Uint32(extBaseTypePath);
-            } else if ("uint64".equals(typeName)) {
-                uintType = new Uint64(extBaseTypePath);
+            switch (typeName) {
+            case "uint8":
+                uintType = Uint8.getInstance();
+                break;
+            case "uint16":
+                uintType = Uint16.getInstance();
+                break;
+            case "uint32":
+                uintType = Uint32.getInstance();
+                break;
+            case "uint64":
+                uintType = Uint64.getInstance();
+                break;
             }
             if (uintType == null) {
                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
             }
-            constraints.addRanges(uintType.getRangeStatements());
+            constraints.addRanges(uintType.getRangeConstraints());
             baseType = uintType;
         } else if ("enumeration".equals(typeName)) {
             List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
             return new EnumerationType(baseTypePath, enumConstants);
         } else if ("string".equals(typeName)) {
-            StringTypeDefinition stringType = new StringType(extBaseTypePath);
-            constraints.addLengths(stringType.getLengthStatements());
+            StringTypeDefinition stringType = StringType.getInstance();
+            constraints.addLengths(stringType.getLengthConstraints());
             baseType = stringType;
         } else if ("bits".equals(typeName)) {
             return new BitsType(baseTypePath, getBits(typeBody, actualPath, moduleName));
@@ -1126,14 +1208,14 @@ public final class ParserListenerUtils {
             final String path = parseLeafrefPath(typeBody);
             final boolean absolute = path.startsWith("/");
             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
-            return new Leafref(baseTypePath, xpath);
+            return new Leafref(xpath);
         } else if ("binary".equals(typeName)) {
-            BinaryTypeDefinition binaryType = new BinaryType(extBaseTypePath);
+            BinaryTypeDefinition binaryType = BinaryType.getInstance();
             constraints.addLengths(binaryType.getLengthConstraints());
             baseType = binaryType;
         } else if ("instance-identifier".equals(typeName)) {
             boolean requireInstance = isRequireInstance(typeBody);
-            return new InstanceIdentifier(extBaseTypePath, null, requireInstance);
+            return new InstanceIdentifier(null, requireInstance);
         }
 
         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
@@ -1145,35 +1227,31 @@ public final class ParserListenerUtils {
             return baseType;
         }
 
-        TypeDefinition<?> result = null;
-        ExtendedType.Builder typeBuilder = null;
-
-        List<QName> path = new ArrayList<QName>(actualPath);
+        List<QName> path = new ArrayList<>(actualPath);
         path.add(new QName(namespace, revision, prefix, typeName));
         SchemaPath schemaPath = new SchemaPath(path, true);
 
         QName qname = schemaPath.getPath().get(schemaPath.getPath().size() - 1);
-        typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath);
+        ExtendedType.Builder typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath);
 
         typeBuilder.ranges(constraints.getRange());
         typeBuilder.lengths(constraints.getLength());
         typeBuilder.patterns(constraints.getPatterns());
         typeBuilder.fractionDigits(constraints.getFractionDigits());
 
-        result = typeBuilder.build();
-        return result;
+        return typeBuilder.build();
     }
 
     private static SchemaPath createTypePath(Stack<QName> actual, String typeName) {
         QName last = actual.peek();
         QName typeQName = new QName(last.getNamespace(), last.getRevision(), last.getPrefix(), typeName);
-        List<QName> path = new ArrayList<QName>(actual);
+        List<QName> path = new ArrayList<>(actual);
         path.add(typeQName);
         return new SchemaPath(path, true);
     }
 
     private static SchemaPath createBaseTypePath(Stack<QName> actual, String typeName) {
-        List<QName> path = new ArrayList<QName>(actual);
+        List<QName> path = new ArrayList<>(actual);
         path.add(BaseTypes.constructQName(typeName));
         return new SchemaPath(path, true);
     }
@@ -1182,7 +1260,7 @@ public final class ParserListenerUtils {
             String prefix, String typeName) {
         QName extTypeName = new QName(namespace, revision, prefix, typeName);
         QName baseTypeName = BaseTypes.constructQName(typeName);
-        List<QName> path = new ArrayList<QName>(actual);
+        List<QName> path = new ArrayList<>(actual);
         path.add(extTypeName);
         path.add(baseTypeName);
         return new SchemaPath(path, true);
@@ -1305,9 +1383,7 @@ public final class ParserListenerUtils {
             }
         }
 
-        MustDefinition must = new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag,
-                errorMessage);
-        return must;
+        return new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag, errorMessage);
     }
 
     /**
@@ -1420,20 +1496,20 @@ public final class ParserListenerUtils {
      *             if this is one of YANG type which MUST contain additional
      *             informations in its body
      */
-    public static void checkMissingBody(final String typeName, final String moduleName, final int line)
-            throws YangParseException {
-        if ("decimal64".equals(typeName)) {
+    public static void checkMissingBody(final String typeName, final String moduleName, final int line) {
+        switch (typeName) {
+        case "decimal64":
             throw new YangParseException(moduleName, line,
                     "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
-        } else if ("identityref".equals(typeName)) {
+        case "identityref":
             throw new YangParseException(moduleName, line,
                     "The 'base' statement MUST be present if the type is 'identityref'.");
-        } else if ("leafref".equals(typeName)) {
+        case "leafref":
             throw new YangParseException(moduleName, line,
                     "The 'path' statement MUST be present if the type is 'leafref'.");
-        } else if ("bits".equals(typeName)) {
+        case "bits":
             throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
-        } else if ("enumeration".equals(typeName)) {
+        case "enumeration":
             throw new YangParseException(moduleName, line,
                     "The 'enum' statement MUST be present if the type is 'enumeration'.");
         }
@@ -1444,7 +1520,8 @@ public final class ParserListenerUtils {
      *
      * @param refineCtx
      *            refine statement
-     * @param moduleName name of current module
+     * @param moduleName
+     *            name of current module
      * @return RefineHolder object representing this refine statement
      */
     public static RefineHolder parseRefine(Refine_stmtContext refineCtx, String moduleName) {
@@ -1600,4 +1677,18 @@ public final class ParserListenerUtils {
         return refine;
     }
 
+    public static String getArgumentString(org.antlr.v4.runtime.ParserRuleContext ctx) {
+        List<StringContext> potentialValues = ctx.getRuleContexts(StringContext.class);
+        checkState(!potentialValues.isEmpty());
+        return ParserListenerUtils.stringFromStringContext(potentialValues.get(0));
+    }
+    
+    public static <T extends ParserRuleContext> Optional<T> getFirstContext(ParserRuleContext context,Class<T> contextType) {
+        List<T> potential = context.getRuleContexts(contextType);
+        if(potential.isEmpty()) {
+            return Optional.absent();
+        }
+        return Optional.of(potential.get(0));
+    }
+
 }