Fixed resolving of leafref types with relative xpath.
[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                 return new Decimal64(baseTypePath, fractionDigits);
1082             }
1083             Decimal64 decimalType = new Decimal64(extBaseTypePath, fractionDigits);
1084             constraints.addRanges(decimalType.getRangeStatements());
1085             baseType = decimalType;
1086         } else if (typeName.startsWith("int")) {
1087             IntegerTypeDefinition intType = null;
1088             if ("int8".equals(typeName)) {
1089                 intType = Int8.getInstance();
1090             } else if ("int16".equals(typeName)) {
1091                 intType = Int16.getInstance();
1092             } else if ("int32".equals(typeName)) {
1093                 intType = Int32.getInstance();
1094             } else if ("int64".equals(typeName)) {
1095                 intType = Int64.getInstance();
1096             }
1097             if (intType == null) {
1098                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1099             }
1100             constraints.addRanges(intType.getRangeStatements());
1101             baseType = intType;
1102         } else if (typeName.startsWith("uint")) {
1103             UnsignedIntegerTypeDefinition uintType = null;
1104             if ("uint8".equals(typeName)) {
1105                 uintType = Uint8.getInstance();
1106             } else if ("uint16".equals(typeName)) {
1107                 uintType = Uint16.getInstance();
1108             } else if ("uint32".equals(typeName)) {
1109                 uintType = Uint32.getInstance();
1110             } else if ("uint64".equals(typeName)) {
1111                 uintType = Uint64.getInstance();
1112             }
1113             if (uintType == null) {
1114                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1115             }
1116             constraints.addRanges(uintType.getRangeStatements());
1117             baseType = uintType;
1118         } else if ("enumeration".equals(typeName)) {
1119             List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
1120             return new EnumerationType(baseTypePath, enumConstants);
1121         } else if ("string".equals(typeName)) {
1122             StringTypeDefinition stringType = StringType.getIntance();
1123             constraints.addLengths(stringType.getLengthStatements());
1124             baseType = stringType;
1125         } else if ("bits".equals(typeName)) {
1126             return new BitsType(baseTypePath, getBits(typeBody, actualPath, moduleName));
1127         } else if ("leafref".equals(typeName)) {
1128             final String path = parseLeafrefPath(typeBody);
1129             final boolean absolute = path.startsWith("/");
1130             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
1131             return new Leafref(xpath);
1132         } else if ("binary".equals(typeName)) {
1133             BinaryTypeDefinition binaryType = BinaryType.getInstance();
1134             constraints.addLengths(binaryType.getLengthConstraints());
1135             baseType = binaryType;
1136         } else if ("instance-identifier".equals(typeName)) {
1137             boolean requireInstance = isRequireInstance(typeBody);
1138             return new InstanceIdentifier(null, requireInstance);
1139         }
1140
1141         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1142             TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1143             typedef.setRanges(constraints.getRange());
1144             typedef.setLengths(constraints.getLength());
1145             typedef.setPatterns(constraints.getPatterns());
1146             typedef.setFractionDigits(constraints.getFractionDigits());
1147             return baseType;
1148         }
1149
1150         TypeDefinition<?> result = null;
1151         ExtendedType.Builder typeBuilder = null;
1152
1153         List<QName> path = new ArrayList<QName>(actualPath);
1154         path.add(new QName(namespace, revision, prefix, typeName));
1155         SchemaPath schemaPath = new SchemaPath(path, true);
1156
1157         QName qname = schemaPath.getPath().get(schemaPath.getPath().size() - 1);
1158         typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath);
1159
1160         typeBuilder.ranges(constraints.getRange());
1161         typeBuilder.lengths(constraints.getLength());
1162         typeBuilder.patterns(constraints.getPatterns());
1163         typeBuilder.fractionDigits(constraints.getFractionDigits());
1164
1165         result = typeBuilder.build();
1166         return result;
1167     }
1168
1169     private static SchemaPath createTypePath(Stack<QName> actual, String typeName) {
1170         QName last = actual.peek();
1171         QName typeQName = new QName(last.getNamespace(), last.getRevision(), last.getPrefix(), typeName);
1172         List<QName> path = new ArrayList<QName>(actual);
1173         path.add(typeQName);
1174         return new SchemaPath(path, true);
1175     }
1176
1177     private static SchemaPath createBaseTypePath(Stack<QName> actual, String typeName) {
1178         List<QName> path = new ArrayList<QName>(actual);
1179         path.add(BaseTypes.constructQName(typeName));
1180         return new SchemaPath(path, true);
1181     }
1182
1183     private static SchemaPath createExtendedBaseTypePath(Stack<QName> actual, URI namespace, Date revision,
1184             String prefix, String typeName) {
1185         QName extTypeName = new QName(namespace, revision, prefix, typeName);
1186         QName baseTypeName = BaseTypes.constructQName(typeName);
1187         List<QName> path = new ArrayList<QName>(actual);
1188         path.add(extTypeName);
1189         path.add(baseTypeName);
1190         return new SchemaPath(path, true);
1191     }
1192
1193     /**
1194      * Parse given context and find identityref base value.
1195      *
1196      * @param ctx
1197      *            type body
1198      * @return identityref base value as String
1199      */
1200     public static String getIdentityrefBase(Type_body_stmtsContext ctx) {
1201         String result = null;
1202         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1203             ParseTree child = ctx.getChild(i);
1204             if (child instanceof Identityref_specificationContext) {
1205                 for (int j = 0; j < child.getChildCount(); j++) {
1206                     ParseTree baseArg = child.getChild(j);
1207                     if (baseArg instanceof Base_stmtContext) {
1208                         result = stringFromNode(baseArg);
1209                         break outer;
1210                     }
1211                 }
1212             }
1213         }
1214         return result;
1215     }
1216
1217     /**
1218      * Parse type body statement and find require-instance value.
1219      *
1220      * @param ctx
1221      *            type body context
1222      * @return require-instance value
1223      */
1224     private static boolean isRequireInstance(Type_body_stmtsContext ctx) {
1225         for (int i = 0; i < ctx.getChildCount(); i++) {
1226             ParseTree child = ctx.getChild(i);
1227             if (child instanceof Instance_identifier_specificationContext) {
1228                 for (int j = 0; j < child.getChildCount(); j++) {
1229                     ParseTree reqStmt = child.getChild(j);
1230                     if (reqStmt instanceof Require_instance_stmtContext) {
1231                         for (int k = 0; k < reqStmt.getChildCount(); k++) {
1232                             ParseTree reqArg = reqStmt.getChild(k);
1233                             if (reqArg instanceof Require_instance_argContext) {
1234                                 return Boolean.valueOf(stringFromNode(reqArg));
1235                             }
1236                         }
1237                     }
1238                 }
1239             }
1240         }
1241         return true;
1242     }
1243
1244     /**
1245      * Parse type body statement and find leafref path.
1246      *
1247      * @param ctx
1248      *            type body context
1249      * @return leafref path as String
1250      */
1251     private static String parseLeafrefPath(Type_body_stmtsContext ctx) {
1252         for (int i = 0; i < ctx.getChildCount(); i++) {
1253             ParseTree child = ctx.getChild(i);
1254             if (child instanceof Leafref_specificationContext) {
1255                 for (int j = 0; j < child.getChildCount(); j++) {
1256                     ParseTree leafRefSpec = child.getChild(j);
1257                     if (leafRefSpec instanceof Path_stmtContext) {
1258                         return stringFromNode(leafRefSpec);
1259                     }
1260                 }
1261             }
1262         }
1263         return null;
1264     }
1265
1266     /**
1267      * Internal helper method for parsing must statement.
1268      *
1269      * @param ctx
1270      *            Must_stmtContext
1271      * @return MustDefinition object based on parsed context
1272      */
1273     public static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
1274         StringBuilder mustText = new StringBuilder();
1275         String description = null;
1276         String reference = null;
1277         String errorAppTag = null;
1278         String errorMessage = null;
1279         for (int i = 0; i < ctx.getChildCount(); ++i) {
1280             ParseTree child = ctx.getChild(i);
1281             if (child instanceof StringContext) {
1282                 final StringContext context = (StringContext) child;
1283                 if (context.getChildCount() == 1) {
1284                     String mustPart = context.getChild(0).getText();
1285                     // trim start and end quotation
1286                     mustText.append(mustPart.substring(1, mustPart.length() - 1));
1287                 } else {
1288                     for (int j = 0; j < context.getChildCount(); j++) {
1289                         String mustPart = context.getChild(j).getText();
1290                         if (j == 0) {
1291                             mustText.append(mustPart.substring(0, mustPart.length() - 1));
1292                             continue;
1293                         }
1294                         if (j % 2 == 0) {
1295                             mustText.append(mustPart.substring(1));
1296                         }
1297                     }
1298                 }
1299             } else if (child instanceof Description_stmtContext) {
1300                 description = stringFromNode(child);
1301             } else if (child instanceof Reference_stmtContext) {
1302                 reference = stringFromNode(child);
1303             } else if (child instanceof Error_app_tag_stmtContext) {
1304                 errorAppTag = stringFromNode(child);
1305             } else if (child instanceof Error_message_stmtContext) {
1306                 errorMessage = stringFromNode(child);
1307             }
1308         }
1309
1310         MustDefinition must = new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag,
1311                 errorMessage);
1312         return must;
1313     }
1314
1315     /**
1316      * Parse given context and set constraints to constraints builder.
1317      *
1318      * @param ctx
1319      *            context to parse
1320      * @param constraints
1321      *            ConstraintsBuilder to fill
1322      */
1323     public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) {
1324         for (int i = 0; i < ctx.getChildCount(); ++i) {
1325             final ParseTree childNode = ctx.getChild(i);
1326             if (childNode instanceof Max_elements_stmtContext) {
1327                 Integer max = parseMaxElements((Max_elements_stmtContext) childNode, constraints.getModuleName());
1328                 constraints.setMaxElements(max);
1329             } else if (childNode instanceof Min_elements_stmtContext) {
1330                 Integer min = parseMinElements((Min_elements_stmtContext) childNode, constraints.getModuleName());
1331                 constraints.setMinElements(min);
1332             } else if (childNode instanceof Must_stmtContext) {
1333                 MustDefinition must = parseMust((Must_stmtContext) childNode);
1334                 constraints.addMustDefinition(must);
1335             } else if (childNode instanceof Mandatory_stmtContext) {
1336                 for (int j = 0; j < childNode.getChildCount(); j++) {
1337                     ParseTree mandatoryTree = childNode.getChild(j);
1338                     if (mandatoryTree instanceof Mandatory_argContext) {
1339                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1340                         constraints.setMandatory(mandatory);
1341                     }
1342                 }
1343             } else if (childNode instanceof When_stmtContext) {
1344                 constraints.addWhenCondition(stringFromNode(childNode));
1345             }
1346         }
1347     }
1348
1349     private static Integer parseMinElements(Min_elements_stmtContext ctx, String moduleName) {
1350         Integer result = null;
1351         try {
1352             for (int i = 0; i < ctx.getChildCount(); i++) {
1353                 ParseTree minArg = ctx.getChild(i);
1354                 if (minArg instanceof Min_value_argContext) {
1355                     result = Integer.valueOf(stringFromNode(minArg));
1356                 }
1357             }
1358             if (result == null) {
1359                 throw new IllegalArgumentException();
1360             }
1361             return result;
1362         } catch (Exception e) {
1363             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
1364         }
1365     }
1366
1367     private static Integer parseMaxElements(Max_elements_stmtContext ctx, String moduleName) {
1368         Integer result = null;
1369         try {
1370             for (int i = 0; i < ctx.getChildCount(); i++) {
1371                 ParseTree maxArg = ctx.getChild(i);
1372                 if (maxArg instanceof Max_value_argContext) {
1373                     result = Integer.valueOf(stringFromNode(maxArg));
1374                 }
1375             }
1376             if (result == null) {
1377                 throw new IllegalArgumentException();
1378             }
1379             return result;
1380         } catch (Exception e) {
1381             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
1382         }
1383     }
1384
1385     /**
1386      * Parse given context and return yin value.
1387      *
1388      * @param ctx
1389      *            context to parse
1390      * @return true if value is 'true', false otherwise
1391      */
1392     public static boolean parseYinValue(Argument_stmtContext ctx) {
1393         boolean yinValue = false;
1394         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1395             ParseTree yin = ctx.getChild(i);
1396             if (yin instanceof Yin_element_stmtContext) {
1397                 for (int j = 0; j < yin.getChildCount(); j++) {
1398                     ParseTree yinArg = yin.getChild(j);
1399                     if (yinArg instanceof Yin_element_argContext) {
1400                         String yinString = stringFromNode(yinArg);
1401                         if ("true".equals(yinString)) {
1402                             yinValue = true;
1403                             break outer;
1404                         }
1405                     }
1406                 }
1407             }
1408         }
1409         return yinValue;
1410     }
1411
1412     /**
1413      * Check this base type.
1414      *
1415      * @param typeName
1416      *            base YANG type name
1417      * @param moduleName
1418      *            name of current module
1419      * @param line
1420      *            line in module
1421      * @throws YangParseException
1422      *             if this is one of YANG type which MUST contain additional
1423      *             informations in its body
1424      */
1425     public static void checkMissingBody(final String typeName, final String moduleName, final int line)
1426             throws YangParseException {
1427         if ("decimal64".equals(typeName)) {
1428             throw new YangParseException(moduleName, line,
1429                     "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1430         } else if ("identityref".equals(typeName)) {
1431             throw new YangParseException(moduleName, line,
1432                     "The 'base' statement MUST be present if the type is 'identityref'.");
1433         } else if ("leafref".equals(typeName)) {
1434             throw new YangParseException(moduleName, line,
1435                     "The 'path' statement MUST be present if the type is 'leafref'.");
1436         } else if ("bits".equals(typeName)) {
1437             throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
1438         } else if ("enumeration".equals(typeName)) {
1439             throw new YangParseException(moduleName, line,
1440                     "The 'enum' statement MUST be present if the type is 'enumeration'.");
1441         }
1442     }
1443
1444     /**
1445      * Parse refine statement.
1446      *
1447      * @param refineCtx
1448      *            refine statement
1449      * @param moduleName name of current module
1450      * @return RefineHolder object representing this refine statement
1451      */
1452     public static RefineHolder parseRefine(Refine_stmtContext refineCtx, String moduleName) {
1453         final String refineTarget = stringFromNode(refineCtx);
1454         final RefineHolder refine = new RefineHolder(moduleName, refineCtx.getStart().getLine(), refineTarget);
1455         for (int i = 0; i < refineCtx.getChildCount(); i++) {
1456             ParseTree refinePom = refineCtx.getChild(i);
1457             if (refinePom instanceof Refine_pomContext) {
1458                 for (int j = 0; j < refinePom.getChildCount(); j++) {
1459                     ParseTree refineStmt = refinePom.getChild(j);
1460                     parseRefineDefault(refine, refineStmt);
1461
1462                     if (refineStmt instanceof Refine_leaf_stmtsContext) {
1463                         parseRefine(refine, (Refine_leaf_stmtsContext) refineStmt);
1464                     } else if (refineStmt instanceof Refine_container_stmtsContext) {
1465                         parseRefine(refine, (Refine_container_stmtsContext) refineStmt);
1466                     } else if (refineStmt instanceof Refine_list_stmtsContext) {
1467                         parseRefine(refine, (Refine_list_stmtsContext) refineStmt);
1468                     } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1469                         parseRefine(refine, (Refine_leaf_list_stmtsContext) refineStmt);
1470                     } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1471                         parseRefine(refine, (Refine_choice_stmtsContext) refineStmt);
1472                     } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1473                         parseRefine(refine, (Refine_anyxml_stmtsContext) refineStmt);
1474                     }
1475                 }
1476             }
1477         }
1478         return refine;
1479     }
1480
1481     private static void parseRefineDefault(RefineHolder refine, ParseTree refineStmt) {
1482         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1483             ParseTree refineArg = refineStmt.getChild(i);
1484             if (refineArg instanceof Description_stmtContext) {
1485                 String description = stringFromNode(refineArg);
1486                 refine.setDescription(description);
1487             } else if (refineArg instanceof Reference_stmtContext) {
1488                 String reference = stringFromNode(refineArg);
1489                 refine.setReference(reference);
1490             } else if (refineArg instanceof Config_stmtContext) {
1491                 Boolean config = parseConfig((Config_stmtContext) refineArg, refine.getModuleName());
1492                 refine.setConfiguration(config);
1493             }
1494         }
1495     }
1496
1497     private static RefineHolder parseRefine(RefineHolder refine, Refine_leaf_stmtsContext refineStmt) {
1498         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1499             ParseTree refineArg = refineStmt.getChild(i);
1500             if (refineArg instanceof Default_stmtContext) {
1501                 String defaultStr = stringFromNode(refineArg);
1502                 refine.setDefaultStr(defaultStr);
1503             } else if (refineArg instanceof Mandatory_stmtContext) {
1504                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1505                     ParseTree mandatoryTree = refineArg.getChild(j);
1506                     if (mandatoryTree instanceof Mandatory_argContext) {
1507                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1508                         refine.setMandatory(mandatory);
1509                     }
1510                 }
1511             } else if (refineArg instanceof Must_stmtContext) {
1512                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1513                 refine.setMust(must);
1514
1515             }
1516         }
1517         return refine;
1518     }
1519
1520     private static RefineHolder parseRefine(RefineHolder refine, Refine_container_stmtsContext refineStmt) {
1521         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1522             ParseTree refineArg = refineStmt.getChild(i);
1523             if (refineArg instanceof Must_stmtContext) {
1524                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1525                 refine.setMust(must);
1526             } else if (refineArg instanceof Presence_stmtContext) {
1527                 refine.setPresence(true);
1528             }
1529         }
1530         return refine;
1531     }
1532
1533     private static RefineHolder parseRefine(RefineHolder refine, Refine_list_stmtsContext refineStmt) {
1534         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1535             ParseTree refineArg = refineStmt.getChild(i);
1536             if (refineArg instanceof Must_stmtContext) {
1537                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1538                 refine.setMust(must);
1539             } else if (refineArg instanceof Max_elements_stmtContext) {
1540                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1541                 refine.setMaxElements(max);
1542             } else if (refineArg instanceof Min_elements_stmtContext) {
1543                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1544                 refine.setMinElements(min);
1545             }
1546         }
1547         return refine;
1548     }
1549
1550     private static RefineHolder parseRefine(RefineHolder refine, Refine_leaf_list_stmtsContext refineStmt) {
1551         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1552             ParseTree refineArg = refineStmt.getChild(i);
1553             if (refineArg instanceof Must_stmtContext) {
1554                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1555                 refine.setMust(must);
1556             } else if (refineArg instanceof Max_elements_stmtContext) {
1557                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1558                 refine.setMaxElements(max);
1559             } else if (refineArg instanceof Min_elements_stmtContext) {
1560                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1561                 refine.setMinElements(min);
1562             }
1563         }
1564         return refine;
1565     }
1566
1567     private static RefineHolder parseRefine(RefineHolder refine, Refine_choice_stmtsContext refineStmt) {
1568         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1569             ParseTree refineArg = refineStmt.getChild(i);
1570             if (refineArg instanceof Default_stmtContext) {
1571                 String defaultStr = stringFromNode(refineArg);
1572                 refine.setDefaultStr(defaultStr);
1573             } else if (refineArg instanceof Mandatory_stmtContext) {
1574                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1575                     ParseTree mandatoryTree = refineArg.getChild(j);
1576                     if (mandatoryTree instanceof Mandatory_argContext) {
1577                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1578                         refine.setMandatory(mandatory);
1579                     }
1580                 }
1581             }
1582         }
1583         return refine;
1584     }
1585
1586     private static RefineHolder parseRefine(RefineHolder refine, Refine_anyxml_stmtsContext refineStmt) {
1587         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1588             ParseTree refineArg = refineStmt.getChild(i);
1589             if (refineArg instanceof Must_stmtContext) {
1590                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1591                 refine.setMust(must);
1592             } else if (refineArg instanceof Mandatory_stmtContext) {
1593                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1594                     ParseTree mandatoryTree = refineArg.getChild(j);
1595                     if (mandatoryTree instanceof Mandatory_argContext) {
1596                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1597                         refine.setMandatory(mandatory);
1598                     }
1599                 }
1600             }
1601         }
1602         return refine;
1603     }
1604
1605 }