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