2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/eplv10.html
8 package org.opendaylight.controller.yang.model.parser.util;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Date;
14 import java.util.List;
15 import java.util.Stack;
17 import org.antlr.v4.runtime.tree.ParseTree;
18 import org.opendaylight.controller.antlrv4.code.gen.YangParser;
19 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext;
20 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bit_stmtContext;
21 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bits_specificationContext;
22 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext;
23 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_stmtContext;
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Decimal64_specificationContext;
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Default_stmtContext;
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext;
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_specificationContext;
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_stmtContext;
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Error_app_tag_stmtContext;
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Error_message_stmtContext;
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext;
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leafref_specificationContext;
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Length_stmtContext;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext;
35 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
36 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_elements_stmtContext;
37 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
38 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Must_stmtContext;
39 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
40 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext;
41 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
42 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Path_stmtContext;
43 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Pattern_stmtContext;
44 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Position_stmtContext;
45 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Presence_stmtContext;
46 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Range_stmtContext;
47 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext;
48 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_anyxml_stmtsContext;
49 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_choice_stmtsContext;
50 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_container_stmtsContext;
51 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_leaf_list_stmtsContext;
52 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_leaf_stmtsContext;
53 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_list_stmtsContext;
54 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_pomContext;
55 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Refine_stmtContext;
56 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_argContext;
57 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_stmtContext;
58 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
59 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext;
60 import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;
61 import org.opendaylight.controller.antlrv4.code.gen.YangParser.String_restrictionsContext;
62 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
63 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext;
64 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Uses_stmtContext;
65 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Value_stmtContext;
66 import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext;
67 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_argContext;
68 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_stmtContext;
69 import org.opendaylight.controller.yang.common.QName;
70 import org.opendaylight.controller.yang.model.api.MustDefinition;
71 import org.opendaylight.controller.yang.model.api.RevisionAwareXPath;
72 import org.opendaylight.controller.yang.model.api.SchemaPath;
73 import org.opendaylight.controller.yang.model.api.Status;
74 import org.opendaylight.controller.yang.model.api.TypeDefinition;
75 import org.opendaylight.controller.yang.model.api.UnknownSchemaNode;
76 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition;
77 import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit;
78 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition;
79 import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair;
80 import org.opendaylight.controller.yang.model.api.type.LengthConstraint;
81 import org.opendaylight.controller.yang.model.api.type.PatternConstraint;
82 import org.opendaylight.controller.yang.model.api.type.RangeConstraint;
83 import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder;
84 import org.opendaylight.controller.yang.model.parser.builder.impl.ConstraintsBuilder;
85 import org.opendaylight.controller.yang.model.parser.util.RefineHolder.Refine;
86 import org.opendaylight.controller.yang.model.util.BaseConstraints;
87 import org.opendaylight.controller.yang.model.util.BinaryType;
88 import org.opendaylight.controller.yang.model.util.BitsType;
89 import org.opendaylight.controller.yang.model.util.EnumerationType;
90 import org.opendaylight.controller.yang.model.util.InstanceIdentifier;
91 import org.opendaylight.controller.yang.model.util.Leafref;
92 import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl;
93 import org.opendaylight.controller.yang.model.util.StringType;
94 import org.opendaylight.controller.yang.model.util.UnknownType;
95 import org.opendaylight.controller.yang.model.util.YangTypesConverter;
96 import org.slf4j.Logger;
97 import org.slf4j.LoggerFactory;
99 public final class YangModelBuilderUtil {
101 private static final Logger logger = LoggerFactory
102 .getLogger(YangModelBuilderUtil.class);
104 private YangModelBuilderUtil() {
108 * Parse given tree and get first string value.
112 * @return first string value from given tree
114 public static String stringFromNode(final ParseTree treeNode) {
115 final String result = "";
116 for (int i = 0; i < treeNode.getChildCount(); ++i) {
117 if (treeNode.getChild(i) instanceof StringContext) {
118 final StringContext context = (StringContext) treeNode
120 if (context != null) {
121 return context.getChild(0).getText().replace("\"", "");
129 * Parse 'description', 'reference' and 'status' statements and fill in
135 * builder to fill in with parsed statements
137 public static void parseSchemaNodeArgs(ParseTree ctx,
138 SchemaNodeBuilder builder) {
139 for (int i = 0; i < ctx.getChildCount(); i++) {
140 ParseTree child = ctx.getChild(i);
141 if (child instanceof Description_stmtContext) {
142 String desc = stringFromNode(child);
143 builder.setDescription(desc);
144 } else if (child instanceof Reference_stmtContext) {
145 String ref = stringFromNode(child);
146 builder.setReference(ref);
147 } else if (child instanceof Status_stmtContext) {
148 Status status = parseStatus((Status_stmtContext) child);
149 builder.setStatus(status);
155 * Parse given context and return its value;
159 * @return value parsed from context
161 public static Status parseStatus(Status_stmtContext ctx) {
162 Status result = null;
163 for (int i = 0; i < ctx.getChildCount(); i++) {
164 ParseTree statusArg = ctx.getChild(i);
165 if (statusArg instanceof Status_argContext) {
166 String statusArgStr = stringFromNode(statusArg);
167 if ("current".equals(statusArgStr)) {
168 result = Status.CURRENT;
169 } else if ("deprecated".equals(statusArgStr)) {
170 result = Status.DEPRECATED;
171 } else if ("obsolete".equals(statusArgStr)) {
172 result = Status.OBSOLETE;
174 logger.warn("Invalid 'status' statement: " + statusArgStr);
182 * Parse given tree and returns units statement as string.
186 * @return value of units statement as string or null if there is no units
189 public static String parseUnits(ParseTree ctx) {
191 for (int i = 0; i < ctx.getChildCount(); i++) {
192 ParseTree child = ctx.getChild(i);
193 if (child instanceof Units_stmtContext) {
194 units = stringFromNode(child);
202 * Create SchemaPath object from given path list with namespace, revision
203 * and prefix based on given values.
206 * current position in model
210 * @return SchemaPath object.
212 public static SchemaPath createActualSchemaPath(List<String> actualPath,
213 URI namespace, Date revision, String prefix) {
214 final List<QName> path = new ArrayList<QName>();
216 // start from index 1 - module name omited
217 for (int i = 1; i < actualPath.size(); i++) {
218 qname = new QName(namespace, revision, prefix, actualPath.get(i));
221 return new SchemaPath(path, true);
225 * Create SchemaPath from given string.
228 * string representation of path
229 * @return SchemaPath object
231 public static SchemaPath parseAugmentPath(String augmentPath) {
232 boolean absolute = augmentPath.startsWith("/");
233 String[] splittedPath = augmentPath.split("/");
234 List<QName> path = new ArrayList<QName>();
236 for (String pathElement : splittedPath) {
237 if (pathElement.length() > 0) {
238 String[] splittedElement = pathElement.split(":");
239 if (splittedElement.length == 1) {
240 name = new QName(null, null, null, splittedElement[0]);
242 name = new QName(null, null, splittedElement[0],
248 return new SchemaPath(path, absolute);
252 * Create java.util.List of QName objects from given key definition as
255 * @param keyDefinition
256 * key definition as string
263 * @return YANG list key as java.util.List of QName objects
265 public static List<QName> createListKey(String keyDefinition,
266 URI namespace, Date revision, String prefix) {
267 List<QName> key = new ArrayList<QName>();
268 String[] splittedKey = keyDefinition.split(" ");
271 for (String keyElement : splittedKey) {
272 if (keyElement.length() != 0) {
273 qname = new QName(namespace, revision, prefix, keyElement);
281 * Parse given type body of enumeration statement.
284 * type body context to parse
286 * actual position in YANG model
290 * @return List of EnumPair object parsed from given context
292 private static List<EnumTypeDefinition.EnumPair> getEnumConstants(
293 Type_body_stmtsContext ctx, List<String> path, URI namespace,
294 Date revision, String prefix) {
295 List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<EnumTypeDefinition.EnumPair>();
297 for (int j = 0; j < ctx.getChildCount(); j++) {
298 ParseTree enumSpecChild = ctx.getChild(j);
299 if (enumSpecChild instanceof Enum_specificationContext) {
300 int highestValue = -1;
301 for (int k = 0; k < enumSpecChild.getChildCount(); k++) {
302 ParseTree enumChild = enumSpecChild.getChild(k);
303 if (enumChild instanceof Enum_stmtContext) {
304 EnumPair enumPair = createEnumPair(
305 (Enum_stmtContext) enumChild, highestValue,
306 path, namespace, revision, prefix);
307 if (enumPair.getValue() > highestValue) {
308 highestValue = enumPair.getValue();
310 enumConstants.add(enumPair);
315 return enumConstants;
319 * Parse enum statement context
322 * enum statement context
323 * @param highestValue
324 * current highest value in enumeration
326 * actual position in YANG model
330 * @return EnumPair object parsed from given context
332 private static EnumTypeDefinition.EnumPair createEnumPair(
333 Enum_stmtContext ctx, final int highestValue, List<String> path,
334 final URI namespace, final Date revision, final String prefix) {
335 final String name = stringFromNode(ctx);
336 final QName qname = new QName(namespace, revision, prefix, name);
337 Integer value = null;
339 String description = null;
340 String reference = null;
341 Status status = null;
343 List<String> enumPairPath = new ArrayList<String>(path);
344 enumPairPath.add(name);
346 for (int i = 0; i < ctx.getChildCount(); i++) {
347 ParseTree child = ctx.getChild(i);
348 if (child instanceof Value_stmtContext) {
349 String valueStr = stringFromNode(child);
350 value = Integer.valueOf(valueStr);
351 } else if (child instanceof Description_stmtContext) {
352 description = stringFromNode(child);
353 } else if (child instanceof Reference_stmtContext) {
354 reference = stringFromNode(child);
355 } else if (child instanceof Status_stmtContext) {
356 status = parseStatus((Status_stmtContext) child);
361 value = highestValue + 1;
363 if (value < -2147483648 || value > 2147483647) {
364 throw new YangParseException(
367 + "': the enum value MUST be in the range from -2147483648 to 2147483647, but was: "
371 EnumPairImpl result = new EnumPairImpl();
372 result.qname = qname;
373 result.path = createActualSchemaPath(enumPairPath, namespace, revision,
375 result.description = description;
376 result.reference = reference;
377 result.status = status;
379 result.value = value;
384 * Internal implementation of EnumPair.
386 private static class EnumPairImpl implements EnumTypeDefinition.EnumPair {
388 private SchemaPath path;
389 private String description;
390 private String reference;
391 private Status status;
392 private List<UnknownSchemaNode> extensionSchemaNodes = Collections
395 private Integer value;
398 public QName getQName() {
403 public SchemaPath getPath() {
408 public String getDescription() {
413 public String getReference() {
418 public Status getStatus() {
423 public List<UnknownSchemaNode> getUnknownSchemaNodes() {
424 return extensionSchemaNodes;
428 public String getName() {
433 public Integer getValue() {
438 public int hashCode() {
439 final int prime = 31;
441 result = prime * result + ((qname == null) ? 0 : qname.hashCode());
442 result = prime * result + ((path == null) ? 0 : path.hashCode());
445 + ((extensionSchemaNodes == null) ? 0
446 : extensionSchemaNodes.hashCode());
447 result = prime * result + ((name == null) ? 0 : name.hashCode());
448 result = prime * result + ((value == null) ? 0 : value.hashCode());
453 public boolean equals(Object obj) {
460 if (getClass() != obj.getClass()) {
463 EnumPairImpl other = (EnumPairImpl) obj;
465 if (other.qname != null) {
468 } else if (!qname.equals(other.qname)) {
472 if (other.path != null) {
475 } else if (!path.equals(other.path)) {
478 if (extensionSchemaNodes == null) {
479 if (other.extensionSchemaNodes != null) {
482 } else if (!extensionSchemaNodes.equals(other.extensionSchemaNodes)) {
486 if (other.name != null) {
489 } else if (!name.equals(other.name)) {
493 if (other.value != null) {
496 } else if (!value.equals(other.value)) {
503 public String toString() {
504 return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name="
505 + name + ", value=" + value + "]";
510 * Get and parse range from given type body context.
513 * type body context to parse
514 * @return List of RangeConstraint created from this context
516 private static List<RangeConstraint> getRangeConstraints(
517 Type_body_stmtsContext ctx) {
518 List<RangeConstraint> rangeConstraints = Collections.emptyList();
519 outer: for (int j = 0; j < ctx.getChildCount(); j++) {
520 ParseTree numRestrChild = ctx.getChild(j);
521 if (numRestrChild instanceof Numerical_restrictionsContext) {
522 for (int k = 0; k < numRestrChild.getChildCount(); k++) {
523 ParseTree rangeChild = numRestrChild.getChild(k);
524 if (rangeChild instanceof Range_stmtContext) {
525 rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild);
531 return rangeConstraints;
535 * Parse given range context.
538 * range context to parse
539 * @return List of RangeConstraints parsed from this context
541 private static List<RangeConstraint> parseRangeConstraints(
542 Range_stmtContext ctx) {
543 List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();
544 String description = null;
545 String reference = null;
547 for (int i = 0; i < ctx.getChildCount(); i++) {
548 ParseTree child = ctx.getChild(i);
549 if (child instanceof Description_stmtContext) {
550 description = stringFromNode(child);
551 } else if (child instanceof Reference_stmtContext) {
552 reference = stringFromNode(child);
556 String rangeStr = stringFromNode(ctx);
557 String trimmed = rangeStr.replace(" ", "");
558 String[] splittedRange = trimmed.split("\\|");
559 for (String rangeDef : splittedRange) {
560 String[] splittedRangeDef = rangeDef.split("\\.\\.");
563 if (splittedRangeDef.length == 1) {
564 min = max = parseNumberConstraintValue(splittedRangeDef[0]);
566 min = parseNumberConstraintValue(splittedRangeDef[0]);
567 max = parseNumberConstraintValue(splittedRangeDef[1]);
569 RangeConstraint range = BaseConstraints.rangeConstraint(min, max,
570 description, reference);
571 rangeConstraints.add(range);
574 return rangeConstraints;
578 * Get and parse length from given type body context.
581 * type body context to parse
582 * @return List of LengthConstraint created from this context
584 private static List<LengthConstraint> getLengthConstraints(
585 Type_body_stmtsContext ctx) {
586 List<LengthConstraint> lengthConstraints = Collections.emptyList();
587 outer: for (int j = 0; j < ctx.getChildCount(); j++) {
588 ParseTree stringRestrChild = ctx.getChild(j);
589 if (stringRestrChild instanceof String_restrictionsContext) {
590 for (int k = 0; k < stringRestrChild.getChildCount(); k++) {
591 ParseTree lengthChild = stringRestrChild.getChild(k);
592 if (lengthChild instanceof Length_stmtContext) {
593 lengthConstraints = parseLengthConstraints((Length_stmtContext) lengthChild);
599 return lengthConstraints;
603 * Parse given length context.
606 * length context to parse
607 * @return List of LengthConstraints parsed from this context
609 private static List<LengthConstraint> parseLengthConstraints(
610 Length_stmtContext ctx) {
611 List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();
612 String description = null;
613 String reference = null;
615 for (int i = 0; i < ctx.getChildCount(); i++) {
616 ParseTree child = ctx.getChild(i);
617 if (child instanceof Description_stmtContext) {
618 description = stringFromNode(child);
619 } else if (child instanceof Reference_stmtContext) {
620 reference = stringFromNode(child);
624 String lengthStr = stringFromNode(ctx);
625 String trimmed = lengthStr.replace(" ", "");
626 String[] splittedRange = trimmed.split("\\|");
627 for (String rangeDef : splittedRange) {
628 String[] splittedRangeDef = rangeDef.split("\\.\\.");
631 if (splittedRangeDef.length == 1) {
632 min = max = parseNumberConstraintValue(splittedRangeDef[0]);
634 min = parseNumberConstraintValue(splittedRangeDef[0]);
635 max = parseNumberConstraintValue(splittedRangeDef[1]);
637 LengthConstraint range = BaseConstraints.lengthConstraint(min, max,
638 description, reference);
639 lengthConstraints.add(range);
642 return lengthConstraints;
648 * @return wrapper object of primitive java type or UnknownBoundaryNumber if
649 * type is one of special YANG values 'min' or 'max'
651 private static Number parseNumberConstraintValue(String value) {
652 Number result = null;
653 if ("min".equals(value) || "max".equals(value)) {
654 result = new UnknownBoundaryNumber(value);
657 result = Long.valueOf(value);
658 } catch (NumberFormatException e) {
659 throw new YangParseException("Unable to parse range value '"
666 private static List<PatternConstraint> getPatternConstraint(
667 Type_body_stmtsContext ctx) {
668 List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
670 outer: for (int j = 0; j < ctx.getChildCount(); j++) {
671 ParseTree stringRestrChild = ctx.getChild(j);
672 if (stringRestrChild instanceof String_restrictionsContext) {
673 for (int k = 0; k < stringRestrChild.getChildCount(); k++) {
674 ParseTree lengthChild = stringRestrChild.getChild(k);
675 if (lengthChild instanceof Pattern_stmtContext) {
676 patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild));
677 if (k == lengthChild.getChildCount() - 1) {
688 * Internal helper method.
692 * @return PatternConstraint object
694 private static PatternConstraint parsePatternConstraint(
695 Pattern_stmtContext ctx) {
696 String description = null;
697 String reference = null;
698 for (int i = 0; i < ctx.getChildCount(); i++) {
699 ParseTree child = ctx.getChild(i);
700 if (child instanceof Description_stmtContext) {
701 description = stringFromNode(child);
702 } else if (child instanceof Reference_stmtContext) {
703 reference = stringFromNode(child);
706 String pattern = patternStringFromNode(ctx);
707 return BaseConstraints.patternConstraint(pattern, description,
712 * Parse given context and return pattern value.
716 * @return pattern value as String
718 public static String patternStringFromNode(final Pattern_stmtContext ctx) {
719 StringBuilder result = new StringBuilder();
720 for (int i = 0; i < ctx.getChildCount(); ++i) {
721 ParseTree child = ctx.getChild(i);
722 if (child instanceof StringContext) {
723 for (int j = 0; j < child.getChildCount(); j++) {
725 String patternToken = child.getChild(j).getText();
726 result.append(patternToken.substring(1,
727 patternToken.length() - 1));
732 return result.toString();
736 * Get fraction digits value from context.
739 * type body context to parse
740 * @return 'fraction-digits' value if present in given context, null
743 private static Integer getFractionDigits(Type_body_stmtsContext ctx) {
744 Integer result = null;
745 for (int j = 0; j < ctx.getChildCount(); j++) {
746 ParseTree dec64specChild = ctx.getChild(j);
747 if (dec64specChild instanceof Decimal64_specificationContext) {
748 result = parseFractionDigits((Decimal64_specificationContext) dec64specChild);
754 private static Integer parseFractionDigits(
755 Decimal64_specificationContext ctx) {
756 Integer result = null;
757 for (int k = 0; k < ctx.getChildCount(); k++) {
758 ParseTree fdChild = ctx.getChild(k);
759 if (fdChild instanceof Fraction_digits_stmtContext) {
760 String value = stringFromNode(fdChild);
762 result = Integer.valueOf(value);
763 } catch (NumberFormatException e) {
764 throw new YangParseException(
765 "Unable to parse fraction digits value '" + value
774 * Internal helper method for parsing bit statements from given type body context.
777 * type body context to parse
779 * current position in YANG model
783 * @return List of Bit objects created from this context
785 private static List<BitsTypeDefinition.Bit> getBits(
786 Type_body_stmtsContext ctx, List<String> actualPath, URI namespace,
787 Date revision, String prefix) {
788 final List<BitsTypeDefinition.Bit> bits = new ArrayList<BitsTypeDefinition.Bit>();
789 for (int j = 0; j < ctx.getChildCount(); j++) {
790 ParseTree bitsSpecChild = ctx.getChild(j);
791 if (bitsSpecChild instanceof Bits_specificationContext) {
792 long highestPosition = -1;
793 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
794 ParseTree bitChild = bitsSpecChild.getChild(k);
795 if (bitChild instanceof Bit_stmtContext) {
796 Bit bit = parseBit((Bit_stmtContext) bitChild,
797 highestPosition, actualPath, namespace,
799 if (bit.getPosition() > highestPosition) {
800 highestPosition = bit.getPosition();
811 * Internal helper method for parsing bit context.
814 * bit statement context to parse
815 * @param highestPosition
816 * current highest position in bits type
818 * current position in YANG model
822 * @return Bit object parsed from this context
824 private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx,
825 long highestPosition, List<String> actualPath, final URI namespace,
826 final Date revision, final String prefix) {
827 String name = stringFromNode(ctx);
828 final QName qname = new QName(namespace, revision, prefix, name);
829 Long position = null;
831 String description = null;
832 String reference = null;
833 Status status = Status.CURRENT;
835 Stack<String> bitPath = new Stack<String>();
836 bitPath.addAll(actualPath);
839 SchemaPath schemaPath = createActualSchemaPath(bitPath, namespace,
842 for (int i = 0; i < ctx.getChildCount(); i++) {
843 ParseTree child = ctx.getChild(i);
844 if (child instanceof Position_stmtContext) {
845 String positionStr = stringFromNode(child);
846 position = Long.valueOf(positionStr);
847 } else if (child instanceof Description_stmtContext) {
848 description = stringFromNode(child);
849 } else if (child instanceof Reference_stmtContext) {
850 reference = stringFromNode(child);
851 } else if (child instanceof Status_stmtContext) {
852 status = parseStatus((Status_stmtContext) child);
856 if (position == null) {
857 position = highestPosition + 1;
859 if (position < 0 || position > 4294967295L) {
860 throw new YangParseException(
863 + "': the position value MUST be in the range 0 to 4294967295");
866 final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
867 return new BitImpl(position, qname, schemaPath, description, reference, status, unknownNodes);
871 * Parse orderedby statement.
874 * Ordered_by_stmtContext
875 * @return true, if orderedby contains value 'user' or false otherwise
877 public static boolean parseUserOrdered(Ordered_by_stmtContext childNode) {
878 boolean result = false;
879 for (int j = 0; j < childNode.getChildCount(); j++) {
880 ParseTree orderArg = childNode.getChild(j);
881 if (orderArg instanceof Ordered_by_argContext) {
882 String orderStr = stringFromNode(orderArg);
883 if ("system".equals(orderStr)) {
885 } else if ("user".equals(orderStr)) {
888 logger.warn("Invalid 'orderedby' statement.");
896 * Parse given config context and return true if it contains string 'true',
900 * config context to parse.
901 * @return true if given context contains string 'true', false otherwise
903 public static boolean parseConfig(final Config_stmtContext ctx) {
904 boolean result = false;
906 for (int i = 0; i < ctx.getChildCount(); ++i) {
907 final ParseTree configContext = ctx.getChild(i);
908 if (configContext instanceof Config_argContext) {
909 final String value = stringFromNode(configContext);
910 if ("true".equals(value)) {
921 * Parse given type body and creates UnknownType definition.
923 * @param typedefQName
924 * qname of current type
927 * @return UnknownType object with constraints from parsed type body
929 public static TypeDefinition<?> parseUnknownTypeBody(QName typedefQName,
930 Type_body_stmtsContext ctx) {
931 UnknownType.Builder unknownType = new UnknownType.Builder(typedefQName);
934 List<RangeConstraint> rangeStatements = getRangeConstraints(ctx);
935 List<LengthConstraint> lengthStatements = getLengthConstraints(ctx);
936 List<PatternConstraint> patternStatements = getPatternConstraint(ctx);
937 Integer fractionDigits = getFractionDigits(ctx);
939 unknownType.rangeStatements(rangeStatements);
940 unknownType.lengthStatements(lengthStatements);
941 unknownType.patterns(patternStatements);
942 unknownType.fractionDigits(fractionDigits);
945 return unknownType.build();
949 * Create TypeDefinition object based on given type name and type body.
956 * current path in schema
963 * @return TypeDefinition object based on parsed values.
965 public static TypeDefinition<?> parseTypeBody(String typeName,
966 Type_body_stmtsContext typeBody, List<String> actualPath,
967 URI namespace, Date revision, String prefix) {
968 TypeDefinition<?> type = null;
970 List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody);
971 Integer fractionDigits = getFractionDigits(typeBody);
972 List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody);
973 List<PatternConstraint> patternStatements = getPatternConstraint(typeBody);
974 List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(
975 typeBody, actualPath, namespace, revision, prefix);
977 if ("decimal64".equals(typeName)) {
978 type = YangTypesConverter.javaTypeForBaseYangDecimal64Type(
979 rangeStatements, fractionDigits);
980 } else if (typeName.startsWith("int")) {
981 type = YangTypesConverter.javaTypeForBaseYangSignedIntegerType(
982 typeName, rangeStatements);
983 } else if (typeName.startsWith("uint")) {
984 type = YangTypesConverter.javaTypeForBaseYangUnsignedIntegerType(
985 typeName, rangeStatements);
986 } else if ("enumeration".equals(typeName)) {
987 type = new EnumerationType(actualPath, namespace, revision, enumConstants);
988 } else if ("string".equals(typeName)) {
989 type = new StringType(lengthStatements, patternStatements);
990 } else if ("bits".equals(typeName)) {
991 type = new BitsType(getBits(typeBody, actualPath, namespace,
993 } else if ("leafref".equals(typeName)) {
994 final String path = parseLeafrefPath(typeBody);
995 final boolean absolute = path.startsWith("/");
996 RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path,
998 type = new Leafref(actualPath, namespace, revision, xpath);
999 } else if ("binary".equals(typeName)) {
1000 List<Byte> bytes = Collections.emptyList();
1001 type = new BinaryType(bytes, lengthStatements, null);
1002 } else if ("instance-identifier".equals(typeName)) {
1003 boolean requireInstance = isRequireInstance(typeBody);
1004 type = new InstanceIdentifier(null, requireInstance);
1009 private static boolean isRequireInstance(Type_body_stmtsContext ctx) {
1010 for (int i = 0; i < ctx.getChildCount(); i++) {
1011 ParseTree child = ctx.getChild(i);
1012 if (child instanceof Require_instance_stmtContext) {
1013 for (int j = 0; j < child.getChildCount(); j++) {
1014 ParseTree reqArg = child.getChild(j);
1015 if (reqArg instanceof Require_instance_argContext) {
1016 return Boolean.valueOf(stringFromNode(reqArg));
1024 private static String parseLeafrefPath(Type_body_stmtsContext ctx) {
1025 for (int i = 0; i < ctx.getChildCount(); i++) {
1026 ParseTree child = ctx.getChild(i);
1027 if (child instanceof Leafref_specificationContext) {
1028 for (int j = 0; j < child.getChildCount(); j++) {
1029 ParseTree leafRefSpec = child.getChild(j);
1030 if (leafRefSpec instanceof Path_stmtContext) {
1031 return stringFromNode(leafRefSpec);
1040 * Internal helper method for parsing Must_stmtContext.
1044 * @return MustDefinition object based on parsed context
1046 public static MustDefinition parseMust(YangParser.Must_stmtContext ctx) {
1047 StringBuilder mustText = new StringBuilder();
1048 String description = null;
1049 String reference = null;
1050 String errorAppTag = null;
1051 String errorMessage = null;
1052 for (int i = 0; i < ctx.getChildCount(); ++i) {
1053 ParseTree child = ctx.getChild(i);
1054 if (child instanceof StringContext) {
1055 final StringContext context = (StringContext) child;
1056 if (context.getChildCount() == 1) {
1057 String mustPart = context.getChild(0).getText();
1058 // trim start and end quotation
1059 mustText.append(mustPart.substring(1, mustPart.length() - 1));
1061 for (int j = 0; j < context.getChildCount(); j++) {
1062 String mustPart = context.getChild(j).getText();
1064 mustText.append(mustPart.substring(0,
1065 mustPart.length() - 1));
1069 mustText.append(mustPart.substring(1));
1073 } else if (child instanceof Description_stmtContext) {
1074 description = stringFromNode(child);
1075 } else if (child instanceof Reference_stmtContext) {
1076 reference = stringFromNode(child);
1077 } else if (child instanceof Error_app_tag_stmtContext) {
1078 errorAppTag = stringFromNode(child);
1079 } else if (child instanceof Error_message_stmtContext) {
1080 errorMessage = stringFromNode(child);
1084 MustDefinition must = new MustDefinitionImpl(mustText.toString(),
1085 description, reference, errorAppTag, errorMessage);
1090 * Parse given tree and set constraints to given builder.
1094 * @param constraintsBuilder
1095 * ConstraintsBuilder to fill
1097 public static void parseConstraints(ParseTree ctx,
1098 ConstraintsBuilder constraintsBuilder) {
1099 for (int i = 0; i < ctx.getChildCount(); ++i) {
1100 final ParseTree childNode = ctx.getChild(i);
1101 if (childNode instanceof Max_elements_stmtContext) {
1102 Integer max = Integer.valueOf(stringFromNode(childNode));
1103 constraintsBuilder.setMinElements(max);
1104 } else if (childNode instanceof Min_elements_stmtContext) {
1105 Integer min = Integer.valueOf(stringFromNode(childNode));
1106 constraintsBuilder.setMinElements(min);
1107 } else if (childNode instanceof Must_stmtContext) {
1108 MustDefinition must = parseMust((Must_stmtContext) childNode);
1109 constraintsBuilder.addMustDefinition(must);
1110 } else if (childNode instanceof Mandatory_stmtContext) {
1111 for (int j = 0; j < childNode.getChildCount(); j++) {
1112 ParseTree mandatoryTree = ctx.getChild(j);
1113 if (mandatoryTree instanceof Mandatory_argContext) {
1114 Boolean mandatory = Boolean
1115 .valueOf(stringFromNode(mandatoryTree));
1116 constraintsBuilder.setMandatory(mandatory);
1119 } else if (childNode instanceof When_stmtContext) {
1120 constraintsBuilder.addWhenCondition(stringFromNode(childNode));
1126 * Parse given context and return yin value.
1130 * @return true if value is 'true', false otherwise
1132 public static boolean parseYinValue(Argument_stmtContext ctx) {
1133 boolean yinValue = false;
1134 outer: for (int j = 0; j < ctx.getChildCount(); j++) {
1135 ParseTree yin = ctx.getChild(j);
1136 if (yin instanceof Yin_element_stmtContext) {
1137 for (int k = 0; k < yin.getChildCount(); k++) {
1138 ParseTree yinArg = yin.getChild(k);
1139 if (yinArg instanceof Yin_element_argContext) {
1140 String yinString = stringFromNode(yinArg);
1141 if ("true".equals(yinString)) {
1152 public static List<RefineHolder> parseRefines(Uses_stmtContext ctx) {
1153 List<RefineHolder> refines = new ArrayList<RefineHolder>();
1155 for (int i = 0; i < ctx.getChildCount(); i++) {
1156 ParseTree child = ctx.getChild(i);
1157 if (child instanceof Refine_stmtContext) {
1158 String refineTarget = stringFromNode(child);
1159 RefineHolder refine = new RefineHolder(refineTarget);
1160 for (int j = 0; j < child.getChildCount(); j++) {
1161 ParseTree refinePom = child.getChild(j);
1162 if (refinePom instanceof Refine_pomContext) {
1163 for (int k = 0; k < refinePom.getChildCount(); k++) {
1164 ParseTree refineStmt = refinePom.getChild(k);
1165 if (refineStmt instanceof Refine_leaf_stmtsContext) {
1167 (Refine_leaf_stmtsContext) refineStmt);
1168 } else if (refineStmt instanceof Refine_container_stmtsContext) {
1171 (Refine_container_stmtsContext) refineStmt);
1172 } else if (refineStmt instanceof Refine_list_stmtsContext) {
1174 (Refine_list_stmtsContext) refineStmt);
1175 } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1178 (Refine_leaf_list_stmtsContext) refineStmt);
1179 } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1181 (Refine_choice_stmtsContext) refineStmt);
1182 } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1184 (Refine_anyxml_stmtsContext) refineStmt);
1189 refines.add(refine);
1195 private static RefineHolder parseRefine(RefineHolder refine,
1196 Refine_leaf_stmtsContext refineStmt) {
1197 refine.setType(Refine.LEAF);
1198 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1199 ParseTree refineArg = refineStmt.getChild(i);
1200 if (refineArg instanceof Default_stmtContext) {
1201 String defaultStr = stringFromNode(refineArg);
1202 refine.setDefaultStr(defaultStr);
1203 } else if (refineArg instanceof Mandatory_stmtContext) {
1204 for (int j = 0; j < refineArg.getChildCount(); j++) {
1205 ParseTree mandatoryTree = refineArg.getChild(j);
1206 if (mandatoryTree instanceof Mandatory_argContext) {
1207 Boolean mandatory = Boolean
1208 .valueOf(stringFromNode(mandatoryTree));
1209 refine.setMandatory(mandatory);
1212 } else if (refineArg instanceof Must_stmtContext) {
1213 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1214 refine.setMust(must);
1221 private static RefineHolder parseRefine(RefineHolder refine,
1222 Refine_container_stmtsContext refineStmt) {
1223 refine.setType(Refine.CONTAINER);
1224 for (int m = 0; m < refineStmt.getChildCount(); m++) {
1225 ParseTree refineArg = refineStmt.getChild(m);
1226 if (refineArg instanceof Must_stmtContext) {
1227 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1228 refine.setMust(must);
1229 } else if (refineArg instanceof Presence_stmtContext) {
1230 refine.setPresence(true);
1236 private static RefineHolder parseRefine(RefineHolder refine,
1237 Refine_list_stmtsContext refineStmt) {
1238 refine.setType(Refine.LIST);
1239 for (int m = 0; m < refineStmt.getChildCount(); m++) {
1240 ParseTree refineArg = refineStmt.getChild(m);
1241 if (refineArg instanceof Must_stmtContext) {
1242 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1243 refine.setMust(must);
1244 } else if (refineArg instanceof Max_elements_stmtContext) {
1245 Integer max = Integer.valueOf(stringFromNode(refineArg));
1246 refine.setMinElements(max);
1247 } else if (refineArg instanceof Min_elements_stmtContext) {
1248 Integer min = Integer.valueOf(stringFromNode(refineArg));
1249 refine.setMinElements(min);
1255 private static RefineHolder parseRefine(RefineHolder refine,
1256 Refine_leaf_list_stmtsContext refineStmt) {
1257 refine.setType(Refine.LEAF_LIST);
1258 for (int m = 0; m < refineStmt.getChildCount(); m++) {
1259 ParseTree refineArg = refineStmt.getChild(m);
1260 if (refineArg instanceof Must_stmtContext) {
1261 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1262 refine.setMust(must);
1263 } else if (refineArg instanceof Max_elements_stmtContext) {
1264 Integer max = Integer.valueOf(stringFromNode(refineArg));
1265 refine.setMinElements(max);
1266 } else if (refineArg instanceof Min_elements_stmtContext) {
1267 Integer min = Integer.valueOf(stringFromNode(refineArg));
1268 refine.setMinElements(min);
1274 private static RefineHolder parseRefine(RefineHolder refine,
1275 Refine_choice_stmtsContext refineStmt) {
1276 refine.setType(Refine.CHOICE);
1277 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1278 ParseTree refineArg = refineStmt.getChild(i);
1279 if (refineArg instanceof Default_stmtContext) {
1280 String defaultStr = stringFromNode(refineArg);
1281 refine.setDefaultStr(defaultStr);
1282 } else if (refineArg instanceof Mandatory_stmtContext) {
1283 for (int j = 0; j < refineArg.getChildCount(); j++) {
1284 ParseTree mandatoryTree = refineArg.getChild(j);
1285 if (mandatoryTree instanceof Mandatory_argContext) {
1286 Boolean mandatory = Boolean
1287 .valueOf(stringFromNode(mandatoryTree));
1288 refine.setMandatory(mandatory);
1296 private static RefineHolder parseRefine(RefineHolder refine,
1297 Refine_anyxml_stmtsContext refineStmt) {
1298 refine.setType(Refine.ANYXML);
1299 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1300 ParseTree refineArg = refineStmt.getChild(i);
1301 if (refineArg instanceof Must_stmtContext) {
1302 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1303 refine.setMust(must);
1304 } else if (refineArg instanceof Mandatory_stmtContext) {
1305 for (int j = 0; j < refineArg.getChildCount(); j++) {
1306 ParseTree mandatoryTree = refineArg.getChild(j);
1307 if (mandatoryTree instanceof Mandatory_argContext) {
1308 Boolean mandatory = Boolean
1309 .valueOf(stringFromNode(mandatoryTree));
1310 refine.setMandatory(mandatory);