BUG-865: deprecate pre-Beryllium parser elements
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangParserListenerImpl.java
index 35dfb65f7e53ec9fdbe44c246ca2d152c0ed1953..ec5e1f1820aa1bf4b5d72249da782f2cf5ee322b 100644 (file)
@@ -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.NavigableMap;
+import java.util.Set;
 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,16 @@ 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.common.QNameModule;
+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,51 +98,75 @@ 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;
 
-import com.google.common.base.Strings;
-
+/**
+ * @deprecated Pre-Beryllium implementation, scheduled for removal.
+ */
+@Deprecated
 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 static final String IMPORT_STR = "import";
+    private static final String UNION_STR = "union";
+    private static final String UNKNOWN_NODE_STR = "unknown-node";
+
+    /**
+     * Date Format is not thread-safe so we cannot make constant from it.
+     */
+    private final DateFormat revisionFormat = new SimpleDateFormat("yyyy-MM-dd");
+    private final SchemaPathStack stack = new SchemaPathStack();
+    private final Map<String, NavigableMap<Date, URI>> namespaceContext;
     private final String sourcePath;
+    private QName moduleQName = QName.create(null, new Date(0L), "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<Stack<QName>> actualPath = new Stack<>();
     private int augmentOrder;
+    private String yangModelPrefix;
 
-    private void addNodeToPath(final QName name) {
-        actualPath.peek().push(name);
-    }
-
-    private QName removeNodeFromPath() {
-        return actualPath.peek().pop();
+    public YangParserListenerImpl(final Map<String, NavigableMap<Date, URI>> namespaceContext, final String sourcePath) {
+        this.namespaceContext = namespaceContext;
+        this.sourcePath = sourcePath;
     }
 
-    public YangParserListenerImpl(final String sourcePath) {
-        this.sourcePath = sourcePath;
+    /**
+     * 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 namespaceContext
+     * @param sourcePath sourcePath
+     * @param walker walker
+     * @param tree tree
+     * @return new instance of YangParserListenerImpl
+     */
+    public static YangParserListenerImpl create(final Map<String, NavigableMap<Date, URI>> namespaceContext,
+            final String sourcePath, final ParseTreeWalker walker, final ParseTree tree) {
+        final YangParserListenerImpl ret = new YangParserListenerImpl(namespaceContext, sourcePath);
+        walker.walk(ret, tree);
+        return ret;
     }
 
     @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<QName>());
+        stack.push();
 
         moduleBuilder = new ModuleBuilder(moduleName, sourcePath);
 
         String description = null;
         String reference = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Description_stmtContext) {
                 description = stringFromNode(child);
             } else if (child instanceof Reference_stmtContext) {
@@ -153,22 +183,23 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void exitModule_stmt(final YangParser.Module_stmtContext ctx) {
-        exitLog("module", "");
-        actualPath.pop();
+        exitLog("module");
+        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<QName>());
+        stack.push();
 
         moduleBuilder = new ModuleBuilder(moduleName, true, sourcePath);
 
         String description = null;
         String reference = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Description_stmtContext) {
                 description = stringFromNode(child);
             } else if (child instanceof Reference_stmtContext) {
@@ -183,13 +214,32 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         moduleBuilder.setReference(reference);
     }
 
-    @Override public void exitSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) {
-        exitLog("submodule", "");
-        actualPath.pop();
+    @Override
+    public void exitSubmodule_stmt(final YangParser.Submodule_stmtContext ctx) {
+        exitLog("submodule");
+        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);
+        final NavigableMap<Date, URI> context = namespaceContext.get(belongsTo);
+        final Map.Entry<Date, URI> 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);
+        for (int i = 0; i < ctx.getChildCount(); ++i) {
+            final ParseTree treeNode = ctx.getChild(i);
+            if (treeNode instanceof Prefix_stmtContext) {
+                yangModelPrefix = stringFromNode(treeNode);
+                moduleBuilder.setPrefix(yangModelPrefix);
+                setLog("prefix", yangModelPrefix);
+            }
+        }
     }
 
     @Override
