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;
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;
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;
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")
162 .add("ArabicPresentationForms-A")
163 .add("ArabicPresentationForms-B")
164 .add("ArabicSupplement")
170 .add("BamumSupplement")
174 .add("BlockElements")
176 .add("BopomofoExtended")
179 .add("BraillePatterns")
182 .add("ByzantineMusicalSymbols")
186 .add("CJKCompatibility")
187 .add("CJKCompatibilityForms")
188 .add("CJKCompatibilityIdeographs")
189 .add("CJKCompatibilityIdeographsSupplement")
190 .add("CJKRadicalsSupplement")
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")
205 .add("CountingRodNumerals")
207 .add("CuneiformNumbersandPunctuation")
208 .add("CurrencySymbols")
209 .add("CypriotSyllabary")
211 .add("CyrillicExtended-A")
212 .add("CyrillicExtended-B")
213 .add("CyrillicSupplementary")
216 .add("DevanagariExtended")
219 .add("EgyptianHieroglyphs")
221 .add("EnclosedAlphanumericSupplement")
222 .add("EnclosedAlphanumerics")
223 .add("EnclosedCJKLettersandMonths")
224 .add("EnclosedIdeographicSupplement")
226 .add("EthiopicExtended")
227 .add("EthiopicExtended-A")
228 .add("EthiopicSupplement")
229 .add("GeneralPunctuation")
230 .add("GeometricShapes")
232 .add("GeorgianSupplement")
235 .add("GreekandCoptic")
236 .add("GreekExtended")
239 .add("HalfwidthandFullwidthForms")
240 .add("HangulCompatibilityJamo")
242 .add("HangulJamoExtended-A")
243 .add("HangulJamoExtended-B")
244 .add("HangulSyllables")
247 .add("HighPrivateUseSurrogates")
248 .add("HighSurrogates")
250 .add("IdeographicDescriptionCharacters")
251 .add("ImperialAramaic")
252 .add("InscriptionalPahlavi")
253 .add("InscriptionalParthian")
254 .add("IPAExtensions")
257 .add("KanaSupplement")
259 .add("Kangxi Radicals")
262 .add("KatakanaPhoneticExtensions")
268 .add("Latin-1Supplement")
269 .add("LatinExtended-A")
270 .add("LatinExtendedAdditional")
271 .add("LatinExtended-B")
272 .add("LatinExtended-C")
273 .add("LatinExtended-D")
275 .add("LetterlikeSymbols")
277 .add("LinearBIdeograms")
278 .add("LinearBSyllabary")
280 .add("LowSurrogates")
286 .add("MathematicalAlphanumericSymbols")
287 .add("MathematicalOperators")
289 .add("MiscellaneousMathematicalSymbols-A")
290 .add("MiscellaneousMathematicalSymbols-B")
291 .add("MiscellaneousSymbols")
292 .add("MiscellaneousSymbolsandArrows")
293 .add("MiscellaneousSymbolsAndPictographs")
294 .add("MiscellaneousTechnical")
295 .add("ModifierToneLetters")
297 .add("MusicalSymbols")
299 .add("MyanmarExtended-A")
307 .add("OldSouthArabian")
309 .add("OpticalCharacterRecognition")
315 .add("PhoneticExtensions")
316 .add("PhoneticExtensionsSupplement")
318 .add("PrivateUseArea")
320 .add("RumiNumeralSymbols")
326 .add("SmallFormVariants")
327 .add("SpacingModifierLetters")
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")
345 .add("TaiXuanJingSymbols")
352 .add("TransportAndMapSymbols")
354 .add("UnifiedCanadianAboriginalSyllabics")
355 .add("UnifiedCanadianAboriginalSyllabicsExtended")
357 .add("VariationSelectors")
358 .add("VariationSelectorsSupplement")
359 .add("VedicExtensions")
360 .add("VerticalForms")
363 .add("YijingHexagramSymbols").build();
365 private ParserListenerUtils() {
369 * Parse given tree and get first string value.
373 * @return first string value from given tree
375 public static String stringFromNode(final ParseTree treeNode) {
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);
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;
402 * It is safe not to check last argument to be same
403 * grammars enforces that.
405 * FIXME: Introduce proper escaping and translation of escaped
409 sb.append(quoteMatcher.removeFrom(str.substring(1, str.length()-1)));
411 return sb.toString();
414 private static String getParentModule(final ParseTree ctx) {
415 ParseTree current = ctx;
416 while (current != null && !(current instanceof Module_stmtContext)) {
417 current = current.getParent();
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();
432 * Parse 'description', 'reference' and 'status' statements and fill in
438 * builder to fill in with parsed statements
439 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
459 * Parse given context and return its value;
463 * @return value parsed from context
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) {
473 result = Status.CURRENT;
476 result = Status.DEPRECATED;
479 result = Status.OBSOLETE;
482 LOG.warn("Invalid 'status' statement: " + statusArgStr);
490 * Parse given tree and returns units statement as string.
494 * @return value of units statement as string or null if there is no units
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);
508 * Parse given tree and returns default statement as string.
512 * @return value of default statement as string or null if there is no
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);
526 * Create java.util.LinkedHashSet of key node names.
529 * Key_stmtContext context
530 * @return YANG list key as java.util.LinkedHashSet of key node names
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));
538 * Parse given type body of enumeration statement.
541 * type body context to parse
543 * actual position in YANG model
545 * current module name
546 * @return List of EnumPair object parsed from given context
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<>();
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();
563 enumConstants.add(enumPair);
568 return enumConstants;
572 * Parse enum statement context
575 * enum statement context
576 * @param highestValue
577 * current highest value in enumeration
579 * actual position in YANG model
581 * current module name
582 * @return EnumPair object parsed from given context
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;
590 String description = null;
591 String reference = null;
592 Status status = null;
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);
599 // yang enum value has same restrictions as JAVA Integer
600 value = Integer.valueOf(valueStr);
601 } catch (NumberFormatException e) {
603 .format("Error on enum '%s': the enum value MUST be in the range from -2147483648 to 2147483647, but was: %s",
605 throw new YangParseException(moduleName, ctx.getStart().getLine(), err, e);
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);
617 value = highestValue + 1;
620 EnumPairImpl result = new EnumPairImpl();
621 result.qname = path.getPathTowardsRoot().iterator().next();
623 result.description = description;
624 result.reference = reference;
625 result.status = status;
627 result.value = value;
632 * Internal implementation of EnumPair.
634 private static class EnumPairImpl implements EnumTypeDefinition.EnumPair {
636 private SchemaPath path;
637 private String description;
638 private String reference;
639 private Status status;
640 private final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
642 private Integer value;
645 public QName getQName() {
650 public SchemaPath getPath() {
655 public String getDescription() {
660 public String getReference() {
665 public Status getStatus() {
670 public List<UnknownSchemaNode> getUnknownSchemaNodes() {
675 public String getName() {
680 public Integer getValue() {
685 public int hashCode() {
686 final int prime = 31;
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);
697 public boolean equals(final Object obj) {
704 if (getClass() != obj.getClass()) {
707 EnumPairImpl other = (EnumPairImpl) obj;
709 if (other.qname != null) {
712 } else if (!qname.equals(other.qname)) {
716 if (other.path != null) {
719 } else if (!path.equals(other.path)) {
722 if (unknownNodes == null) {
723 if (other.unknownNodes != null) {
726 } else if (!unknownNodes.equals(other.unknownNodes)) {
730 if (other.name != null) {
733 } else if (!name.equals(other.name)) {
737 if (other.value != null) {
740 } else if (!value.equals(other.value)) {
747 public String toString() {
748 return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name=" + name + ", value=" + value + "]";
753 * Get and parse range from given type body context.
756 * type body context to parse
758 * name of current module
759 * @return List of RangeConstraint created from this context
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);
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);
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);
788 return Collections.emptyList();
792 * Parse given range context.
795 * range context to parse
797 * name of current module
798 * @return List of RangeConstraints parsed from this context
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();
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));
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);
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 + "\".");
829 RangeConstraint range = BaseConstraints.newRangeConstraint(min, max, description, reference);
830 rangeConstraints.add(range);
833 return rangeConstraints;
837 * Get and parse length from given type body context.
840 * type body context to parse
842 * name of current module
843 * @return List of LengthConstraint created from this context
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);
857 return Collections.emptyList();
861 * Parse given length context.
864 * length context to parse
866 * name of current module
867 * @return List of LengthConstraints parsed from this context
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();
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));
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);
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 + "\".");
898 LengthConstraint range = BaseConstraints.newLengthConstraint(min, max, description, reference);
899 lengthConstraints.add(range);
902 return lengthConstraints;
909 * name of current module
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'
915 private static Number parseNumberConstraintValue(final String value, final String moduleName, final int line) {
917 if ("min".equals(value) || "max".equals(value)) {
918 result = new UnknownBoundaryNumber(value);
921 if (value.indexOf('.') != -1) {
922 result = new BigDecimal(value);
924 result = new BigInteger(value);
926 } catch (NumberFormatException e) {
927 throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
934 * Parse type body and return pattern constraints.
938 * @return list of pattern constraints
940 private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx, final String moduleName) {
941 List<PatternConstraint> patterns = new ArrayList<>();
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,
951 if (constraint != null) {
952 patterns.add(constraint);
962 * Internal helper method.
966 * @return PatternConstraint object
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));
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);
988 private static String fixUnicodeScriptPattern(String rawPattern) {
989 for (int i = 0; i < UNICODE_SCRIPT_FIX_COUNTER; i++) {
991 Pattern.compile(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);
1003 LOG.warn("Regex pattern could not be fixed: {}", rawPattern);
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");
1017 return result.toString();
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();
1028 private static boolean isValidPattern(final String pattern, final Pattern_stmtContext ctx, final String moduleName) {
1030 Pattern.compile(pattern);
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());
1040 * Parse given context and return pattern value.
1044 * @return pattern value as String
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++) {
1053 String patternToken = child.getChild(j).getText();
1054 result.append(patternToken.substring(1, patternToken.length() - 1));
1059 return result.toString();
1063 * Get fraction digits value from type body.
1066 * type body context to parse
1068 * name of current module
1069 * @return 'fraction-digits' value if present in given context, null
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);
1084 * Parse decimal64 fraction-digits value.
1089 * name of current module
1090 * @return fraction-digits value as Integer
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);
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);
1110 * Internal helper method for parsing bit statements from given type body
1114 * type body context to parse
1116 * current position in YANG model
1118 * current module name
1119 * @return List of Bit objects created from this context
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();
1144 * Internal helper method for parsing bit context.
1147 * bit statement context to parse
1148 * @param highestPosition
1149 * current highest position in bits type
1151 * current position in YANG model
1153 * current module name
1154 * @return Bit object parsed from this context
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;
1161 String description = null;
1162 String reference = null;
1163 Status status = Status.CURRENT;
1165 SchemaPath schemaPath = createBaseTypePath(actualPath, name);
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);
1181 if (position == null) {
1182 position = highestPosition + 1;
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");
1189 final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
1190 return new BitImpl(position, schemaPath.getPathTowardsRoot().iterator().next(), schemaPath,
1191 description, reference, status, unknownNodes);
1195 * Parse 'ordered-by' statement.
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".
1202 * Ordered_by_stmtContext
1203 * @return true, if ordered-by contains value 'user', false otherwise
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);
1219 LOG.warn("Invalid 'ordered-by' statement.");
1227 * Get config statement from given context. If there is no config statement,
1228 * return config value of parent
1235 * name of current module
1237 * line in current module
1238 * @return config statement parsed from given context
1239 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1242 public static boolean getConfig(final ParseTree ctx, final Builder node, final String moduleName, final int line) {
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);
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;
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'");
1273 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1276 private static boolean getParentConfig(final Builder node) {
1277 Builder parent = node.getParent();
1280 if (parent instanceof ChoiceCaseBuilder) {
1281 parent = parent.getParent();
1283 if (parent instanceof DataSchemaNodeBuilder) {
1284 config = ((DataSchemaNodeBuilder) parent).isConfiguration();
1292 * Parse config statement.
1295 * config context to parse
1297 * current module name
1298 * @return true if given context contains string 'true', false otherwise
1300 private static Boolean parseConfig(final Config_stmtContext ctx, final String moduleName) {
1301 Boolean result = 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);
1315 throw new YangParseException(moduleName, ctx.getStart().getLine(),
1316 "Failed to parse 'config' statement value: '" + value + "'.");
1325 * Parse unknown type with body.
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
1338 * actual path in model
1340 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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();
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());
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();
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);
1376 * Create TypeDefinition object based on given type name and type body.
1383 * current path in schema
1384 * @param moduleQName
1385 * current module qname
1388 * @return TypeDefinition object based on parsed values.
1390 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1393 public static TypeDefinition<?> parseTypeWithBody(final String typeName, final Type_body_stmtsContext typeBody,
1394 final SchemaPath actualPath, final QName moduleQName, final Builder parent) {
1396 final String moduleName = parent.getModuleName();
1397 final int line = typeBody.getStart().getLine();
1398 TypeDefinition<?> baseType = null;
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);
1405 TypeConstraints constraints = new TypeConstraints(moduleName, line);
1406 constraints.addFractionDigits(fractionDigits);
1407 constraints.addLengths(lengthStatements);
1408 constraints.addPatterns(patternStatements);
1409 constraints.addRanges(rangeStatements);
1411 SchemaPath baseTypePath = createBaseTypePath(actualPath, typeName);
1412 SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, moduleQName, typeName);
1414 if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1415 extBaseTypePath = baseTypePath;
1418 if ("decimal64".equals(typeName)) {
1419 if (rangeStatements.isEmpty()) {
1421 return Decimal64.create(baseTypePath, fractionDigits);
1422 } catch(Exception e) {
1423 throw new YangParseException(moduleName, line, e.getMessage());
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;
1433 intType = Int8.getInstance();
1436 intType = Int16.getInstance();
1439 intType = Int32.getInstance();
1442 intType = Int64.getInstance();
1445 if (intType == null) {
1446 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1448 constraints.addRanges(intType.getRangeConstraints());
1450 } else if (typeName.startsWith("uint")) {
1451 UnsignedIntegerTypeDefinition uintType = null;
1454 uintType = Uint8.getInstance();
1457 uintType = Uint16.getInstance();
1460 uintType = Uint32.getInstance();
1463 uintType = Uint64.getInstance();
1466 if (uintType == null) {
1467 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
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));
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());
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);
1507 typeBuilder.ranges(constraints.getRange());
1508 typeBuilder.lengths(constraints.getLength());
1509 typeBuilder.patterns(constraints.getPatterns());
1510 typeBuilder.fractionDigits(constraints.getFractionDigits());
1512 return typeBuilder.build();
1515 private static SchemaPath createTypePath(final SchemaPath actual, final String typeName) {
1516 QName last = actual.getLastComponent();
1517 return actual.createChild(QName.create(last, typeName));
1520 private static SchemaPath createBaseTypePath(final SchemaPath actual, final String typeName) {
1521 return actual.createChild(BaseTypes.constructQName(typeName));
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));
1531 * Parse given context and find identityref base value.
1535 * @return identityref base value as String
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);
1555 * Parse type body statement and find require-instance value.
1559 * @return require-instance value
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));
1582 * Parse type body statement and find leafref path.
1586 * @return leafref path as String
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);
1604 * Internal helper method for parsing must statement.
1608 * @return MustDefinition object based on parsed context
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));
1625 for (int j = 0; j < context.getChildCount(); j++) {
1626 String mustPart = context.getChild(j).getText();
1628 mustText.append(mustPart.substring(0, mustPart.length() - 1));
1632 mustText.append(mustPart.substring(1));
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));
1647 return MustDefinitionImpl.create(mustText.toString(), description, reference, errorAppTag, errorMessage);
1651 * Parse given context and set constraints to constraints builder.
1655 * @param constraints
1656 * ConstraintsBuilder to fill
1658 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
1681 } else if (childNode instanceof When_stmtContext) {
1682 constraints.addWhenCondition(stringFromNode(childNode));
1687 private static Integer parseMinElements(final Min_elements_stmtContext ctx, final String moduleName) {
1688 Integer result = null;
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));
1696 if (result == null) {
1697 throw new IllegalArgumentException();
1700 } catch (Exception e) {
1701 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
1705 private static Integer parseMaxElements(final Max_elements_stmtContext ctx, final String moduleName) {
1706 Integer result = null;
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;
1715 result = Integer.valueOf(maxValue);
1719 if (result == null) {
1720 throw new IllegalArgumentException();
1723 } catch (Exception e) {
1724 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
1729 * Parse given context and return yin value.
1733 * @return true if value is 'true', false otherwise
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)) {
1756 * Check this base type.
1759 * base YANG type name
1761 * name of current module
1764 * @throws YangParseException
1765 * if this is one of YANG type which MUST contain additional
1766 * informations in its body
1768 public static void checkMissingBody(final String typeName, final String moduleName, final int line) {
1771 throw new YangParseException(moduleName, line,
1772 "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1774 throw new YangParseException(moduleName, line,
1775 "The 'base' statement MUST be present if the type is 'identityref'.");
1777 throw new YangParseException(moduleName, line,
1778 "The 'path' statement MUST be present if the type is 'leafref'.");
1780 throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
1782 throw new YangParseException(moduleName, line,
1783 "The 'enum' statement MUST be present if the type is 'enumeration'.");
1788 * Parse refine statement.
1793 * name of current module
1794 * @return RefineHolder object representing this refine statement
1796 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
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);
1829 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
1849 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
1866 } else if (refineArg instanceof Must_stmtContext) {
1867 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1868 refine.setMust(must);
1876 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
1893 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
1914 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
1935 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
1958 * @deprecated Pre-Beryllium implementation, scheduled for removal.
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);
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));
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();
1991 return Optional.of(potential.get(0));