eb2b65c0d2bc9f4988cb7281a65873de86d60625
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / ParserListenerUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.yangtools.yang.parser.impl;
10
11 import static com.google.common.base.Preconditions.checkState;
12
13 import com.google.common.base.CharMatcher;
14 import com.google.common.base.Optional;
15 import com.google.common.base.Splitter;
16 import com.google.common.collect.ImmutableSet;
17 import com.google.common.collect.Sets;
18 import java.math.BigDecimal;
19 import java.math.BigInteger;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Objects;
25 import java.util.Set;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 import java.util.regex.PatternSyntaxException;
29 import org.antlr.v4.runtime.ParserRuleContext;
30 import org.antlr.v4.runtime.tree.ParseTree;
31 import org.antlr.v4.runtime.tree.TerminalNode;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Bit_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Bits_specificationContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_argContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Decimal64_specificationContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Description_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Enum_specificationContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Enum_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Error_app_tag_stmtContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Error_message_stmtContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Identityref_specificationContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Instance_identifier_specificationContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leafref_specificationContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Length_stmtContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_argContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_elements_stmtContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_value_argContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_value_argContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
59 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Must_stmtContext;
60 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
61 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
62 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
63 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Path_stmtContext;
64 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Pattern_stmtContext;
65 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Position_stmtContext;
66 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Presence_stmtContext;
67 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Range_stmtContext;
68 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Reference_stmtContext;
69 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_anyxml_stmtsContext;
70 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_choice_stmtsContext;
71 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_container_stmtsContext;
72 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_leaf_list_stmtsContext;
73 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_leaf_stmtsContext;
74 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_list_stmtsContext;
75 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_pomContext;
76 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_stmtContext;
77 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Require_instance_argContext;
78 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Require_instance_stmtContext;
79 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
80 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_stmtContext;
81 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.StringContext;
82 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.String_restrictionsContext;
83 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
84 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Units_stmtContext;
85 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Value_stmtContext;
86 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.When_stmtContext;
87 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_argContext;
88 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_stmtContext;
89 import org.opendaylight.yangtools.yang.common.QName;
90 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
91 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
92 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
93 import org.opendaylight.yangtools.yang.model.api.Status;
94 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
95 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
96 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
97 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
98 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
99 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
100 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
101 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
102 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
103 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
104 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
105 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
106 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
107 import org.opendaylight.yangtools.yang.model.util.BaseConstraints;
108 import org.opendaylight.yangtools.yang.model.util.BaseTypes;
109 import org.opendaylight.yangtools.yang.model.util.BinaryType;
110 import org.opendaylight.yangtools.yang.model.util.BitImpl;
111 import org.opendaylight.yangtools.yang.model.util.BitsType;
112 import org.opendaylight.yangtools.yang.model.util.Decimal64;
113 import org.opendaylight.yangtools.yang.model.util.EnumerationType;
114 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
115 import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
116 import org.opendaylight.yangtools.yang.model.util.Int16;
117 import org.opendaylight.yangtools.yang.model.util.Int32;
118 import org.opendaylight.yangtools.yang.model.util.Int64;
119 import org.opendaylight.yangtools.yang.model.util.Int8;
120 import org.opendaylight.yangtools.yang.model.util.Leafref;
121 import org.opendaylight.yangtools.yang.model.util.MustDefinitionImpl;
122 import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
123 import org.opendaylight.yangtools.yang.model.util.StringType;
124 import org.opendaylight.yangtools.yang.model.util.Uint16;
125 import org.opendaylight.yangtools.yang.model.util.Uint32;
126 import org.opendaylight.yangtools.yang.model.util.Uint64;
127 import org.opendaylight.yangtools.yang.model.util.Uint8;
128 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
129 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
130 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
131 import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder;
132 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
133 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
134 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
135 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
136 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
137 import org.opendaylight.yangtools.yang.parser.builder.impl.RefineHolderImpl;
138 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
139 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
140 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
141 import org.opendaylight.yangtools.yang.parser.util.UnknownBoundaryNumber;
142 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
143 import org.slf4j.Logger;
144 import org.slf4j.LoggerFactory;
145
146 public final class ParserListenerUtils {
147     private static final int UNICODE_SCRIPT_FIX_COUNTER = 30;
148     private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class);
149     private static final Splitter KEYDEF_SPLITTER = Splitter.on(' ').omitEmptyStrings();
150     private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
151     private static final Splitter DOT_DOT_SPLITTER = Splitter.on("..").trimResults();
152     private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"');
153     private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\'');
154     private static final Pattern BETWEEN_CURLY_BRACES_PATTERN = Pattern.compile("\\{(.+?)\\}");
155     private static final Set<String> JAVA_UNICODE_BLOCKS = ImmutableSet.<String>builder()
156             .add("AegeanNumbers")
157             .add("AlchemicalSymbols")
158             .add("AlphabeticPresentationForms")
159             .add("AncientGreekMusicalNotation")
160             .add("AncientGreekNumbers")
161             .add("AncientSymbols")
162             .add("Arabic")
163             .add("ArabicPresentationForms-A")
164             .add("ArabicPresentationForms-B")
165             .add("ArabicSupplement")
166             .add("Armenian")
167             .add("Arrows")
168             .add("Avestan")
169             .add("Balinese")
170             .add("Bamum")
171             .add("BamumSupplement")
172             .add("BasicLatin")
173             .add("Batak")
174             .add("Bengali")
175             .add("BlockElements")
176             .add("Bopomofo")
177             .add("BopomofoExtended")
178             .add("BoxDrawing")
179             .add("Brahmi")
180             .add("BraillePatterns")
181             .add("Buginese")
182             .add("Buhid")
183             .add("ByzantineMusicalSymbols")
184             .add("Carian")
185             .add("Cham")
186             .add("Cherokee")
187             .add("CJKCompatibility")
188             .add("CJKCompatibilityForms")
189             .add("CJKCompatibilityIdeographs")
190             .add("CJKCompatibilityIdeographsSupplement")
191             .add("CJKRadicalsSupplement")
192             .add("CJKStrokes")
193             .add("CJKSymbolsandPunctuation")
194             .add("CJKUnifiedIdeographs")
195             .add("CJKUnifiedIdeographsExtensionA")
196             .add("CJKUnifiedIdeographsExtensionB")
197             .add("CJKUnifiedIdeographsExtensionC")
198             .add("CJKUnifiedIdeographsExtensionD")
199             .add("CombiningDiacriticalMarks")
200             .add("CombiningDiacriticalMarksSupplement")
201             .add("CombiningHalfMarks")
202             .add("CombiningDiacriticalMarksforSymbols")
203             .add("CommonIndicNumberForms")
204             .add("ControlPictures")
205             .add("Coptic")
206             .add("CountingRodNumerals")
207             .add("Cuneiform")
208             .add("CuneiformNumbersandPunctuation")
209             .add("CurrencySymbols")
210             .add("CypriotSyllabary")
211             .add("Cyrillic")
212             .add("CyrillicExtended-A")
213             .add("CyrillicExtended-B")
214             .add("CyrillicSupplementary")
215             .add("Deseret")
216             .add("Devanagari")
217             .add("DevanagariExtended")
218             .add("Dingbats")
219             .add("DominoTiles")
220             .add("EgyptianHieroglyphs")
221             .add("Emoticons")
222             .add("EnclosedAlphanumericSupplement")
223             .add("EnclosedAlphanumerics")
224             .add("EnclosedCJKLettersandMonths")
225             .add("EnclosedIdeographicSupplement")
226             .add("Ethiopic")
227             .add("EthiopicExtended")
228             .add("EthiopicExtended-A")
229             .add("EthiopicSupplement")
230             .add("GeneralPunctuation")
231             .add("GeometricShapes")
232             .add("Georgian")
233             .add("GeorgianSupplement")
234             .add("Glagolitic")
235             .add("Gothic")
236             .add("GreekandCoptic")
237             .add("GreekExtended")
238             .add("Gujarati")
239             .add("Gurmukhi")
240             .add("HalfwidthandFullwidthForms")
241             .add("HangulCompatibilityJamo")
242             .add("HangulJamo")
243             .add("HangulJamoExtended-A")
244             .add("HangulJamoExtended-B")
245             .add("HangulSyllables")
246             .add("Hanunoo")
247             .add("Hebrew")
248             .add("HighPrivateUseSurrogates")
249             .add("HighSurrogates")
250             .add("Hiragana")
251             .add("IdeographicDescriptionCharacters")
252             .add("ImperialAramaic")
253             .add("InscriptionalPahlavi")
254             .add("InscriptionalParthian")
255             .add("IPAExtensions")
256             .add("Javanese")
257             .add("Kaithi")
258             .add("KanaSupplement")
259             .add("Kanbun")
260             .add("Kangxi Radicals")
261             .add("Kannada")
262             .add("Katakana")
263             .add("KatakanaPhoneticExtensions")
264             .add("KayahLi")
265             .add("Kharoshthi")
266             .add("Khmer")
267             .add("KhmerSymbols")
268             .add("Lao")
269             .add("Latin-1Supplement")
270             .add("LatinExtended-A")
271             .add("LatinExtendedAdditional")
272             .add("LatinExtended-B")
273             .add("LatinExtended-C")
274             .add("LatinExtended-D")
275             .add("Lepcha")
276             .add("LetterlikeSymbols")
277             .add("Limbu")
278             .add("LinearBIdeograms")
279             .add("LinearBSyllabary")
280             .add("Lisu")
281             .add("LowSurrogates")
282             .add("Lycian")
283             .add("Lydian")
284             .add("MahjongTiles")
285             .add("Malayalam")
286             .add("Mandaic")
287             .add("MathematicalAlphanumericSymbols")
288             .add("MathematicalOperators")
289             .add("MeeteiMayek")
290             .add("MiscellaneousMathematicalSymbols-A")
291             .add("MiscellaneousMathematicalSymbols-B")
292             .add("MiscellaneousSymbols")
293             .add("MiscellaneousSymbolsandArrows")
294             .add("MiscellaneousSymbolsAndPictographs")
295             .add("MiscellaneousTechnical")
296             .add("ModifierToneLetters")
297             .add("Mongolian")
298             .add("MusicalSymbols")
299             .add("Myanmar")
300             .add("MyanmarExtended-A")
301             .add("NewTaiLue")
302             .add("NKo")
303             .add("NumberForms")
304             .add("Ogham")
305             .add("OlChiki")
306             .add("OldItalic")
307             .add("OldPersian")
308             .add("OldSouthArabian")
309             .add("OldTurkic")
310             .add("OpticalCharacterRecognition")
311             .add("Oriya")
312             .add("Osmanya")
313             .add("Phags-pa")
314             .add("PhaistosDisc")
315             .add("Phoenician")
316             .add("PhoneticExtensions")
317             .add("PhoneticExtensionsSupplement")
318             .add("PlayingCards")
319             .add("PrivateUseArea")
320             .add("Rejang")
321             .add("RumiNumeralSymbols")
322             .add("Runic")
323             .add("Samaritan")
324             .add("Saurashtra")
325             .add("Shavian")
326             .add("Sinhala")
327             .add("SmallFormVariants")
328             .add("SpacingModifierLetters")
329             .add("Specials")
330             .add("Sundanese")
331             .add("SuperscriptsandSubscripts")
332             .add("SupplementalArrows-A")
333             .add("SupplementalArrows-B")
334             .add("SupplementalMathematicalOperators")
335             .add("SupplementalPunctuation")
336             .add("SupplementaryPrivateUseArea-A")
337             .add("SupplementaryPrivateUseArea-B")
338             .add("SylotiNagri")
339             .add("Syriac")
340             .add("Tagalog")
341             .add("Tagbanwa")
342             .add("Tags")
343             .add("TaiLe")
344             .add("TaiTham")
345             .add("TaiViet")
346             .add("TaiXuanJingSymbols")
347             .add("Tamil")
348             .add("Telugu")
349             .add("Thaana")
350             .add("Thai")
351             .add("Tibetan")
352             .add("Tifinagh")
353             .add("TransportAndMapSymbols")
354             .add("Ugaritic")
355             .add("UnifiedCanadianAboriginalSyllabics")
356             .add("UnifiedCanadianAboriginalSyllabicsExtended")
357             .add("Vai")
358             .add("VariationSelectors")
359             .add("VariationSelectorsSupplement")
360             .add("VedicExtensions")
361             .add("VerticalForms")
362             .add("YiRadicals")
363             .add("YiSyllables")
364             .add("YijingHexagramSymbols").build();
365
366     private ParserListenerUtils() {
367     }
368
369     /**
370      * Parse given tree and get first string value.
371      *
372      * @param treeNode
373      *            tree to parse
374      * @return first string value from given tree
375      */
376     public static String stringFromNode(final ParseTree treeNode) {
377         String result = "";
378         for (int i = 0; i < treeNode.getChildCount(); ++i) {
379             final ParseTree child = treeNode.getChild(i);
380             if (child instanceof StringContext) {
381                 return stringFromStringContext((StringContext)child);
382             }
383         }
384         return result;
385     }
386
387     private static String stringFromStringContext(final StringContext context) {
388         StringBuilder sb = new StringBuilder();
389         for (TerminalNode stringNode : context.STRING()) {
390             final String str = stringNode.getText();
391             char firstChar = str.charAt(0);
392             final CharMatcher quoteMatcher;
393             if(SINGLE_QUOTE_MATCHER.matches(firstChar)) {
394                 quoteMatcher = SINGLE_QUOTE_MATCHER;
395             } else if (DOUBLE_QUOTE_MATCHER.matches(firstChar)) {
396                 quoteMatcher = DOUBLE_QUOTE_MATCHER;
397             } else {
398                 sb.append(str);
399                 continue;
400             }
401             /*
402              *
403              * It is safe not to check last argument to be same
404              * grammars enforces that.
405              *
406              * FIXME: Introduce proper escaping and translation of escaped
407              * characters here.
408              *
409              */
410             sb.append(quoteMatcher.removeFrom(str.substring(1, str.length()-1)));
411         }
412         return sb.toString();
413     }
414
415     private static String getParentModule(final ParseTree ctx) {
416         ParseTree current = ctx;
417         while (current != null && !(current instanceof Module_stmtContext)) {
418             current = current.getParent();
419         }
420         if (current != null) {
421             Module_stmtContext module = (Module_stmtContext) current;
422             for (int i = 0; i < module.getChildCount(); i++) {
423                 if (module.getChild(i) instanceof StringContext) {
424                     final StringContext str = (StringContext) module.getChild(i);
425                     return str.getChild(0).getText();
426                 }
427             }
428         }
429         return "";
430     }
431
432     /**
433      * Parse 'description', 'reference' and 'status' statements and fill in
434      * given builder.
435      *
436      * @param ctx
437      *            context to parse
438      * @param builder
439      *            builder to fill in with parsed statements
440      */
441     public static void parseSchemaNodeArgs(final ParseTree ctx, final SchemaNodeBuilder builder) {
442         for (int i = 0; i < ctx.getChildCount(); i++) {
443             final ParseTree child = ctx.getChild(i);
444             if (child instanceof Description_stmtContext) {
445                 final String desc = stringFromNode(child);
446                 builder.setDescription(desc);
447             } else if (child instanceof Reference_stmtContext) {
448                 final String ref = stringFromNode(child);
449                 builder.setReference(ref);
450             } else if (child instanceof Status_stmtContext) {
451                 final Status status = parseStatus((Status_stmtContext) child);
452                 builder.setStatus(status);
453             }
454         }
455     }
456
457     /**
458      * Parse given context and return its value;
459      *
460      * @param ctx
461      *            status context
462      * @return value parsed from context
463      */
464     public static Status parseStatus(final Status_stmtContext ctx) {
465         Status result = null;
466         for (int i = 0; i < ctx.getChildCount(); i++) {
467             ParseTree statusArg = ctx.getChild(i);
468             if (statusArg instanceof Status_argContext) {
469                 String statusArgStr = stringFromNode(statusArg);
470                 switch (statusArgStr) {
471                 case "current":
472                     result = Status.CURRENT;
473                     break;
474                 case "deprecated":
475                     result = Status.DEPRECATED;
476                     break;
477                 case "obsolete":
478                     result = Status.OBSOLETE;
479                     break;
480                 default:
481                     LOG.warn("Invalid 'status' statement: " + statusArgStr);
482                 }
483             }
484         }
485         return result;
486     }
487
488     /**
489      * Parse given tree and returns units statement as string.
490      *
491      * @param ctx
492      *            context to parse
493      * @return value of units statement as string or null if there is no units
494      *         statement
495      */
496     public static String parseUnits(final ParseTree ctx) {
497         for (int i = 0; i < ctx.getChildCount(); i++) {
498             ParseTree child = ctx.getChild(i);
499             if (child instanceof Units_stmtContext) {
500                 return stringFromNode(child);
501             }
502         }
503         return null;
504     }
505
506     /**
507      * Parse given tree and returns default statement as string.
508      *
509      * @param ctx
510      *            context to parse
511      * @return value of default statement as string or null if there is no
512      *         default statement
513      */
514     public static String parseDefault(final ParseTree ctx) {
515         for (int i = 0; i < ctx.getChildCount(); i++) {
516             ParseTree child = ctx.getChild(i);
517             if (child instanceof Default_stmtContext) {
518                 return stringFromNode(child);
519             }
520         }
521         return null;
522     }
523
524     /**
525      * Create java.util.LinkedHashSet of key node names.
526      *
527      * @param ctx
528      *            Key_stmtContext context
529      * @return YANG list key as java.util.LinkedHashSet of key node names
530      */
531     public static Set<String> createListKey(final Key_stmtContext ctx) {
532         final String keyDefinition = stringFromNode(ctx);
533         return Sets.<String>newLinkedHashSet(KEYDEF_SPLITTER.split(keyDefinition));
534     }
535
536     /**
537      * Parse given type body of enumeration statement.
538      *
539      * @param ctx
540      *            type body context to parse
541      * @param path
542      *            actual position in YANG model
543      * @param moduleName
544      *            current module name
545      * @return List of EnumPair object parsed from given context
546      */
547     private static List<EnumTypeDefinition.EnumPair> getEnumConstants(final Type_body_stmtsContext ctx,
548             final SchemaPath path, final String moduleName) {
549         List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<>();
550
551         for (int i = 0; i < ctx.getChildCount(); i++) {
552             ParseTree enumSpecChild = ctx.getChild(i);
553             if (enumSpecChild instanceof Enum_specificationContext) {
554                 int highestValue = -1;
555                 for (int j = 0; j < enumSpecChild.getChildCount(); j++) {
556                     ParseTree enumChild = enumSpecChild.getChild(j);
557                     if (enumChild instanceof Enum_stmtContext) {
558                         EnumPair enumPair = createEnumPair((Enum_stmtContext) enumChild, highestValue, path, moduleName);
559                         if (enumPair.getValue() > highestValue) {
560                             highestValue = enumPair.getValue();
561                         }
562                         enumConstants.add(enumPair);
563                     }
564                 }
565             }
566         }
567         return enumConstants;
568     }
569
570     /**
571      * Parse enum statement context
572      *
573      * @param ctx
574      *            enum statement context
575      * @param highestValue
576      *            current highest value in enumeration
577      * @param actualPath
578      *            actual position in YANG model
579      * @param moduleName
580      *            current module name
581      * @return EnumPair object parsed from given context
582      */
583     private static EnumTypeDefinition.EnumPair createEnumPair(final Enum_stmtContext ctx, final int highestValue,
584             final SchemaPath actualPath, final String moduleName) {
585         final String name = stringFromNode(ctx);
586         SchemaPath path = createTypePath(actualPath, name);
587         Integer value = null;
588
589         String description = null;
590         String reference = null;
591         Status status = null;
592
593         for (int i = 0; i < ctx.getChildCount(); i++) {
594             ParseTree child = ctx.getChild(i);
595             if (child instanceof Value_stmtContext) {
596                 String valueStr = stringFromNode(child);
597                 try {
598                     // yang enum value has same restrictions as JAVA Integer
599                     value = Integer.valueOf(valueStr);
600                 } catch (NumberFormatException e) {
601                     String err = String
602                             .format("Error on enum '%s': the enum value MUST be in the range from -2147483648 to 2147483647, but was: %s",
603                                     name, valueStr);
604                     throw new YangParseException(moduleName, ctx.getStart().getLine(), err, e);
605                 }
606             } else if (child instanceof Description_stmtContext) {
607                 description = stringFromNode(child);
608             } else if (child instanceof Reference_stmtContext) {
609                 reference = stringFromNode(child);
610             } else if (child instanceof Status_stmtContext) {
611                 status = parseStatus((Status_stmtContext) child);
612             }
613         }
614
615         if (value == null) {
616             value = highestValue + 1;
617         }
618
619         EnumPairImpl result = new EnumPairImpl();
620         result.qname = path.getPathTowardsRoot().iterator().next();
621         result.path = path;
622         result.description = description;
623         result.reference = reference;
624         result.status = status;
625         result.name = name;
626         result.value = value;
627         return result;
628     }
629
630     /**
631      * Internal implementation of EnumPair.
632      */
633     private static class EnumPairImpl implements EnumTypeDefinition.EnumPair {
634         private QName qname;
635         private SchemaPath path;
636         private String description;
637         private String reference;
638         private Status status;
639         private final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
640         private String name;
641         private Integer value;
642
643         @Override
644         public QName getQName() {
645             return qname;
646         }
647
648         @Override
649         public SchemaPath getPath() {
650             return path;
651         }
652
653         @Override
654         public String getDescription() {
655             return description;
656         }
657
658         @Override
659         public String getReference() {
660             return reference;
661         }
662
663         @Override
664         public Status getStatus() {
665             return status;
666         }
667
668         @Override
669         public List<UnknownSchemaNode> getUnknownSchemaNodes() {
670             return unknownNodes;
671         }
672
673         @Override
674         public String getName() {
675             return name;
676         }
677
678         @Override
679         public Integer getValue() {
680             return value;
681         }
682
683         @Override
684         public int hashCode() {
685             final int prime = 31;
686             int result = 1;
687             result = prime * result + Objects.hashCode(qname);
688             result = prime * result + Objects.hashCode(path);
689             result = prime * result + Objects.hashCode(unknownNodes);
690             result = prime * result + Objects.hashCode(name);
691             result = prime * result + Objects.hashCode(value);
692             return result;
693         }
694
695         @Override
696         public boolean equals(final Object obj) {
697             if (this == obj) {
698                 return true;
699             }
700             if (obj == null) {
701                 return false;
702             }
703             if (getClass() != obj.getClass()) {
704                 return false;
705             }
706             EnumPairImpl other = (EnumPairImpl) obj;
707             if (qname == null) {
708                 if (other.qname != null) {
709                     return false;
710                 }
711             } else if (!qname.equals(other.qname)) {
712                 return false;
713             }
714             if (path == null) {
715                 if (other.path != null) {
716                     return false;
717                 }
718             } else if (!path.equals(other.path)) {
719                 return false;
720             }
721             if (unknownNodes == null) {
722                 if (other.unknownNodes != null) {
723                     return false;
724                 }
725             } else if (!unknownNodes.equals(other.unknownNodes)) {
726                 return false;
727             }
728             if (name == null) {
729                 if (other.name != null) {
730                     return false;
731                 }
732             } else if (!name.equals(other.name)) {
733                 return false;
734             }
735             if (value == null) {
736                 if (other.value != null) {
737                     return false;
738                 }
739             } else if (!value.equals(other.value)) {
740                 return false;
741             }
742             return true;
743         }
744
745         @Override
746         public String toString() {
747             return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name=" + name + ", value=" + value + "]";
748         }
749     }
750
751     /**
752      * Get and parse range from given type body context.
753      *
754      * @param ctx
755      *            type body context to parse
756      * @param moduleName
757      *            name of current module
758      * @return List of RangeConstraint created from this context
759      */
760     private static List<RangeConstraint> getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
761         for (int i = 0; i < ctx.getChildCount(); i++) {
762             ParseTree numRestrChild = ctx.getChild(i);
763
764             if (numRestrChild instanceof Numerical_restrictionsContext) {
765                 for (int j = 0; j < numRestrChild.getChildCount(); j++) {
766                     ParseTree rangeChild = numRestrChild.getChild(j);
767                     if (rangeChild instanceof Range_stmtContext) {
768                         return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
769                     }
770                 }
771             }
772
773             if (numRestrChild instanceof Decimal64_specificationContext) {
774                 for (int j = 0; j < numRestrChild.getChildCount(); j++) {
775                     ParseTree decRestr = numRestrChild.getChild(j);
776                     if (decRestr instanceof Numerical_restrictionsContext) {
777                         for (int k = 0; k < decRestr.getChildCount(); k++) {
778                             ParseTree rangeChild = decRestr.getChild(k);
779                             if (rangeChild instanceof Range_stmtContext) {
780                                 return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
781                             }
782                         }
783                     }
784                 }
785             }
786         }
787         return Collections.emptyList();
788     }
789
790     /**
791      * Parse given range context.
792      *
793      * @param ctx
794      *            range context to parse
795      * @param moduleName
796      *            name of current module
797      * @return List of RangeConstraints parsed from this context
798      */
799     private static List<RangeConstraint> parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) {
800         final int line = ctx.getStart().getLine();
801         Optional<String> description = Optional.absent();
802         Optional<String> reference = Optional.absent();
803
804         for (int i = 0; i < ctx.getChildCount(); i++) {
805             ParseTree child = ctx.getChild(i);
806             if (child instanceof Description_stmtContext) {
807                 description = Optional.fromNullable(stringFromNode(child));
808             } else if (child instanceof Reference_stmtContext) {
809                 reference = Optional.fromNullable(stringFromNode(child));
810             }
811         }
812
813         List<RangeConstraint> rangeConstraints = new ArrayList<>();
814         for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) {
815             final Iterator<String> split = DOT_DOT_SPLITTER.split(def).iterator();
816             final Number min = parseNumberConstraintValue(split.next(), moduleName, line);
817
818             final Number max;
819             if (split.hasNext()) {
820                 max = parseNumberConstraintValue(split.next(), moduleName, line);
821                 if (split.hasNext()) {
822                     throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\".");
823                 }
824             } else {
825                 max = min;
826             }
827
828             RangeConstraint range = BaseConstraints.newRangeConstraint(min, max, description, reference);
829             rangeConstraints.add(range);
830         }
831
832         return rangeConstraints;
833     }
834
835     /**
836      * Get and parse length from given type body context.
837      *
838      * @param ctx
839      *            type body context to parse
840      * @param moduleName
841      *            name of current module
842      * @return List of LengthConstraint created from this context
843      */
844     private static List<LengthConstraint> getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
845         for (int i = 0; i < ctx.getChildCount(); i++) {
846             ParseTree stringRestrChild = ctx.getChild(i);
847             if (stringRestrChild instanceof String_restrictionsContext) {
848                 for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
849                     ParseTree lengthChild = stringRestrChild.getChild(j);
850                     if (lengthChild instanceof Length_stmtContext) {
851                         return parseLengthConstraints((Length_stmtContext) lengthChild, moduleName);
852                     }
853                 }
854             }
855         }
856         return Collections.emptyList();
857     }
858
859     /**
860      * Parse given length context.
861      *
862      * @param ctx
863      *            length context to parse
864      * @param moduleName
865      *            name of current module
866      * @return List of LengthConstraints parsed from this context
867      */
868     private static List<LengthConstraint> parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) {
869         final int line = ctx.getStart().getLine();
870         Optional<String> description = Optional.absent();
871         Optional<String> reference = Optional.absent();
872
873         for (int i = 0; i < ctx.getChildCount(); i++) {
874             ParseTree child = ctx.getChild(i);
875             if (child instanceof Description_stmtContext) {
876                 description = Optional.fromNullable(stringFromNode(child));
877             } else if (child instanceof Reference_stmtContext) {
878                 reference = Optional.fromNullable(stringFromNode(child));
879             }
880         }
881
882         List<LengthConstraint> lengthConstraints = new ArrayList<>();
883         for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) {
884             final Iterator<String> split = DOT_DOT_SPLITTER.split(def).iterator();
885             final Number min = parseNumberConstraintValue(split.next(), moduleName, line);
886
887             final Number max;
888             if (split.hasNext()) {
889                 max = parseNumberConstraintValue(split.next(), moduleName, line);
890                 if (split.hasNext()) {
891                     throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\".");
892                 }
893             } else {
894                 max = min;
895             }
896
897             LengthConstraint range = BaseConstraints.newLengthConstraint(min, max, description, reference);
898             lengthConstraints.add(range);
899         }
900
901         return lengthConstraints;
902     }
903
904     /**
905      * @param value
906      *            value to parse
907      * @param moduleName
908      *            name of current module
909      * @param line
910      *            current line in module
911      * @return wrapper object of primitive java type or UnknownBoundaryNumber if
912      *         type is one of special YANG values 'min' or 'max'
913      */
914     private static Number parseNumberConstraintValue(final String value, final String moduleName, final int line) {
915         Number result;
916         if ("min".equals(value) || "max".equals(value)) {
917             result = new UnknownBoundaryNumber(value);
918         } else {
919             try {
920                 if (value.indexOf('.') != -1) {
921                     result = new BigDecimal(value);
922                 } else {
923                     result = new BigInteger(value);
924                 }
925             } catch (NumberFormatException e) {
926                 throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
927             }
928         }
929         return result;
930     }
931
932     /**
933      * Parse type body and return pattern constraints.
934      *
935      * @param ctx
936      *            type body
937      * @return list of pattern constraints
938      */
939     private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx, final String moduleName) {
940         List<PatternConstraint> patterns = new ArrayList<>();
941
942         for (int i = 0; i < ctx.getChildCount(); i++) {
943             ParseTree stringRestrChild = ctx.getChild(i);
944             if (stringRestrChild instanceof String_restrictionsContext) {
945                 for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
946                     ParseTree lengthChild = stringRestrChild.getChild(j);
947                     if (lengthChild instanceof Pattern_stmtContext) {
948                         final PatternConstraint constraint = parsePatternConstraint((Pattern_stmtContext) lengthChild,
949                             moduleName);
950                         if (constraint != null) {
951                             patterns.add(constraint);
952                         }
953                     }
954                 }
955             }
956         }
957         return patterns;
958     }
959
960     /**
961      * Internal helper method.
962      *
963      * @param ctx
964      *            pattern context
965      * @return PatternConstraint object
966      */
967     private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx, final String moduleName) {
968         Optional<String> description = Optional.absent();
969         Optional<String> reference = Optional.absent();
970         for (int i = 0; i < ctx.getChildCount(); i++) {
971             ParseTree child = ctx.getChild(i);
972             if (child instanceof Description_stmtContext) {
973                 description = Optional.of(stringFromNode(child));
974             } else if (child instanceof Reference_stmtContext) {
975                 reference = Optional.of(stringFromNode(child));
976             }
977         }
978         final String rawPattern = parsePatternString(ctx);
979         final String fixedRawPattern = fixUnicodeScriptPattern(rawPattern);
980         final String pattern = wrapPattern(fixedRawPattern);
981         if (isValidPattern(pattern, ctx, moduleName)) {
982             return BaseConstraints.newPatternConstraint(pattern, description, reference);
983         }
984         return null;
985     }
986
987     private static String fixUnicodeScriptPattern(String rawPattern) {
988         for (int i = 0; i < UNICODE_SCRIPT_FIX_COUNTER; i++) {
989             try {
990                 Pattern.compile(rawPattern);
991                 return rawPattern;
992             } catch(PatternSyntaxException ex) {
993                 LOG.debug("Invalid regex pattern syntax in: {}", rawPattern, ex);
994                 if (ex.getMessage().contains("Unknown character script name")) {
995                     rawPattern = fixUnknownScripts(ex.getMessage(), rawPattern);
996                 } else {
997                     return rawPattern;
998                 }
999             }
1000         }
1001
1002         LOG.warn("Regex pattern could not be fixed: {}", rawPattern);
1003         return rawPattern;
1004     }
1005
1006     private static String fixUnknownScripts(String exMessage, String rawPattern) {
1007         StringBuilder result = new StringBuilder(rawPattern);
1008         Matcher matcher = BETWEEN_CURLY_BRACES_PATTERN.matcher(exMessage);
1009         if (matcher.find()) {
1010             String capturedGroup = matcher.group(1);
1011             if (JAVA_UNICODE_BLOCKS.contains(capturedGroup)) {
1012                 int idx = rawPattern.indexOf("Is" + capturedGroup);
1013                 result = result.replace(idx, idx + 2, "In");
1014             }
1015         }
1016         return result.toString();
1017     }
1018
1019     private static String wrapPattern(String rawPattern) {
1020         final StringBuilder wrapPatternBuilder = new StringBuilder(rawPattern.length() + 2);
1021         wrapPatternBuilder.append('^');
1022         wrapPatternBuilder.append(rawPattern);
1023         wrapPatternBuilder.append('$');
1024         return wrapPatternBuilder.toString();
1025     }
1026
1027     private static boolean isValidPattern(final String pattern, final Pattern_stmtContext ctx, final String moduleName) {
1028         try {
1029             Pattern.compile(pattern);
1030             return true;
1031         } catch (PatternSyntaxException ex) {
1032             LOG.warn("Unable to compile pattern defined in module {} at line {}. Error message: {}",
1033                 moduleName, ctx.getStart().getLine(), ex.getMessage());
1034         }
1035         return false;
1036     }
1037
1038     /**
1039      * Parse given context and return pattern value.
1040      *
1041      * @param ctx
1042      *            context to parse
1043      * @return pattern value as String
1044      */
1045     private static String parsePatternString(final Pattern_stmtContext ctx) {
1046         StringBuilder result = new StringBuilder();
1047         for (int i = 0; i < ctx.getChildCount(); ++i) {
1048             ParseTree child = ctx.getChild(i);
1049             if (child instanceof StringContext) {
1050                 for (int j = 0; j < child.getChildCount(); j++) {
1051                     if (j % 2 == 0) {
1052                         String patternToken = child.getChild(j).getText();
1053                         result.append(patternToken.substring(1, patternToken.length() - 1));
1054                     }
1055                 }
1056             }
1057         }
1058         return result.toString();
1059     }
1060
1061     /**
1062      * Get fraction digits value from type body.
1063      *
1064      * @param ctx
1065      *            type body context to parse
1066      * @param moduleName
1067      *            name of current module
1068      * @return 'fraction-digits' value if present in given context, null
1069      *         otherwise
1070      */
1071     private static Integer getFractionDigits(final Type_body_stmtsContext ctx, final String moduleName) {
1072         Integer result = null;
1073         for (int i = 0; i < ctx.getChildCount(); i++) {
1074             ParseTree dec64specChild = ctx.getChild(i);
1075             if (dec64specChild instanceof Decimal64_specificationContext) {
1076                 result = parseFractionDigits((Decimal64_specificationContext) dec64specChild, moduleName);
1077             }
1078         }
1079         return result;
1080     }
1081
1082     /**
1083      * Parse decimal64 fraction-digits value.
1084      *
1085      * @param ctx
1086      *            decimal64 context
1087      * @param moduleName
1088      *            name of current module
1089      * @return fraction-digits value as Integer
1090      */
1091     private static Integer parseFractionDigits(final Decimal64_specificationContext ctx, final String moduleName) {
1092         Integer result = null;
1093         for (int i = 0; i < ctx.getChildCount(); i++) {
1094             ParseTree fdChild = ctx.getChild(i);
1095             if (fdChild instanceof Fraction_digits_stmtContext) {
1096                 String value = stringFromNode(fdChild);
1097                 try {
1098                     result = Integer.valueOf(value);
1099                 } catch (NumberFormatException e) {
1100                     throw new YangParseException(moduleName, ctx.getStart().getLine(),
1101                             "Unable to parse fraction digits value '" + value + "'.", e);
1102                 }
1103             }
1104         }
1105         return result;
1106     }
1107
1108     /**
1109      * Internal helper method for parsing bit statements from given type body
1110      * context.
1111      *
1112      * @param ctx
1113      *            type body context to parse
1114      * @param actualPath
1115      *            current position in YANG model
1116      * @param moduleName
1117      *            current module name
1118      * @return List of Bit objects created from this context
1119      */
1120     private static List<BitsTypeDefinition.Bit> getBits(final Type_body_stmtsContext ctx, final SchemaPath actualPath,
1121             final String moduleName) {
1122         final List<BitsTypeDefinition.Bit> bits = new ArrayList<>();
1123         for (int j = 0; j < ctx.getChildCount(); j++) {
1124             ParseTree bitsSpecChild = ctx.getChild(j);
1125             if (bitsSpecChild instanceof Bits_specificationContext) {
1126                 long highestPosition = -1;
1127                 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
1128                     ParseTree bitChild = bitsSpecChild.getChild(k);
1129                     if (bitChild instanceof Bit_stmtContext) {
1130                         Bit bit = parseBit((Bit_stmtContext) bitChild, highestPosition, actualPath, moduleName);
1131                         if (bit.getPosition() > highestPosition) {
1132                             highestPosition = bit.getPosition();
1133                         }
1134                         bits.add(bit);
1135                     }
1136                 }
1137             }
1138         }
1139         return bits;
1140     }
1141
1142     /**
1143      * Internal helper method for parsing bit context.
1144      *
1145      * @param ctx
1146      *            bit statement context to parse
1147      * @param highestPosition
1148      *            current highest position in bits type
1149      * @param actualPath
1150      *            current position in YANG model
1151      * @param moduleName
1152      *            current module name
1153      * @return Bit object parsed from this context
1154      */
1155     private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, final long highestPosition,
1156             final SchemaPath actualPath, final String moduleName) {
1157         String name = stringFromNode(ctx);
1158         Long position = null;
1159
1160         String description = null;
1161         String reference = null;
1162         Status status = Status.CURRENT;
1163
1164         SchemaPath schemaPath = createBaseTypePath(actualPath, name);
1165
1166         for (int i = 0; i < ctx.getChildCount(); i++) {
1167             ParseTree child = ctx.getChild(i);
1168             if (child instanceof Position_stmtContext) {
1169                 String positionStr = stringFromNode(child);
1170                 position = Long.valueOf(positionStr);
1171             } else if (child instanceof Description_stmtContext) {
1172                 description = stringFromNode(child);
1173             } else if (child instanceof Reference_stmtContext) {
1174                 reference = stringFromNode(child);
1175             } else if (child instanceof Status_stmtContext) {
1176                 status = parseStatus((Status_stmtContext) child);
1177             }
1178         }
1179
1180         if (position == null) {
1181             position = highestPosition + 1;
1182         }
1183         if (position < 0 || position > 4294967295L) {
1184             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on bit '" + name
1185                     + "': the position value MUST be in the range 0 to 4294967295");
1186         }
1187
1188         final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
1189         return new BitImpl(position, schemaPath.getPathTowardsRoot().iterator().next(), schemaPath,
1190                 description, reference, status, unknownNodes);
1191     }
1192
1193     /**
1194      * Parse 'ordered-by' statement.
1195      *
1196      * The 'ordered-by' statement defines whether the order of entries within a
1197      * list are determined by the user or the system. The argument is one of the
1198      * strings "system" or "user". If not present, order defaults to "system".
1199      *
1200      * @param ctx
1201      *            Ordered_by_stmtContext
1202      * @return true, if ordered-by contains value 'user', false otherwise
1203      */
1204     public static boolean parseUserOrdered(final Ordered_by_stmtContext ctx) {
1205         boolean result = false;
1206         for (int j = 0; j < ctx.getChildCount(); j++) {
1207             ParseTree orderArg = ctx.getChild(j);
1208             if (orderArg instanceof Ordered_by_argContext) {
1209                 String orderStr = stringFromNode(orderArg);
1210                 switch (orderStr) {
1211                 case "system":
1212                     result = false;
1213                     break;
1214                 case "user":
1215                     result = true;
1216                     break;
1217                 default:
1218                     LOG.warn("Invalid 'ordered-by' statement.");
1219                 }
1220             }
1221         }
1222         return result;
1223     }
1224
1225     /**
1226      * Get config statement from given context. If there is no config statement,
1227      * return config value of parent
1228      *
1229      * @param ctx
1230      *            context to parse
1231      * @param node
1232      *            current node
1233      * @param moduleName
1234      *            name of current module
1235      * @param line
1236      *            line in current module
1237      * @return config statement parsed from given context
1238      */
1239     public static boolean getConfig(final ParseTree ctx, final Builder node, final String moduleName, final int line) {
1240         boolean result;
1241         // parse configuration statement
1242         Boolean config = null;
1243         for (int i = 0; i < ctx.getChildCount(); i++) {
1244             ParseTree child = ctx.getChild(i);
1245             if (child instanceof Config_stmtContext) {
1246                 config = parseConfig((Config_stmtContext) child, moduleName);
1247                 break;
1248             }
1249         }
1250
1251         // If 'config' is not specified, the default is the same as the parent
1252         // schema node's 'config' value
1253         boolean parentConfig = getParentConfig(node);
1254         if (config == null) {
1255             result = parentConfig;
1256         } else {
1257             // Check: if a node has 'config' set to 'false', no node underneath
1258             // it can have 'config' set to 'true'
1259             if (!parentConfig && config) {
1260                 throw new YangParseException(moduleName, line,
1261                         "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
1262             }
1263             result = config;
1264         }
1265
1266         return result;
1267     }
1268
1269     private static boolean getParentConfig(final Builder node) {
1270         Builder parent = node.getParent();
1271         boolean config;
1272
1273         if (parent instanceof ChoiceCaseBuilder) {
1274             parent = parent.getParent();
1275         }
1276         if (parent instanceof DataSchemaNodeBuilder) {
1277             config = ((DataSchemaNodeBuilder) parent).isConfiguration();
1278         } else {
1279             config = true;
1280         }
1281         return config;
1282     }
1283
1284     /**
1285      * Parse config statement.
1286      *
1287      * @param ctx
1288      *            config context to parse
1289      * @param moduleName
1290      *            current module name
1291      * @return true if given context contains string 'true', false otherwise
1292      */
1293     private static Boolean parseConfig(final Config_stmtContext ctx, final String moduleName) {
1294         Boolean result = null;
1295         if (ctx != null) {
1296             for (int i = 0; i < ctx.getChildCount(); ++i) {
1297                 final ParseTree configContext = ctx.getChild(i);
1298                 if (configContext instanceof Config_argContext) {
1299                     final String value = stringFromNode(configContext);
1300                     switch (value) {
1301                     case "true":
1302                         result = true;
1303                         break;
1304                     case "false":
1305                         result = false;
1306                         break;
1307                     default:
1308                         throw new YangParseException(moduleName, ctx.getStart().getLine(),
1309                                 "Failed to parse 'config' statement value: '" + value + "'.");
1310                     }
1311                 }
1312             }
1313         }
1314         return result;
1315     }
1316
1317     /**
1318      * Parse unknown type with body.
1319      *
1320      * @param typeBody
1321      *            type body
1322      * @param parent
1323      *            current node parent
1324      * @param prefixedQName
1325      *            type qname with prefix
1326      * @param moduleBuilder
1327      *            current module builder
1328      * @param moduleQName
1329      *            current module qname
1330      * @param actualPath
1331      *            actual path in model
1332      */
1333     public static void parseUnknownTypeWithBody(Type_body_stmtsContext typeBody, TypeAwareBuilder parent,
1334             QName prefixedQName, ModuleBuilder moduleBuilder, QName moduleQName, SchemaPath actualPath) {
1335         final int line = typeBody.getStart().getLine();
1336
1337         List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleBuilder.getName());
1338         List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleBuilder.getName());
1339         List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleBuilder.getName());
1340         Integer fractionDigits = getFractionDigits(typeBody, moduleBuilder.getName());
1341
1342         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1343             TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1344             typedef.setRanges(rangeStatements);
1345             typedef.setLengths(lengthStatements);
1346             typedef.setPatterns(patternStatements);
1347             typedef.setFractionDigits(fractionDigits);
1348             typedef.setTypeQName(prefixedQName);
1349             // add parent node of this type statement to dirty nodes
1350             moduleBuilder.markActualNodeDirty();
1351         } else {
1352             QName qname = QName.create(moduleQName, prefixedQName.getLocalName());
1353             SchemaPath schemaPath = createTypePath(actualPath, prefixedQName.getLocalName());
1354             TypeDefinitionBuilder typeBuilder = new TypeDefinitionBuilderImpl(moduleBuilder.getName(), line, qname, schemaPath);
1355             typeBuilder.setRanges(rangeStatements);
1356             typeBuilder.setLengths(lengthStatements);
1357             typeBuilder.setPatterns(patternStatements);
1358             typeBuilder.setFractionDigits(fractionDigits);
1359             typeBuilder.setTypeQName(prefixedQName);
1360             parent.setTypedef(typeBuilder);
1361             moduleBuilder.getDirtyNodes().add(typeBuilder);
1362         }
1363     }
1364
1365     /**
1366      * Create TypeDefinition object based on given type name and type body.
1367      *
1368      * @param typeName
1369      *            name of type
1370      * @param typeBody
1371      *            type body context
1372      * @param actualPath
1373      *            current path in schema
1374      * @param moduleQName
1375      *            current module qname
1376      * @param parent
1377      *            parent builder
1378      * @return TypeDefinition object based on parsed values.
1379      */
1380     public static TypeDefinition<?> parseTypeWithBody(final String typeName, final Type_body_stmtsContext typeBody,
1381             final SchemaPath actualPath, final QName moduleQName, final Builder parent) {
1382
1383         final String moduleName = parent.getModuleName();
1384         final int line = typeBody.getStart().getLine();
1385         TypeDefinition<?> baseType = null;
1386
1387         Integer fractionDigits = getFractionDigits(typeBody, moduleName);
1388         List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleName);
1389         List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleName);
1390         List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleName);
1391
1392         TypeConstraints constraints = new TypeConstraints(moduleName, line);
1393         constraints.addFractionDigits(fractionDigits);
1394         constraints.addLengths(lengthStatements);
1395         constraints.addPatterns(patternStatements);
1396         constraints.addRanges(rangeStatements);
1397
1398         SchemaPath baseTypePath = createBaseTypePath(actualPath, typeName);
1399         SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, moduleQName, typeName);
1400
1401         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1402             extBaseTypePath = baseTypePath;
1403         }
1404
1405         if ("decimal64".equals(typeName)) {
1406             if (rangeStatements.isEmpty()) {
1407                 try {
1408                     return Decimal64.create(baseTypePath, fractionDigits);
1409                 } catch(Exception e) {
1410                     throw new YangParseException(moduleName, line, e.getMessage());
1411                 }
1412             }
1413             Decimal64 decimalType = Decimal64.create(extBaseTypePath, fractionDigits);
1414             constraints.addRanges(decimalType.getRangeConstraints());
1415             baseType = decimalType;
1416         } else if (typeName.startsWith("int")) {
1417             IntegerTypeDefinition intType = null;
1418             switch (typeName) {
1419             case "int8":
1420                 intType = Int8.getInstance();
1421                 break;
1422             case "int16":
1423                 intType = Int16.getInstance();
1424                 break;
1425             case "int32":
1426                 intType = Int32.getInstance();
1427                 break;
1428             case "int64":
1429                 intType = Int64.getInstance();
1430                 break;
1431             }
1432             if (intType == null) {
1433                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1434             }
1435             constraints.addRanges(intType.getRangeConstraints());
1436             baseType = intType;
1437         } else if (typeName.startsWith("uint")) {
1438             UnsignedIntegerTypeDefinition uintType = null;
1439             switch (typeName) {
1440             case "uint8":
1441                 uintType = Uint8.getInstance();
1442                 break;
1443             case "uint16":
1444                 uintType = Uint16.getInstance();
1445                 break;
1446             case "uint32":
1447                 uintType = Uint32.getInstance();
1448                 break;
1449             case "uint64":
1450                 uintType = Uint64.getInstance();
1451                 break;
1452             }
1453             if (uintType == null) {
1454                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1455             }
1456             constraints.addRanges(uintType.getRangeConstraints());
1457             baseType = uintType;
1458         } else if ("enumeration".equals(typeName)) {
1459             List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
1460             return EnumerationType.create(baseTypePath, enumConstants, Optional.<EnumPair> absent());
1461         } else if ("string".equals(typeName)) {
1462             StringTypeDefinition stringType = StringType.getInstance();
1463             constraints.addLengths(stringType.getLengthConstraints());
1464             baseType = stringType;
1465         } else if ("bits".equals(typeName)) {
1466             return BitsType.create(baseTypePath, getBits(typeBody, actualPath, moduleName));
1467         } else if ("leafref".equals(typeName)) {
1468             final String path = parseLeafrefPath(typeBody);
1469             final boolean absolute = path.startsWith("/");
1470             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
1471             return new Leafref(xpath);
1472         } else if ("binary".equals(typeName)) {
1473             BinaryTypeDefinition binaryType = BinaryType.getInstance();
1474             constraints.addLengths(binaryType.getLengthConstraints());
1475             baseType = binaryType;
1476         } else if ("instance-identifier".equals(typeName)) {
1477             return InstanceIdentifierType.create(isRequireInstance(typeBody));
1478         }
1479
1480         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1481             TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1482             typedef.setRanges(constraints.getRange());
1483             typedef.setLengths(constraints.getLength());
1484             typedef.setPatterns(constraints.getPatterns());
1485             typedef.setFractionDigits(constraints.getFractionDigits());
1486             return baseType;
1487         }
1488
1489         QName qname = QName.create(moduleQName, typeName);
1490         SchemaPath schemaPath = actualPath.createChild(qname);
1491         final Optional<String> opt = Optional.of("");
1492         ExtendedType.Builder typeBuilder = ExtendedType.builder(qname, baseType, opt, opt, schemaPath);
1493
1494         typeBuilder.ranges(constraints.getRange());
1495         typeBuilder.lengths(constraints.getLength());
1496         typeBuilder.patterns(constraints.getPatterns());
1497         typeBuilder.fractionDigits(constraints.getFractionDigits());
1498
1499         return typeBuilder.build();
1500     }
1501
1502     private static SchemaPath createTypePath(final SchemaPath actual, final String typeName) {
1503         QName last = actual.getLastComponent();
1504         return actual.createChild(QName.create(last, typeName));
1505     }
1506
1507     private static SchemaPath createBaseTypePath(final SchemaPath actual, final String typeName) {
1508         return actual.createChild(BaseTypes.constructQName(typeName));
1509     }
1510
1511     private static SchemaPath createExtendedBaseTypePath(final SchemaPath actual, final QName moduleQName, final String typeName) {
1512         return actual.createChild(
1513                 QName.create(moduleQName, typeName),
1514                 BaseTypes.constructQName(typeName));
1515     }
1516
1517     /**
1518      * Parse given context and find identityref base value.
1519      *
1520      * @param ctx
1521      *            type body
1522      * @return identityref base value as String
1523      */
1524     public static String getIdentityrefBase(final Type_body_stmtsContext ctx) {
1525         String result = null;
1526         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1527             ParseTree child = ctx.getChild(i);
1528             if (child instanceof Identityref_specificationContext) {
1529                 for (int j = 0; j < child.getChildCount(); j++) {
1530                     ParseTree baseArg = child.getChild(j);
1531                     if (baseArg instanceof Base_stmtContext) {
1532                         result = stringFromNode(baseArg);
1533                         break outer;
1534                     }
1535                 }
1536             }
1537         }
1538         return result;
1539     }
1540
1541     /**
1542      * Parse type body statement and find require-instance value.
1543      *
1544      * @param ctx
1545      *            type body context
1546      * @return require-instance value
1547      */
1548     private static boolean isRequireInstance(final Type_body_stmtsContext ctx) {
1549         for (int i = 0; i < ctx.getChildCount(); i++) {
1550             ParseTree child = ctx.getChild(i);
1551             if (child instanceof Instance_identifier_specificationContext) {
1552                 for (int j = 0; j < child.getChildCount(); j++) {
1553                     ParseTree reqStmt = child.getChild(j);
1554                     if (reqStmt instanceof Require_instance_stmtContext) {
1555                         for (int k = 0; k < reqStmt.getChildCount(); k++) {
1556                             ParseTree reqArg = reqStmt.getChild(k);
1557                             if (reqArg instanceof Require_instance_argContext) {
1558                                 return Boolean.valueOf(stringFromNode(reqArg));
1559                             }
1560                         }
1561                     }
1562                 }
1563             }
1564         }
1565         return true;
1566     }
1567
1568     /**
1569      * Parse type body statement and find leafref path.
1570      *
1571      * @param ctx
1572      *            type body context
1573      * @return leafref path as String
1574      */
1575     private static String parseLeafrefPath(final Type_body_stmtsContext ctx) {
1576         for (int i = 0; i < ctx.getChildCount(); i++) {
1577             ParseTree child = ctx.getChild(i);
1578             if (child instanceof Leafref_specificationContext) {
1579                 for (int j = 0; j < child.getChildCount(); j++) {
1580                     ParseTree leafRefSpec = child.getChild(j);
1581                     if (leafRefSpec instanceof Path_stmtContext) {
1582                         return stringFromNode(leafRefSpec);
1583                     }
1584                 }
1585             }
1586         }
1587         return null;
1588     }
1589
1590     /**
1591      * Internal helper method for parsing must statement.
1592      *
1593      * @param ctx
1594      *            Must_stmtContext
1595      * @return MustDefinition object based on parsed context
1596      */
1597     private static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
1598         StringBuilder mustText = new StringBuilder();
1599         Optional<String> description = Optional.absent();
1600         Optional<String> reference = Optional.absent();
1601         Optional<String> errorAppTag = Optional.absent();
1602         Optional<String> errorMessage = Optional.absent();
1603         for (int i = 0; i < ctx.getChildCount(); ++i) {
1604             ParseTree child = ctx.getChild(i);
1605             if (child instanceof StringContext) {
1606                 final StringContext context = (StringContext) child;
1607                 if (context.getChildCount() == 1) {
1608                     String mustPart = context.getChild(0).getText();
1609                     // trim start and end quotation
1610                     mustText.append(mustPart.substring(1, mustPart.length() - 1));
1611                 } else {
1612                     for (int j = 0; j < context.getChildCount(); j++) {
1613                         String mustPart = context.getChild(j).getText();
1614                         if (j == 0) {
1615                             mustText.append(mustPart.substring(0, mustPart.length() - 1));
1616                             continue;
1617                         }
1618                         if (j % 2 == 0) {
1619                             mustText.append(mustPart.substring(1));
1620                         }
1621                     }
1622                 }
1623             } else if (child instanceof Description_stmtContext) {
1624                 description = Optional.of(stringFromNode(child));
1625             } else if (child instanceof Reference_stmtContext) {
1626                 reference = Optional.of(stringFromNode(child));
1627             } else if (child instanceof Error_app_tag_stmtContext) {
1628                 errorAppTag = Optional.of(stringFromNode(child));
1629             } else if (child instanceof Error_message_stmtContext) {
1630                 errorMessage = Optional.of(stringFromNode(child));
1631             }
1632         }
1633
1634         return MustDefinitionImpl.create(mustText.toString(), description, reference, errorAppTag, errorMessage);
1635     }
1636
1637     /**
1638      * Parse given context and set constraints to constraints builder.
1639      *
1640      * @param ctx
1641      *            context to parse
1642      * @param constraints
1643      *            ConstraintsBuilder to fill
1644      */
1645     public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) {
1646         for (int i = 0; i < ctx.getChildCount(); ++i) {
1647             final ParseTree childNode = ctx.getChild(i);
1648             if (childNode instanceof Max_elements_stmtContext) {
1649                 Integer max = parseMaxElements((Max_elements_stmtContext) childNode, constraints.getModuleName());
1650                 constraints.setMaxElements(max);
1651             } else if (childNode instanceof Min_elements_stmtContext) {
1652                 Integer min = parseMinElements((Min_elements_stmtContext) childNode, constraints.getModuleName());
1653                 constraints.setMinElements(min);
1654             } else if (childNode instanceof Must_stmtContext) {
1655                 MustDefinition must = parseMust((Must_stmtContext) childNode);
1656                 constraints.addMustDefinition(must);
1657             } else if (childNode instanceof Mandatory_stmtContext) {
1658                 for (int j = 0; j < childNode.getChildCount(); j++) {
1659                     ParseTree mandatoryTree = childNode.getChild(j);
1660                     if (mandatoryTree instanceof Mandatory_argContext) {
1661                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1662                         constraints.setMandatory(mandatory);
1663                     }
1664                 }
1665             } else if (childNode instanceof When_stmtContext) {
1666                 constraints.addWhenCondition(stringFromNode(childNode));
1667             }
1668         }
1669     }
1670
1671     private static Integer parseMinElements(final Min_elements_stmtContext ctx, final String moduleName) {
1672         Integer result = null;
1673         try {
1674             for (int i = 0; i < ctx.getChildCount(); i++) {
1675                 ParseTree minArg = ctx.getChild(i);
1676                 if (minArg instanceof Min_value_argContext) {
1677                     result = Integer.valueOf(stringFromNode(minArg));
1678                 }
1679             }
1680             if (result == null) {
1681                 throw new IllegalArgumentException();
1682             }
1683             return result;
1684         } catch (Exception e) {
1685             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
1686         }
1687     }
1688
1689     private static Integer parseMaxElements(final Max_elements_stmtContext ctx, final String moduleName) {
1690         Integer result = null;
1691         try {
1692             for (int i = 0; i < ctx.getChildCount(); i++) {
1693                 ParseTree maxArg = ctx.getChild(i);
1694                 if (maxArg instanceof Max_value_argContext) {
1695                     String maxValue = stringFromNode(maxArg);
1696                     if ("unbounded".equals(maxValue)) {
1697                         result = Integer.MAX_VALUE;
1698                     } else {
1699                         result = Integer.valueOf(maxValue);
1700                     }
1701                 }
1702             }
1703             if (result == null) {
1704                 throw new IllegalArgumentException();
1705             }
1706             return result;
1707         } catch (Exception e) {
1708             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
1709         }
1710     }
1711
1712     /**
1713      * Parse given context and return yin value.
1714      *
1715      * @param ctx
1716      *            context to parse
1717      * @return true if value is 'true', false otherwise
1718      */
1719     public static boolean parseYinValue(final Argument_stmtContext ctx) {
1720         boolean yinValue = false;
1721         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1722             ParseTree yin = ctx.getChild(i);
1723             if (yin instanceof Yin_element_stmtContext) {
1724                 for (int j = 0; j < yin.getChildCount(); j++) {
1725                     ParseTree yinArg = yin.getChild(j);
1726                     if (yinArg instanceof Yin_element_argContext) {
1727                         String yinString = stringFromNode(yinArg);
1728                         if ("true".equals(yinString)) {
1729                             yinValue = true;
1730                             break outer;
1731                         }
1732                     }
1733                 }
1734             }
1735         }
1736         return yinValue;
1737     }
1738
1739     /**
1740      * Check this base type.
1741      *
1742      * @param typeName
1743      *            base YANG type name
1744      * @param moduleName
1745      *            name of current module
1746      * @param line
1747      *            line in module
1748      * @throws YangParseException
1749      *             if this is one of YANG type which MUST contain additional
1750      *             informations in its body
1751      */
1752     public static void checkMissingBody(final String typeName, final String moduleName, final int line) {
1753         switch (typeName) {
1754         case "decimal64":
1755             throw new YangParseException(moduleName, line,
1756                     "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1757         case "identityref":
1758             throw new YangParseException(moduleName, line,
1759                     "The 'base' statement MUST be present if the type is 'identityref'.");
1760         case "leafref":
1761             throw new YangParseException(moduleName, line,
1762                     "The 'path' statement MUST be present if the type is 'leafref'.");
1763         case "bits":
1764             throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
1765         case "enumeration":
1766             throw new YangParseException(moduleName, line,
1767                     "The 'enum' statement MUST be present if the type is 'enumeration'.");
1768         }
1769     }
1770
1771     /**
1772      * Parse refine statement.
1773      *
1774      * @param refineCtx
1775      *            refine statement
1776      * @param moduleName
1777      *            name of current module
1778      * @return RefineHolder object representing this refine statement
1779      */
1780     public static RefineHolderImpl parseRefine(final Refine_stmtContext refineCtx, final String moduleName) {
1781         final String refineTarget = stringFromNode(refineCtx);
1782         final RefineHolderImpl refine = new RefineHolderImpl(moduleName, refineCtx.getStart().getLine(), refineTarget);
1783         for (int i = 0; i < refineCtx.getChildCount(); i++) {
1784             ParseTree refinePom = refineCtx.getChild(i);
1785             if (refinePom instanceof Refine_pomContext) {
1786                 for (int j = 0; j < refinePom.getChildCount(); j++) {
1787                     ParseTree refineStmt = refinePom.getChild(j);
1788                     parseRefineDefault(refine, refineStmt);
1789
1790                     if (refineStmt instanceof Refine_leaf_stmtsContext) {
1791                         parseRefine(refine, (Refine_leaf_stmtsContext) refineStmt);
1792                     } else if (refineStmt instanceof Refine_container_stmtsContext) {
1793                         parseRefine(refine, (Refine_container_stmtsContext) refineStmt);
1794                     } else if (refineStmt instanceof Refine_list_stmtsContext) {
1795                         parseRefine(refine, (Refine_list_stmtsContext) refineStmt);
1796                     } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1797                         parseRefine(refine, (Refine_leaf_list_stmtsContext) refineStmt);
1798                     } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1799                         parseRefine(refine, (Refine_choice_stmtsContext) refineStmt);
1800                     } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1801                         parseRefine(refine, (Refine_anyxml_stmtsContext) refineStmt);
1802                     }
1803                 }
1804             }
1805         }
1806         return refine;
1807     }
1808
1809     private static void parseRefineDefault(final RefineHolderImpl refine, final ParseTree refineStmt) {
1810         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1811             ParseTree refineArg = refineStmt.getChild(i);
1812             if (refineArg instanceof Description_stmtContext) {
1813                 String description = stringFromNode(refineArg);
1814                 refine.setDescription(description);
1815             } else if (refineArg instanceof Reference_stmtContext) {
1816                 String reference = stringFromNode(refineArg);
1817                 refine.setReference(reference);
1818             } else if (refineArg instanceof Config_stmtContext) {
1819                 Boolean config = parseConfig((Config_stmtContext) refineArg, refine.getModuleName());
1820                 refine.setConfiguration(config);
1821             }
1822         }
1823     }
1824
1825     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_stmtsContext refineStmt) {
1826         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1827             ParseTree refineArg = refineStmt.getChild(i);
1828             if (refineArg instanceof Default_stmtContext) {
1829                 String defaultStr = stringFromNode(refineArg);
1830                 refine.setDefaultStr(defaultStr);
1831             } else if (refineArg instanceof Mandatory_stmtContext) {
1832                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1833                     ParseTree mandatoryTree = refineArg.getChild(j);
1834                     if (mandatoryTree instanceof Mandatory_argContext) {
1835                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1836                         refine.setMandatory(mandatory);
1837                     }
1838                 }
1839             } else if (refineArg instanceof Must_stmtContext) {
1840                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1841                 refine.setMust(must);
1842
1843             }
1844         }
1845         return refine;
1846     }
1847
1848     private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_container_stmtsContext refineStmt) {
1849         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1850             ParseTree refineArg = refineStmt.getChild(i);
1851             if (refineArg instanceof Must_stmtContext) {
1852                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1853                 refine.setMust(must);
1854             } else if (refineArg instanceof Presence_stmtContext) {
1855                 refine.setPresence(true);
1856             }
1857         }
1858         return refine;
1859     }
1860
1861     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_list_stmtsContext refineStmt) {
1862         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1863             ParseTree refineArg = refineStmt.getChild(i);
1864             if (refineArg instanceof Must_stmtContext) {
1865                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1866                 refine.setMust(must);
1867             } else if (refineArg instanceof Max_elements_stmtContext) {
1868                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1869                 refine.setMaxElements(max);
1870             } else if (refineArg instanceof Min_elements_stmtContext) {
1871                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1872                 refine.setMinElements(min);
1873             }
1874         }
1875         return refine;
1876     }
1877
1878     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_list_stmtsContext refineStmt) {
1879         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1880             ParseTree refineArg = refineStmt.getChild(i);
1881             if (refineArg instanceof Must_stmtContext) {
1882                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1883                 refine.setMust(must);
1884             } else if (refineArg instanceof Max_elements_stmtContext) {
1885                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1886                 refine.setMaxElements(max);
1887             } else if (refineArg instanceof Min_elements_stmtContext) {
1888                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1889                 refine.setMinElements(min);
1890             }
1891         }
1892         return refine;
1893     }
1894
1895     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_choice_stmtsContext refineStmt) {
1896         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1897             ParseTree refineArg = refineStmt.getChild(i);
1898             if (refineArg instanceof Default_stmtContext) {
1899                 String defaultStr = stringFromNode(refineArg);
1900                 refine.setDefaultStr(defaultStr);
1901             } else if (refineArg instanceof Mandatory_stmtContext) {
1902                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1903                     ParseTree mandatoryTree = refineArg.getChild(j);
1904                     if (mandatoryTree instanceof Mandatory_argContext) {
1905                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1906                         refine.setMandatory(mandatory);
1907                     }
1908                 }
1909             }
1910         }
1911         return refine;
1912     }
1913
1914     private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_anyxml_stmtsContext refineStmt) {
1915         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1916             ParseTree refineArg = refineStmt.getChild(i);
1917             if (refineArg instanceof Must_stmtContext) {
1918                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1919                 refine.setMust(must);
1920             } else if (refineArg instanceof Mandatory_stmtContext) {
1921                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1922                     ParseTree mandatoryTree = refineArg.getChild(j);
1923                     if (mandatoryTree instanceof Mandatory_argContext) {
1924                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1925                         refine.setMandatory(mandatory);
1926                     }
1927                 }
1928             }
1929         }
1930         return refine;
1931     }
1932
1933     public static String getArgumentString(final org.antlr.v4.runtime.ParserRuleContext ctx) {
1934         List<StringContext> potentialValues = ctx.getRuleContexts(StringContext.class);
1935         checkState(!potentialValues.isEmpty());
1936         return ParserListenerUtils.stringFromStringContext(potentialValues.get(0));
1937     }
1938
1939     public static <T extends ParserRuleContext> Optional<T> getFirstContext(final ParserRuleContext context,final Class<T> contextType) {
1940         List<T> potential = context.getRuleContexts(contextType);
1941         if(potential.isEmpty()) {
1942             return Optional.absent();
1943         }
1944         return Optional.of(potential.get(0));
1945     }
1946
1947 }