@@ -200,11 +250,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(), moduleQName.getLocalName());
                 moduleBuilder.setPrefix(yangModelPrefix);
                 setLog("prefix", yangModelPrefix);
             } else if (treeNode instanceof Yang_version_stmtContext) {
@@ -221,14 +273,14 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void exitModule_header_stmts(final Module_header_stmtsContext ctx) {
-        exitLog("module_header", "");
+        exitLog("module_header");
     }
 
     @Override
     public void enterMeta_stmts(final YangParser.Meta_stmtsContext ctx) {
         enterLog("meta_stmt", "", ctx.getStart().getLine());
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Organization_stmtContext) {
                 final String organization = stringFromNode(child);
                 moduleBuilder.setOrganization(organization);
@@ -251,7 +303,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void exitMeta_stmts(final YangParser.Meta_stmtsContext ctx) {
-        exitLog("meta_stmt", "");
+        exitLog("meta_stmt");
     }
 
     @Override
@@ -267,27 +319,26 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
     @Override
     public void exitRevision_stmts(final Revision_stmtsContext ctx) {
-        exitLog("revisions", "");
+        exitLog("revisions");
     }
 
     private void updateRevisionForRevisionStatement(final ParseTree treeNode) {
         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());
+            final Date revisionDate = revisionFormat.parse(revisionDateStr);
+            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);
+                    final ParseTree child = treeNode.getChild(i);
                     if (child instanceof Reference_stmtContext) {
                         moduleBuilder.setReference(stringFromNode(child));
                     }
                 }
             }
-        } catch (ParseException e) {
-            final String message = "Failed to parse revision string: " + revisionDateStr;
-            LOGGER.warn(message);
+        } catch (final ParseException e) {
+            LOG.warn("Failed to parse revision string: {}", revisionDateStr, e);
         }
     }
 
@@ -295,7 +346,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
     public void enterImport_stmt(final Import_stmtContext ctx) {
         final int line = ctx.getStart().getLine();
         final String importName = stringFromNode(ctx);
-        enterLog("import", importName, line);
+        enterLog(IMPORT_STR, importName, line);
 
         String importPrefix = null;
         Date importRevision = null;
@@ -304,23 +355,48 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
             final ParseTree treeNode = ctx.getChild(i);
             if (treeNode instanceof Prefix_stmtContext) {
                 importPrefix = stringFromNode(treeNode);
-            }
-            if (treeNode instanceof Revision_date_stmtContext) {
-                String importRevisionStr = stringFromNode(treeNode);
+            } else if (treeNode instanceof Revision_date_stmtContext) {
+                final String importRevisionStr = stringFromNode(treeNode);
                 try {
-                    importRevision = SIMPLE_DATE_FORMAT.parse(importRevisionStr);
-                } catch (ParseException e) {
-                    LOGGER.warn("Failed to parse import revision-date at line " + line + ": " + importRevisionStr);
+                    importRevision = revisionFormat.parse(importRevisionStr);
+                } catch (final ParseException e) {
+                    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
     public void exitImport_stmt(final Import_stmtContext ctx) {
-        exitLog("import", "");
+        exitLog(IMPORT_STR);
+    }
+
+    @Override
+    public void enterInclude_stmt(final YangParser.Include_stmtContext ctx) {
+        final int line = ctx.getStart().getLine();
+        final String includeName = stringFromNode(ctx);
+        enterLog(IMPORT_STR, includeName, line);
+
+        Date includeRevision = null;
+        for (int i = 0; i < ctx.getChildCount(); i++) {
+            final ParseTree treeNode = ctx.getChild(i);
+            if (treeNode instanceof Revision_date_stmtContext) {
+                final String importRevisionStr = stringFromNode(treeNode);
+                try {
+                    includeRevision = revisionFormat.parse(importRevisionStr);
+                } catch (final ParseException e) {
+                    LOG.warn("Failed to parse import revision-date at line {}: {}", line, importRevisionStr, e);
+                }
+            }
+        }
+        moduleBuilder.addInclude(includeName, includeRevision);
+    }
+
+    @Override
+    public void exitInclude_stmt(final YangParser.Include_stmtContext ctx) {
+        exitLog("include");
     }
 
     @Override
@@ -328,12 +404,14 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         final int line = ctx.getStart().getLine();
         final String augmentPath = stringFromNode(ctx);
         enterLog(AUGMENT_STR, augmentPath, line);
-        actualPath.push(new Stack<QName>());
+        stack.push();
 
-        AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, augmentOrder++);
+        final SchemaPath targetPath = parseXPathString(augmentPath, line);
+        final AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath,
+                augmentOrder++);
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Description_stmtContext) {
                 builder.setDescription(stringFromNode(child));
             } else if (child instanceof Reference_stmtContext) {
@@ -351,8 +429,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
     @Override
     public void exitAugment_stmt(final YangParser.Augment_stmtContext ctx) {
         moduleBuilder.exitNode();
-        exitLog(AUGMENT_STR, "");
-        actualPath.pop();
+        exitLog(AUGMENT_STR);
+        stack.pop();
     }
 
     @Override
@@ -360,17 +438,16 @@ 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());
+        final QName qname = QName.create(moduleQName, extName);
+        final SchemaPath path = stack.addNodeToPath(qname);
 
