Fixed parsing of typedef statement. Refactored YangParserImpl to improve code readabi...
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / main / java / org / opendaylight / controller / yang / parser / util / YangModelBuilderUtil.java
index 0df5d2cbdfc1eaf99be41250b2f220995b8251de..1e55b2444919fd67f5f46dd2114e8610e3d9e07f 100644 (file)
@@ -36,7 +36,9 @@ import org.opendaylight.controller.antlrv4.code.gen.YangParser.Length_stmtContex
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_elements_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_value_argContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
+import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_value_argContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Must_stmtContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
@@ -74,18 +76,24 @@ import org.opendaylight.controller.yang.model.api.SchemaPath;
 import org.opendaylight.controller.yang.model.api.Status;
 import org.opendaylight.controller.yang.model.api.TypeDefinition;
 import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
+import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition;
 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
+import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition;
+import org.opendaylight.controller.yang.model.api.type.UnsignedIntegerTypeDefinition;
 import org.opendaylight.controller.yang.model.util.BaseConstraints;
+import org.opendaylight.controller.yang.model.util.BaseTypes;
 import org.opendaylight.controller.yang.model.util.BinaryType;
 import org.opendaylight.controller.yang.model.util.BitsType;
 import org.opendaylight.controller.yang.model.util.Decimal64;
 import org.opendaylight.controller.yang.model.util.EnumerationType;
+import org.opendaylight.controller.yang.model.util.ExtendedType;
 import org.opendaylight.controller.yang.model.util.InstanceIdentifier;
 import org.opendaylight.controller.yang.model.util.Int16;
 import org.opendaylight.controller.yang.model.util.Int32;
@@ -99,8 +107,12 @@ import org.opendaylight.controller.yang.model.util.Uint32;
 import org.opendaylight.controller.yang.model.util.Uint64;
 import org.opendaylight.controller.yang.model.util.Uint8;
 import org.opendaylight.controller.yang.model.util.UnknownType;
+import org.opendaylight.controller.yang.parser.builder.api.Builder;
 import org.opendaylight.controller.yang.parser.builder.api.SchemaNodeBuilder;
+import org.opendaylight.controller.yang.parser.builder.api.TypeDefinitionBuilder;
 import org.opendaylight.controller.yang.parser.builder.impl.ConstraintsBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.ModuleBuilder;
