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