-        ExtensionBuilder builder = moduleBuilder.addExtension(qname, line, path);
+        final ExtensionBuilder builder = moduleBuilder.addExtension(qname, line, path);
         parseSchemaNodeArgs(ctx, builder);
 
         String argument = null;
         boolean yin = false;
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Argument_stmtContext) {
                 argument = stringFromNode(child);
                 yin = parseYinValue((Argument_stmtContext) child);
@@ -386,7 +463,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
@@ -394,11 +471,10 @@ 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());
+        final QName typedefQName = QName.create(moduleQName, typedefName);
+        final SchemaPath path = stack.addNodeToPath(typedefQName);
 
-        TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName, path);
+        final TypeDefinitionBuilder builder = moduleBuilder.addTypedef(line, typedefQName, path);
         parseSchemaNodeArgs(ctx, builder);
         builder.setUnits(parseUnits(ctx));
         builder.setDefaultValue(parseDefault(ctx));
@@ -409,7 +485,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
@@ -418,9 +494,9 @@ 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 = null;
+        TypeDefinition<?> type;
         Type_body_stmtsContext typeBody = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
             if (ctx.getChild(i) instanceof Type_body_stmtsContext) {
@@ -430,73 +506,117 @@ 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_STR:
+                    stack.addNodeToPath(BaseTypes.UNION_QNAME);
+                    final UnionTypeBuilder unionBuilder = moduleBuilder.addUnionType(line, moduleQName.getModule());
+                    final Builder parentBuilder = moduleBuilder.getActualNode();
+                    unionBuilder.setParent(parentBuilder);
+                    moduleBuilder.enterNode(unionBuilder);
+                    break;
+                case "identityref":
+                    qname = BaseTypes.IDENTITYREF_QNAME;
+                    final 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());
+            final 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);
+    /**
+     * Method transforms string representation of yang element (i.e. leaf name,
+     * container name etc.) into QName. The namespace of QName is assigned from
+     * parent module same as revision date of module. If String qname parameter
+     * contains ":" the string is evaluated as prefix:name of element. In this
+     * case method will look into import map and extract correct ModuleImport.
+     * If such import is not present in import map the method will throw
+     * {@link YangParseException} <br>
+     * If ModuleImport is present but the value of namespace in ModuleImport is
+     * <code>null</code> the method will throw {@link YangParseException}
+     *
+     * @param qnameString
+     *            QName value as String
+     * @param line
+     *            line in Yang model document where QName occur.
+     * @return transformed string qname parameter as QName structure.
+     *
+     * @throws YangParseException
+     */
+    private QName parseQName(final String qnameString, final int line) {
+        final QName qname;
+        if (qnameString.indexOf(':') == -1) {
+            qname = QName.create(moduleQName, qnameString);
+        } else {
+            final Iterator<String> 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, name);
             } else {
-                typeQName = new QName(null, null, prefix, name);
+                final ModuleImport imp = moduleBuilder.getImport(prefix);
+                if (imp == null) {
+                    LOG.debug("Error in module {} at line {}: No import found with prefix {}", moduleName, line, prefix);
+                    throw new YangParseException(moduleName, line, "Error in module " + moduleName
+                            + " No import found with prefix " + prefix + " not found.");
+                }
+                Date revision = imp.getRevision();
+                final NavigableMap<Date, URI> namespaces = namespaceContext.get(imp.getModuleName());
+                if (namespaces == null) {
+                    throw new YangParseException(moduleName, line, String.format("Imported module %s not found",
+                            imp.getModuleName()));
+                }
+                URI namespace;
+                if (revision == null) {
+                    revision = namespaces.lastEntry().getKey();
+                    namespace = namespaces.lastEntry().getValue();
+                } else {
+                    // FIXME: this lookup does not look right, as we will end up
+                    // with
+                    // a qname which does not have a namespace. At any rate we
+                    // should arrive at a QNameModule!
+                    namespace = namespaces.get(revision);
+                }
+
+                final QNameModule mod = QNameModule.create(namespace, revision).intern();
+                qname = QName.create(mod, name);
             }
