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