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 return "^" + rawPattern + '$';
1024 private static boolean isValidPattern(final String pattern, final Pattern_stmtContext ctx, final String moduleName) {
1026 Pattern.compile(pattern);
1028 } catch (PatternSyntaxException ex) {
1029 LOG.warn("Unable to compile pattern defined in module {} at line {}. Error message: {}",
1030 moduleName, ctx.getStart().getLine(), ex.getMessage());
1036 * Parse given context and return pattern value.
1040 * @return pattern value as String
1042 private static String parsePatternString(final Pattern_stmtContext ctx) {
1043 StringBuilder result = new StringBuilder();
1044 for (int i = 0; i < ctx.getChildCount(); ++i) {
1045 ParseTree child = ctx.getChild(i);
1046 if (child instanceof StringContext) {
1047 for (int j = 0; j < child.getChildCount(); j++) {
1049 String patternToken = child.getChild(j).getText();
1050 result.append(patternToken.substring(1, patternToken.length() - 1));
1055 return result.toString();
1059 * Get fraction digits value from type body.
1062 * type body context to parse
1064 * name of current module
1065 * @return 'fraction-digits' value if present in given context, null
1068 private static Integer getFractionDigits(final Type_body_stmtsContext ctx, final String moduleName) {
1069 Integer result = null;
1070 for (int i = 0; i < ctx.getChildCount(); i++) {
1071 ParseTree dec64specChild = ctx.getChild(i);
1072 if (dec64specChild instanceof Decimal64_specificationContext) {
1073 result = parseFractionDigits((Decimal64_specificationContext) dec64specChild, moduleName);
1080 * Parse decimal64 fraction-digits value.
1085 * name of current module
1086 * @return fraction-digits value as Integer
1088 private static Integer parseFractionDigits(final Decimal64_specificationContext ctx, final String moduleName) {
1089 Integer result = null;
1090 for (int i = 0; i < ctx.getChildCount(); i++) {
1091 ParseTree fdChild = ctx.getChild(i);
1092 if (fdChild instanceof Fraction_digits_stmtContext) {
1093 String value = stringFromNode(fdChild);
1095 result = Integer.valueOf(value);
1096 } catch (NumberFormatException e) {
1097 throw new YangParseException(moduleName, ctx.getStart().getLine(),
1098 "Unable to parse fraction digits value '" + value + "'.", e);
1106 * Internal helper method for parsing bit statements from given type body
1110 * type body context to parse
1112 * current position in YANG model
1114 * current module name
1115 * @return List of Bit objects created from this context
1117 private static List<BitsTypeDefinition.Bit> getBits(final Type_body_stmtsContext ctx, final SchemaPath actualPath,
1118 final String moduleName) {
1119 final List<BitsTypeDefinition.Bit> bits = new ArrayList<>();
1120 for (int j = 0; j < ctx.getChildCount(); j++) {
1121 ParseTree bitsSpecChild = ctx.getChild(j);
1122 if (bitsSpecChild instanceof Bits_specificationContext) {
1123 long highestPosition = -1;
1124 for (int k = 0; k < bitsSpecChild.getChildCount(); k++) {
1125 ParseTree bitChild = bitsSpecChild.getChild(k);
1126 if (bitChild instanceof Bit_stmtContext) {
1127 Bit bit = parseBit((Bit_stmtContext) bitChild, highestPosition, actualPath, moduleName);
1128 if (bit.getPosition() > highestPosition) {
1129 highestPosition = bit.getPosition();
1140 * Internal helper method for parsing bit context.
1143 * bit statement context to parse
1144 * @param highestPosition
1145 * current highest position in bits type
1147 * current position in YANG model
1149 * current module name
1150 * @return Bit object parsed from this context
1152 private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, final long highestPosition,
1153 final SchemaPath actualPath, final String moduleName) {
1154 String name = stringFromNode(ctx);
1155 Long position = null;
1157 String description = null;
1158 String reference = null;
1159 Status status = Status.CURRENT;
1161 SchemaPath schemaPath = createBaseTypePath(actualPath, name);
1163 for (int i = 0; i < ctx.getChildCount(); i++) {
1164 ParseTree child = ctx.getChild(i);
1165 if (child instanceof Position_stmtContext) {
1166 String positionStr = stringFromNode(child);
1167 position = Long.valueOf(positionStr);
1168 } else if (child instanceof Description_stmtContext) {
1169 description = stringFromNode(child);
1170 } else if (child instanceof Reference_stmtContext) {
1171 reference = stringFromNode(child);
1172 } else if (child instanceof Status_stmtContext) {
1173 status = parseStatus((Status_stmtContext) child);
1177 if (position == null) {
1178 position = highestPosition + 1;
1180 if (position < 0 || position > 4294967295L) {
1181 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on bit '" + name
1182 + "': the position value MUST be in the range 0 to 4294967295");
1185 final List<UnknownSchemaNode> unknownNodes = Collections.emptyList();
1186 return new BitImpl(position, schemaPath.getPathTowardsRoot().iterator().next(), schemaPath,
1187 description, reference, status, unknownNodes);
1191 * Parse 'ordered-by' statement.
1193 * The 'ordered-by' statement defines whether the order of entries within a
1194 * list are determined by the user or the system. The argument is one of the
1195 * strings "system" or "user". If not present, order defaults to "system".
1198 * Ordered_by_stmtContext
1199 * @return true, if ordered-by contains value 'user', false otherwise
1201 public static boolean parseUserOrdered(final Ordered_by_stmtContext ctx) {
1202 boolean result = false;
1203 for (int j = 0; j < ctx.getChildCount(); j++) {
1204 ParseTree orderArg = ctx.getChild(j);
1205 if (orderArg instanceof Ordered_by_argContext) {
1206 String orderStr = stringFromNode(orderArg);
1215 LOG.warn("Invalid 'ordered-by' statement.");
1223 * Get config statement from given context. If there is no config statement,
1224 * return config value of parent
1231 * name of current module
1233 * line in current module
1234 * @return config statement parsed from given context
1235 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1238 public static boolean getConfig(final ParseTree ctx, final Builder node, final String moduleName, final int line) {
1240 // parse configuration statement
1241 Boolean config = null;
1242 for (int i = 0; i < ctx.getChildCount(); i++) {
1243 ParseTree child = ctx.getChild(i);
1244 if (child instanceof Config_stmtContext) {
1245 config = parseConfig((Config_stmtContext) child, moduleName);
1250 // If 'config' is not specified, the default is the same as the parent
1251 // schema node's 'config' value
1252 boolean parentConfig = getParentConfig(node);
1253 if (config == null) {
1254 result = parentConfig;
1256 // Check: if a node has 'config' set to 'false', no node underneath
1257 // it can have 'config' set to 'true'
1258 if (!parentConfig && config) {
1259 throw new YangParseException(moduleName, line,
1260 "Can not set 'config' to 'true' if parent node has 'config' set to 'false'");
1269 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1272 private static boolean getParentConfig(final Builder node) {
1273 Builder parent = node.getParent();
1276 if (parent instanceof ChoiceCaseBuilder) {
1277 parent = parent.getParent();
1279 if (parent instanceof DataSchemaNodeBuilder) {
1280 config = ((DataSchemaNodeBuilder) parent).isConfiguration();
1288 * Parse config statement.
1291 * config context to parse
1293 * current module name
1294 * @return true if given context contains string 'true', false otherwise
1296 private static Boolean parseConfig(final Config_stmtContext ctx, final String moduleName) {
1297 Boolean result = null;
1299 for (int i = 0; i < ctx.getChildCount(); ++i) {
1300 final ParseTree configContext = ctx.getChild(i);
1301 if (configContext instanceof Config_argContext) {
1302 final String value = stringFromNode(configContext);
1311 throw new YangParseException(moduleName, ctx.getStart().getLine(),
1312 "Failed to parse 'config' statement value: '" + value + "'.");
1321 * Parse unknown type with body.
1326 * current node parent
1327 * @param prefixedQName
1328 * type qname with prefix
1329 * @param moduleBuilder
1330 * current module builder
1331 * @param moduleQName
1332 * current module qname
1334 * actual path in model
1336 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1339 public static void parseUnknownTypeWithBody(final Type_body_stmtsContext typeBody, final TypeAwareBuilder parent,
1340 final QName prefixedQName, final ModuleBuilder moduleBuilder, final QName moduleQName, final SchemaPath actualPath) {
1341 final int line = typeBody.getStart().getLine();
1343 List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleBuilder.getName());
1344 List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleBuilder.getName());
1345 List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleBuilder.getName());
1346 Integer fractionDigits = getFractionDigits(typeBody, moduleBuilder.getName());
1348 if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1349 TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1350 typedef.setRanges(rangeStatements);
1351 typedef.setLengths(lengthStatements);
1352 typedef.setPatterns(patternStatements);
1353 typedef.setFractionDigits(fractionDigits);
1354 typedef.setTypeQName(prefixedQName);
1355 // add parent node of this type statement to dirty nodes
1356 moduleBuilder.markActualNodeDirty();
1358 QName qname = QName.create(moduleQName, prefixedQName.getLocalName());
1359 SchemaPath schemaPath = createTypePath(actualPath, prefixedQName.getLocalName());
1360 TypeDefinitionBuilder typeBuilder = new TypeDefinitionBuilderImpl(moduleBuilder.getName(), line, qname, schemaPath);
1361 typeBuilder.setRanges(rangeStatements);
1362 typeBuilder.setLengths(lengthStatements);
1363 typeBuilder.setPatterns(patternStatements);
1364 typeBuilder.setFractionDigits(fractionDigits);
1365 typeBuilder.setTypeQName(prefixedQName);
1366 parent.setTypedef(typeBuilder);
1367 moduleBuilder.getDirtyNodes().add(typeBuilder);
1372 * Create TypeDefinition object based on given type name and type body.
1379 * current path in schema
1380 * @param moduleQName
1381 * current module qname
1384 * @return TypeDefinition object based on parsed values.
1386 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1389 public static TypeDefinition<?> parseTypeWithBody(final String typeName, final Type_body_stmtsContext typeBody,
1390 final SchemaPath actualPath, final QName moduleQName, final Builder parent) {
1392 final String moduleName = parent.getModuleName();
1393 final int line = typeBody.getStart().getLine();
1394 TypeDefinition<?> baseType = null;
1396 Integer fractionDigits = getFractionDigits(typeBody, moduleName);
1397 List<LengthConstraint> lengthStatements = getLengthConstraints(typeBody, moduleName);
1398 List<PatternConstraint> patternStatements = getPatternConstraint(typeBody, moduleName);
1399 List<RangeConstraint> rangeStatements = getRangeConstraints(typeBody, moduleName);
1401 TypeConstraints constraints = new TypeConstraints(moduleName, line);
1402 constraints.addFractionDigits(fractionDigits);
1403 constraints.addLengths(lengthStatements);
1404 constraints.addPatterns(patternStatements);
1405 constraints.addRanges(rangeStatements);
1407 SchemaPath baseTypePath = createBaseTypePath(actualPath, typeName);
1408 SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, moduleQName, typeName);
1410 if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1411 extBaseTypePath = baseTypePath;
1414 if ("decimal64".equals(typeName)) {
1415 if (rangeStatements.isEmpty()) {
1417 return Decimal64.create(baseTypePath, fractionDigits);
1418 } catch(Exception e) {
1419 throw new YangParseException(moduleName, line, e.getMessage());
1422 Decimal64 decimalType = Decimal64.create(extBaseTypePath, fractionDigits);
1423 constraints.addRanges(decimalType.getRangeConstraints());
1424 baseType = decimalType;
1425 } else if (typeName.startsWith("int")) {
1426 IntegerTypeDefinition intType = null;
1429 intType = Int8.getInstance();
1432 intType = Int16.getInstance();
1435 intType = Int32.getInstance();
1438 intType = Int64.getInstance();
1441 if (intType == null) {
1442 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1444 constraints.addRanges(intType.getRangeConstraints());
1446 } else if (typeName.startsWith("uint")) {
1447 UnsignedIntegerTypeDefinition uintType = null;
1450 uintType = Uint8.getInstance();
1453 uintType = Uint16.getInstance();
1456 uintType = Uint32.getInstance();
1459 uintType = Uint64.getInstance();
1462 if (uintType == null) {
1463 throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
1465 constraints.addRanges(uintType.getRangeConstraints());
1466 baseType = uintType;
1467 } else if ("enumeration".equals(typeName)) {
1468 List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
1469 return EnumerationType.create(baseTypePath, enumConstants, Optional.<EnumPair> absent());
1470 } else if ("string".equals(typeName)) {
1471 StringTypeDefinition stringType = StringType.getInstance();
1472 constraints.addLengths(stringType.getLengthConstraints());
1473 baseType = stringType;
1474 } else if ("bits".equals(typeName)) {
1475 return BitsType.create(baseTypePath, getBits(typeBody, actualPath, moduleName));
1476 } else if ("leafref".equals(typeName)) {
1477 final String path = parseLeafrefPath(typeBody);
1478 final boolean absolute = path.startsWith("/");
1479 RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, absolute);
1480 return new Leafref(xpath);
1481 } else if ("binary".equals(typeName)) {
1482 BinaryTypeDefinition binaryType = BinaryType.getInstance();
1483 constraints.addLengths(binaryType.getLengthConstraints());
1484 baseType = binaryType;
1485 } else if ("instance-identifier".equals(typeName)) {
1486 return InstanceIdentifierType.create(isRequireInstance(typeBody));
1489 if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) {
1490 TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent;
1491 typedef.setRanges(constraints.getRange());
1492 typedef.setLengths(constraints.getLength());
1493 typedef.setPatterns(constraints.getPatterns());
1494 typedef.setFractionDigits(constraints.getFractionDigits());
1498 QName qname = QName.create(moduleQName, typeName);
1499 SchemaPath schemaPath = actualPath.createChild(qname);
1500 final Optional<String> opt = Optional.of("");
1501 ExtendedType.Builder typeBuilder = ExtendedType.builder(qname, baseType, opt, opt, schemaPath);
1503 typeBuilder.ranges(constraints.getRange());
1504 typeBuilder.lengths(constraints.getLength());
1505 typeBuilder.patterns(constraints.getPatterns());
1506 typeBuilder.fractionDigits(constraints.getFractionDigits());
1508 return typeBuilder.build();
1511 private static SchemaPath createTypePath(final SchemaPath actual, final String typeName) {
1512 QName last = actual.getLastComponent();
1513 return actual.createChild(QName.create(last, typeName));
1516 private static SchemaPath createBaseTypePath(final SchemaPath actual, final String typeName) {
1517 return actual.createChild(BaseTypes.constructQName(typeName));
1520 private static SchemaPath createExtendedBaseTypePath(final SchemaPath actual, final QName moduleQName, final String typeName) {
1521 return actual.createChild(
1522 QName.create(moduleQName, typeName),
1523 BaseTypes.constructQName(typeName));
1527 * Parse given context and find identityref base value.
1531 * @return identityref base value as String
1533 public static String getIdentityrefBase(final Type_body_stmtsContext ctx) {
1534 String result = null;
1535 outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1536 ParseTree child = ctx.getChild(i);
1537 if (child instanceof Identityref_specificationContext) {
1538 for (int j = 0; j < child.getChildCount(); j++) {
1539 ParseTree baseArg = child.getChild(j);
1540 if (baseArg instanceof Base_stmtContext) {
1541 result = stringFromNode(baseArg);
1551 * Parse type body statement and find require-instance value.
1555 * @return require-instance value
1557 private static boolean isRequireInstance(final Type_body_stmtsContext ctx) {
1558 for (int i = 0; i < ctx.getChildCount(); i++) {
1559 ParseTree child = ctx.getChild(i);
1560 if (child instanceof Instance_identifier_specificationContext) {
1561 for (int j = 0; j < child.getChildCount(); j++) {
1562 ParseTree reqStmt = child.getChild(j);
1563 if (reqStmt instanceof Require_instance_stmtContext) {
1564 for (int k = 0; k < reqStmt.getChildCount(); k++) {
1565 ParseTree reqArg = reqStmt.getChild(k);
1566 if (reqArg instanceof Require_instance_argContext) {
1567 return Boolean.valueOf(stringFromNode(reqArg));
1578 * Parse type body statement and find leafref path.
1582 * @return leafref path as String
1584 private static String parseLeafrefPath(final Type_body_stmtsContext ctx) {
1585 for (int i = 0; i < ctx.getChildCount(); i++) {
1586 ParseTree child = ctx.getChild(i);
1587 if (child instanceof Leafref_specificationContext) {
1588 for (int j = 0; j < child.getChildCount(); j++) {
1589 ParseTree leafRefSpec = child.getChild(j);
1590 if (leafRefSpec instanceof Path_stmtContext) {
1591 return stringFromNode(leafRefSpec);
1600 * Internal helper method for parsing must statement.
1604 * @return MustDefinition object based on parsed context
1606 private static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) {
1607 StringBuilder mustText = new StringBuilder();
1608 Optional<String> description = Optional.absent();
1609 Optional<String> reference = Optional.absent();
1610 Optional<String> errorAppTag = Optional.absent();
1611 Optional<String> errorMessage = Optional.absent();
1612 for (int i = 0; i < ctx.getChildCount(); ++i) {
1613 ParseTree child = ctx.getChild(i);
1614 if (child instanceof StringContext) {
1615 final StringContext context = (StringContext) child;
1616 if (context.getChildCount() == 1) {
1617 String mustPart = context.getChild(0).getText();
1618 // trim start and end quotation
1619 mustText.append(mustPart.substring(1, mustPart.length() - 1));
1621 for (int j = 0; j < context.getChildCount(); j++) {
1622 String mustPart = context.getChild(j).getText();
1624 mustText.append(mustPart.substring(0, mustPart.length() - 1));
1628 mustText.append(mustPart.substring(1));
1632 } else if (child instanceof Description_stmtContext) {
1633 description = Optional.of(stringFromNode(child));
1634 } else if (child instanceof Reference_stmtContext) {
1635 reference = Optional.of(stringFromNode(child));
1636 } else if (child instanceof Error_app_tag_stmtContext) {
1637 errorAppTag = Optional.of(stringFromNode(child));
1638 } else if (child instanceof Error_message_stmtContext) {
1639 errorMessage = Optional.of(stringFromNode(child));
1643 return MustDefinitionImpl.create(mustText.toString(), description, reference, errorAppTag, errorMessage);
1647 * Parse given context and set constraints to constraints builder.
1651 * @param constraints
1652 * ConstraintsBuilder to fill
1654 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1657 public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) {
1658 for (int i = 0; i < ctx.getChildCount(); ++i) {
1659 final ParseTree childNode = ctx.getChild(i);
1660 if (childNode instanceof Max_elements_stmtContext) {
1661 Integer max = parseMaxElements((Max_elements_stmtContext) childNode, constraints.getModuleName());
1662 constraints.setMaxElements(max);
1663 } else if (childNode instanceof Min_elements_stmtContext) {
1664 Integer min = parseMinElements((Min_elements_stmtContext) childNode, constraints.getModuleName());
1665 constraints.setMinElements(min);
1666 } else if (childNode instanceof Must_stmtContext) {
1667 MustDefinition must = parseMust((Must_stmtContext) childNode);
1668 constraints.addMustDefinition(must);
1669 } else if (childNode instanceof Mandatory_stmtContext) {
1670 for (int j = 0; j < childNode.getChildCount(); j++) {
1671 ParseTree mandatoryTree = childNode.getChild(j);
1672 if (mandatoryTree instanceof Mandatory_argContext) {
1673 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1674 constraints.setMandatory(mandatory);
1677 } else if (childNode instanceof When_stmtContext) {
1678 constraints.addWhenCondition(stringFromNode(childNode));
1683 private static Integer parseMinElements(final Min_elements_stmtContext ctx, final String moduleName) {
1684 Integer result = null;
1686 for (int i = 0; i < ctx.getChildCount(); i++) {
1687 ParseTree minArg = ctx.getChild(i);
1688 if (minArg instanceof Min_value_argContext) {
1689 result = Integer.valueOf(stringFromNode(minArg));
1692 if (result == null) {
1693 throw new IllegalArgumentException();
1696 } catch (Exception e) {
1697 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse min-elements.", e);
1701 private static Integer parseMaxElements(final Max_elements_stmtContext ctx, final String moduleName) {
1702 Integer result = null;
1704 for (int i = 0; i < ctx.getChildCount(); i++) {
1705 ParseTree maxArg = ctx.getChild(i);
1706 if (maxArg instanceof Max_value_argContext) {
1707 String maxValue = stringFromNode(maxArg);
1708 if ("unbounded".equals(maxValue)) {
1709 result = Integer.MAX_VALUE;
1711 result = Integer.valueOf(maxValue);
1715 if (result == null) {
1716 throw new IllegalArgumentException();
1719 } catch (Exception e) {
1720 throw new YangParseException(moduleName, ctx.getStart().getLine(), "Failed to parse max-elements.", e);
1725 * Parse given context and return yin value.
1729 * @return true if value is 'true', false otherwise
1731 public static boolean parseYinValue(final Argument_stmtContext ctx) {
1732 boolean yinValue = false;
1733 outer: for (int i = 0; i < ctx.getChildCount(); i++) {
1734 ParseTree yin = ctx.getChild(i);
1735 if (yin instanceof Yin_element_stmtContext) {
1736 for (int j = 0; j < yin.getChildCount(); j++) {
1737 ParseTree yinArg = yin.getChild(j);
1738 if (yinArg instanceof Yin_element_argContext) {
1739 String yinString = stringFromNode(yinArg);
1740 if ("true".equals(yinString)) {
1752 * Check this base type.
1755 * base YANG type name
1757 * name of current module
1760 * @throws YangParseException
1761 * if this is one of YANG type which MUST contain additional
1762 * informations in its body
1764 public static void checkMissingBody(final String typeName, final String moduleName, final int line) {
1767 throw new YangParseException(moduleName, line,
1768 "The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
1770 throw new YangParseException(moduleName, line,
1771 "The 'base' statement MUST be present if the type is 'identityref'.");
1773 throw new YangParseException(moduleName, line,
1774 "The 'path' statement MUST be present if the type is 'leafref'.");
1776 throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
1778 throw new YangParseException(moduleName, line,
1779 "The 'enum' statement MUST be present if the type is 'enumeration'.");
1784 * Parse refine statement.
1789 * name of current module
1790 * @return RefineHolder object representing this refine statement
1792 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1795 public static RefineHolderImpl parseRefine(final Refine_stmtContext refineCtx, final String moduleName) {
1796 final String refineTarget = stringFromNode(refineCtx);
1797 final RefineHolderImpl refine = new RefineHolderImpl(moduleName, refineCtx.getStart().getLine(), refineTarget);
1798 for (int i = 0; i < refineCtx.getChildCount(); i++) {
1799 ParseTree refinePom = refineCtx.getChild(i);
1800 if (refinePom instanceof Refine_pomContext) {
1801 for (int j = 0; j < refinePom.getChildCount(); j++) {
1802 ParseTree refineStmt = refinePom.getChild(j);
1803 parseRefineDefault(refine, refineStmt);
1805 if (refineStmt instanceof Refine_leaf_stmtsContext) {
1806 parseRefine(refine, (Refine_leaf_stmtsContext) refineStmt);
1807 } else if (refineStmt instanceof Refine_container_stmtsContext) {
1808 parseRefine(refine, (Refine_container_stmtsContext) refineStmt);
1809 } else if (refineStmt instanceof Refine_list_stmtsContext) {
1810 parseRefine(refine, (Refine_list_stmtsContext) refineStmt);
1811 } else if (refineStmt instanceof Refine_leaf_list_stmtsContext) {
1812 parseRefine(refine, (Refine_leaf_list_stmtsContext) refineStmt);
1813 } else if (refineStmt instanceof Refine_choice_stmtsContext) {
1814 parseRefine(refine, (Refine_choice_stmtsContext) refineStmt);
1815 } else if (refineStmt instanceof Refine_anyxml_stmtsContext) {
1816 parseRefine(refine, (Refine_anyxml_stmtsContext) refineStmt);
1825 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1828 private static void parseRefineDefault(final RefineHolderImpl refine, final ParseTree refineStmt) {
1829 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1830 ParseTree refineArg = refineStmt.getChild(i);
1831 if (refineArg instanceof Description_stmtContext) {
1832 String description = stringFromNode(refineArg);
1833 refine.setDescription(description);
1834 } else if (refineArg instanceof Reference_stmtContext) {
1835 String reference = stringFromNode(refineArg);
1836 refine.setReference(reference);
1837 } else if (refineArg instanceof Config_stmtContext) {
1838 Boolean config = parseConfig((Config_stmtContext) refineArg, refine.getModuleName());
1839 refine.setConfiguration(config);
1845 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1848 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_stmtsContext refineStmt) {
1849 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1850 ParseTree refineArg = refineStmt.getChild(i);
1851 if (refineArg instanceof Default_stmtContext) {
1852 String defaultStr = stringFromNode(refineArg);
1853 refine.setDefaultStr(defaultStr);
1854 } else if (refineArg instanceof Mandatory_stmtContext) {
1855 for (int j = 0; j < refineArg.getChildCount(); j++) {
1856 ParseTree mandatoryTree = refineArg.getChild(j);
1857 if (mandatoryTree instanceof Mandatory_argContext) {
1858 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1859 refine.setMandatory(mandatory);
1862 } else if (refineArg instanceof Must_stmtContext) {
1863 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1864 refine.setMust(must);
1872 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1875 private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_container_stmtsContext refineStmt) {
1876 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1877 ParseTree refineArg = refineStmt.getChild(i);
1878 if (refineArg instanceof Must_stmtContext) {
1879 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1880 refine.setMust(must);
1881 } else if (refineArg instanceof Presence_stmtContext) {
1882 refine.setPresence(true);
1889 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1892 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_list_stmtsContext refineStmt) {
1893 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1894 ParseTree refineArg = refineStmt.getChild(i);
1895 if (refineArg instanceof Must_stmtContext) {
1896 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1897 refine.setMust(must);
1898 } else if (refineArg instanceof Max_elements_stmtContext) {
1899 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1900 refine.setMaxElements(max);
1901 } else if (refineArg instanceof Min_elements_stmtContext) {
1902 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1903 refine.setMinElements(min);
1910 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1913 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_list_stmtsContext refineStmt) {
1914 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1915 ParseTree refineArg = refineStmt.getChild(i);
1916 if (refineArg instanceof Must_stmtContext) {
1917 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1918 refine.setMust(must);
1919 } else if (refineArg instanceof Max_elements_stmtContext) {
1920 Integer max = parseMaxElements((Max_elements_stmtContext) refineArg, refine.getModuleName());
1921 refine.setMaxElements(max);
1922 } else if (refineArg instanceof Min_elements_stmtContext) {
1923 Integer min = parseMinElements((Min_elements_stmtContext) refineArg, refine.getModuleName());
1924 refine.setMinElements(min);
1931 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1934 private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_choice_stmtsContext refineStmt) {
1935 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1936 ParseTree refineArg = refineStmt.getChild(i);
1937 if (refineArg instanceof Default_stmtContext) {
1938 String defaultStr = stringFromNode(refineArg);
1939 refine.setDefaultStr(defaultStr);
1940 } else if (refineArg instanceof Mandatory_stmtContext) {
1941 for (int j = 0; j < refineArg.getChildCount(); j++) {
1942 ParseTree mandatoryTree = refineArg.getChild(j);
1943 if (mandatoryTree instanceof Mandatory_argContext) {
1944 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1945 refine.setMandatory(mandatory);
1954 * @deprecated Pre-Beryllium implementation, scheduled for removal.
1957 private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_anyxml_stmtsContext refineStmt) {
1958 for (int i = 0; i < refineStmt.getChildCount(); i++) {
1959 ParseTree refineArg = refineStmt.getChild(i);
1960 if (refineArg instanceof Must_stmtContext) {
1961 MustDefinition must = parseMust((Must_stmtContext) refineArg);
1962 refine.setMust(must);
1963 } else if (refineArg instanceof Mandatory_stmtContext) {
1964 for (int j = 0; j < refineArg.getChildCount(); j++) {
1965 ParseTree mandatoryTree = refineArg.getChild(j);
1966 if (mandatoryTree instanceof Mandatory_argContext) {
1967 Boolean mandatory = Boolean.valueOf(stringFromNode(mandatoryTree));
1968 refine.setMandatory(mandatory);
1976 public static String getArgumentString(final org.antlr.v4.runtime.ParserRuleContext ctx) {
1977 List<StringContext> potentialValues = ctx.getRuleContexts(StringContext.class);
1978 checkState(!potentialValues.isEmpty());
1979 return ParserListenerUtils.stringFromStringContext(potentialValues.get(0));
1982 public static <T extends ParserRuleContext> Optional<T> getFirstContext(final ParserRuleContext context,final Class<T> contextType) {
1983 List<T> potential = context.getRuleContexts(contextType);
1984 if(potential.isEmpty()) {
1985 return Optional.absent();
1987 return Optional.of(potential.get(0));