-        } else {
-            typeQName = new QName(namespace, revision, yangModelPrefix, typeName);
         }
-        return typeQName;
+        return qname;
     }
 
     @Override
     public void exitType_stmt(final YangParser.Type_stmtContext ctx) {
         final String typeName = stringFromNode(ctx);
-        if ("union".equals(typeName)) {
+        if (UNION_STR.equals(typeName)) {
             moduleBuilder.exitNode();
         }
-        exitLog("type", removeNodeFromPath());
+        exitLog("type", stack.removeNodeFromPath());
     }
 
     @Override
@@ -504,11 +624,10 @@ 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());
+        final QName groupQName = QName.create(moduleQName, groupName);
+        final SchemaPath path = stack.addNodeToPath(groupQName);
 
-        GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName, path);
+        final GroupingBuilder builder = moduleBuilder.addGrouping(ctx.getStart().getLine(), groupQName, path);
         parseSchemaNodeArgs(ctx, builder);
 
         moduleBuilder.enterNode(builder);
@@ -517,7 +636,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
@@ -526,11 +645,10 @@ 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());
+        final QName containerQName = QName.create(moduleQName, containerName);
+        final SchemaPath path = stack.addNodeToPath(containerQName);
 
-        ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(line, containerQName, path);
+        final ContainerSchemaNodeBuilder builder = moduleBuilder.addContainerNode(line, containerQName, path);
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
@@ -549,7 +667,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
@@ -558,11 +676,10 @@ 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());
+        final QName leafQName = QName.create(moduleQName, leafName);
+        final SchemaPath path = stack.addNodeToPath(leafQName);
 
-        LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(line, leafQName, path);
+        final LeafSchemaNodeBuilder builder = moduleBuilder.addLeafNode(line, leafQName, path);
         parseSchemaNodeArgs(ctx, builder);
         parseConstraints(ctx, builder.getConstraints());
         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
@@ -570,7 +687,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         String defaultStr = null;
         String unitsStr = null;
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Default_stmtContext) {
                 defaultStr = stringFromNode(child);
             } else if (child instanceof Units_stmtContext) {
@@ -586,16 +703,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);
+        final UsesNodeBuilder builder = moduleBuilder.addUsesNode(line, groupingPath);
 
         moduleBuilder.enterNode(builder);
     }
@@ -603,20 +721,22 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
     @Override
     public void exitUses_stmt(final YangParser.Uses_stmtContext ctx) {
         moduleBuilder.exitNode();
-        exitLog("uses", "");
+        exitLog("uses");
     }
 
     @Override
     public void enterUses_augment_stmt(final YangParser.Uses_augment_stmtContext ctx) {
-        actualPath.push(new Stack<QName>());
         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++);
