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