2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.yangtools.yang.parser.impl;
11 import static com.google.common.base.Preconditions.checkState;
13 import com.google.common.base.CharMatcher;
14 import com.google.common.base.Optional;
15 import com.google.common.base.Splitter;
16 import com.google.common.collect.ImmutableSet;
17 import com.google.common.collect.Sets;
18 import java.math.BigDecimal;
19 import java.math.BigInteger;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Objects;
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 import java.util.regex.PatternSyntaxException;
29 import org.antlr.v4.runtime.ParserRuleContext;
30 import org.antlr.v4.runtime.tree.ParseTree;
31 import org.antlr.v4.runtime.tree.TerminalNode;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Bit_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Bits_specificationContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_argContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Config_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Decimal64_specificationContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Default_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Description_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Enum_specificationContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Enum_stmtContext;
44 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Error_app_tag_stmtContext;
45 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Error_message_stmtContext;
46 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext;
47 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Identityref_specificationContext;
48 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Instance_identifier_specificationContext;
49 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Key_stmtContext;
50 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Leafref_specificationContext;
51 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Length_stmtContext;
52 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_argContext;
53 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Mandatory_stmtContext;
54 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_elements_stmtContext;
55 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_value_argContext;
56 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
57 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_value_argContext;
58 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
59 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Must_stmtContext;
60 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
61 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
62 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_stmtContext;
63 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Path_stmtContext;
64 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Pattern_stmtContext;
65 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Position_stmtContext;
66 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Presence_stmtContext;
67 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Range_stmtContext;
68 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Reference_stmtContext;
69 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_anyxml_stmtsContext;
70 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_choice_stmtsContext;
71 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_container_stmtsContext;
72 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_leaf_list_stmtsContext;
73 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_leaf_stmtsContext;
74 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_list_stmtsContext;
75 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_pomContext;
76 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Refine_stmtContext;
77 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Require_instance_argContext;
78 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Require_instance_stmtContext;
79 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
80 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_stmtContext;
81 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.StringContext;
82 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.String_restrictionsContext;
83 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Type_body_stmtsContext;
84 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Units_stmtContext;
85 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Value_stmtContext;
86 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.When_stmtContext;
87 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_argContext;
88 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yin_element_stmtContext;
89 import org.opendaylight.yangtools.yang.common.QName;
90 import org.opendaylight.yangtools.yang.model.api.MustDefinition;
91 import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
92 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
93 import org.opendaylight.yangtools.yang.model.api.Status;
94 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
95 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
96 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
97 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
98 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
99 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
100 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition.EnumPair;
101 import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
102 import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
103 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
104 import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;
105 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
106 import org.opendaylight.yangtools.yang.model.api.type.UnsignedIntegerTypeDefinition;
107 import org.opendaylight.yangtools.yang.model.util.BaseConstraints;
108 import org.opendaylight.yangtools.yang.model.util.BaseTypes;
109 import org.opendaylight.yangtools.yang.model.util.BinaryType;
110 import org.opendaylight.yangtools.yang.model.util.BitImpl;
111 import org.opendaylight.yangtools.yang.model.util.BitsType;
112 import org.opendaylight.yangtools.yang.model.util.Decimal64;
113 import org.opendaylight.yangtools.yang.model.util.EnumerationType;
114 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
115 import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType;
116 import org.opendaylight.yangtools.yang.model.util.Int16;
117 import org.opendaylight.yangtools.yang.model.util.Int32;
118 import org.opendaylight.yangtools.yang.model.util.Int64;
119 import org.opendaylight.yangtools.yang.model.util.Int8;
120 import org.opendaylight.yangtools.yang.model.util.Leafref;
121 import org.opendaylight.yangtools.yang.model.util.MustDefinitionImpl;
122 import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
123 import org.opendaylight.yangtools.yang.model.util.StringType;
124 import org.opendaylight.yangtools.yang.model.util.Uint16;
125 import org.opendaylight.yangtools.yang.model.util.Uint32;
126 import org.opendaylight.yangtools.yang.model.util.Uint64;
127 import org.opendaylight.yangtools.yang.model.util.Uint8;
128 import org.opendaylight.yangtools.yang.parser.builder.api.Builder;
129 import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder;
130 import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
131 import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder;
132 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
133 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
134 import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
135 import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
136 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
137 import org.opendaylight.yangtools.yang.parser.builder.impl.RefineHolderImpl;
138 import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl;
139 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
140 import org.opendaylight.yangtools.yang.parser.util.TypeConstraints;
141 import org.opendaylight.yangtools.yang.parser.util.UnknownBoundaryNumber;
142 import org.opendaylight.yangtools.yang.parser.util.YangParseException;
143 import org.slf4j.Logger;
144 import org.slf4j.LoggerFactory;
146 public final class ParserListenerUtils {
147 private static final int UNICODE_SCRIPT_FIX_COUNTER = 30;
148 private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class);
149 private static final Splitter KEYDEF_SPLITTER = Splitter.on(' ').omitEmptyStrings();
150 private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults();
151 private static final Splitter DOT_DOT_SPLITTER = Splitter.on("..").trimResults();
152 private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"');
153 private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\'');
154 private static final Pattern BETWEEN_CURLY_BRACES_PATTERN = Pattern.compile("\\{(.+?)\\}");
155 private static final Set<String> JAVA_UNICODE_BLOCKS = ImmutableSet.<String>builder()
156 .add("AegeanNumbers")
157 .add("AlchemicalSymbols")
158 .add("AlphabeticPresentationForms")
159 .add("AncientGreekMusicalNotation")
160 .add("AncientGreekNumbers")
161 .add("AncientSymbols")
163 .add("ArabicPresentationForms-A")
164 .add("ArabicPresentationForms-B")
165 .add("ArabicSupplement")
171 .add("BamumSupplement")
175 .add("BlockElements")
177 .add("BopomofoExtended")
180 .add("BraillePatterns")
183 .add("ByzantineMusicalSymbols")
187 .add("CJKCompatibility")
188 .add("CJKCompatibilityForms")
189 .add("CJKCompatibilityIdeographs")
190 .add("CJKCompatibilityIdeographsSupplement")
191 .add("CJKRadicalsSupplement")
193 .add("CJKSymbolsandPunctuation")
194 .add("CJKUnifiedIdeographs")
195 .add("CJKUnifiedIdeographsExtensionA")
196 .add("CJKUnifiedIdeographsExtensionB")
197 .add("CJKUnifiedIdeographsExtensionC")
198 .add("CJKUnifiedIdeographsExtensionD")
199 .add("CombiningDiacriticalMarks")
200 .add("CombiningDiacriticalMarksSupplement")
201 .add("CombiningHalfMarks")
202 .add("CombiningDiacriticalMarksforSymbols")
203 .add("CommonIndicNumberForms")
204 .add("ControlPictures")
206 .add("CountingRodNumerals")
208 .add("CuneiformNumbersandPunctuation")
209 .add("CurrencySymbols")
210 .add("CypriotSyllabary")
212 .add("CyrillicExtended-A")
213 .add("CyrillicExtended-B")
214 .add("CyrillicSupplementary")
217 .add("DevanagariExtended")
220 .add("EgyptianHieroglyphs")
222 .add("EnclosedAlphanumericSupplement")
223 .add("EnclosedAlphanumerics")
224 .add("EnclosedCJKLettersandMonths")
225 .add("EnclosedIdeographicSupplement")
227 .add("EthiopicExtended")
228 .add("EthiopicExtended-A")
229 .add("EthiopicSupplement")
230 .add("GeneralPunctuation")
231 .add("GeometricShapes")
233 .add("GeorgianSupplement")
236 .add("GreekandCoptic")
237 .add("GreekExtended")
240 .add("HalfwidthandFullwidthForms")
241 .add("HangulCompatibilityJamo")
243 .add("HangulJamoExtended-A")
244 .add("HangulJamoExtended-B")
245 .add("HangulSyllables")
248 .add("HighPrivateUseSurrogates")
249 .add("HighSurrogates")
251 .add("IdeographicDescriptionCharacters")
252 .add("ImperialAramaic")
253 .add("InscriptionalPahlavi")
254 .add("InscriptionalParthian")
255 .add("IPAExtensions")
258 .add("KanaSupplement")
260 .add("Kangxi Radicals")
263 .add("KatakanaPhoneticExtensions")
269 .add("Latin-1Supplement")
270 .add("LatinExtended-A")
271 .add("LatinExtendedAdditional")
272 .add("LatinExtended-B")
273 .add("LatinExtended-C")
274 .add("LatinExtended-D")
276 .add("LetterlikeSymbols")
278 .add("LinearBIdeograms")
279 .add("LinearBSyllabary")
281 .add("LowSurrogates")
287 .add("MathematicalAlphanumericSymbols")
288 .add("MathematicalOperators")
290 .add("MiscellaneousMathematicalSymbols-A")
291 .add("MiscellaneousMathematicalSymbols-B")
292 .add("MiscellaneousSymbols")
293 .add("MiscellaneousSymbolsandArrows")
294 .add("MiscellaneousSymbolsAndPictographs")
295 .add("MiscellaneousTechnical")
296 .add("ModifierToneLetters")
298 .add("MusicalSymbols")
300 .add("MyanmarExtended-A")
308 .add("OldSouthArabian")
310 .add("OpticalCharacterRecognition")
316 .add("PhoneticExtensions")
317 .add("PhoneticExtensionsSupplement")
319 .add("PrivateUseArea")
321 .add("RumiNumeralSymbols")
327 .add("SmallFormVariants")
328 .add("SpacingModifierLetters")
331 .add("SuperscriptsandSubscripts")
332 .add("SupplementalArrows-A")
333 .add("SupplementalArrows-B")
334 .add("SupplementalMathematicalOperators")
335 .add("SupplementalPunctuation")
336 .add("SupplementaryPrivateUseArea-A")
337 .add("SupplementaryPrivateUseArea-B")
346 .add("TaiXuanJingSymbols")
353 .add("TransportAndMapSymbols")
355 .add("UnifiedCanadianAboriginalSyllabics")
356 .add("UnifiedCanadianAboriginalSyllabicsExtended")
358 .add("VariationSelectors")
359 .add("VariationSelectorsSupplement")
360 .add("VedicExtensions")
361 .add("VerticalForms")
364 .add("YijingHexagramSymbols").build();
366 private ParserListenerUtils() {
370 * Parse given tree and get first string value.
374 * @return first string value from given tree
376 public static String stringFromNode(final ParseTree treeNode) {
378 for (int i = 0; i < treeNode.getChildCount(); ++i) {
379 final ParseTree child = treeNode.getChild(i);
380 if (child instanceof StringContext) {
381 return stringFromStringContext((StringContext)child);
387 private static String stringFromStringContext(final StringContext context) {
388 StringBuilder sb = new StringBuilder();
389 for (TerminalNode stringNode : context.STRING()) {
390 final String str = stringNode.getText();
391 char firstChar = str.charAt(0);
392 final CharMatcher quoteMatcher;
393 if(SINGLE_QUOTE_MATCHER.matches(firstChar)) {
394 quoteMatcher = SINGLE_QUOTE_MATCHER;
395 } else if (DOUBLE_QUOTE_MATCHER.matches(firstChar)) {
396 quoteMatcher = DOUBLE_QUOTE_MATCHER;
403 * It is safe not to check last argument to be same
404 * grammars enforces that.
406 * FIXME: Introduce proper escaping and translation of escaped
410 sb.append(quoteMatcher.removeFrom(str.substring(1, str.length()-1)));
412 return sb.toString();
415 private static String getParentModule(final ParseTree ctx) {
416 ParseTree current = ctx;
417 while (current != null && !(current instanceof Module_stmtContext)) {
418 current = current.getParent();
420 if (current != null) {
421 Module_stmtContext module = (Module_stmtContext) current;
422 for (int i = 0; i < module.getChildCount(); i++) {
423 if (module.getChild(i) instanceof StringContext) {
424 final StringContext str = (StringContext) module.getChild(i);
425 return str.getChild(0).getText();
433 * Parse 'description', 'reference' and 'status' statements and fill in
439 * builder to fill in with parsed statements
441 public static void parseSchemaNodeArgs(final ParseTree ctx, final SchemaNodeBuilder builder) {
442 for (int i = 0; i < ctx.getChildCount(); i++) {
443 final ParseTree child = ctx.getChild(i);
444 if (child instanceof Description_stmtContext) {
445 final String desc = stringFromNode(child);
446 builder.setDescription(desc);
447 } else if (child instanceof Reference_stmtContext) {
448 final String ref = stringFromNode(child);
449 builder.setReference(ref);
450 } else if (child instanceof Status_stmtContext) {
451 final Status status = parseStatus((Status_stmtContext) child);
452 builder.setStatus(status);
458 * Parse given context and return its value;
462 * @return value parsed from context
464 public static Status parseStatus(final Status_stmtContext ctx) {
465 Status result = null;
466 for (int i = 0; i < ctx.getChildCount(); i++) {
467 ParseTree statusArg = ctx.getChild(i);
468 if (statusArg instanceof Status_argContext) {
469 String statusArgStr = stringFromNode(statusArg);
470 switch (statusArgStr) {
472 result = Status.CURRENT;
475 result = Status.DEPRECATED;
478 result = Status.OBSOLETE;
481 LOG.warn("Invalid 'status' statement: " + statusArgStr);
489 * Parse given tree and returns units statement as string.
493 * @return value of units statement as string or null if there is no units
496 public static String parseUnits(final ParseTree ctx) {
497 for (int i = 0; i < ctx.getChildCount(); i++) {
498 ParseTree child = ctx.getChild(i);
499 if (child instanceof Units_stmtContext) {
500 return stringFromNode(child);
507 * Parse given tree and returns default statement as string.
511 * @return value of default statement as string or null if there is no
514 public static String parseDefault(final ParseTree ctx) {
515 for (int i = 0; i < ctx.getChildCount(); i++) {
516 ParseTree child = ctx.getChild(i);
517 if (child instanceof Default_stmtContext) {
518 return stringFromNode(child);
525 * Create java.util.LinkedHashSet of key node names.
528 * Key_stmtContext context
529 * @return YANG list key as java.util.LinkedHashSet of key node names
531 public static Set<String> createListKey(final Key_stmtContext ctx) {
532 final String keyDefinition = stringFromNode(ctx);
533 return Sets.<String>newLinkedHashSet(KEYDEF_SPLITTER.split(keyDefinition));
537 * Parse given type body of enumeration statement.
540 * type body context to parse
542 * actual position in YANG model
544 * current module name
545 * @return List of EnumPair object parsed from given context
547 private static List<EnumTypeDefinition.EnumPair> getEnumConstants(final Type_body_stmtsContext ctx,
548 final SchemaPath path, final String moduleName) {
549 List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<>();
551 for (int i = 0; i < ctx.getChildCount(); i++) {
552 ParseTree enumSpecChild = ctx.getChild(i);
553 if (enumSpecChild instanceof Enum_specificationContext) {
554 int highestValue = -1;
555 for (int j = 0; j < enumSpecChild.getChildCount(); j++) {
556 ParseTree enumChild = enumSpecChild.getChild(j);
557 if (enumChild instanceof Enum_stmtContext) {
558 EnumPair enumPair = createEnumPair((Enum_stmtContext) enumChild, highestValue, path, moduleName);
559 if (enumPair.getValue() > highestValue) {
560 highestValue = enumPair.getValue();
562 enumConstants.add(enumPair);
567 return enumConstants;
571 * Parse enum statement context
574 * enum statement context
575 * @param highestValue
576 * current highest value in enumeration
578 * actual position in YANG model
580 * current module name
581 * @return EnumPair object parsed from given context
583 private static EnumTypeDefinition.EnumPair createEnumPair(final Enum_stmtContext ctx, final int highestValue,
584 final SchemaPath actualPath, final String moduleName) {
585 final String name = stringFromNode(ctx);
586 SchemaPath path = createTypePath(actualPath, name);
587 Integer value = null;
589 String description = null;
590 String reference = null;
591 Status status = null;
593 for (int i = 0; i < ctx.getChildCount(); i++) {
594 ParseTree child = ctx.getChild(i);
595 if (child instanceof Value_stmtContext) {
596 String valueStr = stringFromNode(child);
598 // yang enum value has same restrictions as JAVA Integer
599 value = Integer.valueOf(valueStr);
600 } catch (NumberFormatException e) {
602 .format("Error on enum '%s': the enum value MUST be in the range from -2147483648 to 2147483647, but was: %s",
604 throw new YangParseException(moduleName, ctx.getStart().getLine(), err, e);
606 } else if (child instanceof Description_stmtContext) {
607 description = stringFromNode(child);
608 } else if (child instanceof Reference_stmtContext) {
609 reference = stringFromNode(child);
610 } else if (child instanceof Status_stmtContext) {
611 status = parseStatus((Status_stmtContext) child);
616 value = highestValue + 1;
619 EnumPairImpl result = new EnumPairImpl();
620 result.qname = path.getPathTowardsRoot().iterator().next();
622 result.description = description;
623 result.reference = reference;
624 result.status = status;
626 result.value = value;
631 * Internal implementation of EnumPair.
633 private static class EnumPairImpl implements EnumTypeDefinition.EnumPair {
635 private SchemaPath path;
636 private String description;
637 private String reference;
638 private Status status;
639 private final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
641 private Integer value;
644 public QName getQName() {
649 public SchemaPath getPath() {
654 public String getDescription() {
659 public String getReference() {
664 public Status getStatus() {
669 public List<UnknownSchemaNode> getUnknownSchemaNodes() {
674 public String getName() {
679 public Integer getValue() {
684 public int hashCode() {
685 final int prime = 31;
687 result = prime * result + Objects.hashCode(qname);
688 result = prime * result + Objects.hashCode(path);
689 result = prime * result + Objects.hashCode(unknownNodes);
690 result = prime * result + Objects.hashCode(name);
691 result = prime * result + Objects.hashCode(value);
696 public boolean equals(final Object obj) {
703 if (getClass() != obj.getClass()) {
706 EnumPairImpl other = (EnumPairImpl) obj;
708 if (other.qname != null) {
711 } else if (!qname.equals(other.qname)) {
715 if (other.path != null) {
718 } else if (!path.equals(other.path)) {
721 if (unknownNodes == null) {
722 if (other.unknownNodes != null) {
725 } else if (!unknownNodes.equals(other.unknownNodes)) {
729 if (other.name != null) {
732 } else if (!name.equals(other.name)) {
736 if (other.value != null) {
739 } else if (!value.equals(other.value)) {
746 public String toString() {
747 return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name=" + name + ", value=" + value + "]";
752 * Get and parse range from given type body context.
755 * type body context to parse
757 * name of current module
758 * @return List of RangeConstraint created from this context
760 private static List<RangeConstraint> getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
761 for (int i = 0; i < ctx.getChildCount(); i++) {
762 ParseTree numRestrChild = ctx.getChild(i);
764 if (numRestrChild instanceof Numerical_restrictionsContext) {
765 for (int j = 0; j < numRestrChild.getChildCount(); j++) {
766 ParseTree rangeChild = numRestrChild.getChild(j);
767 if (rangeChild instanceof Range_stmtContext) {
768 return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
773 if (numRestrChild instanceof Decimal64_specificationContext) {
774 for (int j = 0; j < numRestrChild.getChildCount(); j++) {
775 ParseTree decRestr = numRestrChild.getChild(j);
776 if (decRestr instanceof Numerical_restrictionsContext) {
777 for (int k = 0; k < decRestr.getChildCount(); k++) {
778 ParseTree rangeChild = decRestr.getChild(k);
779 if (rangeChild instanceof Range_stmtContext) {
780 return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
787 return Collections.emptyList();
791 * Parse given range context.
794 * range context to parse
796 * name of current module
797 * @return List of RangeConstraints parsed from this context
799 private static List<RangeConstraint> parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) {
800 final int line = ctx.getStart().getLine();
801 Optional<String> description = Optional.absent();
802 Optional<String> reference = Optional.absent();
804 for (int i = 0; i < ctx.getChildCount(); i++) {
805 ParseTree child = ctx.getChild(i);
806 if (child instanceof Description_stmtContext) {
807 description = Optional.fromNullable(stringFromNode(child));
808 } else if (child instanceof Reference_stmtContext) {
809 reference = Optional.fromNullable(stringFromNode(child));
813 List<RangeConstraint> rangeConstraints = new ArrayList<>();
814 for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) {
815 final Iterator<String> split = DOT_DOT_SPLITTER.split(def).iterator();
816 final Number min = parseNumberConstraintValue(split.next(), moduleName, line);
819 if (split.hasNext()) {
820 max = parseNumberConstraintValue(split.next(), moduleName, line);
821 if (split.hasNext()) {
822 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\".");
828 RangeConstraint range = BaseConstraints.newRangeConstraint(min, max, description, reference);
829 rangeConstraints.add(range);
832 return rangeConstraints;
836 * Get and parse length from given type body context.
839 * type body context to parse
841 * name of current module
842 * @return List of LengthConstraint created from this context
844 private static List<LengthConstraint> getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
845 for (int i = 0; i < ctx.getChildCount(); i++) {
846 ParseTree stringRestrChild = ctx.getChild(i);
847 if (stringRestrChild instanceof String_restrictionsContext) {
848 for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
849 ParseTree lengthChild = stringRestrChild.getChild(j);
850 if (lengthChild instanceof Length_stmtContext) {
851 return parseLengthConstraints((Length_stmtContext) lengthChild, moduleName);
856 return Collections.emptyList();
860 * Parse given length context.
863 * length context to parse
865 * name of current module
866 * @return List of LengthConstraints parsed from this context
868 private static List<LengthConstraint> parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) {
869 final int line = ctx.getStart().getLine();
870 Optional<String> description = Optional.absent();
871 Optional<String> reference = Optional.absent();
873 for (int i = 0; i < ctx.getChildCount(); i++) {
874 ParseTree child = ctx.getChild(i);
875 if (child instanceof Description_stmtContext) {
876 description = Optional.fromNullable(stringFromNode(child));
877 } else if (child instanceof Reference_stmtContext) {
878 reference = Optional.fromNullable(stringFromNode(child));
882 List<LengthConstraint> lengthConstraints = new ArrayList<>();
883 for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) {
884 final Iterator<String> split = DOT_DOT_SPLITTER.split(def).iterator();
885 final Number min = parseNumberConstraintValue(split.next(), moduleName, line);
888 if (split.hasNext()) {
889 max = parseNumberConstraintValue(split.next(), moduleName, line);
890 if (split.hasNext()) {
891 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\".");
897 LengthConstraint range = BaseConstraints.newLengthConstraint(min, max, description, reference);
898 lengthConstraints.add(range);
901 return lengthConstraints;
908 * name of current module
910 * current line in module
911 * @return wrapper object of primitive java type or UnknownBoundaryNumber if
912 * type is one of special YANG values 'min' or 'max'
914 private static Number parseNumberConstraintValue(final String value, final String moduleName, final int line) {
916 if ("min".equals(value) || "max".equals(value)) {
917 result = new UnknownBoundaryNumber(value);
920 if (value.indexOf('.') != -1) {
921 result = new BigDecimal(value);
923 result = new BigInteger(value);
925 } catch (NumberFormatException e) {
926 throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
933 * Parse type body and return pattern constraints.
937 * @return list of pattern constraints
939 private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx, final String moduleName) {
940 List<PatternConstraint> patterns = new ArrayList<>();
942 for (int i = 0; i < ctx.getChildCount(); i++) {
943 ParseTree stringRestrChild = ctx.getChild(i);
944 if (stringRestrChild instanceof String_restrictionsContext) {
945 for (int j = 0; j < stringRestrChild.getChildCount(); j++) {
946 ParseTree lengthChild = stringRestrChild.getChild(j);
947 if (lengthChild instanceof Pattern_stmtContext) {
948 final PatternConstraint constraint = parsePatternConstraint((Pattern_stmtContext) lengthChild,
950 if (constraint != null) {
951 patterns.add(constraint);
961 * Internal helper method.
965 * @return PatternConstraint object
967 private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx, final String moduleName) {
968 Optional<String> description = Optional.absent();
969 Optional<String> reference = Optional.absent();
970 for (int i = 0; i < ctx.getChildCount(); i++) {
971 ParseTree child = ctx.getChild(i);
972 if (child instanceof Description_stmtContext) {
973 description = Optional.of(stringFromNode(child));
974 } else if (child instanceof Reference_stmtContext) {
975 reference = Optional.of(stringFromNode(child));
978 final String rawPattern = parsePatternString(ctx);
979 final String fixedRawPattern = fixUnicodeScriptPattern(rawPattern);
980 final String pattern = wrapPattern(fixedRawPattern);
981 if (isValidPattern(pattern, ctx, moduleName)) {
982 return BaseConstraints.newPatternConstraint(pattern, description, reference);
987 private static String fixUnicodeScriptPattern(String rawPattern) {
988 for (int i = 0; i < UNICODE_SCRIPT_FIX_COUNTER; i++) {
990 Pattern.compile(rawPattern);
992 } catch(PatternSyntaxException ex) {
993 LOG.debug("Invalid regex pattern syntax in: {}", rawPattern, ex);
994 if (ex.getMessage().contains("Unknown character script name")) {
995 rawPattern = fixUnknownScripts(ex.getMessage(), rawPattern);
1002 LOG.warn("Regex pattern could not be fixed: {}", rawPattern);
1006 private static String fixUnknownScripts(String exMessage, String rawPattern) {
1007 StringBuilder result = new StringBuilder(rawPattern);
1008 Matcher matcher = BETWEEN_CURLY_BRACES_PATTERN.matcher(exMessage);
1009 if (matcher.find()) {
1010 String capturedGroup = matcher.group(1);
1011 if (JAVA_UNICODE_BLOCKS.contains(capturedGroup)) {
1012 int idx = rawPattern.indexOf("Is" + capturedGroup);
1013 result = result.replace(idx, idx + 2, "In");
1016 return result.toString();
1019 private static String wrapPattern(String rawPattern) {
1020 final StringBuilder wrapPatternBuilder = new StringBuilder(rawPattern.length() + 2);
1021 wrapPatternBuilder.append('^');
1022 wrapPatternBuilder.append(rawPattern);
1023 wrapPatternBuilder.append('$');
1024 return wrapPatternBuilder.toString();
1027 private static boolean isValidPattern(final String pattern, final Pattern_stmtContext ctx, final String moduleName) {
1029 Pattern.compile(pattern);
1031 } catch (PatternSyntaxException ex) {
1032 LOG.warn("Unable to compile pattern defined in module {} at line {}. Error message: {}",
1033 moduleName, ctx.getStart().getLine(), ex.getMessage());
1039 * Parse given context and return pattern value.
1043 * @return pattern value as String
1045 private static String parsePatternString(final Pattern_stmtContext ctx) {
1046 StringBuilder result = new StringBuilder();
1047 for (int i = 0; i < ctx.getChildCount(); ++i) {
1048 ParseTree child = ctx.getChild(i);
1049 if (child instanceof StringContext) {
1050 for (int j = 0; j < child.getChildCount(); j++) {
1052 String patternToken = child.getChild(j).getText();
1053 result.append(patternToken.substring(1, patternToken.length() - 1));
1058 return result.toString();
1062 * Get fraction digits value from type body.
1065 * type body context to parse
1067 * name of current module
1068 * @return 'fraction-digits' value if present in given context, null
1071 private static Integer getFractionDigits(final Type_body_stmtsContext ctx, final String moduleName) {
1072 Integer result = null;
1073 for (int i = 0; i < ctx.getChildCount(); i++) {
1074 ParseTree dec64specChild = ctx.getChild(i);
1075 if (dec64specChild instanceof Decimal64_specificationContext) {
1076 result = parseFractionDigits((Decimal64_specificationContext) dec64specChild, moduleName);
1083 * Parse decimal64 fraction-digits value.
1088 * name of current module
1089 * @return fraction-digits value as Integer
1091 private static Integer parseFractionDigits(final Decimal64_specificationContext ctx, final String moduleName) {
1092 Integer result = null;
1093 for (int i = 0; i < ctx.getChildCount(); i++) {
1094 ParseTree fdChild = ctx.getChild(i);
1095 if (fdChild instanceof Fraction_digits_stmtContext) {
1096 String value = stringFromNode(fdChild);
1098 result = Integer.valueOf(value);
1099 } catch (NumberFormatException e) {
1100 throw new YangParseException(moduleName, ctx.getStart().getLine(),
1101 "Unable to parse fraction digits value '" + value + "'.", e);
1109 * Internal helper method for parsing bit statements from given type body
1113 * type body context to parse
1115 * current position in YANG model
1117 * current module name
1118 * @return List of Bit objects created from this context
1120 private static List<BitsTypeDefinition.Bit> getBits(final Type_body_stmtsContext ctx, final SchemaPath actualPath,
1121 final String moduleName) {
1122 final List<BitsTypeDefinition.Bit> bits = new ArrayList<>();
1123 for (int j = 0; j < ctx.getChildCount(); j++) {
1124 ParseTree bitsSpecChild = ctx.getChild(j);
1125 if (bitsSpecChild instanceof Bits_specificationContext) {
1126 long highestPosition = -1;
1127 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
1128 ParseTree bitChild = bitsSpecChild.getChild(k);
1129 if (bitChild instanceof Bit_stmtContext) {
1130 Bit bit = parseBit((Bit_stmtContext) bitChild, highestPosition, actualPath, moduleName);
1131 if (bit.getPosition() > highestPosition) {
1132 highestPosition = bit.getPosition();
1143 * Internal helper method for parsing bit context.
1146 * bit statement context to parse
1147 * @param highestPosition
1148 * current highest position in bits type
1150 * current position in YANG model
1152 * current module name
1153 * @return Bit object parsed from this context
1155 private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, final long highestPosition,
1156 final SchemaPath actualPath, final String moduleName) {
1157 String name = stringFromNode(ctx);
1158 Long position = null;
1160 String description = null;
1161 String reference = null;
1162 Status status = Status.CURRENT;
1164 SchemaPath schemaPath = createBaseTypePath(actualPath, name);
1166 for (int i = 0; i < ctx.getChildCount(); i++) {
1167 ParseTree child = ctx.getChild(i);
1168 if (child instanceof Position_stmtContext) {
1169 String positionStr = stringFromNode(child);
1170 position = Long.valueOf(positionStr);
1171 } else if (child instanceof Description_stmtContext) {
1172 description = stringFromNode(child);
1173 } else if (child instanceof Reference_stmtContext) {
1174 reference = stringFromNode(child);
1175 } else if (child instanceof Status_stmtContext) {
1176 status = parseStatus((Status_stmtContext) child);
1180 if (position == null) {
1181 position = highestPosition + 1;
1183 if (position < 0 || position > 4294967295L) {
1184 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on bit '" + name
1185 + "': the position value MUST be in the range 0 to 4294967295");
1188 final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
1189 return new BitImpl(position, schemaPath.getPathTowardsRoot().iterator().next(), schemaPath,
1190 description, reference, status, unknownNodes);
1194 * Parse 'ordered-by' statement.
1196 * The 'ordered-by' statement defines whether the order of entries within a
1197 * list are determined by the user or the system. The argument is one of the
1198 * strings "system" or "user". If not present, order defaults to "system".
1201 * Ordered_by_stmtContext
1202 * @return true, if ordered-by contains value 'user', false otherwise
1204 public static boolean parseUserOrdered(final Ordered_by_stmtContext ctx) {
1205 boolean result = false;
1206 for (int j = 0; j < ctx.getChildCount(); j++) {
1207 ParseTree orderArg = ctx.getChild(j);
1208 if (orderArg instanceof Ordered_by_argContext) {
1209 String orderStr = stringFromNode(orderArg);
1218 LOG.warn("Invalid 'ordered-by' statement.");
1226 * Get config statement from given context. If there is no config statement,
1227 * return config value of parent
1234 * name of current module
1236 * line in current module
1237 * @return config statement parsed from given context
1239 public static boolean getConfig(final ParseTree ctx, final Builder node, final String moduleName, final int line) {
1241 // parse configuration statement
1242 Boolean config = null;
1243 for (int i = 0; i < ctx.getChildCount(); i++) {
1244 ParseTree child = ctx.getChild(i);
1245 if (child instanceof Config_stmtContext) {
1246 config = parseConfig((Config_stmtContext) child, moduleName);
1251 // If 'config' is not specified, the default is the same as the parent
1252 // schema node's 'config' value
1253 boolean parentConfig = getParentConfig(node);
1254 if (config == null) {
1255 result = parentConfig;
1257 // Check: if a node has 'config' set to 'false', no node underneath
1258 // it can have 'config' set to 'true'
1259 if (!parentConfig && config) {
1260 throw new YangParseException(moduleName, line,
1261 "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
1269 private static boolean getParentConfig(final Builder node) {
1270 Builder parent = node.getParent();
1273 if (parent instanceof ChoiceCaseBuilder) {
1274 parent = parent.getParent();
1276 if (parent instanceof DataSchemaNodeBuilder) {
1277 config = ((DataSchemaNodeBuilder) parent).isConfiguration();
1285 * Parse config statement.
1288 * config context to parse
1290 * current module name
1291 * @return true if given context contains string 'true', false otherwise
1293 private static Boolean parseConfig(final Config_stmtContext ctx, final String moduleName) {
1294 Boolean result = null;
1296 for (int i = 0; i < ctx.getChildCount(); ++i) {
1297 final ParseTree configContext = ctx.getChild(i);
1298 if (configContext instanceof Config_argContext) {
1299 final String value = stringFromNode(configContext);
1308 throw new YangParseException(moduleName, ctx.getStart().getLine(),
1309 "Failed to parse 'config' statement value: '" + value + "'.");
1318 * Parse unknown type with body.
1323 * current node parent
1324 * @param prefixedQName
1325 * type qname with prefix
1326 * @param moduleBuilder
1327 * current module builder
1328 * @param moduleQName
1329 * current module qname
1331 * actual path in model
1333 public static void parseUnknownTypeWithBody(Type_body_stmtsContext typeBody, TypeAwareBuilder parent,
1334 QName prefixedQName, ModuleBuilder moduleBuilder, QName moduleQName, SchemaPath actualPath) {
1335 final int line = typeBody.getStart().getLine();
1337 List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleBuilder.getName());
1338 List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleBuilder.getName());
1339 List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleBuilder.getName());
1340 Integer fractionDigits = getFractionDigits(typeBody, moduleBuilder.getName());
1342 if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1343 TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1344 typedef.setRanges(rangeStatements);
1345 typedef.setLengths(lengthStatements);
1346 typedef.setPatterns(patternStatements);
1347 typedef.setFractionDigits(fractionDigits);
1348 typedef.setTypeQName(prefixedQName);
1349 // add parent node of this type statement to dirty nodes
1350 moduleBuilder.markActualNodeDirty();
1352 QName qname = QName.create(moduleQName, prefixedQName.getLocalName());
1353 SchemaPath schemaPath = createTypePath(actualPath, prefixedQName.getLocalName());
1354 TypeDefinitionBuilder typeBuilder = new TypeDefinitionBuilderImpl(moduleBuilder.getName(), line, qname, schemaPath);
1355 typeBuilder.setRanges(rangeStatements);
1356 typeBuilder.setLengths(lengthStatements);
1357 typeBuilder.setPatterns(patternStatements);
1358 typeBuilder.setFractionDigits(fractionDigits);
1359 typeBuilder.setTypeQName(prefixedQName);
1360 parent.setTypedef(typeBuilder);
1361 moduleBuilder.getDirtyNodes().add(typeBuilder);
1366 * Create TypeDefinition object based on given type name and type body.
1373 * current path in schema
1374 * @param moduleQName
1375 * current module qname
1378 * @return TypeDefinition object based on parsed values.
1380 public static TypeDefinition<?> parseTypeWithBody(final String typeName, final Type_body_stmtsContext typeBody,
1381 final SchemaPath actualPath, final QName moduleQName, final Builder parent) {
1383 final String moduleName = parent.getModuleName();
1384 final int line = typeBody.getStart().getLine();
1385 TypeDefinition<?> baseType = null;
1387 Integer fractionDigits = getFractionDigits(typeBody, moduleName);
1388 List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleName);
1389 List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleName);
1390 List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleName);
1392 TypeConstraints constraints = new TypeConstraints(moduleName, line);
1393 constraints.addFractionDigits(fractionDigits);
1394 constraints.addLengths(lengthStatements);
1395 constraints.addPatterns(patternStatements);
1396 constraints.addRanges(rangeStatements);
1398 SchemaPath baseTypePath = createBaseTypePath(actualPath, typeName);
1399 SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, moduleQName, typeName);
1401 if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1402 extBaseTypePath = baseTypePath;
1405 if ("decimal64".equals(typeName)) {
1406 if (rangeStatements.isEmpty()) {
1408 return Decimal64.create(baseTypePath, fractionDigits);
1409 } catch(Exception e) {
1410 throw new YangParseException(moduleName, line, e.getMessage());
1413 Decimal64 decimalType = Decimal64.create(extBaseTypePath, fractionDigits);
1414 constraints.addRanges(decimalType.getRangeConstraints());
1415 baseType = decimalType;
1416 } else if (typeName.startsWith("int")) {
1417 IntegerTypeDefinition intType = null;
1420 intType = Int8.getInstance();
1423 intType = Int16.getInstance();
1426 intType = Int32.getInstance();
1429 intType = Int64.getInstance();
1432 if (intType == null) {
1433 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1435 constraints.addRanges(intType.getRangeConstraints());
1437 } else if (typeName.startsWith("uint")) {
1438 UnsignedIntegerTypeDefinition uintType = null;
1441 uintType = Uint8.getInstance();
1444 uintType = Uint16.getInstance();
1447 uintType = Uint32.getInstance();
1450 uintType = Uint64.getInstance();
1453 if (uintType == null) {
1454 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1456 constraints.addRanges(uintType.getRangeConstraints());
1457 baseType = uintType;
1458 } else if ("enumeration".equals(typeName)) {
1459 List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
1460 return EnumerationType.create(baseTypePath, enumConstants, Optional.<EnumPair> absent());
1461 } else if ("string".equals(typeName)) {
1462 StringTypeDefinition stringType = StringType.getInstance();
1463 constraints.addLengths(stringType.getLengthConstraints());
1464 baseType = stringType;
1465 } else if ("bits".equals(typeName)) {
1466 return BitsType.create(baseTypePath, getBits(typeBody, actualPath, moduleName));
1467 } else if ("leafref".equals(typeName)) {
1468 final String path = parseLeafrefPath(typeBody);
1469 final boolean absolute = path.startsWith("/");
1470 RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
1471 return new Leafref(xpath);
1472 } else if ("binary".equals(typeName)) {
1473 BinaryTypeDefinition binaryType = BinaryType.getInstance();
1474 constraints.addLengths(binaryType.getLengthConstraints());
1475 baseType = binaryType;
1476 } else if ("instance-identifier".equals(typeName)) {
1477 return InstanceIdentifierType.create(isRequireInstance(typeBody));
1480 if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1481 TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1482 typedef.setRanges(constraints.getRange());
1483 typedef.setLengths(constraints.getLength());
1484 typedef.setPatterns(constraints.getPatterns());
1485 typedef.setFractionDigits(constraints.getFractionDigits());
1489 QName qname = QName.create(moduleQName, typeName);
1490 SchemaPath schemaPath = actualPath.createChild(qname);
1491 final Optional<String> opt = Optional.of("");
1492 ExtendedType.Builder typeBuilder = ExtendedType.builder(qname, baseType, opt, opt, schemaPath);
1494 typeBuilder.ranges(constraints.getRange());
1495 typeBuilder.lengths(constraints.getLength());
1496 typeBuilder.patterns(constraints.getPatterns());
1497 typeBuilder.fractionDigits(constraints.getFractionDigits());
1499 return typeBuilder.build();
1502 private static SchemaPath createTypePath(final SchemaPath actual, final String typeName) {
1503 QName last = actual.getLastComponent();
1504 return actual.createChild(QName.create(last, typeName));
1507 private static SchemaPath createBaseTypePath(final SchemaPath actual, final String typeName) {
1508 return actual.createChild(BaseTypes.constructQName(typeName));
1511 private static SchemaPath createExtendedBaseTypePath(final SchemaPath actual, final QName moduleQName, final String typeName) {
1512 return actual.createChild(
1513 QName.create(moduleQName, typeName),
1514 BaseTypes.constructQName(typeName));
1518 * Parse given context and find identityref base value.
1522 * @return identityref base value as String
1524 public static String getIdentityrefBase(final Type_body_stmtsContext ctx) {
1525 String result = null;
1526 outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1527 ParseTree child = ctx.getChild(i);
1528 if (child instanceof Identityref_specificationContext) {
1529 for (int j = 0; j < child.getChildCount(); j++) {
1530 ParseTree baseArg = child.getChild(j);
1531 if (baseArg instanceof Base_stmtContext) {
1532 result = stringFromNode(baseArg);
1542 * Parse type body statement and find require-instance value.
1546 * @return require-instance value
1548 private static boolean isRequireInstance(final Type_body_stmtsContext ctx) {
1549 for (int i = 0; i < ctx.getChildCount(); i++) {
1550 ParseTree child = ctx.getChild(i);
1551 if (child instanceof Instance_identifier_specificationContext) {
1552 for (int j = 0; j < child.getChildCount(); j++) {
1553 ParseTree reqStmt = child.getChild(j);
1554 if (reqStmt instanceof Require_instance_stmtContext) {
1555 for (int k = 0; k < reqStmt.getChildCount(); k++) {
1556 ParseTree reqArg = reqStmt.getChild(k);
1557 if (reqArg instanceof Require_instance_argContext) {
1558 return Boolean.valueOf(stringFromNode(reqArg));
1569 * Parse type body statement and find leafref path.
1573 * @return leafref path as String
1575 private static String parseLeafrefPath(final Type_body_stmtsContext ctx) {
1576 for (int i = 0; i < ctx.getChildCount(); i++) {
1577 ParseTree child = ctx.getChild(i);
1578 if (child instanceof Leafref_specificationContext) {
1579 for (int j = 0; j < child.getChildCount(); j++) {
1580 ParseTree leafRefSpec = child.getChild(j);
1581 if (leafRefSpec instanceof Path_stmtContext) {
1582 return stringFromNode(leafRefSpec);
1591 * Internal helper method for parsing must statement.
1595 * @return MustDefinition object based on parsed context
1597 private static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
1598 StringBuilder mustText = new StringBuilder();
1599 Optional<String> description = Optional.absent();
1600 Optional<String> reference = Optional.absent();
1601 Optional<String> errorAppTag = Optional.absent();
1602 Optional<String> errorMessage = Optional.absent();
1603 for (int i = 0; i < ctx.getChildCount(); ++i) {
1604 ParseTree child = ctx.getChild(i);
1605 if (child instanceof StringContext) {
1606 final StringContext context = (StringContext) child;
1607 if (context.getChildCount() == 1) {
1608 String mustPart = context.getChild(0).getText();
1609 // trim start and end quotation
1610 mustText.append(mustPart.substring(1, mustPart.length() - 1));
1612 for (int j = 0; j < context.getChildCount(); j++) {
1613 String mustPart = context.getChild(j).getText();
1615 mustText.append(mustPart.substring(0, mustPart.length() - 1));
1619 mustText.append(mustPart.substring(1));
1623 } else if (child instanceof Description_stmtContext) {
1624 description = Optional.of(stringFromNode(child));
1625 } else if (child instanceof Reference_stmtContext) {
1626 reference = Optional.of(stringFromNode(child));
1627 } else if (child instanceof Error_app_tag_stmtContext) {
1628 errorAppTag = Optional.of(stringFromNode(child));
1629 } else if (child instanceof Error_message_stmtContext) {
1630 errorMessage = Optional.of(stringFromNode(child));
1634 return MustDefinitionImpl.create(mustText.toString(), description, reference, errorAppTag, errorMessage);
1638 * Parse given context and set constraints to constraints builder.
1642 * @param constraints
1643 * ConstraintsBuilder to fill
1645 public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) {
1646 for (int i = 0; i < ctx.getChildCount(); ++i) {
1647 final ParseTree childNode = ctx.getChild(i);
1648 if (childNode instanceof Max_elements_stmtContext) {
1649 Integer max = parseMaxElements((Max_elements_stmtContext) childNode, constraints.getModuleName());
1650 constraints.setMaxElements(max);
1651 } else if (childNode instanceof Min_elements_stmtContext) {
1652 Integer min = parseMinElements((Min_elements_stmtContext) childNode, constraints.getModuleName());
1653 constraints.setMinElements(min);
1654 } else if (childNode instanceof Must_stmtContext) {
1655 MustDefinition must = parseMust((Must_stmtContext) childNode);
1656 constraints.addMustDefinition(must);
1657 } else if (childNode instanceof Mandatory_stmtContext) {
1658 for (int j = 0; j < childNode.getChildCount(); j++) {
1659 ParseTree mandatoryTree = childNode.getChild(j);
1660 if (mandatoryTree instanceof Mandatory_argContext) {
1661 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1662 constraints.setMandatory(mandatory);
1665 } else if (childNode instanceof When_stmtContext) {
1666 constraints.addWhenCondition(stringFromNode(childNode));
1671 private static Integer parseMinElements(final Min_elements_stmtContext ctx, final String moduleName) {
1672 Integer result = null;
1674 for (int i = 0; i < ctx.getChildCount(); i++) {
1675 ParseTree minArg = ctx.getChild(i);
1676 if (minArg instanceof Min_value_argContext) {
1677 result = Integer.valueOf(stringFromNode(minArg));
1680 if (result == null) {
1681 throw new IllegalArgumentException();
1684 } catch (Exception e) {
1685 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
1689 private static Integer parseMaxElements(final Max_elements_stmtContext ctx, final String moduleName) {
1690 Integer result = null;
1692 for (int i = 0; i < ctx.getChildCount(); i++) {
1693 ParseTree maxArg = ctx.getChild(i);
1694 if (maxArg instanceof Max_value_argContext) {
1695 String maxValue = stringFromNode(maxArg);
1696 if ("unbounded".equals(maxValue)) {
1697 result = Integer.MAX_VALUE;
1699 result = Integer.valueOf(maxValue);
1703 if (result == null) {
1704 throw new IllegalArgumentException();
1707 } catch (Exception e) {
1708 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
1713 * Parse given context and return yin value.
1717 * @return true if value is 'true', false otherwise
1719 public static boolean parseYinValue(final Argument_stmtContext ctx) {
1720 boolean yinValue = false;
1721 outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1722 ParseTree yin = ctx.getChild(i);
1723 if (yin instanceof Yin_element_stmtContext) {
1724 for (int j = 0; j < yin.getChildCount(); j++) {
1725 ParseTree yinArg = yin.getChild(j);
1726 if (yinArg instanceof Yin_element_argContext) {
1727 String yinString = stringFromNode(yinArg);
1728 if ("true".equals(yinString)) {
1740 * Check this base type.
1743 * base YANG type name
1745 * name of current module
1748 * @throws YangParseException
1749 * if this is one of YANG type which MUST contain additional
1750 * informations in its body
1752 public static void checkMissingBody(final String typeName, final String moduleName, final int line) {
1755 throw new YangParseException(moduleName, line,
1756 "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1758 throw new YangParseException(moduleName, line,
1759 "The 'base' statement MUST be present if the type is 'identityref'.");
1761 throw new YangParseException(moduleName, line,
1762 "The 'path' statement MUST be present if the type is 'leafref'.");
1764 throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
1766 throw new YangParseException(moduleName, line,
1767 "The 'enum' statement MUST be present if the type is 'enumeration'.");
1772 * Parse refine statement.
1777 * name of current module
1778 * @return RefineHolder object representing this refine statement
1780 public static RefineHolderImpl parseRefine(final Refine_stmtContext refineCtx, final String moduleName) {
1781 final String refineTarget = stringFromNode(refineCtx);
1782 final RefineHolderImpl refine = new RefineHolderImpl(moduleName, refineCtx.getStart().getLine(), refineTarget);
1783 for (int i = 0; i < refineCtx.getChildCount(); i++) {
1784 ParseTree refinePom = refineCtx.getChild(i);
1785 if (refinePom instanceof Refine_pomContext) {
1786 for (int j = 0; j < refinePom.getChildCount(); j++) {
1787 ParseTree refineStmt = refinePom.getChild(j);
1788 parseRefineDefault(refine, refineStmt);
1790 if (refineStmt instanceof Refine_leaf_stmtsContext) {
1791 parseRefine(refine, (Refine_leaf_stmtsContext) refineStmt);
1792 } else if (refineStmt instanceof Refine_container_stmtsContext) {
1793 parseRefine(refine, (Refine_container_stmtsContext) refineStmt);
1794 } else if (refineStmt instanceof Refine_list_stmtsContext) {
1795 parseRefine(refine, (Refine_list_stmtsContext) refineStmt);
1796 } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1797 parseRefine(refine, (Refine_leaf_list_stmtsContext) refineStmt);
1798 } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1799 parseRefine(refine, (Refine_choice_stmtsContext) refineStmt);
1800 } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1801 parseRefine(refine, (Refine_anyxml_stmtsContext) refineStmt);
1809 private static void parseRefineDefault(final RefineHolderImpl refine, final ParseTree refineStmt) {
1810 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1811 ParseTree refineArg = refineStmt.getChild(i);
1812 if (refineArg instanceof Description_stmtContext) {
1813 String description = stringFromNode(refineArg);
1814 refine.setDescription(description);
1815 } else if (refineArg instanceof Reference_stmtContext) {
1816 String reference = stringFromNode(refineArg);
1817 refine.setReference(reference);
1818 } else if (refineArg instanceof Config_stmtContext) {
1819 Boolean config = parseConfig((Config_stmtContext) refineArg, refine.getModuleName());
1820 refine.setConfiguration(config);
1825 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_stmtsContext refineStmt) {
1826 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1827 ParseTree refineArg = refineStmt.getChild(i);
1828 if (refineArg instanceof Default_stmtContext) {
1829 String defaultStr = stringFromNode(refineArg);
1830 refine.setDefaultStr(defaultStr);
1831 } else if (refineArg instanceof Mandatory_stmtContext) {
1832 for (int j = 0; j < refineArg.getChildCount(); j++) {
1833 ParseTree mandatoryTree = refineArg.getChild(j);
1834 if (mandatoryTree instanceof Mandatory_argContext) {
1835 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1836 refine.setMandatory(mandatory);
1839 } else if (refineArg instanceof Must_stmtContext) {
1840 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1841 refine.setMust(must);
1848 private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_container_stmtsContext refineStmt) {
1849 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1850 ParseTree refineArg = refineStmt.getChild(i);
1851 if (refineArg instanceof Must_stmtContext) {
1852 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1853 refine.setMust(must);
1854 } else if (refineArg instanceof Presence_stmtContext) {
1855 refine.setPresence(true);
1861 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_list_stmtsContext refineStmt) {
1862 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1863 ParseTree refineArg = refineStmt.getChild(i);
1864 if (refineArg instanceof Must_stmtContext) {
1865 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1866 refine.setMust(must);
1867 } else if (refineArg instanceof Max_elements_stmtContext) {
1868 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1869 refine.setMaxElements(max);
1870 } else if (refineArg instanceof Min_elements_stmtContext) {
1871 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1872 refine.setMinElements(min);
1878 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_list_stmtsContext refineStmt) {
1879 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1880 ParseTree refineArg = refineStmt.getChild(i);
1881 if (refineArg instanceof Must_stmtContext) {
1882 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1883 refine.setMust(must);
1884 } else if (refineArg instanceof Max_elements_stmtContext) {
1885 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1886 refine.setMaxElements(max);
1887 } else if (refineArg instanceof Min_elements_stmtContext) {
1888 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1889 refine.setMinElements(min);
1895 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_choice_stmtsContext refineStmt) {
1896 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1897 ParseTree refineArg = refineStmt.getChild(i);
1898 if (refineArg instanceof Default_stmtContext) {
1899 String defaultStr = stringFromNode(refineArg);
1900 refine.setDefaultStr(defaultStr);
1901 } else if (refineArg instanceof Mandatory_stmtContext) {
1902 for (int j = 0; j < refineArg.getChildCount(); j++) {
1903 ParseTree mandatoryTree = refineArg.getChild(j);
1904 if (mandatoryTree instanceof Mandatory_argContext) {
1905 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1906 refine.setMandatory(mandatory);
1914 private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_anyxml_stmtsContext refineStmt) {
1915 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1916 ParseTree refineArg = refineStmt.getChild(i);
1917 if (refineArg instanceof Must_stmtContext) {
1918 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1919 refine.setMust(must);
1920 } else if (refineArg instanceof Mandatory_stmtContext) {
1921 for (int j = 0; j < refineArg.getChildCount(); j++) {
1922 ParseTree mandatoryTree = refineArg.getChild(j);
1923 if (mandatoryTree instanceof Mandatory_argContext) {
1924 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1925 refine.setMandatory(mandatory);
1933 public static String getArgumentString(final org.antlr.v4.runtime.ParserRuleContext ctx) {
1934 List<StringContext> potentialValues = ctx.getRuleContexts(StringContext.class);
1935 checkState(!potentialValues.isEmpty());
1936 return ParserListenerUtils.stringFromStringContext(potentialValues.get(0));
1939 public static <T extends ParserRuleContext> Optional<T> getFirstContext(final ParserRuleContext context,final Class<T> contextType) {
1940 List<T> potential = context.getRuleContexts(contextType);
1941 if(potential.isEmpty()) {
1942 return Optional.absent();
1944 return Optional.of(potential.get(0));