+        final SchemaPath targetPath = parseXPathString(augmentPath, line);
+        final AugmentationSchemaBuilder builder = moduleBuilder.addAugment(line, augmentPath, targetPath,
+                augmentOrder++);
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Description_stmtContext) {
                 builder.setDescription(stringFromNode(child));
             } else if (child instanceof Reference_stmtContext) {
@@ -634,8 +754,8 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
     @Override
     public void exitUses_augment_stmt(final YangParser.Uses_augment_stmtContext ctx) {
         moduleBuilder.exitNode();
-        exitLog(AUGMENT_STR, "");
-        actualPath.pop();
+        exitLog(AUGMENT_STR);
+        stack.pop();
     }
 
     @Override
@@ -643,7 +763,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         final String refineString = stringFromNode(ctx);
         enterLog("refine", refineString, ctx.getStart().getLine());
 
-        RefineHolderImpl refine = parseRefine(ctx, moduleName);
+        final RefineHolderImpl refine = parseRefine(ctx, moduleName);
         moduleBuilder.addRefine(refine);
         moduleBuilder.enterNode(refine);
     }
@@ -651,7 +771,7 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
     @Override
     public void exitRefine_stmt(final YangParser.Refine_stmtContext ctx) {
         moduleBuilder.exitNode();
-        exitLog("refine", "");
+        exitLog("refine");
     }
 
     @Override
@@ -659,11 +779,10 @@ 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());
+        final QName leafListQName = QName.create(moduleQName, leafListName);
+        final SchemaPath path = stack.addNodeToPath(leafListQName);
 
-        LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, path);
+        final LeafListSchemaNodeBuilder builder = moduleBuilder.addLeafListNode(line, leafListQName, path);
         moduleBuilder.enterNode(builder);
 
         parseSchemaNodeArgs(ctx, builder);
@@ -684,7 +803,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
@@ -693,11 +812,10 @@ 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());
+        final QName listQName = QName.create(moduleQName, listName);
+        final SchemaPath path = stack.addNodeToPath(listQName);
 
-        ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, path);
+        final ListSchemaNodeBuilder builder = moduleBuilder.addListNode(line, listQName, path);
         moduleBuilder.enterNode(builder);
 
         parseSchemaNodeArgs(ctx, builder);
@@ -705,14 +823,17 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
         builder.setConfiguration(getConfig(ctx, builder, moduleName, line));
 
         for (int i = 0; i < ctx.getChildCount(); ++i) {
-            ParseTree childNode = ctx.getChild(i);
+            final ParseTree childNode = ctx.getChild(i);
             if (childNode instanceof Ordered_by_stmtContext) {
                 final Ordered_by_stmtContext orderedBy = (Ordered_by_stmtContext) childNode;
                 final boolean userOrdered = parseUserOrdered(orderedBy);
                 builder.setUserOrdered(userOrdered);
             } else if (childNode instanceof Key_stmtContext) {
-                List<String> key = createListKey((Key_stmtContext) childNode);
+                final Set<String> key = createListKey((Key_stmtContext) childNode);
                 builder.setKeys(key);
+            } else if (childNode instanceof YangParser.Identifier_stmtContext
+                    && UNION_STR.equals(childNode.getChild(0).toString())) {
+                throw new YangParseException(moduleName, line, "Union statement is not allowed inside a list statement");
             }
         }
     }
@@ -720,7 +841,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
@@ -729,11 +850,10 @@ 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());
+        final QName anyXmlQName = QName.create(moduleQName, anyXmlName);
+        final SchemaPath path = stack.addNodeToPath(anyXmlQName);
 
-        AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, path);
+        final AnyXmlBuilder builder = moduleBuilder.addAnyXml(line, anyXmlQName, path);
         moduleBuilder.enterNode(builder);
 
         parseSchemaNodeArgs(ctx, builder);
