873e3842db0097cb17ec4d1fb6dbd5edd039451b
[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         if ("decimal64".equals(typeName)) {
1012             type = new Decimal64(actualPath, namespace, revision,
1013                     fractionDigits);
1014         } else if (typeName.startsWith("int")) {
1015             if ("int8".equals(typeName)) {
1016                 type = new Int8(actualPath, namespace, revision,
1017                         rangeStatements, null, null);
1018             } else if ("int16".equals(typeName)) {
1019                 type = new Int16(actualPath, namespace, revision,
1020                         rangeStatements, null, null);
1021             } else if ("int32".equals(typeName)) {
1022                 type = new Int32(actualPath, namespace, revision,
1023                         rangeStatements, null, null);
1024             } else if ("int64".equals(typeName)) {
1025                 type = new Int64(actualPath, namespace, revision,
1026                         rangeStatements, null, null);
1027             }
1028         } else if (typeName.startsWith("uint")) {
1029             if ("uint8".equals(typeName)) {
1030                 type = new Uint8(actualPath, namespace, revision,
1031                         rangeStatements, null, null);
1032             } else if ("uint16".equals(typeName)) {
1033                 type = new Uint16(actualPath, namespace, revision,
1034                         rangeStatements, null, null);
1035             } else if ("uint32".equals(typeName)) {
1036                 type = new Uint32(actualPath, namespace, revision,
1037                         rangeStatements, null, null);
1038             } else if ("uint64".equals(typeName)) {
1039                 type = new Uint64(actualPath, namespace, revision,
1040                         rangeStatements, null, null);
1041             }
1042         } else if ("enumeration".equals(typeName)) {
1043             type = new EnumerationType(actualPath, namespace, revision,
1044                     enumConstants);
1045         } else if ("string".equals(typeName)) {
1046             type = new StringType(actualPath, namespace, revision,
1047                     lengthStatements, patternStatements);
1048         } else if ("bits".equals(typeName)) {
1049             type = new BitsType(actualPath, namespace, revision, getBits(
1050                     typeBody, actualPath, namespace, revision, prefix));
1051         } else if ("leafref".equals(typeName)) {
1052             final String path = parseLeafrefPath(typeBody);
1053             final boolean absolute = path.startsWith("/");
1054             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path,
1055                     absolute);
1056             type = new Leafref(actualPath, namespace, revision, xpath);
1057         } else if ("binary".equals(typeName)) {
1058             List<Byte> bytes = Collections.emptyList();
1059             type = new BinaryType(actualPath, namespace, revision, bytes,
1060                     lengthStatements, null);
1061         } else if ("instance-identifier".equals(typeName)) {
1062             boolean requireInstance = isRequireInstance(typeBody);
1063             type = new InstanceIdentifier(actualPath, namespace, revision,
1064                     null, requireInstance);
1065         }
1066         return type;
1067     }
1068
1069     /**
1070      * Parse given context and find identityref base value.
1071      *
1072      * @param ctx
1073      *            type body
1074      * @return identityref base value as String
1075      */
1076     public static String getIdentityrefBase(Type_body_stmtsContext ctx) {
1077         String result = null;
1078         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1079             ParseTree child = ctx.getChild(i);
1080             if (child instanceof Identityref_specificationContext) {
1081                 for (int j = 0; j < child.getChildCount(); j++) {
1082                     ParseTree baseArg = child.getChild(j);
1083                     if (baseArg instanceof Base_stmtContext) {
1084                         result = stringFromNode(baseArg);
1085                         break outer;
1086                     }
1087                 }
1088             }
1089         }
1090         return result;
1091     }
1092
1093     /**
1094      * Parse given context and find require-instance value.
1095      *
1096      * @param ctx
1097      *            type body
1098      * @return require-instance value
1099      */
1100     private static boolean isRequireInstance(Type_body_stmtsContext ctx) {
1101         for (int i = 0; i < ctx.getChildCount(); i++) {
1102             ParseTree child = ctx.getChild(i);
1103             if (child instanceof Require_instance_stmtContext) {
1104                 for (int j = 0; j < child.getChildCount(); j++) {
1105                     ParseTree reqArg = child.getChild(j);
1106                     if (reqArg instanceof Require_instance_argContext) {
1107                         return Boolean.valueOf(stringFromNode(reqArg));
1108                     }
1109                 }
1110             }
1111         }
1112         return false;
1113     }
1114
1115     /**
1116      * Parse given context and find leafref path.
1117      *
1118      * @param ctx
1119      *            type body
1120      * @return leafref path as String
1121      */
1122     private static String parseLeafrefPath(Type_body_stmtsContext ctx) {
1123         for (int i = 0; i < ctx.getChildCount(); i++) {
1124             ParseTree child = ctx.getChild(i);
1125             if (child instanceof Leafref_specificationContext) {
1126                 for (int j = 0; j < child.getChildCount(); j++) {
1127                     ParseTree leafRefSpec = child.getChild(j);
1128                     if (leafRefSpec instanceof Path_stmtContext) {
1129                         return stringFromNode(leafRefSpec);
1130                     }
1131                 }
1132             }
1133         }
1134         return null;
1135     }
1136
1137     /**
1138      * Internal helper method for parsing Must_stmtContext.
1139      *
1140      * @param ctx
1141      *            Must_stmtContext
1142      * @return MustDefinition object based on parsed context
1143      */
1144     public static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
1145         StringBuilder mustText = new StringBuilder();
1146         String description = null;
1147         String reference = null;
1148         String errorAppTag = null;
1149         String errorMessage = null;
1150         for (int i = 0; i < ctx.getChildCount(); ++i) {
1151             ParseTree child = ctx.getChild(i);
1152             if (child instanceof StringContext) {
1153                 final StringContext context = (StringContext) child;
1154                 if (context.getChildCount() == 1) {
1155                     String mustPart = context.getChild(0).getText();
1156                     // trim start and end quotation
1157                     mustText.append(mustPart.substring(1, mustPart.length() - 1));
1158                 } else {
1159                     for (int j = 0; j < context.getChildCount(); j++) {
1160                         String mustPart = context.getChild(j).getText();
1161                         if (j == 0) {
1162                             mustText.append(mustPart.substring(0,
1163                                     mustPart.length() - 1));
1164                             continue;
1165                         }
1166                         if (j % 2 == 0) {
1167                             mustText.append(mustPart.substring(1));
1168                         }
1169                     }
1170                 }
1171             } else if (child instanceof Description_stmtContext) {
1172                 description = stringFromNode(child);
1173             } else if (child instanceof Reference_stmtContext) {
1174                 reference = stringFromNode(child);
1175             } else if (child instanceof Error_app_tag_stmtContext) {
1176                 errorAppTag = stringFromNode(child);
1177             } else if (child instanceof Error_message_stmtContext) {
1178                 errorMessage = stringFromNode(child);
1179             }
1180         }
1181
1182         MustDefinition must = new MustDefinitionImpl(mustText.toString(),
1183                 description, reference, errorAppTag, errorMessage);
1184         return must;
1185     }
1186
1187     /**
1188      * Parse given tree and set constraints to given builder.
1189      *
1190      * @param ctx
1191      *            context to search
1192      * @param constraints
1193      *            ConstraintsBuilder to fill
1194      */
1195     public static void parseConstraints(final ParseTree ctx,
1196             final ConstraintsBuilder constraints) {
1197         for (int i = 0; i < ctx.getChildCount(); ++i) {
1198             final ParseTree childNode = ctx.getChild(i);
1199             if (childNode instanceof Max_elements_stmtContext) {
1200                 Integer max = parseMaxElements((Max_elements_stmtContext) childNode);
1201                 constraints.setMaxElements(max);
1202             } else if (childNode instanceof Min_elements_stmtContext) {
1203                 Integer min = parseMinElements((Min_elements_stmtContext) childNode);
1204                 constraints.setMinElements(min);
1205             } else if (childNode instanceof Must_stmtContext) {
1206                 MustDefinition must = parseMust((Must_stmtContext) childNode);
1207                 constraints.addMustDefinition(must);
1208             } else if (childNode instanceof Mandatory_stmtContext) {
1209                 for (int j = 0; j < childNode.getChildCount(); j++) {
1210                     ParseTree mandatoryTree = ctx.getChild(j);
1211                     if (mandatoryTree instanceof Mandatory_argContext) {
1212                         Boolean mandatory = Boolean
1213                                 .valueOf(stringFromNode(mandatoryTree));
1214                         constraints.setMandatory(mandatory);
1215                     }
1216                 }
1217             } else if (childNode instanceof When_stmtContext) {
1218                 constraints.addWhenCondition(stringFromNode(childNode));
1219             }
1220         }
1221     }
1222
1223     private static Integer parseMinElements(Min_elements_stmtContext ctx) {
1224         Integer result = null;
1225         try {
1226             for (int j = 0; j < ctx.getChildCount(); j++) {
1227                 ParseTree minArg = ctx.getChild(j);
1228                 if (minArg instanceof Min_value_argContext) {
1229                     result = Integer.valueOf(stringFromNode(minArg));
1230                 }
1231             }
1232             if (result == null) {
1233                 throw new IllegalArgumentException();
1234             }
1235             return result;
1236         } catch (Exception e) {
1237             throw new YangParseException(ctx.getStart().getLine(),
1238                     "Failed to parse min-elements.", e);
1239         }
1240     }
1241
1242     private static Integer parseMaxElements(Max_elements_stmtContext ctx) {
1243         Integer result = null;
1244         try {
1245             for (int j = 0; j < ctx.getChildCount(); j++) {
1246                 ParseTree maxArg = ctx.getChild(j);
1247                 if (maxArg instanceof Max_value_argContext) {
1248                     result = Integer.valueOf(stringFromNode(maxArg));
1249                 }
1250             }
1251             if (result == null) {
1252                 throw new IllegalArgumentException();
1253             }
1254             return result;
1255         } catch (Exception e) {
1256             throw new YangParseException(ctx.getStart().getLine(),
1257                     "Failed to parse max-elements.", e);
1258         }
1259     }
1260
1261     /**
1262      * Parse given context and return yin value.
1263      *
1264      * @param ctx
1265      *            context to parse
1266      * @return true if value is 'true', false otherwise
1267      */
1268     public static boolean parseYinValue(Argument_stmtContext ctx) {
1269         boolean yinValue = false;
1270         outer: for (int j = 0; j < ctx.getChildCount(); j++) {
1271             ParseTree yin = ctx.getChild(j);
1272             if (yin instanceof Yin_element_stmtContext) {
1273                 for (int k = 0; k < yin.getChildCount(); k++) {
1274                     ParseTree yinArg = yin.getChild(k);
1275                     if (yinArg instanceof Yin_element_argContext) {
1276                         String yinString = stringFromNode(yinArg);
1277                         if ("true".equals(yinString)) {
1278                             yinValue = true;
1279                             break outer;
1280                         }
1281                     }
1282                 }
1283             }
1284         }
1285         return yinValue;
1286     }
1287
1288     /**
1289      * Check this base type.
1290      *
1291      * @param typeName
1292      *            base YANG type name
1293      * @param moduleName
1294      *            name of current module
1295      * @param line
1296      *            line in module
1297      * @throws YangParseException
1298      *             if this is one of YANG type which MUST contain additional
1299      *             informations in its body
1300      */
1301     public static void checkMissingBody(final String typeName,
1302             final String moduleName, final int line) throws YangParseException {
1303         if ("decimal64".equals(typeName)) {
1304             throw new YangParseException(moduleName, line,
1305                     "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1306         } else if ("identityref".equals(typeName)) {
1307             throw new YangParseException(moduleName, line,
1308                     "The 'base' statement MUST be present if the type is 'identityref'.");
1309         } else if ("leafref".equals(typeName)) {
1310             throw new YangParseException(moduleName, line,
1311                     "The 'path' statement MUST be present if the type is 'leafref'.");
1312         } else if ("bits".equals(typeName)) {
1313             throw new YangParseException(moduleName, line,
1314                     "The 'bit' statement MUST be present if the type is 'bits'.");
1315         } else if ("enumeration".equals(typeName)) {
1316             throw new YangParseException(moduleName, line,
1317                     "The 'enum' statement MUST be present if the type is 'enumeration'.");
1318         }
1319     }
1320
1321     /**
1322      * Parse refine statement.
1323      *
1324      * @param refineCtx
1325      *            refine statement
1326      * @param line
1327      *            current line in yang model
1328      * @return RefineHolder object representing this refine statement
1329      */
1330     public static RefineHolder parseRefine(Refine_stmtContext refineCtx) {
1331         final String refineTarget = stringFromNode(refineCtx);
1332         final RefineHolder refine = new RefineHolder(refineTarget, refineCtx
1333                 .getStart().getLine());
1334         for (int j = 0; j < refineCtx.getChildCount(); j++) {
1335             ParseTree refinePom = refineCtx.getChild(j);
1336             if (refinePom instanceof Refine_pomContext) {
1337                 for (int k = 0; k < refinePom.getChildCount(); k++) {
1338                     ParseTree refineStmt = refinePom.getChild(k);
1339                     parseRefineDefault(refine, refineStmt);
1340
1341                     if (refineStmt instanceof Refine_leaf_stmtsContext) {
1342                         parseRefine(refine,
1343                                 (Refine_leaf_stmtsContext) refineStmt);
1344                     } else if (refineStmt instanceof Refine_container_stmtsContext) {
1345                         parseRefine(refine,
1346                                 (Refine_container_stmtsContext) refineStmt);
1347                     } else if (refineStmt instanceof Refine_list_stmtsContext) {
1348                         parseRefine(refine,
1349                                 (Refine_list_stmtsContext) refineStmt);
1350                     } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1351                         parseRefine(refine,
1352                                 (Refine_leaf_list_stmtsContext) refineStmt);
1353                     } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1354                         parseRefine(refine,
1355                                 (Refine_choice_stmtsContext) refineStmt);
1356                     } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1357                         parseRefine(refine,
1358                                 (Refine_anyxml_stmtsContext) refineStmt);
1359                     }
1360                 }
1361             }
1362         }
1363         return refine;
1364     }
1365
1366     private static void parseRefineDefault(RefineHolder refine,
1367             ParseTree refineStmt) {
1368         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1369             ParseTree refineArg = refineStmt.getChild(i);
1370             if (refineArg instanceof Description_stmtContext) {
1371                 String description = stringFromNode(refineArg);
1372                 refine.setDescription(description);
1373             } else if (refineArg instanceof Reference_stmtContext) {
1374                 String reference = stringFromNode(refineArg);
1375                 refine.setReference(reference);
1376             } else if (refineArg instanceof Config_stmtContext) {
1377                 boolean config = parseConfig((Config_stmtContext) refineArg);
1378                 refine.setConfig(config);
1379             }
1380         }
1381     }
1382
1383     private static RefineHolder parseRefine(RefineHolder refine,
1384             Refine_leaf_stmtsContext refineStmt) {
1385         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1386             ParseTree refineArg = refineStmt.getChild(i);
1387             if (refineArg instanceof Default_stmtContext) {
1388                 String defaultStr = stringFromNode(refineArg);
1389                 refine.setDefaultStr(defaultStr);
1390             } else if (refineArg instanceof Mandatory_stmtContext) {
1391                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1392                     ParseTree mandatoryTree = refineArg.getChild(j);
1393                     if (mandatoryTree instanceof Mandatory_argContext) {
1394                         Boolean mandatory = Boolean
1395                                 .valueOf(stringFromNode(mandatoryTree));
1396                         refine.setMandatory(mandatory);
1397                     }
1398                 }
1399             } else if (refineArg instanceof Must_stmtContext) {
1400                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1401                 refine.setMust(must);
1402
1403             }
1404         }
1405         return refine;
1406     }
1407
1408     private static RefineHolder parseRefine(RefineHolder refine,
1409             Refine_container_stmtsContext refineStmt) {
1410         for (int m = 0; m < refineStmt.getChildCount(); m++) {
1411             ParseTree refineArg = refineStmt.getChild(m);
1412             if (refineArg instanceof Must_stmtContext) {
1413                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1414                 refine.setMust(must);
1415             } else if (refineArg instanceof Presence_stmtContext) {
1416                 refine.setPresence(true);
1417             }
1418         }
1419         return refine;
1420     }
1421
1422     private static RefineHolder parseRefine(RefineHolder refine,
1423             Refine_list_stmtsContext refineStmt) {
1424         for (int m = 0; m < refineStmt.getChildCount(); m++) {
1425             ParseTree refineArg = refineStmt.getChild(m);
1426             if (refineArg instanceof Must_stmtContext) {
1427                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1428                 refine.setMust(must);
1429             } else if (refineArg instanceof Max_elements_stmtContext) {
1430                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg);
1431                 refine.setMaxElements(max);
1432             } else if (refineArg instanceof Min_elements_stmtContext) {
1433                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg);
1434                 refine.setMinElements(min);
1435             }
1436         }
1437         return refine;
1438     }
1439
1440     private static RefineHolder parseRefine(RefineHolder refine,
1441             Refine_leaf_list_stmtsContext refineStmt) {
1442         for (int m = 0; m < refineStmt.getChildCount(); m++) {
1443             ParseTree refineArg = refineStmt.getChild(m);
1444             if (refineArg instanceof Must_stmtContext) {
1445                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1446                 refine.setMust(must);
1447             } else if (refineArg instanceof Max_elements_stmtContext) {
1448                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg);
1449                 refine.setMaxElements(max);
1450             } else if (refineArg instanceof Min_elements_stmtContext) {
1451                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg);
1452                 refine.setMinElements(min);
1453             }
1454         }
1455         return refine;
1456     }
1457
1458     private static RefineHolder parseRefine(RefineHolder refine,
1459             Refine_choice_stmtsContext refineStmt) {
1460         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1461             ParseTree refineArg = refineStmt.getChild(i);
1462             if (refineArg instanceof Default_stmtContext) {
1463                 String defaultStr = stringFromNode(refineArg);
1464                 refine.setDefaultStr(defaultStr);
1465             } else if (refineArg instanceof Mandatory_stmtContext) {
1466                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1467                     ParseTree mandatoryTree = refineArg.getChild(j);
1468                     if (mandatoryTree instanceof Mandatory_argContext) {
1469                         Boolean mandatory = Boolean
1470                                 .valueOf(stringFromNode(mandatoryTree));
1471                         refine.setMandatory(mandatory);
1472                     }
1473                 }
1474             }
1475         }
1476         return refine;
1477     }
1478
1479     private static RefineHolder parseRefine(RefineHolder refine,
1480             Refine_anyxml_stmtsContext refineStmt) {
1481         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1482             ParseTree refineArg = refineStmt.getChild(i);
1483             if (refineArg instanceof Must_stmtContext) {
1484                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1485                 refine.setMust(must);
1486             } else if (refineArg instanceof Mandatory_stmtContext) {
1487                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1488                     ParseTree mandatoryTree = refineArg.getChild(j);
1489                     if (mandatoryTree instanceof Mandatory_argContext) {
1490                         Boolean mandatory = Boolean
1491                                 .valueOf(stringFromNode(mandatoryTree));
1492                         refine.setMandatory(mandatory);
1493                     }
1494                 }
1495             }
1496         }
1497         return refine;
1498     }
1499
1500 }