X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Fimpl%2FParserListenerUtils.java;h=fadb1a23536237d29688e11c8da6a42b340ee92f;hb=42abb28b99a02f9580f4676ce5c315628e5bcd24;hp=49f4178731f59221fa5660efd59a1816ba210efc;hpb=f909cd8a286ed28d2be7a3ba8737bb64c41fadd7;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java index 49f4178731..fadb1a2353 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/ParserListenerUtils.java @@ -3,20 +3,28 @@ * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/eplv10.html + * and is available at http://www.eclipse.org/legal/epl-v10.html */ + package org.opendaylight.yangtools.yang.parser.impl; import static com.google.common.base.Preconditions.checkState; - +import com.google.common.base.CharMatcher; +import com.google.common.base.Optional; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; import java.math.BigDecimal; -import java.net.URI; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; +import java.util.Iterator; import java.util.List; -import java.util.Stack; - +import java.util.Objects; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; @@ -103,7 +111,7 @@ import org.opendaylight.yangtools.yang.model.util.BitsType; import org.opendaylight.yangtools.yang.model.util.Decimal64; import org.opendaylight.yangtools.yang.model.util.EnumerationType; import org.opendaylight.yangtools.yang.model.util.ExtendedType; -import org.opendaylight.yangtools.yang.model.util.InstanceIdentifier; +import org.opendaylight.yangtools.yang.model.util.InstanceIdentifierType; import org.opendaylight.yangtools.yang.model.util.Int16; import org.opendaylight.yangtools.yang.model.util.Int32; import org.opendaylight.yangtools.yang.model.util.Int64; @@ -116,15 +124,17 @@ import org.opendaylight.yangtools.yang.model.util.Uint16; import org.opendaylight.yangtools.yang.model.util.Uint32; import org.opendaylight.yangtools.yang.model.util.Uint64; import org.opendaylight.yangtools.yang.model.util.Uint8; -import org.opendaylight.yangtools.yang.model.util.UnknownType; import org.opendaylight.yangtools.yang.parser.builder.api.Builder; -import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.ConstraintsBuilder; +import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.RefineBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder; +import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder; +import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.RefineHolderImpl; +import org.opendaylight.yangtools.yang.parser.builder.impl.TypeDefinitionBuilderImpl; import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder; import org.opendaylight.yangtools.yang.parser.util.TypeConstraints; import org.opendaylight.yangtools.yang.parser.util.UnknownBoundaryNumber; @@ -132,10 +142,225 @@ import org.opendaylight.yangtools.yang.parser.util.YangParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Optional; - public final class ParserListenerUtils { + private static final int UNICODE_SCRIPT_FIX_COUNTER = 30; private static final Logger LOG = LoggerFactory.getLogger(ParserListenerUtils.class); + private static final Splitter KEYDEF_SPLITTER = Splitter.on(' ').omitEmptyStrings(); + private static final Splitter PIPE_SPLITTER = Splitter.on('|').trimResults(); + private static final Splitter DOT_DOT_SPLITTER = Splitter.on("..").trimResults(); + private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"'); + private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\''); + private static final Pattern BETWEEN_CURLY_BRACES_PATTERN = Pattern.compile("\\{(.+?)\\}"); + private static final Set JAVA_UNICODE_BLOCKS = ImmutableSet.builder() + .add("AegeanNumbers") + .add("AlchemicalSymbols") + .add("AlphabeticPresentationForms") + .add("AncientGreekMusicalNotation") + .add("AncientGreekNumbers") + .add("AncientSymbols") + .add("Arabic") + .add("ArabicPresentationForms-A") + .add("ArabicPresentationForms-B") + .add("ArabicSupplement") + .add("Armenian") + .add("Arrows") + .add("Avestan") + .add("Balinese") + .add("Bamum") + .add("BamumSupplement") + .add("BasicLatin") + .add("Batak") + .add("Bengali") + .add("BlockElements") + .add("Bopomofo") + .add("BopomofoExtended") + .add("BoxDrawing") + .add("Brahmi") + .add("BraillePatterns") + .add("Buginese") + .add("Buhid") + .add("ByzantineMusicalSymbols") + .add("Carian") + .add("Cham") + .add("Cherokee") + .add("CJKCompatibility") + .add("CJKCompatibilityForms") + .add("CJKCompatibilityIdeographs") + .add("CJKCompatibilityIdeographsSupplement") + .add("CJKRadicalsSupplement") + .add("CJKStrokes") + .add("CJKSymbolsandPunctuation") + .add("CJKUnifiedIdeographs") + .add("CJKUnifiedIdeographsExtensionA") + .add("CJKUnifiedIdeographsExtensionB") + .add("CJKUnifiedIdeographsExtensionC") + .add("CJKUnifiedIdeographsExtensionD") + .add("CombiningDiacriticalMarks") + .add("CombiningDiacriticalMarksSupplement") + .add("CombiningHalfMarks") + .add("CombiningDiacriticalMarksforSymbols") + .add("CommonIndicNumberForms") + .add("ControlPictures") + .add("Coptic") + .add("CountingRodNumerals") + .add("Cuneiform") + .add("CuneiformNumbersandPunctuation") + .add("CurrencySymbols") + .add("CypriotSyllabary") + .add("Cyrillic") + .add("CyrillicExtended-A") + .add("CyrillicExtended-B") + .add("CyrillicSupplementary") + .add("Deseret") + .add("Devanagari") + .add("DevanagariExtended") + .add("Dingbats") + .add("DominoTiles") + .add("EgyptianHieroglyphs") + .add("Emoticons") + .add("EnclosedAlphanumericSupplement") + .add("EnclosedAlphanumerics") + .add("EnclosedCJKLettersandMonths") + .add("EnclosedIdeographicSupplement") + .add("Ethiopic") + .add("EthiopicExtended") + .add("EthiopicExtended-A") + .add("EthiopicSupplement") + .add("GeneralPunctuation") + .add("GeometricShapes") + .add("Georgian") + .add("GeorgianSupplement") + .add("Glagolitic") + .add("Gothic") + .add("GreekandCoptic") + .add("GreekExtended") + .add("Gujarati") + .add("Gurmukhi") + .add("HalfwidthandFullwidthForms") + .add("HangulCompatibilityJamo") + .add("HangulJamo") + .add("HangulJamoExtended-A") + .add("HangulJamoExtended-B") + .add("HangulSyllables") + .add("Hanunoo") + .add("Hebrew") + .add("HighPrivateUseSurrogates") + .add("HighSurrogates") + .add("Hiragana") + .add("IdeographicDescriptionCharacters") + .add("ImperialAramaic") + .add("InscriptionalPahlavi") + .add("InscriptionalParthian") + .add("IPAExtensions") + .add("Javanese") + .add("Kaithi") + .add("KanaSupplement") + .add("Kanbun") + .add("Kangxi Radicals") + .add("Kannada") + .add("Katakana") + .add("KatakanaPhoneticExtensions") + .add("KayahLi") + .add("Kharoshthi") + .add("Khmer") + .add("KhmerSymbols") + .add("Lao") + .add("Latin-1Supplement") + .add("LatinExtended-A") + .add("LatinExtendedAdditional") + .add("LatinExtended-B") + .add("LatinExtended-C") + .add("LatinExtended-D") + .add("Lepcha") + .add("LetterlikeSymbols") + .add("Limbu") + .add("LinearBIdeograms") + .add("LinearBSyllabary") + .add("Lisu") + .add("LowSurrogates") + .add("Lycian") + .add("Lydian") + .add("MahjongTiles") + .add("Malayalam") + .add("Mandaic") + .add("MathematicalAlphanumericSymbols") + .add("MathematicalOperators") + .add("MeeteiMayek") + .add("MiscellaneousMathematicalSymbols-A") + .add("MiscellaneousMathematicalSymbols-B") + .add("MiscellaneousSymbols") + .add("MiscellaneousSymbolsandArrows") + .add("MiscellaneousSymbolsAndPictographs") + .add("MiscellaneousTechnical") + .add("ModifierToneLetters") + .add("Mongolian") + .add("MusicalSymbols") + .add("Myanmar") + .add("MyanmarExtended-A") + .add("NewTaiLue") + .add("NKo") + .add("NumberForms") + .add("Ogham") + .add("OlChiki") + .add("OldItalic") + .add("OldPersian") + .add("OldSouthArabian") + .add("OldTurkic") + .add("OpticalCharacterRecognition") + .add("Oriya") + .add("Osmanya") + .add("Phags-pa") + .add("PhaistosDisc") + .add("Phoenician") + .add("PhoneticExtensions") + .add("PhoneticExtensionsSupplement") + .add("PlayingCards") + .add("PrivateUseArea") + .add("Rejang") + .add("RumiNumeralSymbols") + .add("Runic") + .add("Samaritan") + .add("Saurashtra") + .add("Shavian") + .add("Sinhala") + .add("SmallFormVariants") + .add("SpacingModifierLetters") + .add("Specials") + .add("Sundanese") + .add("SuperscriptsandSubscripts") + .add("SupplementalArrows-A") + .add("SupplementalArrows-B") + .add("SupplementalMathematicalOperators") + .add("SupplementalPunctuation") + .add("SupplementaryPrivateUseArea-A") + .add("SupplementaryPrivateUseArea-B") + .add("SylotiNagri") + .add("Syriac") + .add("Tagalog") + .add("Tagbanwa") + .add("Tags") + .add("TaiLe") + .add("TaiTham") + .add("TaiViet") + .add("TaiXuanJingSymbols") + .add("Tamil") + .add("Telugu") + .add("Thaana") + .add("Thai") + .add("Tibetan") + .add("Tifinagh") + .add("TransportAndMapSymbols") + .add("Ugaritic") + .add("UnifiedCanadianAboriginalSyllabics") + .add("UnifiedCanadianAboriginalSyllabicsExtended") + .add("Vai") + .add("VariationSelectors") + .add("VariationSelectorsSupplement") + .add("VedicExtensions") + .add("VerticalForms") + .add("YiRadicals") + .add("YiSyllables") + .add("YijingHexagramSymbols").build(); private ParserListenerUtils() { } @@ -150,31 +375,40 @@ public final class ParserListenerUtils { public static String stringFromNode(final ParseTree treeNode) { String result = ""; for (int i = 0; i < treeNode.getChildCount(); ++i) { - if (treeNode.getChild(i) instanceof StringContext) { - final StringContext context = (StringContext) treeNode.getChild(i); - if (context != null) { - return stringFromStringContext(context); - - } + final ParseTree child = treeNode.getChild(i); + if (child instanceof StringContext) { + return stringFromStringContext((StringContext)child); } } return result; } - public static String stringFromStringContext(final StringContext context) { - StringBuilder str = new StringBuilder(); + private static String stringFromStringContext(final StringContext context) { + StringBuilder sb = new StringBuilder(); for (TerminalNode stringNode : context.STRING()) { - String result = stringNode.getText(); - if(!result.contains("\"")){ - str.append(result); - } else if (!(result.startsWith("\"")) && result.endsWith("\"")) { - LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(context), - context.getStart().getLine()); + final String str = stringNode.getText(); + char firstChar = str.charAt(0); + final CharMatcher quoteMatcher; + if(SINGLE_QUOTE_MATCHER.matches(firstChar)) { + quoteMatcher = SINGLE_QUOTE_MATCHER; + } else if (DOUBLE_QUOTE_MATCHER.matches(firstChar)) { + quoteMatcher = DOUBLE_QUOTE_MATCHER; } else { - str.append(result.replace("\"", "")); + sb.append(str); + continue; } - } - return str.toString(); + /* + * + * It is safe not to check last argument to be same + * grammars enforces that. + * + * FIXME: Introduce proper escaping and translation of escaped + * characters here. + * + */ + sb.append(quoteMatcher.removeFrom(str.substring(1, str.length()-1))); + } + return sb.toString(); } private static String getParentModule(final ParseTree ctx) { @@ -182,7 +416,7 @@ public final class ParserListenerUtils { while (current != null && !(current instanceof Module_stmtContext)) { current = current.getParent(); } - if (current instanceof Module_stmtContext) { + if (current != null) { Module_stmtContext module = (Module_stmtContext) current; for (int i = 0; i < module.getChildCount(); i++) { if (module.getChild(i) instanceof StringContext) { @@ -202,7 +436,9 @@ public final class ParserListenerUtils { * context to parse * @param builder * builder to fill in with parsed statements + * @deprecated Pre-Beryllium implementation, scheduled for removal. */ + @Deprecated public static void parseSchemaNodeArgs(final ParseTree ctx, final SchemaNodeBuilder builder) { for (int i = 0; i < ctx.getChildCount(); i++) { final ParseTree child = ctx.getChild(i); @@ -259,15 +495,13 @@ public final class ParserListenerUtils { * statement */ public static String parseUnits(final ParseTree ctx) { - String units = null; for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree child = ctx.getChild(i); if (child instanceof Units_stmtContext) { - units = stringFromNode(child); - break; + return stringFromNode(child); } } - return units; + return null; } /** @@ -279,45 +513,25 @@ public final class ParserListenerUtils { * default statement */ public static String parseDefault(final ParseTree ctx) { - String defaultValue = null; for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree child = ctx.getChild(i); if (child instanceof Default_stmtContext) { - defaultValue = stringFromNode(child); - break; + return stringFromNode(child); } } - return defaultValue; - } - - /** - * Create SchemaPath from actualPath and new node name. - * - * @param actualPath - * current position in model - * @return SchemaPath object - */ - public static SchemaPath createActualSchemaPath(final Stack actualPath) { - return SchemaPath.create(actualPath, true); + return null; } /** - * Create java.util.List of key node names. + * Create java.util.LinkedHashSet of key node names. * * @param ctx * Key_stmtContext context - * @return YANG list key as java.util.List of key node names + * @return YANG list key as java.util.LinkedHashSet of key node names */ - public static List createListKey(final Key_stmtContext ctx) { - String keyDefinition = stringFromNode(ctx); - List keys = new ArrayList<>(); - String[] splittedKey = keyDefinition.split(" "); - for (String keyElement : splittedKey) { - if (!keyElement.isEmpty()) { - keys.add(keyElement); - } - } - return keys; + public static Set createListKey(final Key_stmtContext ctx) { + final String keyDefinition = stringFromNode(ctx); + return Sets.newLinkedHashSet(KEYDEF_SPLITTER.split(keyDefinition)); } /** @@ -332,7 +546,7 @@ public final class ParserListenerUtils { * @return List of EnumPair object parsed from given context */ private static List getEnumConstants(final Type_body_stmtsContext ctx, - final Stack path, final String moduleName) { + final SchemaPath path, final String moduleName) { List enumConstants = new ArrayList<>(); for (int i = 0; i < ctx.getChildCount(); i++) { @@ -368,7 +582,7 @@ public final class ParserListenerUtils { * @return EnumPair object parsed from given context */ private static EnumTypeDefinition.EnumPair createEnumPair(final Enum_stmtContext ctx, final int highestValue, - final Stack actualPath, final String moduleName) { + final SchemaPath actualPath, final String moduleName) { final String name = stringFromNode(ctx); SchemaPath path = createTypePath(actualPath, name); Integer value = null; @@ -381,7 +595,15 @@ public final class ParserListenerUtils { ParseTree child = ctx.getChild(i); if (child instanceof Value_stmtContext) { String valueStr = stringFromNode(child); - value = Integer.valueOf(valueStr); + try { + // yang enum value has same restrictions as JAVA Integer + value = Integer.valueOf(valueStr); + } catch (NumberFormatException e) { + String err = String + .format("Error on enum '%s': the enum value MUST be in the range from -2147483648 to 2147483647, but was: %s", + name, valueStr); + throw new YangParseException(moduleName, ctx.getStart().getLine(), err, e); + } } else if (child instanceof Description_stmtContext) { description = stringFromNode(child); } else if (child instanceof Reference_stmtContext) { @@ -394,10 +616,6 @@ public final class ParserListenerUtils { if (value == null) { value = highestValue + 1; } - if (value < -2147483648 || value > 2147483647) { - throw new YangParseException(moduleName, ctx.getStart().getLine(), "Error on enum '" + name - + "': the enum value MUST be in the range from -2147483648 to 2147483647, but was: " + value); - } EnumPairImpl result = new EnumPairImpl(); result.qname = path.getPathTowardsRoot().iterator().next(); @@ -467,11 +685,11 @@ public final class ParserListenerUtils { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((qname == null) ? 0 : qname.hashCode()); - result = prime * result + ((path == null) ? 0 : path.hashCode()); - result = prime * result + ((unknownNodes == null) ? 0 : unknownNodes.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); + result = prime * result + Objects.hashCode(qname); + result = prime * result + Objects.hashCode(path); + result = prime * result + Objects.hashCode(unknownNodes); + result = prime * result + Objects.hashCode(name); + result = prime * result + Objects.hashCode(value); return result; } @@ -541,16 +759,14 @@ public final class ParserListenerUtils { * @return List of RangeConstraint created from this context */ private static List getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) { - List rangeConstraints = Collections.emptyList(); - outer: for (int i = 0; i < ctx.getChildCount(); i++) { + for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree numRestrChild = ctx.getChild(i); if (numRestrChild instanceof Numerical_restrictionsContext) { for (int j = 0; j < numRestrChild.getChildCount(); j++) { ParseTree rangeChild = numRestrChild.getChild(j); if (rangeChild instanceof Range_stmtContext) { - rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild, moduleName); - break outer; + return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName); } } } @@ -562,16 +778,14 @@ public final class ParserListenerUtils { for (int k = 0; k < decRestr.getChildCount(); k++) { ParseTree rangeChild = decRestr.getChild(k); if (rangeChild instanceof Range_stmtContext) { - rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild, moduleName); - break outer; + return parseRangeConstraints((Range_stmtContext) rangeChild, moduleName); } } - } } } } - return rangeConstraints; + return Collections.emptyList(); } /** @@ -585,33 +799,34 @@ public final class ParserListenerUtils { */ private static List parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) { final int line = ctx.getStart().getLine(); - List rangeConstraints = new ArrayList<>(); - String description = null; - String reference = null; + Optional description = Optional.absent(); + Optional reference = Optional.absent(); for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree child = ctx.getChild(i); if (child instanceof Description_stmtContext) { - description = stringFromNode(child); + description = Optional.fromNullable(stringFromNode(child)); } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); + reference = Optional.fromNullable(stringFromNode(child)); } } - String rangeStr = stringFromNode(ctx); - String trimmed = rangeStr.replace(" ", ""); - String[] splittedRange = trimmed.split("\\|"); - for (String rangeDef : splittedRange) { - String[] splittedRangeDef = rangeDef.split("\\.\\."); - Number min; - Number max; - if (splittedRangeDef.length == 1) { - min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line); + List rangeConstraints = new ArrayList<>(); + for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) { + final Iterator split = DOT_DOT_SPLITTER.split(def).iterator(); + final Number min = parseNumberConstraintValue(split.next(), moduleName, line); + + final Number max; + if (split.hasNext()) { + max = parseNumberConstraintValue(split.next(), moduleName, line); + if (split.hasNext()) { + throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\"."); + } } else { - min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line); - max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line); + max = min; } - RangeConstraint range = BaseConstraints.rangeConstraint(min, max, description, reference); + + RangeConstraint range = BaseConstraints.newRangeConstraint(min, max, description, reference); rangeConstraints.add(range); } @@ -628,20 +843,18 @@ public final class ParserListenerUtils { * @return List of LengthConstraint created from this context */ private static List getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) { - List lengthConstraints = Collections.emptyList(); - outer: for (int i = 0; i < ctx.getChildCount(); i++) { + for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree stringRestrChild = ctx.getChild(i); if (stringRestrChild instanceof String_restrictionsContext) { for (int j = 0; j < stringRestrChild.getChildCount(); j++) { ParseTree lengthChild = stringRestrChild.getChild(j); if (lengthChild instanceof Length_stmtContext) { - lengthConstraints = parseLengthConstraints((Length_stmtContext) lengthChild, moduleName); - break outer; + return parseLengthConstraints((Length_stmtContext) lengthChild, moduleName); } } } } - return lengthConstraints; + return Collections.emptyList(); } /** @@ -655,33 +868,34 @@ public final class ParserListenerUtils { */ private static List parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) { final int line = ctx.getStart().getLine(); - List lengthConstraints = new ArrayList<>(); - String description = null; - String reference = null; + Optional description = Optional.absent(); + Optional reference = Optional.absent(); for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree child = ctx.getChild(i); if (child instanceof Description_stmtContext) { - description = stringFromNode(child); + description = Optional.fromNullable(stringFromNode(child)); } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); + reference = Optional.fromNullable(stringFromNode(child)); } } - String lengthStr = stringFromNode(ctx); - String trimmed = lengthStr.replace(" ", ""); - String[] splittedRange = trimmed.split("\\|"); - for (String rangeDef : splittedRange) { - String[] splittedRangeDef = rangeDef.split("\\.\\."); - Number min; - Number max; - if (splittedRangeDef.length == 1) { - min = max = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line); + List lengthConstraints = new ArrayList<>(); + for (String def : PIPE_SPLITTER.split(stringFromNode(ctx))) { + final Iterator split = DOT_DOT_SPLITTER.split(def).iterator(); + final Number min = parseNumberConstraintValue(split.next(), moduleName, line); + + final Number max; + if (split.hasNext()) { + max = parseNumberConstraintValue(split.next(), moduleName, line); + if (split.hasNext()) { + throw new YangParseException(moduleName, ctx.getStart().getLine(), "Malformed length constraint \"" + def + "\"."); + } } else { - min = parseNumberConstraintValue(splittedRangeDef[0], moduleName, line); - max = parseNumberConstraintValue(splittedRangeDef[1], moduleName, line); + max = min; } - LengthConstraint range = BaseConstraints.lengthConstraint(min, max, description, reference); + + LengthConstraint range = BaseConstraints.newLengthConstraint(min, max, description, reference); lengthConstraints.add(range); } @@ -704,10 +918,10 @@ public final class ParserListenerUtils { result = new UnknownBoundaryNumber(value); } else { try { - if (value.contains(".")) { + if (value.indexOf('.') != -1) { result = new BigDecimal(value); } else { - result = Long.valueOf(value); + result = new BigInteger(value); } } catch (NumberFormatException e) { throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e); @@ -723,7 +937,7 @@ public final class ParserListenerUtils { * type body * @return list of pattern constraints */ - private static List getPatternConstraint(final Type_body_stmtsContext ctx) { + private static List getPatternConstraint(final Type_body_stmtsContext ctx, final String moduleName) { List patterns = new ArrayList<>(); for (int i = 0; i < ctx.getChildCount(); i++) { @@ -732,7 +946,11 @@ public final class ParserListenerUtils { for (int j = 0; j < stringRestrChild.getChildCount(); j++) { ParseTree lengthChild = stringRestrChild.getChild(j); if (lengthChild instanceof Pattern_stmtContext) { - patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild)); + final PatternConstraint constraint = parsePatternConstraint((Pattern_stmtContext) lengthChild, + moduleName); + if (constraint != null) { + patterns.add(constraint); + } } } } @@ -747,19 +965,75 @@ public final class ParserListenerUtils { * pattern context * @return PatternConstraint object */ - private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx) { - String description = null; - String reference = null; + private static PatternConstraint parsePatternConstraint(final Pattern_stmtContext ctx, final String moduleName) { + Optional description = Optional.absent(); + Optional reference = Optional.absent(); for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree child = ctx.getChild(i); if (child instanceof Description_stmtContext) { - description = stringFromNode(child); + description = Optional.of(stringFromNode(child)); } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); + reference = Optional.of(stringFromNode(child)); + } + } + final String rawPattern = parsePatternString(ctx); + final String fixedRawPattern = fixUnicodeScriptPattern(rawPattern); + final String pattern = wrapPattern(fixedRawPattern); + if (isValidPattern(pattern, ctx, moduleName)) { + return BaseConstraints.newPatternConstraint(pattern, description, reference); + } + return null; + } + + private static String fixUnicodeScriptPattern(String rawPattern) { + for (int i = 0; i < UNICODE_SCRIPT_FIX_COUNTER; i++) { + try { + Pattern.compile(rawPattern); + return rawPattern; + } catch(PatternSyntaxException ex) { + LOG.debug("Invalid regex pattern syntax in: {}", rawPattern, ex); + if (ex.getMessage().contains("Unknown character script name")) { + rawPattern = fixUnknownScripts(ex.getMessage(), rawPattern); + } else { + return rawPattern; + } + } + } + + LOG.warn("Regex pattern could not be fixed: {}", rawPattern); + return rawPattern; + } + + private static String fixUnknownScripts(final String exMessage, final String rawPattern) { + StringBuilder result = new StringBuilder(rawPattern); + Matcher matcher = BETWEEN_CURLY_BRACES_PATTERN.matcher(exMessage); + if (matcher.find()) { + String capturedGroup = matcher.group(1); + if (JAVA_UNICODE_BLOCKS.contains(capturedGroup)) { + int idx = rawPattern.indexOf("Is" + capturedGroup); + result = result.replace(idx, idx + 2, "In"); } } - String pattern = parsePatternString(ctx); - return BaseConstraints.patternConstraint(pattern, description, reference); + return result.toString(); + } + + private static String wrapPattern(final String rawPattern) { + final StringBuilder wrapPatternBuilder = new StringBuilder(rawPattern.length() + 2); + wrapPatternBuilder.append('^'); + wrapPatternBuilder.append(rawPattern); + wrapPatternBuilder.append('$'); + return wrapPatternBuilder.toString(); + } + + private static boolean isValidPattern(final String pattern, final Pattern_stmtContext ctx, final String moduleName) { + try { + Pattern.compile(pattern); + return true; + } catch (PatternSyntaxException ex) { + LOG.warn("Unable to compile pattern defined in module {} at line {}. Error message: {}", + moduleName, ctx.getStart().getLine(), ex.getMessage()); + } + return false; } /** @@ -844,7 +1118,7 @@ public final class ParserListenerUtils { * current module name * @return List of Bit objects created from this context */ - private static List getBits(final Type_body_stmtsContext ctx, final Stack actualPath, + private static List getBits(final Type_body_stmtsContext ctx, final SchemaPath actualPath, final String moduleName) { final List bits = new ArrayList<>(); for (int j = 0; j < ctx.getChildCount(); j++) { @@ -880,7 +1154,7 @@ public final class ParserListenerUtils { * @return Bit object parsed from this context */ private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, final long highestPosition, - final Stack actualPath, final String moduleName) { + final SchemaPath actualPath, final String moduleName) { String name = stringFromNode(ctx); Long position = null; @@ -962,7 +1236,9 @@ public final class ParserListenerUtils { * @param line * line in current module * @return config statement parsed from given context + * @deprecated Pre-Beryllium implementation, scheduled for removal. */ + @Deprecated public static boolean getConfig(final ParseTree ctx, final Builder node, final String moduleName, final int line) { boolean result; // parse configuration statement @@ -993,9 +1269,13 @@ public final class ParserListenerUtils { return result; } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static boolean getParentConfig(final Builder node) { Builder parent = node.getParent(); - boolean config = false; + boolean config; if (parent instanceof ChoiceCaseBuilder) { parent = parent.getParent(); @@ -1042,61 +1322,54 @@ public final class ParserListenerUtils { } /** - * Parse type body and create UnknownType definition. + * Parse unknown type with body. * - * @param typedefQName - * qname of current type - * @param ctx + * @param typeBody * type body - * @param actualPath - * actual path in model - * @param namespace - * module namespace - * @param revision - * module revision - * @param prefix - * module prefix * @param parent * current node parent - * @return UnknownType object with constraints from parsed type body + * @param prefixedQName + * type qname with prefix + * @param moduleBuilder + * current module builder + * @param moduleQName + * current module qname + * @param actualPath + * actual path in model + * + * @deprecated Pre-Beryllium implementation, scheduled for removal. */ - public static TypeDefinition parseUnknownTypeWithBody(final QName typedefQName, - final Type_body_stmtsContext ctx, final Stack actualPath, final URI namespace, final Date revision, - final String prefix, final Builder parent) { - String moduleName = parent.getModuleName(); - String typeName = typedefQName.getLocalName(); - - UnknownType.Builder unknownType = new UnknownType.Builder(typedefQName); - - if (ctx != null) { - List rangeStatements = getRangeConstraints(ctx, moduleName); - List lengthStatements = getLengthConstraints(ctx, moduleName); - List patternStatements = getPatternConstraint(ctx); - Integer fractionDigits = getFractionDigits(ctx, moduleName); - - if (parent instanceof TypeDefinitionBuilder) { - TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent; - typedef.setRanges(rangeStatements); - typedef.setLengths(lengthStatements); - typedef.setPatterns(patternStatements); - typedef.setFractionDigits(fractionDigits); - return unknownType.build(); - } else { - TypeDefinition baseType = unknownType.build(); - QName qname = new QName(namespace, revision, prefix, typeName); - SchemaPath schemaPath = createTypePath(actualPath, typeName); + @Deprecated + public static void parseUnknownTypeWithBody(final Type_body_stmtsContext typeBody, final TypeAwareBuilder parent, + final QName prefixedQName, final ModuleBuilder moduleBuilder, final QName moduleQName, final SchemaPath actualPath) { + final int line = typeBody.getStart().getLine(); - ExtendedType.Builder typeBuilder = new ExtendedType.Builder(qname, baseType, null, null, schemaPath); - typeBuilder.ranges(rangeStatements); - typeBuilder.lengths(lengthStatements); - typeBuilder.patterns(patternStatements); - typeBuilder.fractionDigits(fractionDigits); + List rangeStatements = getRangeConstraints(typeBody, moduleBuilder.getName()); + List lengthStatements = getLengthConstraints(typeBody, moduleBuilder.getName()); + List patternStatements = getPatternConstraint(typeBody, moduleBuilder.getName()); + Integer fractionDigits = getFractionDigits(typeBody, moduleBuilder.getName()); - return typeBuilder.build(); - } + if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) { + TypeDefinitionBuilder typedef = (TypeDefinitionBuilder) parent; + typedef.setRanges(rangeStatements); + typedef.setLengths(lengthStatements); + typedef.setPatterns(patternStatements); + typedef.setFractionDigits(fractionDigits); + typedef.setTypeQName(prefixedQName); + // add parent node of this type statement to dirty nodes + moduleBuilder.markActualNodeDirty(); + } else { + QName qname = QName.create(moduleQName, prefixedQName.getLocalName()); + SchemaPath schemaPath = createTypePath(actualPath, prefixedQName.getLocalName()); + TypeDefinitionBuilder typeBuilder = new TypeDefinitionBuilderImpl(moduleBuilder.getName(), line, qname, schemaPath); + typeBuilder.setRanges(rangeStatements); + typeBuilder.setLengths(lengthStatements); + typeBuilder.setPatterns(patternStatements); + typeBuilder.setFractionDigits(fractionDigits); + typeBuilder.setTypeQName(prefixedQName); + parent.setTypedef(typeBuilder); + moduleBuilder.getDirtyNodes().add(typeBuilder); } - - return unknownType.build(); } /** @@ -1108,19 +1381,17 @@ public final class ParserListenerUtils { * type body context * @param actualPath * current path in schema - * @param namespace - * current namespace - * @param revision - * current revision - * @param prefix - * current prefix + * @param moduleQName + * current module qname * @param parent * parent builder * @return TypeDefinition object based on parsed values. + * + * @deprecated Pre-Beryllium implementation, scheduled for removal. */ + @Deprecated public static TypeDefinition parseTypeWithBody(final String typeName, final Type_body_stmtsContext typeBody, - final Stack actualPath, final URI namespace, final Date revision, final String prefix, - final Builder parent) { + final SchemaPath actualPath, final QName moduleQName, final Builder parent) { final String moduleName = parent.getModuleName(); final int line = typeBody.getStart().getLine(); @@ -1128,7 +1399,7 @@ public final class ParserListenerUtils { Integer fractionDigits = getFractionDigits(typeBody, moduleName); List lengthStatements = getLengthConstraints(typeBody, moduleName); - List patternStatements = getPatternConstraint(typeBody); + List patternStatements = getPatternConstraint(typeBody, moduleName); List rangeStatements = getRangeConstraints(typeBody, moduleName); TypeConstraints constraints = new TypeConstraints(moduleName, line); @@ -1138,7 +1409,7 @@ public final class ParserListenerUtils { constraints.addRanges(rangeStatements); SchemaPath baseTypePath = createBaseTypePath(actualPath, typeName); - SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, namespace, revision, prefix, typeName); + SchemaPath extBaseTypePath = createExtendedBaseTypePath(actualPath, moduleQName, typeName); if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) { extBaseTypePath = baseTypePath; @@ -1147,12 +1418,12 @@ public final class ParserListenerUtils { if ("decimal64".equals(typeName)) { if (rangeStatements.isEmpty()) { try { - return new Decimal64(baseTypePath, fractionDigits); + return Decimal64.create(baseTypePath, fractionDigits); } catch(Exception e) { throw new YangParseException(moduleName, line, e.getMessage()); } } - Decimal64 decimalType = new Decimal64(extBaseTypePath, fractionDigits); + Decimal64 decimalType = Decimal64.create(extBaseTypePath, fractionDigits); constraints.addRanges(decimalType.getRangeConstraints()); baseType = decimalType; } else if (typeName.startsWith("int")) { @@ -1199,13 +1470,13 @@ public final class ParserListenerUtils { baseType = uintType; } else if ("enumeration".equals(typeName)) { List enumConstants = getEnumConstants(typeBody, actualPath, moduleName); - return new EnumerationType(baseTypePath, enumConstants); + return EnumerationType.create(baseTypePath, enumConstants, Optional. absent()); } else if ("string".equals(typeName)) { StringTypeDefinition stringType = StringType.getInstance(); constraints.addLengths(stringType.getLengthConstraints()); baseType = stringType; } else if ("bits".equals(typeName)) { - return new BitsType(baseTypePath, getBits(typeBody, actualPath, moduleName)); + return BitsType.create(baseTypePath, getBits(typeBody, actualPath, moduleName)); } else if ("leafref".equals(typeName)) { final String path = parseLeafrefPath(typeBody); final boolean absolute = path.startsWith("/"); @@ -1216,8 +1487,7 @@ public final class ParserListenerUtils { constraints.addLengths(binaryType.getLengthConstraints()); baseType = binaryType; } else if ("instance-identifier".equals(typeName)) { - boolean requireInstance = isRequireInstance(typeBody); - return new InstanceIdentifier(null, requireInstance); + return InstanceIdentifierType.create(isRequireInstance(typeBody)); } if (parent instanceof TypeDefinitionBuilder && !(parent instanceof UnionTypeBuilder)) { @@ -1229,12 +1499,10 @@ public final class ParserListenerUtils { return baseType; } - List path = new ArrayList<>(actualPath); - path.add(new QName(namespace, revision, prefix, typeName)); - SchemaPath schemaPath = SchemaPath.create(path, true); - - QName qname = schemaPath.getPath().get(schemaPath.getPath().size() - 1); - ExtendedType.Builder typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath); + QName qname = QName.create(moduleQName, typeName); + SchemaPath schemaPath = actualPath.createChild(qname); + final Optional opt = Optional.of(""); + ExtendedType.Builder typeBuilder = ExtendedType.builder(qname, baseType, opt, opt, schemaPath); typeBuilder.ranges(constraints.getRange()); typeBuilder.lengths(constraints.getLength()); @@ -1244,28 +1512,19 @@ public final class ParserListenerUtils { return typeBuilder.build(); } - private static SchemaPath createTypePath(final Stack actual, final String typeName) { - QName last = actual.peek(); - QName typeQName = new QName(last.getNamespace(), last.getRevision(), last.getPrefix(), typeName); - List path = new ArrayList<>(actual); - path.add(typeQName); - return SchemaPath.create(path, true); + private static SchemaPath createTypePath(final SchemaPath actual, final String typeName) { + QName last = actual.getLastComponent(); + return actual.createChild(QName.create(last, typeName)); } - private static SchemaPath createBaseTypePath(final Stack actual, final String typeName) { - List path = new ArrayList<>(actual); - path.add(BaseTypes.constructQName(typeName)); - return SchemaPath.create(path, true); + private static SchemaPath createBaseTypePath(final SchemaPath actual, final String typeName) { + return actual.createChild(BaseTypes.constructQName(typeName)); } - private static SchemaPath createExtendedBaseTypePath(final Stack actual, final URI namespace, final Date revision, - final String prefix, final String typeName) { - QName extTypeName = new QName(namespace, revision, prefix, typeName); - QName baseTypeName = BaseTypes.constructQName(typeName); - List path = new ArrayList<>(actual); - path.add(extTypeName); - path.add(baseTypeName); - return SchemaPath.create(path, true); + private static SchemaPath createExtendedBaseTypePath(final SchemaPath actual, final QName moduleQName, final String typeName) { + return actual.createChild( + QName.create(moduleQName, typeName), + BaseTypes.constructQName(typeName)); } /** @@ -1348,12 +1607,12 @@ public final class ParserListenerUtils { * Must_stmtContext * @return MustDefinition object based on parsed context */ - public static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) { + private static MustDefinition parseMust(final YangParser.Must_stmtContext ctx) { StringBuilder mustText = new StringBuilder(); - String description = null; - String reference = null; - String errorAppTag = null; - String errorMessage = null; + Optional description = Optional.absent(); + Optional reference = Optional.absent(); + Optional errorAppTag = Optional.absent(); + Optional errorMessage = Optional.absent(); for (int i = 0; i < ctx.getChildCount(); ++i) { ParseTree child = ctx.getChild(i); if (child instanceof StringContext) { @@ -1375,17 +1634,17 @@ public final class ParserListenerUtils { } } } else if (child instanceof Description_stmtContext) { - description = stringFromNode(child); + description = Optional.of(stringFromNode(child)); } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); + reference = Optional.of(stringFromNode(child)); } else if (child instanceof Error_app_tag_stmtContext) { - errorAppTag = stringFromNode(child); + errorAppTag = Optional.of(stringFromNode(child)); } else if (child instanceof Error_message_stmtContext) { - errorMessage = stringFromNode(child); + errorMessage = Optional.of(stringFromNode(child)); } } - return new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag, errorMessage); + return MustDefinitionImpl.create(mustText.toString(), description, reference, errorAppTag, errorMessage); } /** @@ -1395,7 +1654,10 @@ public final class ParserListenerUtils { * context to parse * @param constraints * ConstraintsBuilder to fill + * + * @deprecated Pre-Beryllium implementation, scheduled for removal. */ + @Deprecated public static void parseConstraints(final ParseTree ctx, final ConstraintsBuilder constraints) { for (int i = 0; i < ctx.getChildCount(); ++i) { final ParseTree childNode = ctx.getChild(i); @@ -1446,7 +1708,12 @@ public final class ParserListenerUtils { for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree maxArg = ctx.getChild(i); if (maxArg instanceof Max_value_argContext) { - result = Integer.valueOf(stringFromNode(maxArg)); + String maxValue = stringFromNode(maxArg); + if ("unbounded".equals(maxValue)) { + result = Integer.MAX_VALUE; + } else { + result = Integer.valueOf(maxValue); + } } } if (result == null) { @@ -1525,7 +1792,10 @@ public final class ParserListenerUtils { * @param moduleName * name of current module * @return RefineHolder object representing this refine statement + * + * @deprecated Pre-Beryllium implementation, scheduled for removal. */ + @Deprecated public static RefineHolderImpl parseRefine(final Refine_stmtContext refineCtx, final String moduleName) { final String refineTarget = stringFromNode(refineCtx); final RefineHolderImpl refine = new RefineHolderImpl(moduleName, refineCtx.getStart().getLine(), refineTarget); @@ -1555,6 +1825,10 @@ public final class ParserListenerUtils { return refine; } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static void parseRefineDefault(final RefineHolderImpl refine, final ParseTree refineStmt) { for (int i = 0; i < refineStmt.getChildCount(); i++) { ParseTree refineArg = refineStmt.getChild(i); @@ -1571,6 +1845,10 @@ public final class ParserListenerUtils { } } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_stmtsContext refineStmt) { for (int i = 0; i < refineStmt.getChildCount(); i++) { ParseTree refineArg = refineStmt.getChild(i); @@ -1594,6 +1872,10 @@ public final class ParserListenerUtils { return refine; } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_container_stmtsContext refineStmt) { for (int i = 0; i < refineStmt.getChildCount(); i++) { ParseTree refineArg = refineStmt.getChild(i); @@ -1607,6 +1889,10 @@ public final class ParserListenerUtils { return refine; } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_list_stmtsContext refineStmt) { for (int i = 0; i < refineStmt.getChildCount(); i++) { ParseTree refineArg = refineStmt.getChild(i); @@ -1624,6 +1910,10 @@ public final class ParserListenerUtils { return refine; } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_leaf_list_stmtsContext refineStmt) { for (int i = 0; i < refineStmt.getChildCount(); i++) { ParseTree refineArg = refineStmt.getChild(i); @@ -1641,6 +1931,10 @@ public final class ParserListenerUtils { return refine; } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static RefineBuilder parseRefine(final RefineHolderImpl refine, final Refine_choice_stmtsContext refineStmt) { for (int i = 0; i < refineStmt.getChildCount(); i++) { ParseTree refineArg = refineStmt.getChild(i); @@ -1660,6 +1954,10 @@ public final class ParserListenerUtils { return refine; } + /** + * @deprecated Pre-Beryllium implementation, scheduled for removal. + */ + @Deprecated private static RefineBuilder parseRefine(final RefineBuilder refine, final Refine_anyxml_stmtsContext refineStmt) { for (int i = 0; i < refineStmt.getChildCount(); i++) { ParseTree refineArg = refineStmt.getChild(i);