@@ -744,7 +864,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
@@ -753,11 +873,10 @@ 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());
+        final QName choiceQName = QName.create(moduleQName, choiceName);
+        final SchemaPath path = stack.addNodeToPath(choiceQName);
 
-        ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName, path);
+        final ChoiceBuilder builder = moduleBuilder.addChoice(line, choiceQName, path);
         moduleBuilder.enterNode(builder);
 
         parseSchemaNodeArgs(ctx, builder);
@@ -766,9 +885,9 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
 
         // set 'default' case
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Default_stmtContext) {
-                String defaultCase = stringFromNode(child);
+                final String defaultCase = stringFromNode(child);
                 builder.setDefaultCase(defaultCase);
                 break;
             }
@@ -778,7 +897,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
@@ -787,11 +906,10 @@ 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());
+        final QName caseQName = QName.create(moduleQName, caseName);
+        final SchemaPath path = stack.addNodeToPath(caseQName);
 
-        ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName, path);
+        final ChoiceCaseBuilder builder = moduleBuilder.addCase(line, caseQName, path);
         moduleBuilder.enterNode(builder);
 
         parseSchemaNodeArgs(ctx, builder);
@@ -801,7 +919,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
@@ -810,11 +928,10 @@ 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());
+        final QName notificationQName = QName.create(moduleQName, notificationName);
+        final SchemaPath path = stack.addNodeToPath(notificationQName);
 
-        NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName, path);
+        final NotificationBuilder builder = moduleBuilder.addNotification(line, notificationQName, path);
         moduleBuilder.enterNode(builder);
 
         parseSchemaNodeArgs(ctx, builder);
@@ -823,7 +940,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
@@ -835,34 +952,18 @@ public final class YangParserListenerImpl extends YangParserBaseListener {
     @Override
     public void exitIdentifier_stmt(final YangParser.Identifier_stmtContext ctx) {
         moduleBuilder.exitNode();
-        exitLog("unknown-node", removeNodeFromPath());
-    }
-
-    @Override public void enterUnknown_statement(final YangParser.Unknown_statementContext ctx) {
-        handleUnknownNode(ctx.getStart().getLine(), ctx);
-    }
-
-    @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());
+        exitLog(UNKNOWN_NODE_STR, stack.removeNodeFromPath());
     }
 
-    @Override public void enterUnknown_statement3(final YangParser.Unknown_statement3Context ctx) {
+    @Override
+    public void enterUnknown_statement(final YangParser.Unknown_statementContext ctx) {
         handleUnknownNode(ctx.getStart().getLine(), ctx);
     }
 
-    @Override public void exitUnknown_statement3(final YangParser.Unknown_statement3Context ctx) {
+    @Override
+    public void exitUnknown_statement(final YangParser.Unknown_statementContext ctx) {
         moduleBuilder.exitNode();
-        exitLog("unknown-node", removeNodeFromPath());
+        exitLog(UNKNOWN_NODE_STR, stack.removeNodeFromPath());
     }
 
     @Override
@@ -871,21 +972,19 @@ 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());
+        final QName rpcQName = QName.create(moduleQName, rpcName);
+        final SchemaPath path = stack.addNodeToPath(rpcQName);
 
-        RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path);
+        final RpcDefinitionBuilder rpcBuilder = moduleBuilder.addRpc(line, rpcQName, path);
         moduleBuilder.enterNode(rpcBuilder);
 
-
         parseSchemaNodeArgs(ctx, rpcBuilder);
     }
 
     @Override
     public void exitRpc_stmt(final YangParser.Rpc_stmtContext ctx) {
         moduleBuilder.exitNode();
-        exitLog("rpc", removeNodeFromPath());
+        exitLog("rpc", stack.removeNodeFromPath());
     }
 
     @Override
@@ -894,11 +993,10 @@ 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());
+        final QName rpcQName = QName.create(moduleQName, input);
+        final SchemaPath path = stack.addNodeToPath(rpcQName);
 
-        ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
+        final ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcInput(line, rpcQName, path);
         moduleBuilder.enterNode(builder);
         builder.setConfiguration(true);
 
