Fixed bug in Decimal64 constructor.
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / ParserListenerUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.parser.util;
9
10 import java.net.URI;
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;
16
17 import org.antlr.v4.runtime.tree.ParseTree;
18 import org.opendaylight.yangtools.antlrv4.code.gen.*;
19 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
20 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
21 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Bit_stmtContext;
22 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Bits_specificationContext;
23 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_argContext;
24 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_stmtContext;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Decimal64_specificationContext;
26 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Description_stmtContext;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Enum_specificationContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Enum_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Error_app_tag_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Error_message_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Identityref_specificationContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Instance_identifier_specificationContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leafref_specificationContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Length_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_argContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_elements_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_value_argContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_value_argContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Must_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Path_stmtContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Pattern_stmtContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Position_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Presence_stmtContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Range_stmtContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Reference_stmtContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_anyxml_stmtsContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_choice_stmtsContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_container_stmtsContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_leaf_list_stmtsContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_leaf_stmtsContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_list_stmtsContext;
59 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_pomContext;
60 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_stmtContext;
61 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Require_instance_argContext;
62 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Require_instance_stmtContext;
63 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
64 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_stmtContext;
65 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.StringContext;
66 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.String_restrictionsContext;
67 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
68 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Units_stmtContext;
69 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Value_stmtContext;
70 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.When_stmtContext;
71 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_argContext;
72 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_stmtContext;
73 import org.opendaylight.yangtools.yang.common.QName;
74 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
75 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
76 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
77 import org.opendaylight.yangtools.yang.model.api.Status;
78 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
79 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
80 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
81 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
82 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
83 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
84 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
85 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
86 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
87 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
88 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
89 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
90 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
91 import org.opendaylight.yangtools.yang.model.util.BaseConstraints;
92 import org.opendaylight.yangtools.yang.model.util.BaseTypes;
93 import org.opendaylight.yangtools.yang.model.util.BinaryType;
94 import org.opendaylight.yangtools.yang.model.util.BitsType;
95 import org.opendaylight.yangtools.yang.model.util.Decimal64;
96 import org.opendaylight.yangtools.yang.model.util.EnumerationType;
97 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
98 import org.opendaylight.yangtools.yang.model.util.InstanceIdentifier;
99 import org.opendaylight.yangtools.yang.model.util.Int16;
100 import org.opendaylight.yangtools.yang.model.util.Int32;
101 import org.opendaylight.yangtools.yang.model.util.Int64;
102 import org.opendaylight.yangtools.yang.model.util.Int8;
103 import org.opendaylight.yangtools.yang.model.util.Leafref;
104 import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
105 import org.opendaylight.yangtools.yang.model.util.StringType;
106 import org.opendaylight.yangtools.yang.model.util.Uint16;
107 import org.opendaylight.yangtools.yang.model.util.Uint32;
108 import org.opendaylight.yangtools.yang.model.util.Uint64;
109 import org.opendaylight.yangtools.yang.model.util.Uint8;
110 import org.opendaylight.yangtools.yang.model.util.UnknownType;
111 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
112 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
113 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
114 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
115 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
116 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
117 import org.opendaylight.yangtools.yang.parser.builder.impl.ConstraintsBuilder;
118 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
119 import org.slf4j.Logger;
120 import org.slf4j.LoggerFactory;
121
122 public final class ParserListenerUtils {
123     private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class);
124
125     private ParserListenerUtils() {
126     }
127
128     /**
129      * Parse given tree and get first string value.
130      *
131      * @param treeNode
132      *            tree to parse
133      * @return first string value from given tree
134      */
135     public static String stringFromNode(final ParseTree treeNode) {
136         final String result = "";
137         for (int i = 0; i < treeNode.getChildCount(); ++i) {
138             if (treeNode.getChild(i) instanceof StringContext) {
139                 final StringContext context = (StringContext) treeNode.getChild(i);
140                 if (context != null) {
141                     return context.getChild(0).getText().replace("\"", "");
142                 }
143             }
144         }
145         return result;
146     }
147
148     /**
149      * Parse 'description', 'reference' and 'status' statements and fill in
150      * given builder.
151      *
152      * @param ctx
153      *            context to parse
154      * @param builder
155      *            builder to fill in with parsed statements
156      */
157     public static void parseSchemaNodeArgs(final ParseTree ctx, final SchemaNodeBuilder builder) {
158         for (int i = 0; i < ctx.getChildCount(); i++) {
159             final ParseTree child = ctx.getChild(i);
160             if (child instanceof Description_stmtContext) {
161                 final String desc = stringFromNode(child);
162                 builder.setDescription(desc);
163             } else if (child instanceof Reference_stmtContext) {
164                 final String ref = stringFromNode(child);
165                 builder.setReference(ref);
166             } else if (child instanceof Status_stmtContext) {
167                 final Status status = parseStatus((Status_stmtContext) child);
168                 builder.setStatus(status);
169             }
170         }
171     }
172
173     /**
174      * Parse given context and return its value;
175      *
176      * @param ctx
177      *            status context
178      * @return value parsed from context
179      */
180     public static Status parseStatus(final Status_stmtContext ctx) {
181         Status result = null;
182         for (int i = 0; i < ctx.getChildCount(); i++) {
183             ParseTree statusArg = ctx.getChild(i);
184             if (statusArg instanceof Status_argContext) {
185                 String statusArgStr = stringFromNode(statusArg);
186                 if ("current".equals(statusArgStr)) {
187                     result = Status.CURRENT;
188                 } else if ("deprecated".equals(statusArgStr)) {
189                     result = Status.DEPRECATED;
190                 } else if ("obsolete".equals(statusArgStr)) {
191                     result = Status.OBSOLETE;
192                 } else {
193                     LOG.warn("Invalid 'status' statement: " + statusArgStr);
194                 }
195             }
196         }
197         return result;
198     }
199
200     /**
201      * Parse given tree and returns units statement as string.
202      *
203      * @param ctx
204      *            context to parse
205      * @return value of units statement as string or null if there is no units
206      *         statement
207      */
208     public static String parseUnits(final ParseTree ctx) {
209         String units = null;
210         for (int i = 0; i < ctx.getChildCount(); i++) {
211             ParseTree child = ctx.getChild(i);
212             if (child instanceof Units_stmtContext) {
213                 units = stringFromNode(child);
214                 break;
215             }
216         }
217         return units;
218     }
219
220     /**
221      * Parse given tree and returns default statement as string.
222      *
223      * @param ctx
224      *            context to parse
225      * @return value of default statement as string or null if there is no
226      *         default statement
227      */
228     public static String parseDefault(final ParseTree ctx) {
229         String defaultValue = null;
230         for (int i = 0; i < ctx.getChildCount(); i++) {
231             ParseTree child = ctx.getChild(i);
232             if (child instanceof Default_stmtContext) {
233                 defaultValue = stringFromNode(child);
234                 break;
235             }
236         }
237         return defaultValue;
238     }
239
240     /**
241      * Create SchemaPath from actualPath and new node name.
242      *
243      * @param actualPath
244      *            current position in model
245      * @return SchemaPath object
246      */
247     public static SchemaPath createActualSchemaPath(final Stack<QName> actualPath) {
248         final List<QName> path = new ArrayList<QName>(actualPath);
249         return new SchemaPath(path, true);
250     }
251
252     /**
253      * Create java.util.List of QName objects from given key definition as
254      * string.
255      *
256      * @param keyDefinition
257      *            key definition as string
258      * @param namespace
259      *            current namespace
260      * @param revision
261      *            current revision
262      * @param prefix
263      *            current prefix
264      * @return YANG list key as java.util.List of QName objects
265      */
266     public static List<QName> createListKey(final String keyDefinition, final URI namespace, final Date revision,
267             final String prefix) {
268         List<QName> key = new ArrayList<QName>();
269         String[] splittedKey = keyDefinition.split(" ");
270
271         QName qname = null;
272         for (String keyElement : splittedKey) {
273             if (keyElement.length() != 0) {
274                 qname = new QName(namespace, revision, prefix, keyElement);
275                 key.add(qname);
276             }
277         }
278         return key;
279     }
280
281     /**
282      * Parse given type body of enumeration statement.
283      *
284      * @param ctx
285      *            type body context to parse
286      * @param path
287      *            actual position in YANG model
288      * @param moduleName
289      *            current module name
290      * @return List of EnumPair object parsed from given context
291      */
292     private static List<EnumTypeDefinition.EnumPair> getEnumConstants(final Type_body_stmtsContext ctx,
293             final Stack<QName> path, final String moduleName) {
294         List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<EnumTypeDefinition.EnumPair>();
295
296         for (int i = 0; i < ctx.getChildCount(); i++) {
297             ParseTree enumSpecChild = ctx.getChild(i);
298             if (enumSpecChild instanceof Enum_specificationContext) {
299                 int highestValue = -1;
300                 for (int j = 0; j < enumSpecChild.getChildCount(); j++) {
301                     ParseTree enumChild = enumSpecChild.getChild(j);
302                     if (enumChild instanceof Enum_stmtContext) {
303                         EnumPair enumPair = createEnumPair((Enum_stmtContext) enumChild, highestValue, path, moduleName);
304                         if (enumPair.getValue() > highestValue) {
305                             highestValue = enumPair.getValue();
306                         }
307                         enumConstants.add(enumPair);
308                     }
309                 }
310             }
311         }
312         return enumConstants;
313     }
314
315     /**
316      * Parse enum statement context
317      *
318      * @param ctx
319      *            enum statement context
320      * @param highestValue
321      *            current highest value in enumeration
322      * @param path
323      *            actual position in YANG model
324      * @param moduleName
325      *            current module name
326      * @return EnumPair object parsed from given context
327      */
328     private static EnumTypeDefinition.EnumPair createEnumPair(final Enum_stmtContext ctx, final int highestValue,
329             final Stack<QName> actualPath, final String moduleName) {
330         final String name = stringFromNode(ctx);
331         SchemaPath path = createTypePath(actualPath, name);
332         Integer value = null;
333
334         String description = null;
335         String reference = null;
336         Status status = null;
337
338         for (int i = 0; i < ctx.getChildCount(); i++) {
339             ParseTree child = ctx.getChild(i);
340             if (child instanceof Value_stmtContext) {
341                 String valueStr = stringFromNode(child);
342                 value = Integer.valueOf(valueStr);
343             } else if (child instanceof Description_stmtContext) {
344                 description = stringFromNode(child);
345             } else if (child instanceof Reference_stmtContext) {
346                 reference = stringFromNode(child);
347             } else if (child instanceof Status_stmtContext) {
348                 status = parseStatus((Status_stmtContext) child);
349             }
350         }
351
352         if (value == null) {
353             value = highestValue + 1;
354         }
355         if (value < -2147483648 || value > 2147483647) {
356             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on enum '" + name
357                     + "': the enum value MUST be in the range from -2147483648 to 2147483647, but was: " + value);
358         }
359
360         EnumPairImpl result = new EnumPairImpl();
361         result.qname = path.getPath().get(path.getPath().size() - 1);
362         result.path = path;
363         result.description = description;
364         result.reference = reference;
365         result.status = status;
366         result.name = name;
367         result.value = value;
368         return result;
369     }
370
371     /**
372      * Internal implementation of EnumPair.
373      */
374     private static class EnumPairImpl implements EnumTypeDefinition.EnumPair {
375         private QName qname;
376         private SchemaPath path;
377         private String description;
378         private String reference;
379         private Status status;
380         private List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
381         private String name;
382         private Integer value;
383
384         @Override
385         public QName getQName() {
386             return qname;
387         }
388
389         @Override
390         public SchemaPath getPath() {
391             return path;
392         }
393
394         @Override
395         public String getDescription() {
396             return description;
397         }
398
399         @Override
400         public String getReference() {
401             return reference;
402         }
403
404         @Override
405         public Status getStatus() {
406             return status;
407         }
408
409         @Override
410         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
411             return unknownNodes;
412         }
413
414         @Override
415         public String getName() {
416             return name;
417         }
418
419         @Override
420         public Integer getValue() {
421             return value;
422         }
423
424         @Override
425         public int hashCode() {
426             final int prime = 31;
427             int result = 1;
428             result = prime * result + ((qname == null) ? 0 : qname.hashCode());
429             result = prime * result + ((path == null) ? 0 : path.hashCode());
430             result = prime * result + ((unknownNodes == null) ? 0 : unknownNodes.hashCode());
431             result = prime * result + ((name == null) ? 0 : name.hashCode());
432             result = prime * result + ((value == null) ? 0 : value.hashCode());
433             return result;
434         }
435
436         @Override
437         public boolean equals(Object obj) {
438             if (this == obj) {
439                 return true;
440             }
441             if (obj == null) {
442                 return false;
443             }
444             if (getClass() != obj.getClass()) {
445                 return false;
446             }
447             EnumPairImpl other = (EnumPairImpl) obj;
448             if (qname == null) {
449                 if (other.qname != null) {
450                     return false;
451                 }
452             } else if (!qname.equals(other.qname)) {
453                 return false;
454             }
455             if (path == null) {
456                 if (other.path != null) {
457                     return false;
458                 }
459             } else if (!path.equals(other.path)) {
460                 return false;
461             }
462             if (unknownNodes == null) {
463                 if (other.unknownNodes != null) {
464                     return false;
465                 }
466             } else if (!unknownNodes.equals(other.unknownNodes)) {
467                 return false;
468             }
469             if (name == null) {
470                 if (other.name != null) {
471                     return false;
472                 }
473             } else if (!name.equals(other.name)) {
474                 return false;
475             }
476             if (value == null) {
477                 if (other.value != null) {
478                     return false;
479                 }
480             } else if (!value.equals(other.value)) {
481                 return false;
482             }
483             return true;
484         }
485
486         @Override
487         public String toString() {
488             return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name=" + name + ", value=" + value + "]";
489         }
490     }
491
492     /**
493      * Get and parse range from given type body context.
494      *
495      * @param ctx
496      *            type body context to parse
497      * @param moduleName
498      * @return List of RangeConstraint created from this context
499      */
500     private static List<RangeConstraint> getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
501         List<RangeConstraint> rangeConstraints = Collections.emptyList();
502         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
503             ParseTree numRestrChild = ctx.getChild(i);
504             if (numRestrChild instanceof Numerical_restrictionsContext) {
505                 for (int j = 0; j < numRestrChild.getChildCount(); j++) {
506                     ParseTree rangeChild = numRestrChild.getChild(j);
507                     if (rangeChild instanceof Range_stmtContext) {
508                         rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
509                         break outer;
510                     }
511                 }
512             }
513         }
514         return rangeConstraints;
515     }
516
517     /**
518      * Parse given range context.
519      *
520      * @param ctx
521      *            range context to parse
522      * @param moduleName
523      * @return List of RangeConstraints parsed from this context
524      */
525     private static List<RangeConstraint> parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) {
526         final int line = ctx.getStart().getLine();
527         List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();
528         String description = null;
529         String reference = null;
530
531         for (int i = 0; i < ctx.getChildCount(); i++) {
532             ParseTree child = ctx.getChild(i);
533             if (child instanceof Description_stmtContext) {
534                 description = stringFromNode(child);
535             } else if (child instanceof Reference_stmtContext) {
536                 reference = stringFromNode(child);
537             }
538         }
539
540         String rangeStr = stringFromNode(ctx);
541         String trimmed = rangeStr.replace(" ", "");
542         String[] splittedRange = trimmed.split("\\|");
543         for (String rangeDef : splittedRange) {
544             String[] splittedRangeDef = rangeDef.split("\\.\\.");
545             Number min;
546             Number max;
547             if (splittedRangeDef.length == 1) {
548                 min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
549             } else {
550                 min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
551                 max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line);
552             }
553             RangeConstraint range = BaseConstraints.rangeConstraint(min, max, description, reference);
554             rangeConstraints.add(range);
555         }
556
557         return rangeConstraints;
558     }
559
560     /**
561      * Get and parse length from given type body context.
562      *
563      * @param ctx
564      *            type body context to parse
565      * @param moduleName
566      * @return List of LengthConstraint created from this context
567      */
568     private static List<LengthConstraint> getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
569         List<LengthConstraint> lengthConstraints = Collections.emptyList();
570         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
571             ParseTree stringRestrChild = ctx.getChild(i);
572             if (stringRestrChild instanceof String_restrictionsContext) {
573                 for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
574                     ParseTree lengthChild = stringRestrChild.getChild(j);
575                     if (lengthChild instanceof Length_stmtContext) {
576                         lengthConstraints = parseLengthConstraints((Length_stmtContext) lengthChild, moduleName);
577                         break outer;
578                     }
579                 }
580             }
581         }
582         return lengthConstraints;
583     }
584
585     /**
586      * Parse given length context.
587      *
588      * @param ctx
589      *            length context to parse
590      * @param moduleName
591      * @return List of LengthConstraints parsed from this context
592      */
593     private static List<LengthConstraint> parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) {
594         final int line = ctx.getStart().getLine();
595         List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();
596         String description = null;
597         String reference = null;
598
599         for (int i = 0; i < ctx.getChildCount(); i++) {
600             ParseTree child = ctx.getChild(i);
601             if (child instanceof Description_stmtContext) {
602                 description = stringFromNode(child);
603             } else if (child instanceof Reference_stmtContext) {
604                 reference = stringFromNode(child);
605             }
606         }
607
608         String lengthStr = stringFromNode(ctx);
609         String trimmed = lengthStr.replace(" ", "");
610         String[] splittedRange = trimmed.split("\\|");
611         for (String rangeDef : splittedRange) {
612             String[] splittedRangeDef = rangeDef.split("\\.\\.");
613             Number min;
614             Number max;
615             if (splittedRangeDef.length == 1) {
616                 min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
617             } else {
618                 min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line);
619                 max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line);
620             }
621             LengthConstraint range = BaseConstraints.lengthConstraint(min, max, description, reference);
622             lengthConstraints.add(range);
623         }
624
625         return lengthConstraints;
626     }
627
628     /**
629      * @param value
630      *            value to parse
631      * @param moduleName name of current module
632      * @param line current line in module
633      * @return wrapper object of primitive java type or UnknownBoundaryNumber if
634      *         type is one of special YANG values 'min' or 'max'
635      */
636     private static Number parseNumberConstraintValue(final String value, final String moduleName, final int line) {
637         Number result = null;
638         if ("min".equals(value) || "max".equals(value)) {
639             result = new UnknownBoundaryNumber(value);
640         } else {
641             try {
642                 result = Long.valueOf(value);
643             } catch (NumberFormatException e) {
644                 throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
645             }
646         }
647         return result;
648     }
649
650     /**
651      * Parse type body and return pattern constraints.
652      *
653      * @param ctx
654      *            type body
655      * @return list of pattern constraints
656      */
657     private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx) {
658         List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
659
660         for (int i = 0; i < ctx.getChildCount(); i++) {
661             ParseTree stringRestrChild = ctx.getChild(i);
662             if (stringRestrChild instanceof String_restrictionsContext) {
663                 for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
664                     ParseTree lengthChild = stringRestrChild.getChild(j);
665                     if (lengthChild instanceof Pattern_stmtContext) {
666                         patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild));
667                     }
668                 }
669             }
670         }
671         return patterns;
672     }
673
674     /**
675      * Internal helper method.
676      *
677      * @param ctx
678      *            pattern context
679      * @return PatternConstraint object
680      */
681     private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx) {
682         String description = null;
683         String reference = null;
684         for (int i = 0; i < ctx.getChildCount(); i++) {
685             ParseTree child = ctx.getChild(i);
686             if (child instanceof Description_stmtContext) {
687                 description = stringFromNode(child);
688             } else if (child instanceof Reference_stmtContext) {
689                 reference = stringFromNode(child);
690             }
691         }
692         String pattern = patternStringFromNode(ctx);
693         return BaseConstraints.patternConstraint(pattern, description, reference);
694     }
695
696     /**
697      * Parse given context and return pattern value.
698      *
699      * @param ctx
700      *            context to parse
701      * @return pattern value as String
702      */
703     public static String patternStringFromNode(final Pattern_stmtContext ctx) {
704         StringBuilder result = new StringBuilder();
705         for (int i = 0; i < ctx.getChildCount(); ++i) {
706             ParseTree child = ctx.getChild(i);
707             if (child instanceof StringContext) {
708                 for (int j = 0; j < child.getChildCount(); j++) {
709                     if (j % 2 == 0) {
710                         String patternToken = child.getChild(j).getText();
711                         result.append(patternToken.substring(1, patternToken.length() - 1));
712                     }
713                 }
714             }
715         }
716         return result.toString();
717     }
718
719     /**
720      * Get fraction digits value from type body.
721      *
722      * @param ctx
723      *            type body context to parse
724      * @param moduleName
725      *            name of current module
726      * @return 'fraction-digits' value if present in given context, null
727      *         otherwise
728      */
729     private static Integer getFractionDigits(Type_body_stmtsContext ctx, String moduleName) {
730         Integer result = null;
731         for (int i = 0; i < ctx.getChildCount(); i++) {
732             ParseTree dec64specChild = ctx.getChild(i);
733             if (dec64specChild instanceof Decimal64_specificationContext) {
734                 result = parseFractionDigits((Decimal64_specificationContext) dec64specChild, moduleName);
735             }
736         }
737         return result;
738     }
739
740     /**
741      * Parse decimal64 fraction-digits value.
742      *
743      * @param ctx
744      *            decimal64 context
745      * @param moduleName
746      *            name of current module
747      * @return fraction-digits value as Integer
748      */
749     private static Integer parseFractionDigits(Decimal64_specificationContext ctx, String moduleName) {
750         Integer result = null;
751         for (int i = 0; i < ctx.getChildCount(); i++) {
752             ParseTree fdChild = ctx.getChild(i);
753             if (fdChild instanceof Fraction_digits_stmtContext) {
754                 String value = stringFromNode(fdChild);
755                 try {
756                     result = Integer.valueOf(value);
757                 } catch (NumberFormatException e) {
758                     throw new YangParseException(moduleName, ctx.getStart().getLine(),
759                             "Unable to parse fraction digits value '" + value + "'.", e);
760                 }
761             }
762         }
763         return result;
764     }
765
766     /**
767      * Internal helper method for parsing bit statements from given type body
768      * context.
769      *
770      * @param ctx
771      *            type body context to parse
772      * @param actualPath
773      *            current position in YANG model
774      * @param moduleName
775      *            current module name
776      * @return List of Bit objects created from this context
777      */
778     private static List<BitsTypeDefinition.Bit> getBits(Type_body_stmtsContext ctx, Stack<QName> actualPath,
779             String moduleName) {
780         final List<BitsTypeDefinition.Bit> bits = new ArrayList<BitsTypeDefinition.Bit>();
781         for (int j = 0; j < ctx.getChildCount(); j++) {
782             ParseTree bitsSpecChild = ctx.getChild(j);
783             if (bitsSpecChild instanceof Bits_specificationContext) {
784                 long highestPosition = -1;
785                 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
786                     ParseTree bitChild = bitsSpecChild.getChild(k);
787                     if (bitChild instanceof Bit_stmtContext) {
788                         Bit bit = parseBit((Bit_stmtContext) bitChild, highestPosition, actualPath, moduleName);
789                         if (bit.getPosition() > highestPosition) {
790                             highestPosition = bit.getPosition();
791                         }
792                         bits.add(bit);
793                     }
794                 }
795             }
796         }
797         return bits;
798     }
799
800     /**
801      * Internal helper method for parsing bit context.
802      *
803      * @param ctx
804      *            bit statement context to parse
805      * @param highestPosition
806      *            current highest position in bits type
807      * @param actualPath
808      *            current position in YANG model
809      * @param moduleName
810      *            current module name
811      * @return Bit object parsed from this context
812      */
813     private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, long highestPosition,
814             Stack<QName> actualPath, final String moduleName) {
815         String name = stringFromNode(ctx);
816         Long position = null;
817
818         String description = null;
819         String reference = null;
820         Status status = Status.CURRENT;
821
822         SchemaPath schemaPath = createBaseTypePath(actualPath, name);
823
824         for (int i = 0; i < ctx.getChildCount(); i++) {
825             ParseTree child = ctx.getChild(i);
826             if (child instanceof Position_stmtContext) {
827                 String positionStr = stringFromNode(child);
828                 position = Long.valueOf(positionStr);
829             } else if (child instanceof Description_stmtContext) {
830                 description = stringFromNode(child);
831             } else if (child instanceof Reference_stmtContext) {
832                 reference = stringFromNode(child);
833             } else if (child instanceof Status_stmtContext) {
834                 status = parseStatus((Status_stmtContext) child);
835             }
836         }
837
838         if (position == null) {
839             position = highestPosition + 1;
840         }
841         if (position < 0 || position > 4294967295L) {
842             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on bit '" + name
843                     + "': the position value MUST be in the range 0 to 4294967295");
844         }
845
846         final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
847         return new BitImpl(position, schemaPath.getPath().get(schemaPath.getPath().size() - 1), schemaPath,
848                 description, reference, status, unknownNodes);
849     }
850
851     /**
852      * Parse 'ordered-by' statement.
853      *
854      * The 'ordered-by' statement defines whether the order of entries within a
855      * list are determined by the user or the system. The argument is one of the
856      * strings "system" or "user". If not present, order defaults to "system".
857      *
858      * @param ctx
859      *            Ordered_by_stmtContext
860      * @return true, if ordered-by contains value 'user', false otherwise
861      */
862     public static boolean parseUserOrdered(Ordered_by_stmtContext ctx) {
863         boolean result = false;
864         for (int j = 0; j < ctx.getChildCount(); j++) {
865             ParseTree orderArg = ctx.getChild(j);
866             if (orderArg instanceof Ordered_by_argContext) {
867                 String orderStr = stringFromNode(orderArg);
868                 if ("system".equals(orderStr)) {
869                     result = false;
870                 } else if ("user".equals(orderStr)) {
871                     result = true;
872                 } else {
873                     LOG.warn("Invalid 'ordered-by' statement.");
874                 }
875             }
876         }
877         return result;
878     }
879
880     /**
881      * Get config statement from given context. If there is no config statement,
882      * return config value of parent
883      *
884      * @param ctx
885      *            context to parse
886      * @param parent
887      *            parent node
888      * @param moduleName
889      *            name of current module
890      * @param line
891      *            line in current module
892      * @return config statement parsed from given context
893      */
894     public static Boolean getConfig(final ParseTree ctx, final Builder parent, final String moduleName, final int line) {
895         Boolean result = null;
896         // parse configuration statement
897         Boolean config = null;
898         for (int i = 0; i < ctx.getChildCount(); i++) {
899             ParseTree child = ctx.getChild(i);
900             if (child instanceof Config_stmtContext) {
901                 config = parseConfig((Config_stmtContext) child, moduleName);
902                 break;
903             }
904         }
905
906         // If 'config' is not specified, the default is the same as the parent
907         // schema node's 'config' value
908         if (config == null) {
909             if (parent instanceof DataSchemaNodeBuilder) {
910                 Boolean parentConfig = ((DataSchemaNodeBuilder) parent).isConfiguration();
911                 // If the parent node is a rpc input or output, it can has
912                 // config set to null
913                 result = parentConfig == null ? true : parentConfig;
914             } else if (parent instanceof ChoiceCaseBuilder) {
915                 // If the parent node is a 'case' node, the value is the same as
916                 // the 'case' node's parent 'choice' node
917                 ChoiceCaseBuilder choiceCase = (ChoiceCaseBuilder) parent;
918                 Builder choice = choiceCase.getParent();
919                 Boolean parentConfig = null;
920                 if (choice instanceof ChoiceBuilder) {
921                     parentConfig = ((ChoiceBuilder) choice).isConfiguration();
922                 } else {
923                     parentConfig = true;
924                 }
925                 result = parentConfig;
926             } else {
927                 result = true;
928             }
929         } else {
930             // Check first: if a node has 'config' set to 'false', no node
931             // underneath it can have 'config' set to 'true'
932             if (parent instanceof DataSchemaNodeBuilder && !(parent instanceof ChoiceCaseBuilder)) {
933                 Boolean parentConfig = ((DataSchemaNodeBuilder) parent).isConfiguration();
934                 if (!parentConfig && config) {
935                     throw new YangParseException(moduleName, line,
936                             "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
937                 }
938             }
939             result = config;
940         }
941
942         return result;
943     }
944
945     /**
946      * Parse config statement.
947      *
948      * @param ctx
949      *            config context to parse
950      * @param moduleName
951      *            current module name
952      * @return true if given context contains string 'true', false otherwise
953      */
954     private static Boolean parseConfig(final Config_stmtContext ctx, final String moduleName) {
955         Boolean result = null;
956         if (ctx != null) {
957             for (int i = 0; i < ctx.getChildCount(); ++i) {
958                 final ParseTree configContext = ctx.getChild(i);
959                 if (configContext instanceof Config_argContext) {
960                     final String value = stringFromNode(configContext);
961                     if ("true".equals(value)) {
962                         result = true;
963                         break;
964                     } else if ("false".equals(value)) {
965                         result = false;
966                         break;
967                     } else {
968                         throw new YangParseException(moduleName, ctx.getStart().getLine(),
969                                 "Failed to parse 'config' statement value: '" + value + "'.");
970                     }
971                 }
972             }
973         }
974         return result;
975     }
976
977     /**
978      * Parse type body and create UnknownType definition.
979      *
980      * @param typedefQName
981      *            qname of current type
982      * @param ctx
983      *            type body
984      * @param actualPath
985      * @param namespace
986      * @param revision
987      * @param prefix
988      * @param parent
989      * @return UnknownType object with constraints from parsed type body
990      */
991     public static TypeDefinition<?> parseUnknownTypeWithBody(final QName typedefQName,
992             final Type_body_stmtsContext ctx, final Stack<QName> actualPath, final URI namespace, final Date revision,
993             final String prefix, final Builder parent) {
994         String moduleName = parent.getModuleName();
995         String typeName = typedefQName.getLocalName();
996
997         UnknownType.Builder unknownType = new UnknownType.Builder(typedefQName);
998
999         if (ctx != null) {
1000             List<RangeConstraint> rangeStatements = getRangeConstraints(ctx, moduleName);
1001             List<LengthConstraint> lengthStatements = getLengthConstraints(ctx, moduleName);
1002             List<PatternConstraint> patternStatements = getPatternConstraint(ctx);
1003             Integer fractionDigits = getFractionDigits(ctx, moduleName);
1004
1005             if (parent instanceof TypeDefinitionBuilder) {
1006                 TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1007                 typedef.setRanges(rangeStatements);
1008                 typedef.setLengths(lengthStatements);
1009                 typedef.setPatterns(patternStatements);
1010                 typedef.setFractionDigits(fractionDigits);
1011                 return unknownType.build();
1012             } else {
1013                 TypeDefinition<?> baseType = unknownType.build();
1014                 TypeDefinition<?> result = null;
1015                 QName qname = new QName(namespace, revision, prefix, typeName);
1016                 SchemaPath schemaPath = createTypePath(actualPath, typeName);
1017
1018                 ExtendedType.Builder typeBuilder = new ExtendedType.Builder(qname, baseType, null, null, schemaPath);
1019                 typeBuilder.ranges(rangeStatements);
1020                 typeBuilder.lengths(lengthStatements);
1021                 typeBuilder.patterns(patternStatements);
1022                 typeBuilder.fractionDigits(fractionDigits);
1023                 result = typeBuilder.build();
1024
1025                 return result;
1026             }
1027         } else {
1028             unknownType.setReferenceOnly(true);
1029         }
1030
1031         return unknownType.build();
1032     }
1033
1034     /**
1035      * Create TypeDefinition object based on given type name and type body.
1036      *
1037      * @param typeName
1038      *            name of type
1039      * @param typeBody
1040      *            type body context
1041      * @param actualPath
1042      *            current path in schema
1043      * @param namespace
1044      *            current namespace
1045      * @param revision
1046      *            current revision
1047      * @param prefix
1048      *            current prefix
1049      * @param parent
1050      *            parent builder
1051      * @return TypeDefinition object based on parsed values.
1052      */
1053     public static TypeDefinition<?> parseTypeWithBody(final String typeName, final Type_body_stmtsContext typeBody,
1054             final Stack<QName> actualPath, final URI namespace, final Date revision, final String prefix,
1055             final Builder parent) {
1056
1057         final String moduleName = parent.getModuleName();
1058         final int line = typeBody.getStart().getLine();
1059         TypeDefinition<?> baseType = null;
1060
1061         Integer fractionDigits = getFractionDigits(typeBody, moduleName);
1062         List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleName);
1063         List<PatternConstraint> patternStatements = getPatternConstraint(typeBody);
1064         List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleName);
1065
1066         TypeConstraints constraints = new TypeConstraints(moduleName, line);
1067         constraints.addFractionDigits(fractionDigits);
1068         constraints.addLengths(lengthStatements);
1069         constraints.addPatterns(patternStatements);
1070         constraints.addRanges(rangeStatements);
1071
1072         SchemaPath baseTypePath = createBaseTypePath(actualPath, typeName);
1073         SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, namespace, revision, prefix, typeName);
1074
1075         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1076             extBaseTypePath = baseTypePath;
1077         }
1078
1079         if ("decimal64".equals(typeName)) {
1080             if (rangeStatements.isEmpty()) {
1081                 try {
1082                     return new Decimal64(baseTypePath, fractionDigits);
1083                 } catch(Exception e) {
1084                     throw new YangParseException(moduleName, line, e.getMessage());
1085                 }
1086             }
1087             Decimal64 decimalType = new Decimal64(extBaseTypePath, fractionDigits);
1088             constraints.addRanges(decimalType.getRangeStatements());
1089             baseType = decimalType;
1090         } else if (typeName.startsWith("int")) {
1091             IntegerTypeDefinition intType = null;
1092             if ("int8".equals(typeName)) {
1093                 intType = Int8.getInstance();
1094             } else if ("int16".equals(typeName)) {
1095                 intType = Int16.getInstance();
1096             } else if ("int32".equals(typeName)) {
1097                 intType = Int32.getInstance();
1098             } else if ("int64".equals(typeName)) {
1099                 intType = Int64.getInstance();
1100             }
1101             if (intType == null) {
1102                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1103             }
1104             constraints.addRanges(intType.getRangeStatements());
1105             baseType = intType;
1106         } else if (typeName.startsWith("uint")) {
1107             UnsignedIntegerTypeDefinition uintType = null;
1108             if ("uint8".equals(typeName)) {
1109                 uintType = Uint8.getInstance();
1110             } else if ("uint16".equals(typeName)) {
1111                 uintType = Uint16.getInstance();
1112             } else if ("uint32".equals(typeName)) {
1113                 uintType = Uint32.getInstance();
1114             } else if ("uint64".equals(typeName)) {
1115                 uintType = Uint64.getInstance();
1116             }
1117             if (uintType == null) {
1118                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1119             }
1120             constraints.addRanges(uintType.getRangeStatements());
1121             baseType = uintType;
1122         } else if ("enumeration".equals(typeName)) {
1123             List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
1124             return new EnumerationType(baseTypePath, enumConstants);
1125         } else if ("string".equals(typeName)) {
1126             StringTypeDefinition stringType = StringType.getIntance();
1127             constraints.addLengths(stringType.getLengthStatements());
1128             baseType = stringType;
1129         } else if ("bits".equals(typeName)) {
1130             return new BitsType(baseTypePath, getBits(typeBody, actualPath, moduleName));
1131         } else if ("leafref".equals(typeName)) {
1132             final String path = parseLeafrefPath(typeBody);
1133             final boolean absolute = path.startsWith("/");
1134             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
1135             return new Leafref(xpath);
1136         } else if ("binary".equals(typeName)) {
1137             BinaryTypeDefinition binaryType = BinaryType.getInstance();
1138             constraints.addLengths(binaryType.getLengthConstraints());
1139             baseType = binaryType;
1140         } else if ("instance-identifier".equals(typeName)) {
1141             boolean requireInstance = isRequireInstance(typeBody);
1142             return new InstanceIdentifier(null, requireInstance);
1143         }
1144
1145         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1146             TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1147             typedef.setRanges(constraints.getRange());
1148             typedef.setLengths(constraints.getLength());
1149             typedef.setPatterns(constraints.getPatterns());
1150             typedef.setFractionDigits(constraints.getFractionDigits());
1151             return baseType;
1152         }
1153
1154         TypeDefinition<?> result = null;
1155         ExtendedType.Builder typeBuilder = null;
1156
1157         List<QName> path = new ArrayList<QName>(actualPath);
1158         path.add(new QName(namespace, revision, prefix, typeName));
1159         SchemaPath schemaPath = new SchemaPath(path, true);
1160
1161         QName qname = schemaPath.getPath().get(schemaPath.getPath().size() - 1);
1162         typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath);
1163
1164         typeBuilder.ranges(constraints.getRange());
1165         typeBuilder.lengths(constraints.getLength());
1166         typeBuilder.patterns(constraints.getPatterns());
1167         typeBuilder.fractionDigits(constraints.getFractionDigits());
1168
1169         result = typeBuilder.build();
1170         return result;
1171     }
1172
1173     private static SchemaPath createTypePath(Stack<QName> actual, String typeName) {
1174         QName last = actual.peek();
1175         QName typeQName = new QName(last.getNamespace(), last.getRevision(), last.getPrefix(), typeName);
1176         List<QName> path = new ArrayList<QName>(actual);
1177         path.add(typeQName);
1178         return new SchemaPath(path, true);
1179     }
1180
1181     private static SchemaPath createBaseTypePath(Stack<QName> actual, String typeName) {
1182         List<QName> path = new ArrayList<QName>(actual);
1183         path.add(BaseTypes.constructQName(typeName));
1184         return new SchemaPath(path, true);
1185     }
1186
1187     private static SchemaPath createExtendedBaseTypePath(Stack<QName> actual, URI namespace, Date revision,
1188             String prefix, String typeName) {
1189         QName extTypeName = new QName(namespace, revision, prefix, typeName);
1190         QName baseTypeName = BaseTypes.constructQName(typeName);
1191         List<QName> path = new ArrayList<QName>(actual);
1192         path.add(extTypeName);
1193         path.add(baseTypeName);
1194         return new SchemaPath(path, true);
1195     }
1196
1197     /**
1198      * Parse given context and find identityref base value.
1199      *
1200      * @param ctx
1201      *            type body
1202      * @return identityref base value as String
1203      */
1204     public static String getIdentityrefBase(Type_body_stmtsContext ctx) {
1205         String result = null;
1206         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1207             ParseTree child = ctx.getChild(i);
1208             if (child instanceof Identityref_specificationContext) {
1209                 for (int j = 0; j < child.getChildCount(); j++) {
1210                     ParseTree baseArg = child.getChild(j);
1211                     if (baseArg instanceof Base_stmtContext) {
1212                         result = stringFromNode(baseArg);
1213                         break outer;
1214                     }
1215                 }
1216             }
1217         }
1218         return result;
1219     }
1220
1221     /**
1222      * Parse type body statement and find require-instance value.
1223      *
1224      * @param ctx
1225      *            type body context
1226      * @return require-instance value
1227      */
1228     private static boolean isRequireInstance(Type_body_stmtsContext ctx) {
1229         for (int i = 0; i < ctx.getChildCount(); i++) {
1230             ParseTree child = ctx.getChild(i);
1231             if (child instanceof Instance_identifier_specificationContext) {
1232                 for (int j = 0; j < child.getChildCount(); j++) {
1233                     ParseTree reqStmt = child.getChild(j);
1234                     if (reqStmt instanceof Require_instance_stmtContext) {
1235                         for (int k = 0; k < reqStmt.getChildCount(); k++) {
1236                             ParseTree reqArg = reqStmt.getChild(k);
1237                             if (reqArg instanceof Require_instance_argContext) {
1238                                 return Boolean.valueOf(stringFromNode(reqArg));
1239                             }
1240                         }
1241                     }
1242                 }
1243             }
1244         }
1245         return true;
1246     }
1247
1248     /**
1249      * Parse type body statement and find leafref path.
1250      *
1251      * @param ctx
1252      *            type body context
1253      * @return leafref path as String
1254      */
1255     private static String parseLeafrefPath(Type_body_stmtsContext ctx) {
1256         for (int i = 0; i < ctx.getChildCount(); i++) {
1257             ParseTree child = ctx.getChild(i);
1258             if (child instanceof Leafref_specificationContext) {
1259                 for (int j = 0; j < child.getChildCount(); j++) {
1260                     ParseTree leafRefSpec = child.getChild(j);
1261                     if (leafRefSpec instanceof Path_stmtContext) {
1262                         return stringFromNode(leafRefSpec);
1263                     }
1264                 }
1265             }
1266         }
1267         return null;
1268     }
1269
1270     /**
1271      * Internal helper method for parsing must statement.
1272      *
1273      * @param ctx
1274      *            Must_stmtContext
1275      * @return MustDefinition object based on parsed context
1276      */
1277     public static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
1278         StringBuilder mustText = new StringBuilder();
1279         String description = null;
1280         String reference = null;
1281         String errorAppTag = null;
1282         String errorMessage = null;
1283         for (int i = 0; i < ctx.getChildCount(); ++i) {
1284             ParseTree child = ctx.getChild(i);
1285             if (child instanceof StringContext) {
1286                 final StringContext context = (StringContext) child;
1287                 if (context.getChildCount() == 1) {
1288                     String mustPart = context.getChild(0).getText();
1289                     // trim start and end quotation
1290                     mustText.append(mustPart.substring(1, mustPart.length() - 1));
1291                 } else {
1292                     for (int j = 0; j < context.getChildCount(); j++) {
1293                         String mustPart = context.getChild(j).getText();
1294                         if (j == 0) {
1295                             mustText.append(mustPart.substring(0, mustPart.length() - 1));
1296                             continue;
1297                         }
1298                         if (j % 2 == 0) {
1299                             mustText.append(mustPart.substring(1));
1300                         }
1301                     }
1302                 }
1303             } else if (child instanceof Description_stmtContext) {
1304                 description = stringFromNode(child);
1305             } else if (child instanceof Reference_stmtContext) {
1306                 reference = stringFromNode(child);
1307             } else if (child instanceof Error_app_tag_stmtContext) {
1308                 errorAppTag = stringFromNode(child);
1309             } else if (child instanceof Error_message_stmtContext) {
1310                 errorMessage = stringFromNode(child);
1311             }
1312         }
1313
1314         MustDefinition must = new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag,
1315                 errorMessage);
1316         return must;
1317     }
1318
1319     /**
1320      * Parse given context and set constraints to constraints builder.
1321      *
1322      * @param ctx
1323      *            context to parse
1324      * @param constraints
1325      *            ConstraintsBuilder to fill
1326      */
1327     public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) {
1328         for (int i = 0; i < ctx.getChildCount(); ++i) {
1329             final ParseTree childNode = ctx.getChild(i);
1330             if (childNode instanceof Max_elements_stmtContext) {
1331                 Integer max = parseMaxElements((Max_elements_stmtContext) childNode, constraints.getModuleName());
1332                 constraints.setMaxElements(max);
1333             } else if (childNode instanceof Min_elements_stmtContext) {
1334                 Integer min = parseMinElements((Min_elements_stmtContext) childNode, constraints.getModuleName());
1335                 constraints.setMinElements(min);
1336             } else if (childNode instanceof Must_stmtContext) {
1337                 MustDefinition must = parseMust((Must_stmtContext) childNode);
1338                 constraints.addMustDefinition(must);
1339             } else if (childNode instanceof Mandatory_stmtContext) {
1340                 for (int j = 0; j < childNode.getChildCount(); j++) {
1341                     ParseTree mandatoryTree = childNode.getChild(j);
1342                     if (mandatoryTree instanceof Mandatory_argContext) {
1343                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1344                         constraints.setMandatory(mandatory);
1345                     }
1346                 }
1347             } else if (childNode instanceof When_stmtContext) {
1348                 constraints.addWhenCondition(stringFromNode(childNode));
1349             }
1350         }
1351     }
1352
1353     private static Integer parseMinElements(Min_elements_stmtContext ctx, String moduleName) {
1354         Integer result = null;
1355         try {
1356             for (int i = 0; i < ctx.getChildCount(); i++) {
1357                 ParseTree minArg = ctx.getChild(i);
1358                 if (minArg instanceof Min_value_argContext) {
1359                     result = Integer.valueOf(stringFromNode(minArg));
1360                 }
1361             }
1362             if (result == null) {
1363                 throw new IllegalArgumentException();
1364             }
1365             return result;
1366         } catch (Exception e) {
1367             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
1368         }
1369     }
1370
1371     private static Integer parseMaxElements(Max_elements_stmtContext ctx, String moduleName) {
1372         Integer result = null;
1373         try {
1374             for (int i = 0; i < ctx.getChildCount(); i++) {
1375                 ParseTree maxArg = ctx.getChild(i);
1376                 if (maxArg instanceof Max_value_argContext) {
1377                     result = Integer.valueOf(stringFromNode(maxArg));
1378                 }
1379             }
1380             if (result == null) {
1381                 throw new IllegalArgumentException();
1382             }
1383             return result;
1384         } catch (Exception e) {
1385             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
1386         }
1387     }
1388
1389     /**
1390      * Parse given context and return yin value.
1391      *
1392      * @param ctx
1393      *            context to parse
1394      * @return true if value is 'true', false otherwise
1395      */
1396     public static boolean parseYinValue(Argument_stmtContext ctx) {
1397         boolean yinValue = false;
1398         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1399             ParseTree yin = ctx.getChild(i);
1400             if (yin instanceof Yin_element_stmtContext) {
1401                 for (int j = 0; j < yin.getChildCount(); j++) {
1402                     ParseTree yinArg = yin.getChild(j);
1403                     if (yinArg instanceof Yin_element_argContext) {
1404                         String yinString = stringFromNode(yinArg);
1405                         if ("true".equals(yinString)) {
1406                             yinValue = true;
1407                             break outer;
1408                         }
1409                     }
1410                 }
1411             }
1412         }
1413         return yinValue;
1414     }
1415
1416     /**
1417      * Check this base type.
1418      *
1419      * @param typeName
1420      *            base YANG type name
1421      * @param moduleName
1422      *            name of current module
1423      * @param line
1424      *            line in module
1425      * @throws YangParseException
1426      *             if this is one of YANG type which MUST contain additional
1427      *             informations in its body
1428      */
1429     public static void checkMissingBody(final String typeName, final String moduleName, final int line)
1430             throws YangParseException {
1431         if ("decimal64".equals(typeName)) {
1432             throw new YangParseException(moduleName, line,
1433                     "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1434         } else if ("identityref".equals(typeName)) {
1435             throw new YangParseException(moduleName, line,
1436                     "The 'base' statement MUST be present if the type is 'identityref'.");
1437         } else if ("leafref".equals(typeName)) {
1438             throw new YangParseException(moduleName, line,
1439                     "The 'path' statement MUST be present if the type is 'leafref'.");
1440         } else if ("bits".equals(typeName)) {
1441             throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
1442         } else if ("enumeration".equals(typeName)) {
1443             throw new YangParseException(moduleName, line,
1444                     "The 'enum' statement MUST be present if the type is 'enumeration'.");
1445         }
1446     }
1447
1448     /**
1449      * Parse refine statement.
1450      *
1451      * @param refineCtx
1452      *            refine statement
1453      * @param moduleName name of current module
1454      * @return RefineHolder object representing this refine statement
1455      */
1456     public static RefineHolder parseRefine(Refine_stmtContext refineCtx, String moduleName) {
1457         final String refineTarget = stringFromNode(refineCtx);
1458         final RefineHolder refine = new RefineHolder(moduleName, refineCtx.getStart().getLine(), refineTarget);
1459         for (int i = 0; i < refineCtx.getChildCount(); i++) {
1460             ParseTree refinePom = refineCtx.getChild(i);
1461             if (refinePom instanceof Refine_pomContext) {
1462                 for (int j = 0; j < refinePom.getChildCount(); j++) {
1463                     ParseTree refineStmt = refinePom.getChild(j);
1464                     parseRefineDefault(refine, refineStmt);
1465
1466                     if (refineStmt instanceof Refine_leaf_stmtsContext) {
1467                         parseRefine(refine, (Refine_leaf_stmtsContext) refineStmt);
1468                     } else if (refineStmt instanceof Refine_container_stmtsContext) {
1469                         parseRefine(refine, (Refine_container_stmtsContext) refineStmt);
1470                     } else if (refineStmt instanceof Refine_list_stmtsContext) {
1471                         parseRefine(refine, (Refine_list_stmtsContext) refineStmt);
1472                     } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1473                         parseRefine(refine, (Refine_leaf_list_stmtsContext) refineStmt);
1474                     } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1475                         parseRefine(refine, (Refine_choice_stmtsContext) refineStmt);
1476                     } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1477                         parseRefine(refine, (Refine_anyxml_stmtsContext) refineStmt);
1478                     }
1479                 }
1480             }
1481         }
1482         return refine;
1483     }
1484
1485     private static void parseRefineDefault(RefineHolder refine, ParseTree refineStmt) {
1486         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1487             ParseTree refineArg = refineStmt.getChild(i);
1488             if (refineArg instanceof Description_stmtContext) {
1489                 String description = stringFromNode(refineArg);
1490                 refine.setDescription(description);
1491             } else if (refineArg instanceof Reference_stmtContext) {
1492                 String reference = stringFromNode(refineArg);
1493                 refine.setReference(reference);
1494             } else if (refineArg instanceof Config_stmtContext) {
1495                 Boolean config = parseConfig((Config_stmtContext) refineArg, refine.getModuleName());
1496                 refine.setConfiguration(config);
1497             }
1498         }
1499     }
1500
1501     private static RefineHolder parseRefine(RefineHolder refine, Refine_leaf_stmtsContext refineStmt) {
1502         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1503             ParseTree refineArg = refineStmt.getChild(i);
1504             if (refineArg instanceof Default_stmtContext) {
1505                 String defaultStr = stringFromNode(refineArg);
1506                 refine.setDefaultStr(defaultStr);
1507             } else if (refineArg instanceof Mandatory_stmtContext) {
1508                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1509                     ParseTree mandatoryTree = refineArg.getChild(j);
1510                     if (mandatoryTree instanceof Mandatory_argContext) {
1511                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1512                         refine.setMandatory(mandatory);
1513                     }
1514                 }
1515             } else if (refineArg instanceof Must_stmtContext) {
1516                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1517                 refine.setMust(must);
1518
1519             }
1520         }
1521         return refine;
1522     }
1523
1524     private static RefineHolder parseRefine(RefineHolder refine, Refine_container_stmtsContext refineStmt) {
1525         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1526             ParseTree refineArg = refineStmt.getChild(i);
1527             if (refineArg instanceof Must_stmtContext) {
1528                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1529                 refine.setMust(must);
1530             } else if (refineArg instanceof Presence_stmtContext) {
1531                 refine.setPresence(true);
1532             }
1533         }
1534         return refine;
1535     }
1536
1537     private static RefineHolder parseRefine(RefineHolder refine, Refine_list_stmtsContext refineStmt) {
1538         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1539             ParseTree refineArg = refineStmt.getChild(i);
1540             if (refineArg instanceof Must_stmtContext) {
1541                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1542                 refine.setMust(must);
1543             } else if (refineArg instanceof Max_elements_stmtContext) {
1544                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1545                 refine.setMaxElements(max);
1546             } else if (refineArg instanceof Min_elements_stmtContext) {
1547                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1548                 refine.setMinElements(min);
1549             }
1550         }
1551         return refine;
1552     }
1553
1554     private static RefineHolder parseRefine(RefineHolder refine, Refine_leaf_list_stmtsContext refineStmt) {
1555         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1556             ParseTree refineArg = refineStmt.getChild(i);
1557             if (refineArg instanceof Must_stmtContext) {
1558                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1559                 refine.setMust(must);
1560             } else if (refineArg instanceof Max_elements_stmtContext) {
1561                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1562                 refine.setMaxElements(max);
1563             } else if (refineArg instanceof Min_elements_stmtContext) {
1564                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1565                 refine.setMinElements(min);
1566             }
1567         }
1568         return refine;
1569     }
1570
1571     private static RefineHolder parseRefine(RefineHolder refine, Refine_choice_stmtsContext refineStmt) {
1572         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1573             ParseTree refineArg = refineStmt.getChild(i);
1574             if (refineArg instanceof Default_stmtContext) {
1575                 String defaultStr = stringFromNode(refineArg);
1576                 refine.setDefaultStr(defaultStr);
1577             } else if (refineArg instanceof Mandatory_stmtContext) {
1578                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1579                     ParseTree mandatoryTree = refineArg.getChild(j);
1580                     if (mandatoryTree instanceof Mandatory_argContext) {
1581                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1582                         refine.setMandatory(mandatory);
1583                     }
1584                 }
1585             }
1586         }
1587         return refine;
1588     }
1589
1590     private static RefineHolder parseRefine(RefineHolder refine, Refine_anyxml_stmtsContext refineStmt) {
1591         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1592             ParseTree refineArg = refineStmt.getChild(i);
1593             if (refineArg instanceof Must_stmtContext) {
1594                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1595                 refine.setMust(must);
1596             } else if (refineArg instanceof Mandatory_stmtContext) {
1597                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1598                     ParseTree mandatoryTree = refineArg.getChild(j);
1599                     if (mandatoryTree instanceof Mandatory_argContext) {
1600                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1601                         refine.setMandatory(mandatory);
1602                     }
1603                 }
1604             }
1605         }
1606         return refine;
1607     }
1608
1609 }