+import org.opendaylight.controller.yang.parser.builder.impl.UnionTypeBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -372,6 +384,7 @@ public final class YangModelBuilderUtil {
         }
         if (value < -2147483648 || value > 2147483647) {
             throw new YangParseException(
+                    ctx.getStart().getLine(),
                     "Error on enum '"
                             + name
                             + "': the enum value MUST be in the range from -2147483648 to 2147483647, but was: "
@@ -671,8 +684,8 @@ public final class YangModelBuilderUtil {
             try {
                 result = Long.valueOf(value);
             } catch (NumberFormatException e) {
-                throw new YangParseException("Error on line " + line
-                        + ": Unable to parse range value '" + value + "'.", e);
+                throw new YangParseException(line,
+                        "Unable to parse range value '" + value + "'.", e);
             }
         }
         return result;
@@ -790,7 +803,7 @@ public final class YangModelBuilderUtil {
                 try {
                     result = Integer.valueOf(value);
                 } catch (NumberFormatException e) {
-                    throw new YangParseException(
+                    throw new YangParseException(ctx.getStart().getLine(),
                             "Unable to parse fraction digits value '" + value
                                     + "'.", e);
                 }
@@ -888,6 +901,7 @@ public final class YangModelBuilderUtil {
         }
         if (position < 0 || position > 4294967295L) {
             throw new YangParseException(
+                    ctx.getStart().getLine(),
                     "Error on bit '"
                             + name
                             + "': the position value MUST be in the range 0 to 4294967295");
@@ -958,19 +972,48 @@ public final class YangModelBuilderUtil {
      * @return UnknownType object with constraints from parsed type body
      */
     public static TypeDefinition<?> parseUnknownTypeBody(QName typedefQName,
-            Type_body_stmtsContext ctx) {
+            Type_body_stmtsContext ctx, final List<String> actualPath,
+            final URI namespace, final Date revision, final String prefix,
+            Builder parent, ModuleBuilder moduleBuilder) {
+        String typeName = typedefQName.getLocalName();
+
         UnknownType.Builder unknownType = new UnknownType.Builder(typedefQName);
+
         if (ctx != null) {
             List<RangeConstraint> rangeStatements = getRangeConstraints(ctx);
             List<LengthConstraint> lengthStatements = getLengthConstraints(ctx);
             List<PatternConstraint> patternStatements = getPatternConstraint(ctx);
             Integer fractionDigits = getFractionDigits(ctx);
 
-            unknownType.rangeStatements(rangeStatements);
-            unknownType.lengthStatements(lengthStatements);
-            unknownType.patterns(patternStatements);
-            unknownType.fractionDigits(fractionDigits);
+            if (parent instanceof TypeDefinitionBuilder) {
+                TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
+                typedef.setRanges(rangeStatements);
+                typedef.setLengths(lengthStatements);
+                typedef.setPatterns(patternStatements);
+                typedef.setFractionDigits(fractionDigits);
+                return unknownType.build();
+            } else {
+                TypeDefinition<?> baseType = unknownType.build();
+                TypeDefinition<?> result = null;
+                QName qname = new QName(namespace, revision, prefix, typeName);
+                ExtendedType.Builder typeBuilder = null;
+
+                SchemaPath schemaPath = createTypeSchemaPath(actualPath,
+                        namespace, revision, prefix, typeName, false, false);
+                typeBuilder = new ExtendedType.Builder(qname, baseType, "", "",
+                        schemaPath);
+
+                typeBuilder.ranges(rangeStatements);
+                typeBuilder.lengths(lengthStatements);
+                typeBuilder.patterns(patternStatements);
+                typeBuilder.fractionDigits(fractionDigits);
+
+                result = typeBuilder.build();
+
+                return result;
+            }
         }
+
         return unknownType.build();
     }
 
@@ -994,8 +1037,8 @@ public final class YangModelBuilderUtil {
     public static TypeDefinition<?> parseTypeBody(final String typeName,
             final Type_body_stmtsContext typeBody,
             final List<String> actualPath, final URI namespace,
-            final Date revision, final String prefix) {
-        TypeDefinition<?> type = null;
+            final Date revision, final String prefix, Builder parent) {
+        TypeDefinition<?> baseType = null;
 
         List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody);
         Integer fractionDigits = getFractionDigits(typeBody);
@@ -1004,62 +1047,143 @@ public final class YangModelBuilderUtil {
         List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(
                 typeBody, actualPath, namespace, revision, prefix);
 
+        TypeConstraints constraints = new TypeConstraints();
+        constraints.addFractionDigits(fractionDigits);
+        constraints.addLengths(lengthStatements);
+        constraints.addPatterns(patternStatements);
+        constraints.addRanges(rangeStatements);
+
+        SchemaPath baseTypePathFinal = createTypeSchemaPath(actualPath,
+                namespace, revision, prefix, typeName, true, true);
+        SchemaPath baseTypePath = createTypeSchemaPath(actualPath, namespace,
+                revision, prefix, typeName, true, false);
+
         if ("decimal64".equals(typeName)) {
-            type = new Decimal64(actualPath, namespace, revision,
-                    fractionDigits);
+            if (rangeStatements.isEmpty()) {
+                return new Decimal64(baseTypePathFinal, fractionDigits);
+            }
+            Decimal64 decimalType = new Decimal64(baseTypePath, fractionDigits);
+            constraints.addRanges(decimalType.getRangeStatements());
+            baseType = decimalType;
         } else if (typeName.startsWith("int")) {
+            IntegerTypeDefinition intType = null;
             if ("int8".equals(typeName)) {
-                type = new Int8(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                intType = new Int8(baseTypePath);
             } else if ("int16".equals(typeName)) {
-                type = new Int16(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                intType = new Int16(baseTypePath);
             } else if ("int32".equals(typeName)) {
-                type = new Int32(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                intType = new Int32(baseTypePath);
             } else if ("int64".equals(typeName)) {
-                type = new Int64(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                intType = new Int64(baseTypePath);
             }
+            constraints.addRanges(intType.getRangeStatements());
+            baseType = intType;
         } else if (typeName.startsWith("uint")) {
+            UnsignedIntegerTypeDefinition uintType = null;
             if ("uint8".equals(typeName)) {
-                type = new Uint8(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                uintType = new Uint8(baseTypePath);
             } else if ("uint16".equals(typeName)) {
-                type = new Uint16(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                uintType = new Uint16(baseTypePath);
             } else if ("uint32".equals(typeName)) {
-                type = new Uint32(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                uintType = new Uint32(baseTypePath);
             } else if ("uint64".equals(typeName)) {
-                type = new Uint64(actualPath, namespace, revision,
-                        rangeStatements, null, null);
+                uintType = new Uint64(baseTypePath);
             }
+            constraints.addRanges(uintType.getRangeStatements());
+            baseType = uintType;
         } else if ("enumeration".equals(typeName)) {
-            type = new EnumerationType(actualPath, namespace, revision,
-                    enumConstants);
+            return new EnumerationType(baseTypePathFinal, enumConstants);
         } else if ("string".equals(typeName)) {
-            type = new StringType(actualPath, namespace, revision,
-                    lengthStatements, patternStatements);
+            StringTypeDefinition stringType = new StringType(baseTypePath);
+            constraints.addLengths(stringType.getLengthStatements());
+            baseType = stringType;
         } else if ("bits".equals(typeName)) {
-            type = new BitsType(actualPath, namespace, revision, getBits(
-                    typeBody, actualPath, namespace, revision, prefix));
+            return new BitsType(baseTypePathFinal, getBits(typeBody,
+                    actualPath, namespace, revision, prefix));
         } else if ("leafref".equals(typeName)) {
             final String path = parseLeafrefPath(typeBody);
             final boolean absolute = path.startsWith("/");
             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path,
                     absolute);
-            type = new Leafref(actualPath, namespace, revision, xpath);
+            return new Leafref(baseTypePathFinal, xpath);
         } else if ("binary".equals(typeName)) {
-            List<Byte> bytes = Collections.emptyList();
-            type = new BinaryType(actualPath, namespace, revision, bytes,
-                    lengthStatements, null);
+            BinaryTypeDefinition binaryType = new BinaryType(baseTypePath);
+            constraints.addLengths(binaryType.getLengthConstraints());
+            baseType = binaryType;
         } else if ("instance-identifier".equals(typeName)) {
             boolean requireInstance = isRequireInstance(typeBody);
-            type = new InstanceIdentifier(actualPath, namespace, revision,
-                    null, requireInstance);
+            baseType = new InstanceIdentifier(baseTypePath, null,
+                    requireInstance);
         }
-        return type;
+
+        if (parent instanceof TypeDefinitionBuilder
+                && !(parent instanceof UnionTypeBuilder)) {
+            TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
+            typedef.setRanges(constraints.getRange());
+            typedef.setLengths(constraints.getLength());
+            typedef.setPatterns(constraints.getPatterns());
+            typedef.setFractionDigits(constraints.getFractionDigits());
+            return baseType;
+        }
+
+        TypeDefinition<?> result = null;
+        QName qname = new QName(namespace, revision, prefix, typeName);
+        ExtendedType.Builder typeBuilder = null;
+
+        SchemaPath schemaPath = createTypeSchemaPath(actualPath, namespace,
+                revision, prefix, typeName, false, false);
+        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;
+    }
+
+    /**
+     * Create SchemaPath object from given path list with namespace, revision
+     * and prefix based on given values.
+     *
+     * @param actualPath
+     *            current position in model
+     * @param namespace
+     * @param revision
+     * @param prefix
+     * @param typeName
+     * @param isBaseYangType
+     *            if this is base yang type
+     * @param isBaseYangTypeFinal
+     *            if this is base yang type without restrictions
+     * @return SchemaPath object.
+     */
+    private static SchemaPath createTypeSchemaPath(
+            final List<String> actualPath, final URI namespace,
+            final Date revision, final String prefix, final String typeName,
+            final boolean isBaseYangType, final boolean isBaseYangTypeFinal) {
+        List<String> typePath = new ArrayList<String>(actualPath);
+        if (isBaseYangType && !isBaseYangTypeFinal) {
+            typePath.add(typeName);
+        }
+
+        final List<QName> path = new ArrayList<QName>();
+        QName qname;
+        // start from index 1 -> module name omited
+        for (int i = 1; i < typePath.size(); i++) {
+            qname = new QName(namespace, revision, prefix, typePath.get(i));
+            path.add(qname);
+        }
+        QName typeQName;
+        if (isBaseYangType) {
+            typeQName = new QName(BaseTypes.BaseTypesNamespace, typeName);
+        } else {
+            typeQName = new QName(namespace, revision, prefix, typeName);
+        }
+        path.add(typeQName);
+        return new SchemaPath(path, true);
     }
 
     /**
@@ -1193,10 +1317,10 @@ public final class YangModelBuilderUtil {
         for (int i = 0; i < ctx.getChildCount(); ++i) {
             final ParseTree childNode = ctx.getChild(i);
             if (childNode instanceof Max_elements_stmtContext) {
-                Integer max = Integer.valueOf(stringFromNode(childNode));
-                constraints.setMinElements(max);
+                Integer max = parseMaxElements((Max_elements_stmtContext) childNode);
+                constraints.setMaxElements(max);
             } else if (childNode instanceof Min_elements_stmtContext) {
-                Integer min = Integer.valueOf(stringFromNode(childNode));
+                Integer min = parseMinElements((Min_elements_stmtContext) childNode);
                 constraints.setMinElements(min);
             } else if (childNode instanceof Must_stmtContext) {
                 MustDefinition must = parseMust((Must_stmtContext) childNode);
@@ -1216,6 +1340,44 @@ public final class YangModelBuilderUtil {
         }
     }
 
+    private static Integer parseMinElements(Min_elements_stmtContext ctx) {
+        Integer result = null;
+        try {
+            for (int j = 0; j < ctx.getChildCount(); j++) {
+                ParseTree minArg = ctx.getChild(j);
+                if (minArg instanceof Min_value_argContext) {
+                    result = Integer.valueOf(stringFromNode(minArg));
+                }
+            }
+            if (result == null) {
+                throw new IllegalArgumentException();
+            }
+            return result;
+        } catch (Exception e) {
+            throw new YangParseException(ctx.getStart().getLine(),
+                    "Failed to parse min-elements.", e);
+        }
+    }
+
+    private static Integer parseMaxElements(Max_elements_stmtContext ctx) {
+        Integer result = null;
+        try {
+            for (int j = 0; j < ctx.getChildCount(); j++) {
+                ParseTree maxArg = ctx.getChild(j);
+                if (maxArg instanceof Max_value_argContext) {
+                    result = Integer.valueOf(stringFromNode(maxArg));
+                }
+            }
+            if (result == null) {
+                throw new IllegalArgumentException();
+            }
+            return result;
+        } catch (Exception e) {
+            throw new YangParseException(ctx.getStart().getLine(),
+                    "Failed to parse max-elements.", e);
+        }
+    }
+
     /**
      * Parse given context and return yin value.
      *
@@ -1278,8 +1440,12 @@ public final class YangModelBuilderUtil {
 
     /**
      * Parse refine statement.
-     * @param refineCtx refine statement
-     * @return
+     *
+     * @param refineCtx
+     *            refine statement
+     * @param line
+     *            current line in yang model
+     * @return RefineHolder object representing this refine statement
      */
     public static RefineHolder parseRefine(Refine_stmtContext refineCtx) {
         final String refineTarget = stringFromNode(refineCtx);
@@ -1290,6 +1456,8 @@ public final class YangModelBuilderUtil {
             if (refinePom instanceof Refine_pomContext) {
                 for (int k = 0; k < refinePom.getChildCount(); k++) {
                     ParseTree refineStmt = refinePom.getChild(k);
+                    parseRefineDefault(refine, refineStmt);
+
                     if (refineStmt instanceof Refine_leaf_stmtsContext) {
                         parseRefine(refine,
                                 (Refine_leaf_stmtsContext) refineStmt);
@@ -1315,6 +1483,23 @@ public final class YangModelBuilderUtil {
         return refine;
     }
 
+    private static void parseRefineDefault(RefineHolder refine,
+            ParseTree refineStmt) {
+        for (int i = 0; i < refineStmt.getChildCount(); i++) {
+            ParseTree refineArg = refineStmt.getChild(i);
+            if (refineArg instanceof Description_stmtContext) {
+                String description = stringFromNode(refineArg);
+                refine.setDescription(description);
+            } else if (refineArg instanceof Reference_stmtContext) {
+                String reference = stringFromNode(refineArg);
+                refine.setReference(reference);
+            } else if (refineArg instanceof Config_stmtContext) {
+                boolean config = parseConfig((Config_stmtContext) refineArg);
+                refine.setConfig(config);
+            }
+        }
+    }
+
     private static RefineHolder parseRefine(RefineHolder refine,
             Refine_leaf_stmtsContext refineStmt) {
         for (int i = 0; i < refineStmt.getChildCount(); i++) {
@@ -1362,10 +1547,10 @@ public final class YangModelBuilderUtil {
                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
                 refine.setMust(must);
             } else if (refineArg instanceof Max_elements_stmtContext) {
-                Integer max = Integer.valueOf(stringFromNode(refineArg));
-                refine.setMinElements(max);
+                Integer max = parseMaxElements((Max_elements_stmtContext) refineArg);
+                refine.setMaxElements(max);
             } else if (refineArg instanceof Min_elements_stmtContext) {
-                Integer min = Integer.valueOf(stringFromNode(refineArg));
+                Integer min = parseMinElements((Min_elements_stmtContext) refineArg);
                 refine.setMinElements(min);
             }
         }
@@ -1380,10 +1565,10 @@ public final class YangModelBuilderUtil {
                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
                 refine.setMust(must);
             } else if (refineArg instanceof Max_elements_stmtContext) {
-                Integer max = Integer.valueOf(stringFromNode(refineArg));
-                refine.setMinElements(max);
+                Integer max = parseMaxElements((Max_elements_stmtContext) refineArg);
+                refine.setMaxElements(max);
             } else if (refineArg instanceof Min_elements_stmtContext) {
-                Integer min = Integer.valueOf(stringFromNode(refineArg));
+                Integer min = parseMinElements((Min_elements_stmtContext) refineArg);
                 refine.setMinElements(min);
             }
         }