BUG-865: deprecate pre-Beryllium parser elements
[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         final StringBuilder wrapPatternBuilder = new StringBuilder(rawPattern.length() + 2);
1022         wrapPatternBuilder.append('^');
1023         wrapPatternBuilder.append(rawPattern);
1024         wrapPatternBuilder.append('$');
1025         return wrapPatternBuilder.toString();
1026     }
1027
1028     private static boolean isValidPattern(final String pattern, final Pattern_stmtContext ctx, final String moduleName) {
1029         try {
1030             Pattern.compile(pattern);
1031             return true;
1032         } catch (PatternSyntaxException ex) {
1033             LOG.warn("Unable to compile pattern defined in module {} at line {}. Error message: {}",
1034                 moduleName, ctx.getStart().getLine(), ex.getMessage());
1035         }
1036         return false;
1037     }
1038
1039     /**
1040      * Parse given context and return pattern value.
1041      *
1042      * @param ctx
1043      *            context to parse
1044      * @return pattern value as String
1045      */
1046     private static String parsePatternString(final Pattern_stmtContext ctx) {
1047         StringBuilder result = new StringBuilder();
1048         for (int i = 0; i < ctx.getChildCount(); ++i) {
1049             ParseTree child = ctx.getChild(i);
1050             if (child instanceof StringContext) {
1051                 for (int j = 0; j < child.getChildCount(); j++) {
1052                     if (j % 2 == 0) {
1053                         String patternToken = child.getChild(j).getText();
1054                         result.append(patternToken.substring(1, patternToken.length() - 1));
1055                     }
1056                 }
1057             }
1058         }
1059         return result.toString();
1060     }
1061
1062     /**
1063      * Get fraction digits value from type body.
1064      *
1065      * @param ctx
1066      *            type body context to parse
1067      * @param moduleName
1068      *            name of current module
1069      * @return 'fraction-digits' value if present in given context, null
1070      *         otherwise
1071      */
1072     private static Integer getFractionDigits(final Type_body_stmtsContext ctx, final String moduleName) {
1073         Integer result = null;
1074         for (int i = 0; i < ctx.getChildCount(); i++) {
1075             ParseTree dec64specChild = ctx.getChild(i);
1076             if (dec64specChild instanceof Decimal64_specificationContext) {
1077                 result = parseFractionDigits((Decimal64_specificationContext) dec64specChild, moduleName);
1078             }
1079         }
1080         return result;
1081     }
1082
1083     /**
1084      * Parse decimal64 fraction-digits value.
1085      *
1086      * @param ctx
1087      *            decimal64 context
1088      * @param moduleName
1089      *            name of current module
1090      * @return fraction-digits value as Integer
1091      */
1092     private static Integer parseFractionDigits(final Decimal64_specificationContext ctx, final String moduleName) {
1093         Integer result = null;
1094         for (int i = 0; i < ctx.getChildCount(); i++) {
1095             ParseTree fdChild = ctx.getChild(i);
1096             if (fdChild instanceof Fraction_digits_stmtContext) {
1097                 String value = stringFromNode(fdChild);
1098                 try {
1099                     result = Integer.valueOf(value);
1100                 } catch (NumberFormatException e) {
1101                     throw new YangParseException(moduleName, ctx.getStart().getLine(),
1102                             "Unable to parse fraction digits value '" + value + "'.", e);
1103                 }
1104             }
1105         }
1106         return result;
1107     }
1108
1109     /**
1110      * Internal helper method for parsing bit statements from given type body
1111      * context.
1112      *
1113      * @param ctx
1114      *            type body context to parse
1115      * @param actualPath
1116      *            current position in YANG model
1117      * @param moduleName
1118      *            current module name
1119      * @return List of Bit objects created from this context
1120      */
1121     private static List<BitsTypeDefinition.Bit> getBits(final Type_body_stmtsContext ctx, final SchemaPath actualPath,
1122             final String moduleName) {
1123         final List<BitsTypeDefinition.Bit> bits = new ArrayList<>();
1124         for (int j = 0; j < ctx.getChildCount(); j++) {
1125             ParseTree bitsSpecChild = ctx.getChild(j);
1126             if (bitsSpecChild instanceof Bits_specificationContext) {
1127                 long highestPosition = -1;
1128                 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
1129                     ParseTree bitChild = bitsSpecChild.getChild(k);
1130                     if (bitChild instanceof Bit_stmtContext) {
1131                         Bit bit = parseBit((Bit_stmtContext) bitChild, highestPosition, actualPath, moduleName);
1132                         if (bit.getPosition() > highestPosition) {
1133                             highestPosition = bit.getPosition();
1134                         }
1135                         bits.add(bit);
1136                     }
1137                 }
1138             }
1139         }
1140         return bits;
1141     }
1142
1143     /**
1144      * Internal helper method for parsing bit context.
1145      *
1146      * @param ctx
1147      *            bit statement context to parse
1148      * @param highestPosition
1149      *            current highest position in bits type
1150      * @param actualPath
1151      *            current position in YANG model
1152      * @param moduleName
1153      *            current module name
1154      * @return Bit object parsed from this context
1155      */
1156     private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, final long highestPosition,
1157             final SchemaPath actualPath, final String moduleName) {
1158         String name = stringFromNode(ctx);
1159         Long position = null;
1160
1161         String description = null;
1162         String reference = null;
1163         Status status = Status.CURRENT;
1164
1165         SchemaPath schemaPath = createBaseTypePath(actualPath, name);
1166
1167         for (int i = 0; i < ctx.getChildCount(); i++) {
1168             ParseTree child = ctx.getChild(i);
1169             if (child instanceof Position_stmtContext) {
1170                 String positionStr = stringFromNode(child);
1171                 position = Long.valueOf(positionStr);
1172             } else if (child instanceof Description_stmtContext) {
1173                 description = stringFromNode(child);
1174             } else if (child instanceof Reference_stmtContext) {
1175                 reference = stringFromNode(child);
1176             } else if (child instanceof Status_stmtContext) {
1177                 status = parseStatus((Status_stmtContext) child);
1178             }
1179         }
1180
1181         if (position == null) {
1182             position = highestPosition + 1;
1183         }
1184         if (position < 0 || position > 4294967295L) {
1185             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on bit '" + name
1186                     + "': the position value MUST be in the range 0 to 4294967295");
1187         }
1188
1189         final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
1190         return new BitImpl(position, schemaPath.getPathTowardsRoot().iterator().next(), schemaPath,
1191                 description, reference, status, unknownNodes);
1192     }
1193
1194     /**
1195      * Parse 'ordered-by' statement.
1196      *
1197      * The 'ordered-by' statement defines whether the order of entries within a
1198      * list are determined by the user or the system. The argument is one of the
1199      * strings "system" or "user". If not present, order defaults to "system".
1200      *
1201      * @param ctx
1202      *            Ordered_by_stmtContext
1203      * @return true, if ordered-by contains value 'user', false otherwise
1204      */
1205     public static boolean parseUserOrdered(final Ordered_by_stmtContext ctx) {
1206         boolean result = false;
1207         for (int j = 0; j < ctx.getChildCount(); j++) {
1208             ParseTree orderArg = ctx.getChild(j);
1209             if (orderArg instanceof Ordered_by_argContext) {
1210                 String orderStr = stringFromNode(orderArg);
1211                 switch (orderStr) {
1212                 case "system":
1213                     result = false;
1214                     break;
1215                 case "user":
1216                     result = true;
1217                     break;
1218                 default:
1219                     LOG.warn("Invalid 'ordered-by' statement.");
1220                 }
1221             }
1222         }
1223         return result;
1224     }
1225
1226     /**
1227      * Get config statement from given context. If there is no config statement,
1228      * return config value of parent
1229      *
1230      * @param ctx
1231      *            context to parse
1232      * @param node
1233      *            current node
1234      * @param moduleName
1235      *            name of current module
1236      * @param line
1237      *            line in current module
1238      * @return config statement parsed from given context
1239      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1240      */
1241     @Deprecated
1242     public static boolean getConfig(final ParseTree ctx, final Builder node, final String moduleName, final int line) {
1243         boolean result;
1244         // parse configuration statement
1245         Boolean config = null;
1246         for (int i = 0; i < ctx.getChildCount(); i++) {
1247             ParseTree child = ctx.getChild(i);
1248             if (child instanceof Config_stmtContext) {
1249                 config = parseConfig((Config_stmtContext) child, moduleName);
1250                 break;
1251             }
1252         }
1253
1254         // If 'config' is not specified, the default is the same as the parent
1255         // schema node's 'config' value
1256         boolean parentConfig = getParentConfig(node);
1257         if (config == null) {
1258             result = parentConfig;
1259         } else {
1260             // Check: if a node has 'config' set to 'false', no node underneath
1261             // it can have 'config' set to 'true'
1262             if (!parentConfig && config) {
1263                 throw new YangParseException(moduleName, line,
1264                         "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
1265             }
1266             result = config;
1267         }
1268
1269         return result;
1270     }
1271
1272     /**
1273      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1274      */
1275     @Deprecated
1276     private static boolean getParentConfig(final Builder node) {
1277         Builder parent = node.getParent();
1278         boolean config;
1279
1280         if (parent instanceof ChoiceCaseBuilder) {
1281             parent = parent.getParent();
1282         }
1283         if (parent instanceof DataSchemaNodeBuilder) {
1284             config = ((DataSchemaNodeBuilder) parent).isConfiguration();
1285         } else {
1286             config = true;
1287         }
1288         return config;
1289     }
1290
1291     /**
1292      * Parse config statement.
1293      *
1294      * @param ctx
1295      *            config context to parse
1296      * @param moduleName
1297      *            current module name
1298      * @return true if given context contains string 'true', false otherwise
1299      */
1300     private static Boolean parseConfig(final Config_stmtContext ctx, final String moduleName) {
1301         Boolean result = null;
1302         if (ctx != null) {
1303             for (int i = 0; i < ctx.getChildCount(); ++i) {
1304                 final ParseTree configContext = ctx.getChild(i);
1305                 if (configContext instanceof Config_argContext) {
1306                     final String value = stringFromNode(configContext);
1307                     switch (value) {
1308                     case "true":
1309                         result = true;
1310                         break;
1311                     case "false":
1312                         result = false;
1313                         break;
1314                     default:
1315                         throw new YangParseException(moduleName, ctx.getStart().getLine(),
1316                                 "Failed to parse 'config' statement value: '" + value + "'.");
1317                     }
1318                 }
1319             }
1320         }
1321         return result;
1322     }
1323
1324     /**
1325      * Parse unknown type with body.
1326      *
1327      * @param typeBody
1328      *            type body
1329      * @param parent
1330      *            current node parent
1331      * @param prefixedQName
1332      *            type qname with prefix
1333      * @param moduleBuilder
1334      *            current module builder
1335      * @param moduleQName
1336      *            current module qname
1337      * @param actualPath
1338      *            actual path in model
1339      *
1340      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1341      */
1342     @Deprecated
1343     public static void parseUnknownTypeWithBody(final Type_body_stmtsContext typeBody, final TypeAwareBuilder parent,
1344             final QName prefixedQName, final ModuleBuilder moduleBuilder, final QName moduleQName, final SchemaPath actualPath) {
1345         final int line = typeBody.getStart().getLine();
1346
1347         List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleBuilder.getName());
1348         List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleBuilder.getName());
1349         List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleBuilder.getName());
1350         Integer fractionDigits = getFractionDigits(typeBody, moduleBuilder.getName());
1351
1352         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1353             TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1354             typedef.setRanges(rangeStatements);
1355             typedef.setLengths(lengthStatements);
1356             typedef.setPatterns(patternStatements);
1357             typedef.setFractionDigits(fractionDigits);
1358             typedef.setTypeQName(prefixedQName);
1359             // add parent node of this type statement to dirty nodes
1360             moduleBuilder.markActualNodeDirty();
1361         } else {
1362             QName qname = QName.create(moduleQName, prefixedQName.getLocalName());
1363             SchemaPath schemaPath = createTypePath(actualPath, prefixedQName.getLocalName());
1364             TypeDefinitionBuilder typeBuilder = new TypeDefinitionBuilderImpl(moduleBuilder.getName(), line, qname, schemaPath);
1365             typeBuilder.setRanges(rangeStatements);
1366             typeBuilder.setLengths(lengthStatements);
1367             typeBuilder.setPatterns(patternStatements);
1368             typeBuilder.setFractionDigits(fractionDigits);
1369             typeBuilder.setTypeQName(prefixedQName);
1370             parent.setTypedef(typeBuilder);
1371             moduleBuilder.getDirtyNodes().add(typeBuilder);
1372         }
1373     }
1374
1375     /**
1376      * Create TypeDefinition object based on given type name and type body.
1377      *
1378      * @param typeName
1379      *            name of type
1380      * @param typeBody
1381      *            type body context
1382      * @param actualPath
1383      *            current path in schema
1384      * @param moduleQName
1385      *            current module qname
1386      * @param parent
1387      *            parent builder
1388      * @return TypeDefinition object based on parsed values.
1389      *
1390      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1391      */
1392     @Deprecated
1393     public static TypeDefinition<?> parseTypeWithBody(final String typeName, final Type_body_stmtsContext typeBody,
1394             final SchemaPath actualPath, final QName moduleQName, final Builder parent) {
1395
1396         final String moduleName = parent.getModuleName();
1397         final int line = typeBody.getStart().getLine();
1398         TypeDefinition<?> baseType = null;
1399
1400         Integer fractionDigits = getFractionDigits(typeBody, moduleName);
1401         List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleName);
1402         List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleName);
1403         List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleName);
1404
1405         TypeConstraints constraints = new TypeConstraints(moduleName, line);
1406         constraints.addFractionDigits(fractionDigits);
1407         constraints.addLengths(lengthStatements);
1408         constraints.addPatterns(patternStatements);
1409         constraints.addRanges(rangeStatements);
1410
1411         SchemaPath baseTypePath = createBaseTypePath(actualPath, typeName);
1412         SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, moduleQName, typeName);
1413
1414         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1415             extBaseTypePath = baseTypePath;
1416         }
1417
1418         if ("decimal64".equals(typeName)) {
1419             if (rangeStatements.isEmpty()) {
1420                 try {
1421                     return Decimal64.create(baseTypePath, fractionDigits);
1422                 } catch(Exception e) {
1423                     throw new YangParseException(moduleName, line, e.getMessage());
1424                 }
1425             }
1426             Decimal64 decimalType = Decimal64.create(extBaseTypePath, fractionDigits);
1427             constraints.addRanges(decimalType.getRangeConstraints());
1428             baseType = decimalType;
1429         } else if (typeName.startsWith("int")) {
1430             IntegerTypeDefinition intType = null;
1431             switch (typeName) {
1432             case "int8":
1433                 intType = Int8.getInstance();
1434                 break;
1435             case "int16":
1436                 intType = Int16.getInstance();
1437                 break;
1438             case "int32":
1439                 intType = Int32.getInstance();
1440                 break;
1441             case "int64":
1442                 intType = Int64.getInstance();
1443                 break;
1444             }
1445             if (intType == null) {
1446                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1447             }
1448             constraints.addRanges(intType.getRangeConstraints());
1449             baseType = intType;
1450         } else if (typeName.startsWith("uint")) {
1451             UnsignedIntegerTypeDefinition uintType = null;
1452             switch (typeName) {
1453             case "uint8":
1454                 uintType = Uint8.getInstance();
1455                 break;
1456             case "uint16":
1457                 uintType = Uint16.getInstance();
1458                 break;
1459             case "uint32":
1460                 uintType = Uint32.getInstance();
1461                 break;
1462             case "uint64":
1463                 uintType = Uint64.getInstance();
1464                 break;
1465             }
1466             if (uintType == null) {
1467                 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1468             }
1469             constraints.addRanges(uintType.getRangeConstraints());
1470             baseType = uintType;
1471         } else if ("enumeration".equals(typeName)) {
1472             List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
1473             return EnumerationType.create(baseTypePath, enumConstants, Optional.<EnumPair> absent());
1474         } else if ("string".equals(typeName)) {
1475             StringTypeDefinition stringType = StringType.getInstance();
1476             constraints.addLengths(stringType.getLengthConstraints());
1477             baseType = stringType;
1478         } else if ("bits".equals(typeName)) {
1479             return BitsType.create(baseTypePath, getBits(typeBody, actualPath, moduleName));
1480         } else if ("leafref".equals(typeName)) {
1481             final String path = parseLeafrefPath(typeBody);
1482             final boolean absolute = path.startsWith("/");
1483             RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
1484             return new Leafref(xpath);
1485         } else if ("binary".equals(typeName)) {
1486             BinaryTypeDefinition binaryType = BinaryType.getInstance();
1487             constraints.addLengths(binaryType.getLengthConstraints());
1488             baseType = binaryType;
1489         } else if ("instance-identifier".equals(typeName)) {
1490             return InstanceIdentifierType.create(isRequireInstance(typeBody));
1491         }
1492
1493         if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1494             TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1495             typedef.setRanges(constraints.getRange());
1496             typedef.setLengths(constraints.getLength());
1497             typedef.setPatterns(constraints.getPatterns());
1498             typedef.setFractionDigits(constraints.getFractionDigits());
1499             return baseType;
1500         }
1501
1502         QName qname = QName.create(moduleQName, typeName);
1503         SchemaPath schemaPath = actualPath.createChild(qname);
1504         final Optional<String> opt = Optional.of("");
1505         ExtendedType.Builder typeBuilder = ExtendedType.builder(qname, baseType, opt, opt, schemaPath);
1506
1507         typeBuilder.ranges(constraints.getRange());
1508         typeBuilder.lengths(constraints.getLength());
1509         typeBuilder.patterns(constraints.getPatterns());
1510         typeBuilder.fractionDigits(constraints.getFractionDigits());
1511
1512         return typeBuilder.build();
1513     }
1514
1515     private static SchemaPath createTypePath(final SchemaPath actual, final String typeName) {
1516         QName last = actual.getLastComponent();
1517         return actual.createChild(QName.create(last, typeName));
1518     }
1519
1520     private static SchemaPath createBaseTypePath(final SchemaPath actual, final String typeName) {
1521         return actual.createChild(BaseTypes.constructQName(typeName));
1522     }
1523
1524     private static SchemaPath createExtendedBaseTypePath(final SchemaPath actual, final QName moduleQName, final String typeName) {
1525         return actual.createChild(
1526                 QName.create(moduleQName, typeName),
1527                 BaseTypes.constructQName(typeName));
1528     }
1529
1530     /**
1531      * Parse given context and find identityref base value.
1532      *
1533      * @param ctx
1534      *            type body
1535      * @return identityref base value as String
1536      */
1537     public static String getIdentityrefBase(final Type_body_stmtsContext ctx) {
1538         String result = null;
1539         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1540             ParseTree child = ctx.getChild(i);
1541             if (child instanceof Identityref_specificationContext) {
1542                 for (int j = 0; j < child.getChildCount(); j++) {
1543                     ParseTree baseArg = child.getChild(j);
1544                     if (baseArg instanceof Base_stmtContext) {
1545                         result = stringFromNode(baseArg);
1546                         break outer;
1547                     }
1548                 }
1549             }
1550         }
1551         return result;
1552     }
1553
1554     /**
1555      * Parse type body statement and find require-instance value.
1556      *
1557      * @param ctx
1558      *            type body context
1559      * @return require-instance value
1560      */
1561     private static boolean isRequireInstance(final Type_body_stmtsContext ctx) {
1562         for (int i = 0; i < ctx.getChildCount(); i++) {
1563             ParseTree child = ctx.getChild(i);
1564             if (child instanceof Instance_identifier_specificationContext) {
1565                 for (int j = 0; j < child.getChildCount(); j++) {
1566                     ParseTree reqStmt = child.getChild(j);
1567                     if (reqStmt instanceof Require_instance_stmtContext) {
1568                         for (int k = 0; k < reqStmt.getChildCount(); k++) {
1569                             ParseTree reqArg = reqStmt.getChild(k);
1570                             if (reqArg instanceof Require_instance_argContext) {
1571                                 return Boolean.valueOf(stringFromNode(reqArg));
1572                             }
1573                         }
1574                     }
1575                 }
1576             }
1577         }
1578         return true;
1579     }
1580
1581     /**
1582      * Parse type body statement and find leafref path.
1583      *
1584      * @param ctx
1585      *            type body context
1586      * @return leafref path as String
1587      */
1588     private static String parseLeafrefPath(final Type_body_stmtsContext ctx) {
1589         for (int i = 0; i < ctx.getChildCount(); i++) {
1590             ParseTree child = ctx.getChild(i);
1591             if (child instanceof Leafref_specificationContext) {
1592                 for (int j = 0; j < child.getChildCount(); j++) {
1593                     ParseTree leafRefSpec = child.getChild(j);
1594                     if (leafRefSpec instanceof Path_stmtContext) {
1595                         return stringFromNode(leafRefSpec);
1596                     }
1597                 }
1598             }
1599         }
1600         return null;
1601     }
1602
1603     /**
1604      * Internal helper method for parsing must statement.
1605      *
1606      * @param ctx
1607      *            Must_stmtContext
1608      * @return MustDefinition object based on parsed context
1609      */
1610     private static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
1611         StringBuilder mustText = new StringBuilder();
1612         Optional<String> description = Optional.absent();
1613         Optional<String> reference = Optional.absent();
1614         Optional<String> errorAppTag = Optional.absent();
1615         Optional<String> errorMessage = Optional.absent();
1616         for (int i = 0; i < ctx.getChildCount(); ++i) {
1617             ParseTree child = ctx.getChild(i);
1618             if (child instanceof StringContext) {
1619                 final StringContext context = (StringContext) child;
1620                 if (context.getChildCount() == 1) {
1621                     String mustPart = context.getChild(0).getText();
1622                     // trim start and end quotation
1623                     mustText.append(mustPart.substring(1, mustPart.length() - 1));
1624                 } else {
1625                     for (int j = 0; j < context.getChildCount(); j++) {
1626                         String mustPart = context.getChild(j).getText();
1627                         if (j == 0) {
1628                             mustText.append(mustPart.substring(0, mustPart.length() - 1));
1629                             continue;
1630                         }
1631                         if (j % 2 == 0) {
1632                             mustText.append(mustPart.substring(1));
1633                         }
1634                     }
1635                 }
1636             } else if (child instanceof Description_stmtContext) {
1637                 description = Optional.of(stringFromNode(child));
1638             } else if (child instanceof Reference_stmtContext) {
1639                 reference = Optional.of(stringFromNode(child));
1640             } else if (child instanceof Error_app_tag_stmtContext) {
1641                 errorAppTag = Optional.of(stringFromNode(child));
1642             } else if (child instanceof Error_message_stmtContext) {
1643                 errorMessage = Optional.of(stringFromNode(child));
1644             }
1645         }
1646
1647         return MustDefinitionImpl.create(mustText.toString(), description, reference, errorAppTag, errorMessage);
1648     }
1649
1650     /**
1651      * Parse given context and set constraints to constraints builder.
1652      *
1653      * @param ctx
1654      *            context to parse
1655      * @param constraints
1656      *            ConstraintsBuilder to fill
1657      *
1658      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1659      */
1660     @Deprecated
1661     public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) {
1662         for (int i = 0; i < ctx.getChildCount(); ++i) {
1663             final ParseTree childNode = ctx.getChild(i);
1664             if (childNode instanceof Max_elements_stmtContext) {
1665                 Integer max = parseMaxElements((Max_elements_stmtContext) childNode, constraints.getModuleName());
1666                 constraints.setMaxElements(max);
1667             } else if (childNode instanceof Min_elements_stmtContext) {
1668                 Integer min = parseMinElements((Min_elements_stmtContext) childNode, constraints.getModuleName());
1669                 constraints.setMinElements(min);
1670             } else if (childNode instanceof Must_stmtContext) {
1671                 MustDefinition must = parseMust((Must_stmtContext) childNode);
1672                 constraints.addMustDefinition(must);
1673             } else if (childNode instanceof Mandatory_stmtContext) {
1674                 for (int j = 0; j < childNode.getChildCount(); j++) {
1675                     ParseTree mandatoryTree = childNode.getChild(j);
1676                     if (mandatoryTree instanceof Mandatory_argContext) {
1677                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1678                         constraints.setMandatory(mandatory);
1679                     }
1680                 }
1681             } else if (childNode instanceof When_stmtContext) {
1682                 constraints.addWhenCondition(stringFromNode(childNode));
1683             }
1684         }
1685     }
1686
1687     private static Integer parseMinElements(final Min_elements_stmtContext ctx, final String moduleName) {
1688         Integer result = null;
1689         try {
1690             for (int i = 0; i < ctx.getChildCount(); i++) {
1691                 ParseTree minArg = ctx.getChild(i);
1692                 if (minArg instanceof Min_value_argContext) {
1693                     result = Integer.valueOf(stringFromNode(minArg));
1694                 }
1695             }
1696             if (result == null) {
1697                 throw new IllegalArgumentException();
1698             }
1699             return result;
1700         } catch (Exception e) {
1701             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
1702         }
1703     }
1704
1705     private static Integer parseMaxElements(final Max_elements_stmtContext ctx, final String moduleName) {
1706         Integer result = null;
1707         try {
1708             for (int i = 0; i < ctx.getChildCount(); i++) {
1709                 ParseTree maxArg = ctx.getChild(i);
1710                 if (maxArg instanceof Max_value_argContext) {
1711                     String maxValue = stringFromNode(maxArg);
1712                     if ("unbounded".equals(maxValue)) {
1713                         result = Integer.MAX_VALUE;
1714                     } else {
1715                         result = Integer.valueOf(maxValue);
1716                     }
1717                 }
1718             }
1719             if (result == null) {
1720                 throw new IllegalArgumentException();
1721             }
1722             return result;
1723         } catch (Exception e) {
1724             throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
1725         }
1726     }
1727
1728     /**
1729      * Parse given context and return yin value.
1730      *
1731      * @param ctx
1732      *            context to parse
1733      * @return true if value is 'true', false otherwise
1734      */
1735     public static boolean parseYinValue(final Argument_stmtContext ctx) {
1736         boolean yinValue = false;
1737         outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1738             ParseTree yin = ctx.getChild(i);
1739             if (yin instanceof Yin_element_stmtContext) {
1740                 for (int j = 0; j < yin.getChildCount(); j++) {
1741                     ParseTree yinArg = yin.getChild(j);
1742                     if (yinArg instanceof Yin_element_argContext) {
1743                         String yinString = stringFromNode(yinArg);
1744                         if ("true".equals(yinString)) {
1745                             yinValue = true;
1746                             break outer;
1747                         }
1748                     }
1749                 }
1750             }
1751         }
1752         return yinValue;
1753     }
1754
1755     /**
1756      * Check this base type.
1757      *
1758      * @param typeName
1759      *            base YANG type name
1760      * @param moduleName
1761      *            name of current module
1762      * @param line
1763      *            line in module
1764      * @throws YangParseException
1765      *             if this is one of YANG type which MUST contain additional
1766      *             informations in its body
1767      */
1768     public static void checkMissingBody(final String typeName, final String moduleName, final int line) {
1769         switch (typeName) {
1770         case "decimal64":
1771             throw new YangParseException(moduleName, line,
1772                     "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1773         case "identityref":
1774             throw new YangParseException(moduleName, line,
1775                     "The 'base' statement MUST be present if the type is 'identityref'.");
1776         case "leafref":
1777             throw new YangParseException(moduleName, line,
1778                     "The 'path' statement MUST be present if the type is 'leafref'.");
1779         case "bits":
1780             throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
1781         case "enumeration":
1782             throw new YangParseException(moduleName, line,
1783                     "The 'enum' statement MUST be present if the type is 'enumeration'.");
1784         }
1785     }
1786
1787     /**
1788      * Parse refine statement.
1789      *
1790      * @param refineCtx
1791      *            refine statement
1792      * @param moduleName
1793      *            name of current module
1794      * @return RefineHolder object representing this refine statement
1795      *
1796      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1797      */
1798     @Deprecated
1799     public static RefineHolderImpl parseRefine(final Refine_stmtContext refineCtx, final String moduleName) {
1800         final String refineTarget = stringFromNode(refineCtx);
1801         final RefineHolderImpl refine = new RefineHolderImpl(moduleName, refineCtx.getStart().getLine(), refineTarget);
1802         for (int i = 0; i < refineCtx.getChildCount(); i++) {
1803             ParseTree refinePom = refineCtx.getChild(i);
1804             if (refinePom instanceof Refine_pomContext) {
1805                 for (int j = 0; j < refinePom.getChildCount(); j++) {
1806                     ParseTree refineStmt = refinePom.getChild(j);
1807                     parseRefineDefault(refine, refineStmt);
1808
1809                     if (refineStmt instanceof Refine_leaf_stmtsContext) {
1810                         parseRefine(refine, (Refine_leaf_stmtsContext) refineStmt);
1811                     } else if (refineStmt instanceof Refine_container_stmtsContext) {
1812                         parseRefine(refine, (Refine_container_stmtsContext) refineStmt);
1813                     } else if (refineStmt instanceof Refine_list_stmtsContext) {
1814                         parseRefine(refine, (Refine_list_stmtsContext) refineStmt);
1815                     } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1816                         parseRefine(refine, (Refine_leaf_list_stmtsContext) refineStmt);
1817                     } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1818                         parseRefine(refine, (Refine_choice_stmtsContext) refineStmt);
1819                     } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1820                         parseRefine(refine, (Refine_anyxml_stmtsContext) refineStmt);
1821                     }
1822                 }
1823             }
1824         }
1825         return refine;
1826     }
1827
1828     /**
1829      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1830      */
1831     @Deprecated
1832     private static void parseRefineDefault(final RefineHolderImpl refine, final ParseTree refineStmt) {
1833         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1834             ParseTree refineArg = refineStmt.getChild(i);
1835             if (refineArg instanceof Description_stmtContext) {
1836                 String description = stringFromNode(refineArg);
1837                 refine.setDescription(description);
1838             } else if (refineArg instanceof Reference_stmtContext) {
1839                 String reference = stringFromNode(refineArg);
1840                 refine.setReference(reference);
1841             } else if (refineArg instanceof Config_stmtContext) {
1842                 Boolean config = parseConfig((Config_stmtContext) refineArg, refine.getModuleName());
1843                 refine.setConfiguration(config);
1844             }
1845         }
1846     }
1847
1848     /**
1849      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1850      */
1851     @Deprecated
1852     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_stmtsContext refineStmt) {
1853         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1854             ParseTree refineArg = refineStmt.getChild(i);
1855             if (refineArg instanceof Default_stmtContext) {
1856                 String defaultStr = stringFromNode(refineArg);
1857                 refine.setDefaultStr(defaultStr);
1858             } else if (refineArg instanceof Mandatory_stmtContext) {
1859                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1860                     ParseTree mandatoryTree = refineArg.getChild(j);
1861                     if (mandatoryTree instanceof Mandatory_argContext) {
1862                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1863                         refine.setMandatory(mandatory);
1864                     }
1865                 }
1866             } else if (refineArg instanceof Must_stmtContext) {
1867                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1868                 refine.setMust(must);
1869
1870             }
1871         }
1872         return refine;
1873     }
1874
1875     /**
1876      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1877      */
1878     @Deprecated
1879     private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_container_stmtsContext refineStmt) {
1880         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1881             ParseTree refineArg = refineStmt.getChild(i);
1882             if (refineArg instanceof Must_stmtContext) {
1883                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1884                 refine.setMust(must);
1885             } else if (refineArg instanceof Presence_stmtContext) {
1886                 refine.setPresence(true);
1887             }
1888         }
1889         return refine;
1890     }
1891
1892     /**
1893      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1894      */
1895     @Deprecated
1896     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_list_stmtsContext refineStmt) {
1897         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1898             ParseTree refineArg = refineStmt.getChild(i);
1899             if (refineArg instanceof Must_stmtContext) {
1900                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1901                 refine.setMust(must);
1902             } else if (refineArg instanceof Max_elements_stmtContext) {
1903                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1904                 refine.setMaxElements(max);
1905             } else if (refineArg instanceof Min_elements_stmtContext) {
1906                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1907                 refine.setMinElements(min);
1908             }
1909         }
1910         return refine;
1911     }
1912
1913     /**
1914      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1915      */
1916     @Deprecated
1917     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_list_stmtsContext refineStmt) {
1918         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1919             ParseTree refineArg = refineStmt.getChild(i);
1920             if (refineArg instanceof Must_stmtContext) {
1921                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1922                 refine.setMust(must);
1923             } else if (refineArg instanceof Max_elements_stmtContext) {
1924                 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1925                 refine.setMaxElements(max);
1926             } else if (refineArg instanceof Min_elements_stmtContext) {
1927                 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1928                 refine.setMinElements(min);
1929             }
1930         }
1931         return refine;
1932     }
1933
1934     /**
1935      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1936      */
1937     @Deprecated
1938     private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_choice_stmtsContext refineStmt) {
1939         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1940             ParseTree refineArg = refineStmt.getChild(i);
1941             if (refineArg instanceof Default_stmtContext) {
1942                 String defaultStr = stringFromNode(refineArg);
1943                 refine.setDefaultStr(defaultStr);
1944             } else if (refineArg instanceof Mandatory_stmtContext) {
1945                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1946                     ParseTree mandatoryTree = refineArg.getChild(j);
1947                     if (mandatoryTree instanceof Mandatory_argContext) {
1948                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1949                         refine.setMandatory(mandatory);
1950                     }
1951                 }
1952             }
1953         }
1954         return refine;
1955     }
1956
1957     /**
1958      * @deprecated Pre-Beryllium implementation, scheduled for removal.
1959      */
1960     @Deprecated
1961     private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_anyxml_stmtsContext refineStmt) {
1962         for (int i = 0; i < refineStmt.getChildCount(); i++) {
1963             ParseTree refineArg = refineStmt.getChild(i);
1964             if (refineArg instanceof Must_stmtContext) {
1965                 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1966                 refine.setMust(must);
1967             } else if (refineArg instanceof Mandatory_stmtContext) {
1968                 for (int j = 0; j < refineArg.getChildCount(); j++) {
1969                     ParseTree mandatoryTree = refineArg.getChild(j);
1970                     if (mandatoryTree instanceof Mandatory_argContext) {
1971                         Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1972                         refine.setMandatory(mandatory);
1973                     }
1974                 }
1975             }
1976         }
1977         return refine;
1978     }
1979
1980     public static String getArgumentString(final org.antlr.v4.runtime.ParserRuleContext ctx) {
1981         List<StringContext> potentialValues = ctx.getRuleContexts(StringContext.class);
1982         checkState(!potentialValues.isEmpty());
1983         return ParserListenerUtils.stringFromStringContext(potentialValues.get(0));
1984     }
1985
1986     public static <T extends ParserRuleContext> Optional<T> getFirstContext(final ParserRuleContext context,final Class<T> contextType) {
1987         List<T> potential = context.getRuleContexts(contextType);
1988         if(potential.isEmpty()) {
1989             return Optional.absent();
1990         }
1991         return Optional.of(potential.get(0));
1992     }
1993
1994 }