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