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