@@ -909,7 +1007,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
@@ -918,11 +1016,10 @@ 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());
+        final QName rpcQName = QName.create(moduleQName, output);
+        final SchemaPath path = stack.addNodeToPath(rpcQName);
 
-        ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
+        final ContainerSchemaNodeBuilder builder = moduleBuilder.addRpcOutput(path, rpcQName, line);
         moduleBuilder.enterNode(builder);
         builder.setConfiguration(true);
 
@@ -933,7 +1030,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
@@ -942,11 +1039,10 @@ 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());
+        final QName featureQName = QName.create(moduleQName, featureName);
+        final SchemaPath path = stack.addNodeToPath(featureQName);
 
-        FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path);
+        final FeatureBuilder featureBuilder = moduleBuilder.addFeature(line, featureQName, path);
         moduleBuilder.enterNode(featureBuilder);
 
         parseSchemaNodeArgs(ctx, featureBuilder);
@@ -955,22 +1051,28 @@ 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;
-        DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
+
+        final SchemaPath targetPath = parseXPathString(targetPathStr, line);
+        final DeviationBuilder builder = moduleBuilder.addDeviation(line, targetPath);
         moduleBuilder.enterNode(builder);
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Reference_stmtContext) {
                 reference = stringFromNode(child);
             } else if (child instanceof Deviate_not_supported_stmtContext) {
@@ -987,10 +1089,26 @@ 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<QName> path = new ArrayList<>();
+        for (final String pathElement : SLASH_SPLITTER.split(xpathString)) {
+            final Iterator<String> 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();
-        exitLog("deviation", "");
+        exitLog("deviation");
     }
 
     @Override
@@ -999,20 +1117,18 @@ 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);
+        final SchemaPath path = stack.addNodeToPath(identityQName);
 
-        IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path);
+        final IdentitySchemaNodeBuilder builder = moduleBuilder.addIdentity(identityQName, line, path);
         moduleBuilder.enterNode(builder);
 
-
         parseSchemaNodeArgs(ctx, builder);
 
         for (int i = 0; i < ctx.getChildCount(); i++) {
-            ParseTree child = ctx.getChild(i);
+            final ParseTree child = ctx.getChild(i);
             if (child instanceof Base_stmtContext) {
-                String baseIdentityName = stringFromNode(child);
+                final String baseIdentityName = stringFromNode(child);
                 builder.setBaseIdentityName(baseIdentityName);
             }
         }
@@ -1021,66 +1137,66 @@ 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, final String p2) {
-        LOGGER.trace("exiting {} {}", p1, p2);
+    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);
+        enterLog(UNKNOWN_NODE_STR, 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]);
-        }
+        final QName nodeType = parseQName(nodeTypeStr, line);
 
         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]);
+            // FIXME: rewrite whole method to handle unknown nodes properly.
+            // This should be bugfix for bug
+            // https://bugs.opendaylight.org/show_bug.cgi?id=1539
+            // After this fix bug
+            // https://bugs.opendaylight.org/show_bug.cgi?id=1538 MUST be fixed
+            // since
+            // they are dependent!!!
+            if (Strings.isNullOrEmpty(nodeParameter)) {
+                qname = nodeType;
+            } else {
+                final Iterable<String> splittedName = COLON_SPLITTER.split(nodeParameter);
+                final Iterator<String> 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) {
+        } catch (IllegalArgumentException | YangParseException ex) {
             qname = nodeType;
-
         }
-        addNodeToPath(qname);
-        SchemaPath path = createActualSchemaPath(actualPath.peek());
 
-        UnknownSchemaNodeBuilderImpl builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
+        final SchemaPath path = stack.addNodeToPath(qname);
+
+        final UnknownSchemaNodeBuilderImpl builder = moduleBuilder.addUnknownSchemaNode(line, qname, path);
         builder.setNodeType(nodeType);
         builder.setNodeParameter(nodeParameter);
 
-
         parseSchemaNodeArgs(ctx, builder);
         moduleBuilder.enterNode(builder);
     }