*/
package org.opendaylight.yangtools.yang.parser.util;
+import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Max_value_argContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_elements_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Min_value_argContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Must_stmtContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Numerical_restrictionsContext;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Ordered_by_argContext;
import org.opendaylight.yangtools.yang.parser.builder.api.DataSchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceBuilder;
import org.opendaylight.yangtools.yang.parser.builder.impl.ChoiceCaseBuilder;
import org.opendaylight.yangtools.yang.parser.builder.impl.ConstraintsBuilder;
import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
/**
* Parse given tree and get first string value.
- *
+ *
* @param treeNode
* tree to parse
* @return first string value from given tree
*/
public static String stringFromNode(final ParseTree treeNode) {
- final String result = "";
+ 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 context.getChild(0).getText().replace("\"", "");
+ result = context.getChild(0).getText();
+ if (!(result.startsWith("\"")) && result.endsWith("\"")) {
+ LOG.error("Syntax error in module {} at line {}: missing '\"'.", getParentModule(treeNode),
+ context.getStart().getLine());
+ }
+ return result.replace("\"", "");
}
}
}
return result;
}
+ private static String getParentModule(final ParseTree ctx) {
+ ParseTree current = ctx;
+ while (current != null && !(current instanceof Module_stmtContext)) {
+ current = current.getParent();
+ }
+ if (current instanceof Module_stmtContext) {
+ Module_stmtContext module = (Module_stmtContext) current;
+ for (int i = 0; i < module.getChildCount(); i++) {
+ if (module.getChild(i) instanceof StringContext) {
+ final StringContext str = (StringContext) module.getChild(i);
+ return str.getChild(0).getText();
+ }
+ }
+ }
+ return "";
+ }
+
/**
* Parse 'description', 'reference' and 'status' statements and fill in
* given builder.
- *
+ *
* @param ctx
* context to parse
* @param builder
/**
* Parse given context and return its value;
- *
+ *
* @param ctx
* status context
* @return value parsed from context
ParseTree statusArg = ctx.getChild(i);
if (statusArg instanceof Status_argContext) {
String statusArgStr = stringFromNode(statusArg);
- if ("current".equals(statusArgStr)) {
+ switch (statusArgStr) {
+ case "current":
result = Status.CURRENT;
- } else if ("deprecated".equals(statusArgStr)) {
+ break;
+ case "deprecated":
result = Status.DEPRECATED;
- } else if ("obsolete".equals(statusArgStr)) {
+ break;
+ case "obsolete":
result = Status.OBSOLETE;
- } else {
+ break;
+ default:
LOG.warn("Invalid 'status' statement: " + statusArgStr);
}
}
/**
* Parse given tree and returns units statement as string.
- *
+ *
* @param ctx
* context to parse
* @return value of units statement as string or null if there is no units
/**
* Parse given tree and returns default statement as string.
- *
+ *
* @param ctx
* context to parse
* @return value of default statement as string or null if there is no
/**
* Create SchemaPath from actualPath and new node name.
- *
+ *
* @param actualPath
* current position in model
* @return SchemaPath object
*/
public static SchemaPath createActualSchemaPath(final Stack<QName> actualPath) {
- final List<QName> path = new ArrayList<QName>(actualPath);
+ final List<QName> path = new ArrayList<>(actualPath);
return new SchemaPath(path, true);
}
/**
* Create java.util.List of QName objects from given key definition as
* string.
- *
+ *
* @param keyDefinition
* key definition as string
* @param namespace
*/
public static List<QName> createListKey(final String keyDefinition, final URI namespace, final Date revision,
final String prefix) {
- List<QName> key = new ArrayList<QName>();
+ List<QName> key = new ArrayList<>();
String[] splittedKey = keyDefinition.split(" ");
- QName qname = null;
+ QName qname;
for (String keyElement : splittedKey) {
if (keyElement.length() != 0) {
qname = new QName(namespace, revision, prefix, keyElement);
/**
* Parse given type body of enumeration statement.
- *
+ *
* @param ctx
* type body context to parse
* @param path
*/
private static List<EnumTypeDefinition.EnumPair> getEnumConstants(final Type_body_stmtsContext ctx,
final Stack<QName> path, final String moduleName) {
- List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<EnumTypeDefinition.EnumPair>();
+ List<EnumTypeDefinition.EnumPair> enumConstants = new ArrayList<>();
for (int i = 0; i < ctx.getChildCount(); i++) {
ParseTree enumSpecChild = ctx.getChild(i);
/**
* Parse enum statement context
- *
+ *
* @param ctx
* enum statement context
* @param highestValue
* current highest value in enumeration
- * @param path
+ * @param actualPath
* actual position in YANG model
* @param moduleName
* current module name
/**
* Get and parse range from given type body context.
- *
+ *
* @param ctx
* type body context to parse
* @param moduleName
+ * name of current module
* @return List of RangeConstraint created from this context
*/
private static List<RangeConstraint> getRangeConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
List<RangeConstraint> rangeConstraints = Collections.emptyList();
outer: 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 (numRestrChild instanceof Decimal64_specificationContext) {
+ for (int j = 0; j < numRestrChild.getChildCount(); j++) {
+ ParseTree decRestr = numRestrChild.getChild(j);
+ if (decRestr instanceof Numerical_restrictionsContext) {
+ 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 rangeConstraints;
}
/**
* Parse given range context.
- *
+ *
* @param ctx
* range context to parse
* @param moduleName
+ * name of current module
* @return List of RangeConstraints parsed from this context
*/
private static List<RangeConstraint> parseRangeConstraints(final Range_stmtContext ctx, final String moduleName) {
final int line = ctx.getStart().getLine();
- List<RangeConstraint> rangeConstraints = new ArrayList<RangeConstraint>();
+ List<RangeConstraint> rangeConstraints = new ArrayList<>();
String description = null;
String reference = null;
/**
* Get and parse length from given type body context.
- *
+ *
* @param ctx
* type body context to parse
* @param moduleName
+ * name of current module
* @return List of LengthConstraint created from this context
*/
private static List<LengthConstraint> getLengthConstraints(final Type_body_stmtsContext ctx, final String moduleName) {
/**
* Parse given length context.
- *
+ *
* @param ctx
* length context to parse
* @param moduleName
+ * name of current module
* @return List of LengthConstraints parsed from this context
*/
private static List<LengthConstraint> parseLengthConstraints(final Length_stmtContext ctx, final String moduleName) {
final int line = ctx.getStart().getLine();
- List<LengthConstraint> lengthConstraints = new ArrayList<LengthConstraint>();
+ List<LengthConstraint> lengthConstraints = new ArrayList<>();
String description = null;
String reference = null;
* type is one of special YANG values 'min' or 'max'
*/
private static Number parseNumberConstraintValue(final String value, final String moduleName, final int line) {
- Number result = null;
+ Number result;
if ("min".equals(value) || "max".equals(value)) {
result = new UnknownBoundaryNumber(value);
} else {
try {
- result = Long.valueOf(value);
+ if (value.contains(".")) {
+ result = new BigDecimal(value);
+ } else {
+ result = Long.valueOf(value);
+ }
} catch (NumberFormatException e) {
throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
}
/**
* Parse type body and return pattern constraints.
- *
+ *
* @param ctx
* type body
* @return list of pattern constraints
*/
private static List<PatternConstraint> getPatternConstraint(final Type_body_stmtsContext ctx) {
- List<PatternConstraint> patterns = new ArrayList<PatternConstraint>();
+ List<PatternConstraint> patterns = new ArrayList<>();
for (int i = 0; i < ctx.getChildCount(); i++) {
ParseTree stringRestrChild = ctx.getChild(i);
/**
* Internal helper method.
- *
+ *
* @param ctx
* pattern context
* @return PatternConstraint object
reference = stringFromNode(child);
}
}
- String pattern = patternStringFromNode(ctx);
+ String pattern = parsePatternString(ctx);
return BaseConstraints.patternConstraint(pattern, description, reference);
}
/**
* Parse given context and return pattern value.
- *
+ *
* @param ctx
* context to parse
* @return pattern value as String
*/
- public static String patternStringFromNode(final Pattern_stmtContext ctx) {
+ private static String parsePatternString(final Pattern_stmtContext ctx) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < ctx.getChildCount(); ++i) {
ParseTree child = ctx.getChild(i);
/**
* Get fraction digits value from type body.
- *
+ *
* @param ctx
* type body context to parse
* @param moduleName
/**
* Parse decimal64 fraction-digits value.
- *
+ *
* @param ctx
* decimal64 context
* @param moduleName
/**
* Internal helper method for parsing bit statements from given type body
* context.
- *
+ *
* @param ctx
* type body context to parse
* @param actualPath
*/
private static List<BitsTypeDefinition.Bit> getBits(Type_body_stmtsContext ctx, Stack<QName> actualPath,
String moduleName) {
- final List<BitsTypeDefinition.Bit> bits = new ArrayList<BitsTypeDefinition.Bit>();
+ final List<BitsTypeDefinition.Bit> bits = new ArrayList<>();
for (int j = 0; j < ctx.getChildCount(); j++) {
ParseTree bitsSpecChild = ctx.getChild(j);
if (bitsSpecChild instanceof Bits_specificationContext) {
/**
* Internal helper method for parsing bit context.
- *
+ *
* @param ctx
* bit statement context to parse
* @param highestPosition
/**
* Parse 'ordered-by' statement.
- *
+ *
* The 'ordered-by' statement defines whether the order of entries within a
* list are determined by the user or the system. The argument is one of the
* strings "system" or "user". If not present, order defaults to "system".
- *
+ *
* @param ctx
* Ordered_by_stmtContext
* @return true, if ordered-by contains value 'user', false otherwise
ParseTree orderArg = ctx.getChild(j);
if (orderArg instanceof Ordered_by_argContext) {
String orderStr = stringFromNode(orderArg);
- if ("system".equals(orderStr)) {
+ switch (orderStr) {
+ case "system":
result = false;
- } else if ("user".equals(orderStr)) {
+ break;
+ case "user":
result = true;
- } else {
+ break;
+ default:
LOG.warn("Invalid 'ordered-by' statement.");
}
}
/**
* Get config statement from given context. If there is no config statement,
* return config value of parent
- *
+ *
* @param ctx
* context to parse
* @param parent
* @return config statement parsed from given context
*/
public static Boolean getConfig(final ParseTree ctx, final Builder parent, final String moduleName, final int line) {
- Boolean result = null;
+ Boolean result;
// parse configuration statement
Boolean config = null;
for (int i = 0; i < ctx.getChildCount(); i++) {
// If the parent node is a rpc input or output, it can has
// config set to null
result = parentConfig == null ? true : parentConfig;
- } else if (parent instanceof ChoiceCaseBuilder) {
- // If the parent node is a 'case' node, the value is the same as
- // the 'case' node's parent 'choice' node
- ChoiceCaseBuilder choiceCase = (ChoiceCaseBuilder) parent;
- Builder choice = choiceCase.getParent();
- Boolean parentConfig = null;
- if (choice instanceof ChoiceBuilder) {
- parentConfig = ((ChoiceBuilder) choice).isConfiguration();
- } else {
- parentConfig = true;
- }
- result = parentConfig;
} else {
result = true;
}
/**
* Parse config statement.
- *
+ *
* @param ctx
* config context to parse
* @param moduleName
final ParseTree configContext = ctx.getChild(i);
if (configContext instanceof Config_argContext) {
final String value = stringFromNode(configContext);
- if ("true".equals(value)) {
+ switch (value) {
+ case "true":
result = true;
break;
- } else if ("false".equals(value)) {
+ case "false":
result = false;
break;
- } else {
+ default:
throw new YangParseException(moduleName, ctx.getStart().getLine(),
"Failed to parse 'config' statement value: '" + value + "'.");
}
/**
* Parse type body and create UnknownType definition.
- *
+ *
* @param typedefQName
* qname of current type
* @param ctx
* 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
*/
public static TypeDefinition<?> parseUnknownTypeWithBody(final QName typedefQName,
return unknownType.build();
} else {
TypeDefinition<?> baseType = unknownType.build();
- TypeDefinition<?> result = null;
QName qname = new QName(namespace, revision, prefix, typeName);
SchemaPath schemaPath = createTypePath(actualPath, typeName);
typeBuilder.lengths(lengthStatements);
typeBuilder.patterns(patternStatements);
typeBuilder.fractionDigits(fractionDigits);
- result = typeBuilder.build();
- return result;
+ return typeBuilder.build();
}
- } else {
- unknownType.setReferenceOnly(true);
}
return unknownType.build();
/**
* Create TypeDefinition object based on given type name and type body.
- *
+ *
* @param typeName
* name of type
* @param typeBody
}
}
Decimal64 decimalType = new Decimal64(extBaseTypePath, fractionDigits);
- constraints.addRanges(decimalType.getRangeStatements());
+ constraints.addRanges(decimalType.getRangeConstraints());
baseType = decimalType;
} else if (typeName.startsWith("int")) {
IntegerTypeDefinition intType = null;
- if ("int8".equals(typeName)) {
+ switch (typeName) {
+ case "int8":
intType = Int8.getInstance();
- } else if ("int16".equals(typeName)) {
+ break;
+ case "int16":
intType = Int16.getInstance();
- } else if ("int32".equals(typeName)) {
+ break;
+ case "int32":
intType = Int32.getInstance();
- } else if ("int64".equals(typeName)) {
+ break;
+ case "int64":
intType = Int64.getInstance();
+ break;
}
if (intType == null) {
throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
}
- constraints.addRanges(intType.getRangeStatements());
+ constraints.addRanges(intType.getRangeConstraints());
baseType = intType;
} else if (typeName.startsWith("uint")) {
UnsignedIntegerTypeDefinition uintType = null;
- if ("uint8".equals(typeName)) {
+ switch (typeName) {
+ case "uint8":
uintType = Uint8.getInstance();
- } else if ("uint16".equals(typeName)) {
+ break;
+ case "uint16":
uintType = Uint16.getInstance();
- } else if ("uint32".equals(typeName)) {
+ break;
+ case "uint32":
uintType = Uint32.getInstance();
- } else if ("uint64".equals(typeName)) {
+ break;
+ case "uint64":
uintType = Uint64.getInstance();
+ break;
}
if (uintType == null) {
throw new YangParseException(moduleName, line, "Unknown yang type " + typeName);
}
- constraints.addRanges(uintType.getRangeStatements());
+ constraints.addRanges(uintType.getRangeConstraints());
baseType = uintType;
} else if ("enumeration".equals(typeName)) {
List<EnumTypeDefinition.EnumPair> enumConstants = getEnumConstants(typeBody, actualPath, moduleName);
return new EnumerationType(baseTypePath, enumConstants);
} else if ("string".equals(typeName)) {
- StringTypeDefinition stringType = StringType.getIntance();
- constraints.addLengths(stringType.getLengthStatements());
+ StringTypeDefinition stringType = StringType.getInstance();
+ constraints.addLengths(stringType.getLengthConstraints());
baseType = stringType;
} else if ("bits".equals(typeName)) {
return new BitsType(baseTypePath, getBits(typeBody, actualPath, moduleName));
return baseType;
}
- TypeDefinition<?> result = null;
- ExtendedType.Builder typeBuilder = null;
-
- List<QName> path = new ArrayList<QName>(actualPath);
+ List<QName> path = new ArrayList<>(actualPath);
path.add(new QName(namespace, revision, prefix, typeName));
SchemaPath schemaPath = new SchemaPath(path, true);
QName qname = schemaPath.getPath().get(schemaPath.getPath().size() - 1);
- typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath);
+ ExtendedType.Builder typeBuilder = new ExtendedType.Builder(qname, baseType, "", "", schemaPath);
typeBuilder.ranges(constraints.getRange());
typeBuilder.lengths(constraints.getLength());
typeBuilder.patterns(constraints.getPatterns());
typeBuilder.fractionDigits(constraints.getFractionDigits());
- result = typeBuilder.build();
- return result;
+ return typeBuilder.build();
}
private static SchemaPath createTypePath(Stack<QName> actual, String typeName) {
QName last = actual.peek();
QName typeQName = new QName(last.getNamespace(), last.getRevision(), last.getPrefix(), typeName);
- List<QName> path = new ArrayList<QName>(actual);
+ List<QName> path = new ArrayList<>(actual);
path.add(typeQName);
return new SchemaPath(path, true);
}
private static SchemaPath createBaseTypePath(Stack<QName> actual, String typeName) {
- List<QName> path = new ArrayList<QName>(actual);
+ List<QName> path = new ArrayList<>(actual);
path.add(BaseTypes.constructQName(typeName));
return new SchemaPath(path, true);
}
String prefix, String typeName) {
QName extTypeName = new QName(namespace, revision, prefix, typeName);
QName baseTypeName = BaseTypes.constructQName(typeName);
- List<QName> path = new ArrayList<QName>(actual);
+ List<QName> path = new ArrayList<>(actual);
path.add(extTypeName);
path.add(baseTypeName);
return new SchemaPath(path, true);
/**
* Parse given context and find identityref base value.
- *
+ *
* @param ctx
* type body
* @return identityref base value as String
/**
* Parse type body statement and find require-instance value.
- *
+ *
* @param ctx
* type body context
* @return require-instance value
/**
* Parse type body statement and find leafref path.
- *
+ *
* @param ctx
* type body context
* @return leafref path as String
/**
* Internal helper method for parsing must statement.
- *
+ *
* @param ctx
* Must_stmtContext
* @return MustDefinition object based on parsed context
}
}
- MustDefinition must = new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag,
- errorMessage);
- return must;
+ return new MustDefinitionImpl(mustText.toString(), description, reference, errorAppTag, errorMessage);
}
/**
* Parse given context and set constraints to constraints builder.
- *
+ *
* @param ctx
* context to parse
* @param constraints
/**
* Parse given context and return yin value.
- *
+ *
* @param ctx
* context to parse
* @return true if value is 'true', false otherwise
/**
* Check this base type.
- *
+ *
* @param typeName
* base YANG type name
* @param moduleName
* informations in its body
*/
public static void checkMissingBody(final String typeName, final String moduleName, final int line) {
- if ("decimal64".equals(typeName)) {
+ switch (typeName) {
+ case "decimal64":
throw new YangParseException(moduleName, line,
"The 'fraction-digits' statement MUST be present if the type is 'decimal64'.");
- } else if ("identityref".equals(typeName)) {
+ case "identityref":
throw new YangParseException(moduleName, line,
"The 'base' statement MUST be present if the type is 'identityref'.");
- } else if ("leafref".equals(typeName)) {
+ case "leafref":
throw new YangParseException(moduleName, line,
"The 'path' statement MUST be present if the type is 'leafref'.");
- } else if ("bits".equals(typeName)) {
+ case "bits":
throw new YangParseException(moduleName, line, "The 'bit' statement MUST be present if the type is 'bits'.");
- } else if ("enumeration".equals(typeName)) {
+ case "enumeration":
throw new YangParseException(moduleName, line,
"The 'enum' statement MUST be present if the type is 'enumeration'.");
}
/**
* Parse refine statement.
- *
+ *
* @param refineCtx
* refine statement
* @param moduleName