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%2FYangParserListenerImpl.java;h=417747a07ef0cfb8e14d0e0108dc8dd4ecb2cd05;hb=752f127fb427346655185457d6c38f289595ab2d;hp=bd532bdf13038bb6a8363eda6a2480863fcb8378;hpb=c6b4017ff4babad7e237c56ebe299efc90a6f990;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java index bd532bdf13..417747a07e 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/impl/YangParserListenerImpl.java @@ -8,7 +8,6 @@ package org.opendaylight.yangtools.yang.parser.impl; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.checkMissingBody; -import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.createActualSchemaPath; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.createListKey; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getConfig; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.getIdentityrefBase; @@ -19,20 +18,25 @@ import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.pa import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.parseStatus; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.parseTypeWithBody; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.parseUnits; -import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.parseUnknownTypeWithBody; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.parseUserOrdered; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.parseYinValue; import static org.opendaylight.yangtools.yang.parser.impl.ParserListenerUtils.stringFromNode; +import com.google.common.base.Splitter; import com.google.common.base.Strings; +import com.google.common.collect.Iterables; import java.net.URI; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.Iterator; import java.util.List; -import java.util.Stack; +import java.util.Map; +import java.util.TreeMap; import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Argument_stmtContext; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Base_stmtContext; @@ -66,14 +70,15 @@ import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.When_stmtContext; import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Yang_version_stmtContext; import org.opendaylight.yangtools.antlrv4.code.gen.YangParserBaseListener; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.model.api.ModuleImport; import org.opendaylight.yangtools.yang.model.api.SchemaPath; import org.opendaylight.yangtools.yang.model.api.TypeDefinition; import org.opendaylight.yangtools.yang.model.util.BaseTypes; -import org.opendaylight.yangtools.yang.model.util.YangTypesConverter; import org.opendaylight.yangtools.yang.parser.builder.api.AugmentationSchemaBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.Builder; import org.opendaylight.yangtools.yang.parser.builder.api.ExtensionBuilder; import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder; +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.api.UsesNodeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.AnyXmlBuilder; @@ -92,42 +97,60 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.RefineHolderImpl; import org.opendaylight.yangtools.yang.parser.builder.impl.RpcDefinitionBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder; import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilderImpl; +import org.opendaylight.yangtools.yang.parser.util.YangParseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + public final class YangParserListenerImpl extends YangParserBaseListener { - private static final Logger LOGGER = LoggerFactory.getLogger(YangParserListenerImpl.class); + private static final Logger LOG = LoggerFactory.getLogger(YangParserListenerImpl.class); + private static final Splitter SLASH_SPLITTER = Splitter.on('/').omitEmptyStrings(); + private static final Splitter COLON_SPLITTER = Splitter.on(':'); private static final String AUGMENT_STR = "augment"; + private final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + private final SchemaPathStack stack = new SchemaPathStack(); + private final Map> namespaceContext; private final String sourcePath; + private QName moduleQName = new QName(null, new Date(0L), null, "dummy"); private ModuleBuilder moduleBuilder; private String moduleName; - private URI namespace; - private String yangModelPrefix; - private Date revision = new Date(0L); - - private final DateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); - private final Stack> actualPath = new Stack<>(); private int augmentOrder; + private String yangModelPrefix; - private void addNodeToPath(final QName name) { - actualPath.peek().push(name); + public YangParserListenerImpl(final Map> namespaceContext, final String sourcePath) { + this.namespaceContext = namespaceContext; + this.sourcePath = sourcePath; } - private QName removeNodeFromPath() { - return actualPath.peek().pop(); + /** + * Create a new instance. + * + * FIXME: the resulting type needs to be extracted, such that we can reuse + * the "BaseListener" aspect, which need not be exposed to the user. + * Maybe factor out a base class into repo.spi? + * + * @param namespaceContext + * @param sourcePath + * @param walker + * @param tree + * @return + */ + public static YangParserListenerImpl create(final Map> namespaceContext, + final String sourcePath, final ParseTreeWalker walker, final ParseTree tree) { + final YangParserListenerImpl ret = new YangParserListenerImpl(namespaceContext, sourcePath); + walker.walk(ret, tree); + return ret; } - public YangParserListenerImpl(final String sourcePath) { - this.sourcePath = sourcePath; - } + @Override public void enterModule_stmt(final YangParser.Module_stmtContext ctx) { moduleName = stringFromNode(ctx); - LOGGER.trace("entering module " + moduleName); + LOG.trace("entering module {}", moduleName); enterLog("module", moduleName, 0); - actualPath.push(new Stack()); + stack.push(); moduleBuilder = new ModuleBuilder(moduleName, sourcePath); @@ -152,14 +175,15 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitModule_stmt(final YangParser.Module_stmtContext ctx) { exitLog("module"); - actualPath.pop(); + stack.pop(); } - @Override public void enterSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) { + @Override + public void enterSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) { moduleName = stringFromNode(ctx); - LOGGER.trace("entering submodule " + moduleName); + LOG.trace("entering submodule {}", moduleName); enterLog("submodule", moduleName, 0); - actualPath.push(new Stack()); + stack.push(); moduleBuilder = new ModuleBuilder(moduleName, true, sourcePath); @@ -181,13 +205,24 @@ public final class YangParserListenerImpl extends YangParserBaseListener { moduleBuilder.setReference(reference); } - @Override public void exitSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) { + @Override + public void exitSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) { exitLog("submodule"); - actualPath.pop(); + stack.pop(); } - @Override public void enterBelongs_to_stmt(final YangParser.Belongs_to_stmtContext ctx) { - moduleBuilder.setBelongsTo(stringFromNode(ctx)); + @Override + public void enterBelongs_to_stmt(final YangParser.Belongs_to_stmtContext ctx) { + final String belongsTo = stringFromNode(ctx); + TreeMap context = namespaceContext.get(belongsTo); + Map.Entry entry = context.firstEntry(); + // TODO + // Submodule will contain namespace and revision from module to which it + // belongs. If there are multiple modules with same name and different + // revisions, it will has revision from the newest one. + this.moduleQName = QName.create(entry.getValue(), entry.getKey(), moduleQName.getLocalName()); + moduleBuilder.setQNameModule(moduleQName.getModule()); + moduleBuilder.setBelongsTo(belongsTo); } @Override @@ -198,11 +233,13 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final ParseTree treeNode = ctx.getChild(i); if (treeNode instanceof Namespace_stmtContext) { final String namespaceStr = stringFromNode(treeNode); - namespace = URI.create(namespaceStr); - moduleBuilder.setNamespace(namespace); + final URI namespace = URI.create(namespaceStr); + this.moduleQName = QName.create(namespace, moduleQName.getRevision(), moduleQName.getLocalName()); + moduleBuilder.setQNameModule(moduleQName.getModule()); setLog("namespace", namespaceStr); } else if (treeNode instanceof Prefix_stmtContext) { yangModelPrefix = stringFromNode(treeNode); + this.moduleQName = QName.create(moduleQName.getModule(), yangModelPrefix, moduleQName.getLocalName()); moduleBuilder.setPrefix(yangModelPrefix); setLog("prefix", yangModelPrefix); } else if (treeNode instanceof Yang_version_stmtContext) { @@ -272,10 +309,10 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String revisionDateStr = stringFromNode(treeNode); try { final Date revisionDate = SIMPLE_DATE_FORMAT.parse(revisionDateStr); - if ((revisionDate != null) && (this.revision.compareTo(revisionDate) < 0)) { - this.revision = revisionDate; - moduleBuilder.setRevision(this.revision); - setLog("revision", this.revision.toString()); + if ((revisionDate != null) && (this.moduleQName.getRevision().compareTo(revisionDate) < 0)) { + this.moduleQName = QName.create(moduleQName.getNamespace(), revisionDate, moduleQName.getLocalName()); + moduleBuilder.setQNameModule(moduleQName.getModule()); + setLog("revision", revisionDate.toString()); for (int i = 0; i < treeNode.getChildCount(); ++i) { ParseTree child = treeNode.getChild(i); if (child instanceof Reference_stmtContext) { @@ -284,8 +321,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { } } } catch (ParseException e) { - final String message = "Failed to parse revision string: " + revisionDateStr; - LOGGER.warn(message); + LOG.warn("Failed to parse revision string: {}", revisionDateStr, e); } } @@ -308,12 +344,12 @@ public final class YangParserListenerImpl extends YangParserBaseListener { try { importRevision = SIMPLE_DATE_FORMAT.parse(importRevisionStr); } catch (ParseException e) { - LOGGER.warn("Failed to parse import revision-date at line " + line + ": " + importRevisionStr); + LOG.warn("Failed to parse import revision-date at line {}: {}", line, importRevisionStr, e); } } } moduleBuilder.addModuleImport(importName, importRevision, importPrefix); - setLog("import", "(" + importName + "; " + importRevision + "; " + importPrefix + ")"); + LOG.trace("setting import ({}; {}; {})", importName, importRevision, importPrefix); } @Override @@ -321,14 +357,40 @@ public final class YangParserListenerImpl extends YangParserBaseListener { exitLog("import"); } + @Override + public void enterInclude_stmt(YangParser.Include_stmtContext ctx) { + final int line = ctx.getStart().getLine(); + final String includeName = stringFromNode(ctx); + enterLog("import", includeName, line); + + Date includeRevision = null; + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree treeNode = ctx.getChild(i); + if (treeNode instanceof Revision_date_stmtContext) { + String importRevisionStr = stringFromNode(treeNode); + try { + includeRevision = SIMPLE_DATE_FORMAT.parse(importRevisionStr); + } catch (ParseException e) { + LOG.warn("Failed to parse import revision-date at line {}: {}", line, importRevisionStr, e); + } + } + } + moduleBuilder.addInclude(includeName, includeRevision); + } + + @Override public void exitInclude_stmt(YangParser.Include_stmtContext ctx) { + exitLog("include"); + } + @Override public void enterAugment_stmt(final YangParser.Augment_stmtContext ctx) { final int line = ctx.getStart().getLine(); final String augmentPath = stringFromNode(ctx); enterLog(AUGMENT_STR, augmentPath, line); - actualPath.push(new Stack()); + stack.push(); - AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, augmentOrder++); + SchemaPath targetPath = parseXPathString(augmentPath, line); + AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath, augmentOrder++); for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree child = ctx.getChild(i); @@ -350,7 +412,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { public void exitAugment_stmt(final YangParser.Augment_stmtContext ctx) { moduleBuilder.exitNode(); exitLog(AUGMENT_STR); - actualPath.pop(); + stack.pop(); } @Override @@ -358,9 +420,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final int line = ctx.getStart().getLine(); final String extName = stringFromNode(ctx); enterLog("extension", extName, line); - QName qname = new QName(namespace, revision, yangModelPrefix, extName); - addNodeToPath(qname); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName qname = QName.create(moduleQName, extName); + SchemaPath path = stack.addNodeToPath(qname); ExtensionBuilder builder = moduleBuilder.addExtension(qname, line, path); parseSchemaNodeArgs(ctx, builder); @@ -384,7 +445,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitExtension_stmt(final YangParser.Extension_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("extension", removeNodeFromPath()); + exitLog("extension", stack.removeNodeFromPath()); } @Override @@ -392,9 +453,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final int line = ctx.getStart().getLine(); final String typedefName = stringFromNode(ctx); enterLog("typedef", typedefName, line); - QName typedefQName = new QName(namespace, revision, yangModelPrefix, typedefName); - addNodeToPath(typedefQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName typedefQName = QName.create(moduleQName, typedefName); + SchemaPath path = stack.addNodeToPath(typedefQName); TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName, path); parseSchemaNodeArgs(ctx, builder); @@ -407,7 +467,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitTypedef_stmt(final YangParser.Typedef_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("typedef", removeNodeFromPath()); + exitLog("typedef", stack.removeNodeFromPath()); } @Override @@ -416,7 +476,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String typeName = stringFromNode(ctx); enterLog("type", typeName, line); - final QName typeQName = parseQName(typeName); + final QName typeQName = parseQName(typeName, line); TypeDefinition type; Type_body_stmtsContext typeBody = null; @@ -428,64 +488,83 @@ public final class YangParserListenerImpl extends YangParserBaseListener { } // if this is base yang type... - if (YangTypesConverter.isBaseYangType(typeName)) { + if (BaseTypes.isYangBuildInType(typeName)) { if (typeBody == null) { // check for types which must have body checkMissingBody(typeName, moduleName, line); // if there are no constraints, just grab default base yang type - type = YangTypesConverter.javaTypeForBaseYangType(typeName); - addNodeToPath(type.getQName()); + type = BaseTypes.defaultBaseTypeFor(typeName).orNull(); + stack.addNodeToPath(type.getQName()); moduleBuilder.setType(type); } else { QName qname; switch (typeName) { - case "union": - qname = BaseTypes.constructQName("union"); - addNodeToPath(qname); - UnionTypeBuilder unionBuilder = moduleBuilder.addUnionType(line, namespace, revision); - Builder parent = moduleBuilder.getActualNode(); - unionBuilder.setParent(parent); - moduleBuilder.enterNode(unionBuilder); - break; - case "identityref": - qname = BaseTypes.constructQName("identityref"); - addNodeToPath(qname); - SchemaPath path = createActualSchemaPath(actualPath.peek()); - moduleBuilder.addIdentityrefType(line, path, getIdentityrefBase(typeBody)); - break; - default: - type = parseTypeWithBody(typeName, typeBody, actualPath.peek(), namespace, revision, - yangModelPrefix, moduleBuilder.getActualNode()); - moduleBuilder.setType(type); - addNodeToPath(type.getQName()); + case "union": + qname = BaseTypes.UNION_QNAME; + stack.addNodeToPath(qname); + UnionTypeBuilder unionBuilder = moduleBuilder.addUnionType(line, moduleQName.getModule()); + Builder parent = moduleBuilder.getActualNode(); + unionBuilder.setParent(parent); + moduleBuilder.enterNode(unionBuilder); + break; + case "identityref": + qname = BaseTypes.IDENTITYREF_QNAME; + SchemaPath path = stack.addNodeToPath(qname); + moduleBuilder.addIdentityrefType(line, path, getIdentityrefBase(typeBody)); + break; + default: + type = parseTypeWithBody(typeName, typeBody, stack.currentSchemaPath(), moduleQName, + moduleBuilder.getActualNode()); + moduleBuilder.setType(type); + stack.addNodeToPath(type.getQName()); } } } else { - type = parseUnknownTypeWithBody(typeQName, typeBody, actualPath.peek(), namespace, revision, - yangModelPrefix, moduleBuilder.getActualNode()); - // add parent node of this type statement to dirty nodes - moduleBuilder.markActualNodeDirty(); - moduleBuilder.setType(type); - addNodeToPath(type.getQName()); + TypeAwareBuilder parent = (TypeAwareBuilder) moduleBuilder.getActualNode(); + if (typeBody == null) { + parent.setTypeQName(typeQName); + moduleBuilder.markActualNodeDirty(); + } else { + ParserListenerUtils.parseUnknownTypeWithBody(typeBody, parent, typeQName, moduleBuilder, + moduleQName, stack.currentSchemaPath()); + } + stack.addNodeToPath(QName.create(moduleQName.getModule(), typeQName.getLocalName())); } - } - private QName parseQName(final String typeName) { - QName typeQName; - if (typeName.contains(":")) { - String[] splittedName = typeName.split(":"); - String prefix = splittedName[0]; - String name = splittedName[1]; - if (prefix.equals(yangModelPrefix)) { - typeQName = new QName(namespace, revision, prefix, name); + private QName parseQName(final String qnameString, final int line) { + final QName qname; + if (qnameString.indexOf(':') == -1) { + qname = QName.create(moduleQName.getNamespace(), moduleQName.getRevision(), qnameString); + } else { + final Iterator split = COLON_SPLITTER.split(qnameString).iterator(); + final String prefix = split.next(); + final String name = split.next(); + if (prefix.equals(moduleBuilder.getPrefix())) { + qname = QName.create(moduleQName.getNamespace(), moduleQName.getRevision(), name); } else { - typeQName = new QName(null, null, prefix, name); + ModuleImport imp = moduleBuilder.getImport(prefix); + if (imp == null) { + LOG.warn("Error in module {} at line {}: No import found with prefix {}", moduleName, line, prefix); + return QName.create(name); + } + Date revision = imp.getRevision(); + TreeMap namespaces = namespaceContext.get(imp.getModuleName()); + URI namespace; + if (revision == null) { + if (namespaces == null) { + throw new YangParseException(moduleName, line, "imported module " + imp.getModuleName() + + " with prefix " + imp.getPrefix() + " not found."); + } + revision = namespaces.lastEntry().getKey(); + namespace = namespaces.lastEntry().getValue(); + } else { + namespace = namespaces.get(revision); + } + qname = QName.create(namespace, revision, name); } - } else { - typeQName = new QName(namespace, revision, yangModelPrefix, typeName); } - return typeQName; + return qname; } @Override @@ -494,7 +573,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { if ("union".equals(typeName)) { moduleBuilder.exitNode(); } - exitLog("type", removeNodeFromPath()); + exitLog("type", stack.removeNodeFromPath()); } @Override @@ -502,9 +581,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final int line = ctx.getStart().getLine(); final String groupName = stringFromNode(ctx); enterLog("grouping", groupName, line); - QName groupQName = new QName(namespace, revision, yangModelPrefix, groupName); - addNodeToPath(groupQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName groupQName = QName.create(moduleQName, groupName); + SchemaPath path = stack.addNodeToPath(groupQName); GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName, path); parseSchemaNodeArgs(ctx, builder); @@ -515,7 +593,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitGrouping_stmt(final YangParser.Grouping_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("grouping", removeNodeFromPath()); + exitLog("grouping", stack.removeNodeFromPath()); } @Override @@ -524,9 +602,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String containerName = stringFromNode(ctx); enterLog("container", containerName, line); - QName containerQName = new QName(namespace, revision, yangModelPrefix, containerName); - addNodeToPath(containerQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName containerQName = QName.create(moduleQName, containerName); + SchemaPath path = stack.addNodeToPath(containerQName); ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(line, containerQName, path); parseSchemaNodeArgs(ctx, builder); @@ -547,7 +624,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitContainer_stmt(final Container_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("container", removeNodeFromPath()); + exitLog("container", stack.removeNodeFromPath()); } @Override @@ -556,9 +633,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String leafName = stringFromNode(ctx); enterLog("leaf", leafName, line); - QName leafQName = new QName(namespace, revision, yangModelPrefix, leafName); - addNodeToPath(leafQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName leafQName = QName.create(moduleQName, leafName); + SchemaPath path = stack.addNodeToPath(leafQName); LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(line, leafQName, path); parseSchemaNodeArgs(ctx, builder); @@ -584,16 +660,17 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitLeaf_stmt(final YangParser.Leaf_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("leaf", removeNodeFromPath()); + exitLog("leaf", stack.removeNodeFromPath()); } @Override public void enterUses_stmt(final YangParser.Uses_stmtContext ctx) { final int line = ctx.getStart().getLine(); final String groupingPathStr = stringFromNode(ctx); + final SchemaPath groupingPath = parseXPathString(groupingPathStr, line); enterLog("uses", groupingPathStr, line); - UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPathStr); + UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPath); moduleBuilder.enterNode(builder); } @@ -606,12 +683,13 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void enterUses_augment_stmt(final YangParser.Uses_augment_stmtContext ctx) { - actualPath.push(new Stack()); final int line = ctx.getStart().getLine(); final String augmentPath = stringFromNode(ctx); enterLog(AUGMENT_STR, augmentPath, line); + stack.push(); - AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, augmentOrder++); + SchemaPath targetPath = parseXPathString(augmentPath, line); + AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath, augmentOrder++); for (int i = 0; i < ctx.getChildCount(); i++) { ParseTree child = ctx.getChild(i); @@ -633,7 +711,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { public void exitUses_augment_stmt(final YangParser.Uses_augment_stmtContext ctx) { moduleBuilder.exitNode(); exitLog(AUGMENT_STR); - actualPath.pop(); + stack.pop(); } @Override @@ -657,9 +735,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final int line = ctx.getStart().getLine(); final String leafListName = stringFromNode(ctx); enterLog("leaf-list", leafListName, line); - QName leafListQName = new QName(namespace, revision, yangModelPrefix, leafListName); - addNodeToPath(leafListQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName leafListQName = QName.create(moduleQName, leafListName); + SchemaPath path = stack.addNodeToPath(leafListQName); LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, path); moduleBuilder.enterNode(builder); @@ -682,7 +759,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitLeaf_list_stmt(final YangParser.Leaf_list_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("leaf-list", removeNodeFromPath()); + exitLog("leaf-list", stack.removeNodeFromPath()); } @Override @@ -691,9 +768,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String listName = stringFromNode(ctx); enterLog("list", listName, line); - QName listQName = new QName(namespace, revision, yangModelPrefix, listName); - addNodeToPath(listQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName listQName = QName.create(moduleQName, listName); + SchemaPath path = stack.addNodeToPath(listQName); ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, path); moduleBuilder.enterNode(builder); @@ -718,7 +794,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitList_stmt(final List_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("list", removeNodeFromPath()); + exitLog("list", stack.removeNodeFromPath()); } @Override @@ -727,9 +803,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String anyXmlName = stringFromNode(ctx); enterLog("anyxml", anyXmlName, line); - QName anyXmlQName = new QName(namespace, revision, yangModelPrefix, anyXmlName); - addNodeToPath(anyXmlQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName anyXmlQName = QName.create(moduleQName, anyXmlName); + SchemaPath path = stack.addNodeToPath(anyXmlQName); AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, path); moduleBuilder.enterNode(builder); @@ -742,7 +817,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitAnyxml_stmt(final YangParser.Anyxml_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("anyxml", removeNodeFromPath()); + exitLog("anyxml", stack.removeNodeFromPath()); } @Override @@ -751,9 +826,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String choiceName = stringFromNode(ctx); enterLog("choice", choiceName, line); - QName choiceQName = new QName(namespace, revision, yangModelPrefix, choiceName); - addNodeToPath(choiceQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName choiceQName = QName.create(moduleQName, choiceName); + SchemaPath path = stack.addNodeToPath(choiceQName); ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName, path); moduleBuilder.enterNode(builder); @@ -776,7 +850,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitChoice_stmt(final YangParser.Choice_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("choice", removeNodeFromPath()); + exitLog("choice", stack.removeNodeFromPath()); } @Override @@ -785,9 +859,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String caseName = stringFromNode(ctx); enterLog("case", caseName, line); - QName caseQName = new QName(namespace, revision, yangModelPrefix, caseName); - addNodeToPath(caseQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName caseQName = QName.create(moduleQName, caseName); + SchemaPath path = stack.addNodeToPath(caseQName); ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName, path); moduleBuilder.enterNode(builder); @@ -799,7 +872,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitCase_stmt(final YangParser.Case_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("case", removeNodeFromPath()); + exitLog("case", stack.removeNodeFromPath()); } @Override @@ -808,9 +881,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String notificationName = stringFromNode(ctx); enterLog("notification", notificationName, line); - QName notificationQName = new QName(namespace, revision, yangModelPrefix, notificationName); - addNodeToPath(notificationQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName notificationQName = QName.create(moduleQName, notificationName); + SchemaPath path = stack.addNodeToPath(notificationQName); NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName, path); moduleBuilder.enterNode(builder); @@ -821,7 +893,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitNotification_stmt(final YangParser.Notification_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("notification", removeNodeFromPath()); + exitLog("notification", stack.removeNodeFromPath()); } // Unknown nodes @@ -833,7 +905,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitIdentifier_stmt(final YangParser.Identifier_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("unknown-node", removeNodeFromPath()); + exitLog("unknown-node", stack.removeNodeFromPath()); } @Override public void enterUnknown_statement(final YangParser.Unknown_statementContext ctx) { @@ -842,25 +914,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitUnknown_statement(final YangParser.Unknown_statementContext ctx) { moduleBuilder.exitNode(); - exitLog("unknown-node", removeNodeFromPath()); - } - - @Override public void enterUnknown_statement2(final YangParser.Unknown_statement2Context ctx) { - handleUnknownNode(ctx.getStart().getLine(), ctx); - } - - @Override public void exitUnknown_statement2(final YangParser.Unknown_statement2Context ctx) { - moduleBuilder.exitNode(); - exitLog("unknown-node", removeNodeFromPath()); - } - - @Override public void enterUnknown_statement3(final YangParser.Unknown_statement3Context ctx) { - handleUnknownNode(ctx.getStart().getLine(), ctx); - } - - @Override public void exitUnknown_statement3(final YangParser.Unknown_statement3Context ctx) { - moduleBuilder.exitNode(); - exitLog("unknown-node", removeNodeFromPath()); + exitLog("unknown-node", stack.removeNodeFromPath()); } @Override @@ -869,9 +923,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String rpcName = stringFromNode(ctx); enterLog("rpc", rpcName, line); - QName rpcQName = new QName(namespace, revision, yangModelPrefix, rpcName); - addNodeToPath(rpcQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName rpcQName = QName.create(moduleQName, rpcName); + SchemaPath path = stack.addNodeToPath(rpcQName); RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path); moduleBuilder.enterNode(rpcBuilder); @@ -883,7 +936,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitRpc_stmt(final YangParser.Rpc_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("rpc", removeNodeFromPath()); + exitLog("rpc", stack.removeNodeFromPath()); } @Override @@ -892,9 +945,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String input = "input"; enterLog(input, input, line); - QName rpcQName = new QName(namespace, revision, yangModelPrefix, input); - addNodeToPath(rpcQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName rpcQName = QName.create(moduleQName, input); + SchemaPath path = stack.addNodeToPath(rpcQName); ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path); moduleBuilder.enterNode(builder); @@ -907,7 +959,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitInput_stmt(final YangParser.Input_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("input", removeNodeFromPath()); + exitLog("input", stack.removeNodeFromPath()); } @Override @@ -916,9 +968,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String output = "output"; enterLog(output, output, line); - QName rpcQName = new QName(namespace, revision, yangModelPrefix, output); - addNodeToPath(rpcQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName rpcQName = QName.create(moduleQName, output); + SchemaPath path = stack.addNodeToPath(rpcQName); ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line); moduleBuilder.enterNode(builder); @@ -931,7 +982,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitOutput_stmt(final YangParser.Output_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("output", removeNodeFromPath()); + exitLog("output", stack.removeNodeFromPath()); } @Override @@ -940,9 +991,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String featureName = stringFromNode(ctx); enterLog("feature", featureName, line); - QName featureQName = new QName(namespace, revision, yangModelPrefix, featureName); - addNodeToPath(featureQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + QName featureQName = QName.create(moduleQName, featureName); + SchemaPath path = stack.addNodeToPath(featureQName); FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path); moduleBuilder.enterNode(featureBuilder); @@ -953,17 +1003,23 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitFeature_stmt(final YangParser.Feature_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("feature", removeNodeFromPath()); + exitLog("feature", stack.removeNodeFromPath()); } @Override public void enterDeviation_stmt(final YangParser.Deviation_stmtContext ctx) { final int line = ctx.getStart().getLine(); - final String targetPath = stringFromNode(ctx); - enterLog("deviation", targetPath, line); + final String targetPathStr = stringFromNode(ctx); + if (!targetPathStr.startsWith("/")) { + throw new YangParseException(moduleName, line, + "Deviation argument string must be an absolute schema node identifier."); + } + enterLog("deviation", targetPathStr, line); String reference = null; String deviate = null; + + SchemaPath targetPath = parseXPathString(targetPathStr, line); DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath); moduleBuilder.enterNode(builder); @@ -985,6 +1041,22 @@ public final class YangParserListenerImpl extends YangParserBaseListener { builder.setDeviate(deviate); } + public SchemaPath parseXPathString(final String xpathString, final int line) { + final boolean absolute = !xpathString.isEmpty() && xpathString.charAt(0) == '/'; + + final List path = new ArrayList<>(); + for (String pathElement : SLASH_SPLITTER.split(xpathString)) { + final Iterator it = COLON_SPLITTER.split(pathElement).iterator(); + final String s = it.next(); + if (it.hasNext()) { + path.add(parseQName(pathElement, line)); + } else { + path.add(QName.create(moduleQName, s)); + } + } + return SchemaPath.create(path, absolute); + } + @Override public void exitDeviation_stmt(final YangParser.Deviation_stmtContext ctx) { moduleBuilder.exitNode(); @@ -997,14 +1069,12 @@ public final class YangParserListenerImpl extends YangParserBaseListener { final String identityName = stringFromNode(ctx); enterLog("identity", identityName, line); - final QName identityQName = new QName(namespace, revision, yangModelPrefix, identityName); - addNodeToPath(identityQName); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + final QName identityQName = QName.create(moduleQName, identityName); + SchemaPath path = stack.addNodeToPath(identityQName); IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path); moduleBuilder.enterNode(builder); - parseSchemaNodeArgs(ctx, builder); for (int i = 0; i < ctx.getChildCount(); i++) { @@ -1019,66 +1089,59 @@ public final class YangParserListenerImpl extends YangParserBaseListener { @Override public void exitIdentity_stmt(final YangParser.Identity_stmtContext ctx) { moduleBuilder.exitNode(); - exitLog("identity", removeNodeFromPath()); + exitLog("identity", stack.removeNodeFromPath()); } public ModuleBuilder getModuleBuilder() { return moduleBuilder; } - private void enterLog(final String p1, final String p2, final int line) { - LOGGER.trace("entering {} {} ({})", p1, p2, line); + private static void enterLog(final String p1, final String p2, final int line) { + LOG.trace("entering {} {} ({})", p1, p2, line); } - private void exitLog(final String p1) { - LOGGER.trace("exiting {}", p1); + private static void exitLog(final String p1) { + LOG.trace("exiting {}", p1); } - private void exitLog(final String p1, final QName p2) { - LOGGER.trace("exiting {} {}", p1, p2.getLocalName()); + private static void exitLog(final String p1, final QName p2) { + LOG.trace("exiting {} {}", p1, p2.getLocalName()); } - private void setLog(final String p1, final String p2) { - LOGGER.trace("setting {} {}", p1, p2); + private static void setLog(final String p1, final String p2) { + LOG.trace("setting {} {}", p1, p2); } private void handleUnknownNode(final int line, final ParseTree ctx) { final String nodeParameter = stringFromNode(ctx); enterLog("unknown-node", nodeParameter, line); - QName nodeType; final String nodeTypeStr = ctx.getChild(0).getText(); - final String[] splittedElement = nodeTypeStr.split(":"); - if (splittedElement.length == 1) { - nodeType = new QName(namespace, revision, yangModelPrefix, splittedElement[0]); - } else { - nodeType = new QName(namespace, revision, splittedElement[0], splittedElement[1]); - } + QName nodeType = parseQName(nodeTypeStr, line); - QName qname; + QName qname = null; try { - if (!Strings.isNullOrEmpty(nodeParameter)) { - String[] splittedName = nodeParameter.split(":"); - if (splittedName.length == 2) { - qname = new QName(null, null, splittedName[0], splittedName[1]); + if (Strings.isNullOrEmpty(nodeParameter)) { + qname = nodeType; + } else { + final Iterable splittedName = COLON_SPLITTER.split(nodeParameter); + final Iterator it = splittedName.iterator(); + if (Iterables.size(splittedName) == 2) { + qname = parseQName(nodeParameter, line); } else { - qname = new QName(namespace, revision, yangModelPrefix, splittedName[0]); + qname = QName.create(moduleQName, it.next()); } - } else { - qname = nodeType; } } catch (IllegalArgumentException e) { qname = nodeType; - } - addNodeToPath(qname); - SchemaPath path = createActualSchemaPath(actualPath.peek()); + + SchemaPath path = stack.addNodeToPath(qname); UnknownSchemaNodeBuilderImpl builder = moduleBuilder.addUnknownSchemaNode(line, qname, path); builder.setNodeType(nodeType); builder.setNodeParameter(nodeParameter); - parseSchemaNodeArgs(ctx, builder); moduleBuilder.enterNode(builder); }