Merge "Update the NETCONF stack"
diff --git a/src/ast_commands.hpp b/src/ast_commands.hpp
index a1c377b..787fb94 100644
--- a/src/ast_commands.hpp
+++ b/src/ast_commands.hpp
@@ -40,27 +40,27 @@
 struct ls_ : x3::position_tagged {
     bool operator==(const ls_& b) const;
     std::vector<LsOption> m_options;
-    boost::optional<path_> m_path;
+    boost::optional<boost::variant<dataPath_, schemaPath_>> m_path;
 };
 
 struct cd_ : x3::position_tagged {
     bool operator==(const cd_& b) const;
-    path_ m_path;
+    dataPath_ m_path;
 };
 
 struct create_ : x3::position_tagged {
     bool operator==(const create_& b) const;
-    path_ m_path;
+    dataPath_ m_path;
 };
 
 struct delete_ : x3::position_tagged {
     bool operator==(const delete_& b) const;
-    path_ m_path;
+    dataPath_ m_path;
 };
 
 struct set_ : x3::position_tagged {
     bool operator==(const set_& b) const;
-    path_ m_path;
+    dataPath_ m_path;
     leaf_data_ m_data;
 };
 
@@ -70,7 +70,7 @@
 
 struct get_ : x3::position_tagged {
     bool operator==(const get_& b) const;
-    boost::optional<path_> m_path;
+    boost::optional<boost::variant<dataPath_, schemaPath_>> m_path;
 };
 
 using command_ = boost::variant<discard_, ls_, cd_, create_, delete_, set_, commit_, get_>;
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index b19ece0..0cb64f1 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -121,7 +121,18 @@
         }
     }
 };
+struct list_class {
+    template <typename T, typename Iterator, typename Context>
+    void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
+    {
+        auto& parserContext = x3::get<parser_context_tag>(context);
+        const Schema& schema = parserContext.m_schema;
 
+        if (!schema.isList(parserContext.m_curPath, {parserContext.m_curModule, ast.m_name})) {
+            _pass(context) = false;
+        }
+    }
+};
 struct nodeup_class {
     template <typename T, typename Iterator, typename Context>
     void on_success(Iterator const&, Iterator const&, T&, Context const& context)
@@ -157,7 +168,6 @@
     }
 };
 
-
 struct module_class {
     template <typename T, typename Iterator, typename Context>
     void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
@@ -175,7 +185,7 @@
     }
 };
 
-struct node_class {
+struct schemaNode_class {
     template <typename T, typename Iterator, typename Context>
     void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
     {
@@ -191,6 +201,24 @@
     }
 };
 
+struct dataNodeList_class;
+
+struct dataNode_class {
+    template <typename T, typename Iterator, typename Context>
+    void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
+    {
+        auto& parserContext = x3::get<parser_context_tag>(context);
+        if (ast.m_suffix.type() == typeid(nodeup_)) {
+            parserContext.m_curPath.m_nodes.pop_back();
+            if (parserContext.m_curPath.m_nodes.empty())
+                parserContext.m_topLevelModulePresent = false;
+        } else {
+            parserContext.m_curPath.m_nodes.push_back(dataNodeToSchemaNode(ast));
+            parserContext.m_curModule = boost::none;
+        }
+    }
+};
+
 struct absoluteStart_class {
     template <typename T, typename Iterator, typename Context>
     void on_success(Iterator const&, Iterator const&, T&, Context const& context)
@@ -200,7 +228,25 @@
     }
 };
 
-struct path_class {
+struct dataNodesListEnd_class;
+
+struct dataPathListEnd_class;
+
+struct dataPath_class {
+    template <typename Iterator, typename Exception, typename Context>
+    x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
+    {
+        auto& parserContext = x3::get<parser_context_tag>(context);
+        if (parserContext.m_errorMsg.empty()) {
+            parserContext.m_errorMsg = "Expected path.";
+            return x3::error_handler_result::fail;
+        } else {
+            return x3::error_handler_result::rethrow;
+        }
+    }
+};
+
+struct schemaPath_class {
     template <typename Iterator, typename Exception, typename Context>
     x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
     {
@@ -240,7 +286,7 @@
             if (ast.m_path.m_nodes.back().m_prefix)
                 module = ast.m_path.m_nodes.back().m_prefix.value().m_name;
             container_ cont = boost::get<container_>(ast.m_path.m_nodes.back().m_suffix);
-            path_ location = pathWithoutLastNode(parserContext.m_curPath);
+            schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
 
             if (!schema.isPresenceContainer(location, {module, cont.m_name})) {
                 parserContext.m_errorMsg = "This container is not a presence container.";
@@ -290,7 +336,10 @@
         auto& schema = parserContext.m_schema;
         if (parserContext.m_errorMsg.empty()) {
             leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
-            path_ location = pathWithoutLastNode(parserContext.m_curPath);
+            schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
+            if (location.m_nodes.empty()) {
+                parserContext.m_curModule = parserContext.m_curPath.m_nodes.back().m_prefix->m_name;
+            }
             parserContext.m_errorMsg = "Expected " + leafDataTypeToString(schema.leafType(location, {parserContext.m_curModule, leaf.m_name})) + " here:";
             return x3::error_handler_result::fail;
         }
@@ -316,7 +365,7 @@
             module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
 
         leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
-        path_ location = pathWithoutLastNode(parserContext.m_curPath);
+        schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
 
         if (schema.leafType(location, {module, leaf.m_name}) != m_type) {
             _pass(context) = false;
@@ -341,7 +390,7 @@
             module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
 
         leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
-        path_ location = pathWithoutLastNode(parserContext.m_curPath);
+        schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
 
         if (!schema.leafEnumHasValue(location, {module, leaf.m_name}, ast.m_value)) {
             _pass(context) = false;
@@ -412,3 +461,18 @@
         return x3::error_handler_result::fail;
     }
 };
+
+struct initializeContext_class {
+    template <typename T, typename Iterator, typename Context>
+    void on_success(Iterator const&, Iterator const&, T&, Context const& context)
+    {
+        auto& parserContext = x3::get<parser_context_tag>(context);
+        parserContext.m_curPath = parserContext.m_curPathOrig;
+        parserContext.m_tmpListKeys.clear();
+        parserContext.m_tmpListName.clear();
+        if (!parserContext.m_curPath.m_nodes.empty() && parserContext.m_curPath.m_nodes.at(0).m_prefix)
+            parserContext.m_topLevelModulePresent = true;
+        else
+            parserContext.m_topLevelModulePresent = false;
+    }
+};
diff --git a/src/ast_path.cpp b/src/ast_path.cpp
index bb14425..1f01a72 100644
--- a/src/ast_path.cpp
+++ b/src/ast_path.cpp
@@ -30,21 +30,38 @@
     return this->m_name == b.m_name;
 }
 
-node_::node_() = default;
+dataNode_::dataNode_() = default;
 
-node_::node_(decltype(m_suffix) node)
+dataNode_::dataNode_(decltype(m_suffix) node)
     : m_suffix(node)
 {
 }
 
-node_::node_(module_ module, decltype(m_suffix) node)
+dataNode_::dataNode_(module_ module, decltype(m_suffix) node)
     : m_prefix(module)
     , m_suffix(node)
 {
 }
 
+schemaNode_::schemaNode_(decltype(m_suffix) node)
+    : m_suffix(node)
+{
+}
 
-bool node_::operator==(const node_& b) const
+schemaNode_::schemaNode_(module_ module, decltype(m_suffix) node)
+    : m_prefix(module)
+    , m_suffix(node)
+{
+}
+
+schemaNode_::schemaNode_() = default;
+
+bool schemaNode_::operator==(const schemaNode_& b) const
+{
+    return this->m_suffix == b.m_suffix && this->m_prefix == b.m_prefix;
+}
+
+bool dataNode_::operator==(const dataNode_& b) const
 {
     return this->m_suffix == b.m_suffix && this->m_prefix == b.m_prefix;
 }
@@ -65,7 +82,24 @@
     return (this->m_name == b.m_name && this->m_keys == b.m_keys);
 }
 
-bool path_::operator==(const path_& b) const
+bool list_::operator==(const list_& b) const
+{
+    return (this->m_name == b.m_name);
+}
+
+list_::list_(const std::string& listName)
+    : m_name(listName)
+{
+}
+
+bool schemaPath_::operator==(const schemaPath_& b) const
+{
+    if (this->m_nodes.size() != b.m_nodes.size())
+        return false;
+    return this->m_nodes == b.m_nodes;
+}
+
+bool dataPath_::operator==(const dataPath_& b) const
 {
     if (this->m_nodes.size() != b.m_nodes.size())
         return false;
@@ -118,12 +152,12 @@
     }
 };
 
-std::string nodeToSchemaString(decltype(path_::m_nodes)::value_type node)
+std::string nodeToSchemaString(decltype(dataPath_::m_nodes)::value_type node)
 {
     return boost::apply_visitor(nodeToSchemaStringVisitor(), node.m_suffix);
 }
 
-std::string pathToDataString(const path_& path)
+std::string pathToDataString(const dataPath_& path)
 {
     std::string res;
     for (const auto it : path.m_nodes)
@@ -135,7 +169,12 @@
     return res;
 }
 
-std::string pathToAbsoluteSchemaString(const path_& path)
+std::string pathToAbsoluteSchemaString(const dataPath_& path)
+{
+    return pathToAbsoluteSchemaString(dataPathToSchemaPath(path));
+}
+
+std::string pathToAbsoluteSchemaString(const schemaPath_& path)
 {
     std::string res;
     if (path.m_nodes.empty()) {
@@ -152,7 +191,7 @@
     return res;
 }
 
-std::string pathToSchemaString(const path_& path)
+std::string pathToSchemaString(const schemaPath_& path)
 {
     std::string res;
     for (const auto it : path.m_nodes) {
@@ -163,3 +202,40 @@
     }
     return res;
 }
+
+std::string pathToSchemaString(const dataPath_& path)
+{
+    return pathToSchemaString(dataPathToSchemaPath(path));
+}
+
+struct dataSuffixToSchemaSuffix : boost::static_visitor<decltype(schemaNode_::m_suffix)> {
+    auto operator()(const listElement_& listElement) const
+    {
+        return list_{listElement.m_name};
+    }
+
+    template <typename T>
+    auto operator()(const T& suffix) const
+    {
+        return suffix;
+    }
+};
+
+schemaNode_ dataNodeToSchemaNode(const dataNode_& node)
+{
+    schemaNode_ res;
+    res.m_prefix = node.m_prefix;
+    res.m_suffix = boost::apply_visitor(dataSuffixToSchemaSuffix(), node.m_suffix);
+    return res;
+}
+
+schemaPath_ dataPathToSchemaPath(const dataPath_& path)
+{
+        schemaPath_ res{path.m_scope, {}};
+
+        std::transform(path.m_nodes.begin(), path.m_nodes.end(),
+                       std::back_inserter(res.m_nodes),
+                       [](const dataNode_& node) { return dataNodeToSchemaNode(node); });
+
+        return res;
+}
diff --git a/src/ast_path.hpp b/src/ast_path.hpp
index dab06ea..2711a30 100644
--- a/src/ast_path.hpp
+++ b/src/ast_path.hpp
@@ -53,19 +53,38 @@
     std::map<std::string, std::string> m_keys;
 };
 
+struct list_ {
+    list_() {}
+    list_(const std::string& listName);
+
+    bool operator==(const list_& b) const;
+
+    std::string m_name;
+};
+
 struct module_ {
     bool operator==(const module_& b) const;
     std::string m_name;
 };
 
-struct node_ {
+struct schemaNode_ {
     boost::optional<module_> m_prefix;
-    boost::variant<container_, listElement_, nodeup_, leaf_> m_suffix;
+    boost::variant<container_, list_, nodeup_, leaf_> m_suffix;
 
-    node_();
-    node_(decltype(m_suffix) node);
-    node_(module_ module, decltype(m_suffix) node);
-    bool operator==(const node_& b) const;
+    schemaNode_();
+    schemaNode_(decltype(m_suffix) node);
+    schemaNode_(module_ module, decltype(m_suffix) node);
+    bool operator==(const schemaNode_& b) const;
+};
+
+struct dataNode_ {
+    boost::optional<module_> m_prefix;
+    boost::variant<container_, listElement_, nodeup_, leaf_, list_> m_suffix;
+
+    dataNode_();
+    dataNode_(decltype(m_suffix) node);
+    dataNode_(module_ module, decltype(m_suffix) node);
+    bool operator==(const dataNode_& b) const;
 };
 
 enum class Scope {
@@ -73,20 +92,31 @@
     Relative
 };
 
-struct path_ {
-    bool operator==(const path_& b) const;
+struct schemaPath_ {
+    bool operator==(const schemaPath_& b) const;
     Scope m_scope = Scope::Relative;
-    std::vector<node_> m_nodes;
+    std::vector<schemaNode_> m_nodes;
 };
 
-std::string nodeToSchemaString(decltype(path_::m_nodes)::value_type node);
+struct dataPath_ {
+    bool operator==(const dataPath_& b) const;
+    Scope m_scope = Scope::Relative;
+    std::vector<dataNode_> m_nodes;
+};
 
-std::string pathToAbsoluteSchemaString(const path_& path);
-std::string pathToDataString(const path_& path);
-std::string pathToSchemaString(const path_& path);
+std::string nodeToSchemaString(decltype(dataPath_::m_nodes)::value_type node);
+
+std::string pathToAbsoluteSchemaString(const dataPath_& path);
+std::string pathToAbsoluteSchemaString(const schemaPath_& path);
+std::string pathToDataString(const dataPath_& path);
+std::string pathToSchemaString(const schemaPath_& path);
+schemaNode_ dataNodeToSchemaNode(const dataNode_& node);
+schemaPath_ dataPathToSchemaPath(const dataPath_& path);
 
 BOOST_FUSION_ADAPT_STRUCT(container_, m_name)
 BOOST_FUSION_ADAPT_STRUCT(listElement_, m_name, m_keys)
 BOOST_FUSION_ADAPT_STRUCT(module_, m_name)
-BOOST_FUSION_ADAPT_STRUCT(node_, m_prefix, m_suffix)
-BOOST_FUSION_ADAPT_STRUCT(path_, m_scope, m_nodes)
+BOOST_FUSION_ADAPT_STRUCT(dataNode_, m_prefix, m_suffix)
+BOOST_FUSION_ADAPT_STRUCT(schemaNode_, m_prefix, m_suffix)
+BOOST_FUSION_ADAPT_STRUCT(dataPath_, m_scope, m_nodes)
+BOOST_FUSION_ADAPT_STRUCT(schemaPath_, m_scope, m_nodes)
diff --git a/src/grammars.hpp b/src/grammars.hpp
index 03753e8..7caa45c 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -19,14 +19,20 @@
 x3::rule<listPrefix_class, std::string> const listPrefix = "listPrefix";
 x3::rule<listSuffix_class, std::vector<keyValue_>> const listSuffix = "listSuffix";
 x3::rule<listElement_class, listElement_> const listElement = "listElement";
+x3::rule<list_class, list_> const list = "list";
 x3::rule<nodeup_class, nodeup_> const nodeup = "nodeup";
 x3::rule<container_class, container_> const container = "container";
 x3::rule<leaf_class, leaf_> const leaf = "leaf";
 x3::rule<module_class, module_> const module = "module";
-x3::rule<node_class, node_> const node = "node";
+x3::rule<dataNode_class, dataNode_> const dataNode = "dataNode";
+x3::rule<schemaNode_class, schemaNode_> const schemaNode = "schemaNode";
 x3::rule<absoluteStart_class, Scope> const absoluteStart = "absoluteStart";
-x3::rule<path_class, path_> const path = "path";
-x3::rule<leaf_path_class, path_> const leafPath = "leafPath";
+x3::rule<schemaPath_class, schemaPath_> const schemaPath = "schemaPath";
+x3::rule<dataNodeList_class, decltype(dataPath_::m_nodes)::value_type> const dataNodeList = "dataNodeList";
+x3::rule<dataNodesListEnd_class, decltype(dataPath_::m_nodes)> const dataNodesListEnd = "dataNodesListEnd";
+x3::rule<dataPathListEnd_class, dataPath_> const dataPathListEnd = "dataPathListEnd";
+x3::rule<dataPath_class, dataPath_> const dataPath = "dataPath";
+x3::rule<leaf_path_class, dataPath_> const leafPath = "leafPath";
 
 x3::rule<leaf_data_class, leaf_data_> const leaf_data = "leaf_data";
 x3::rule<leaf_data_enum_class, enum_> const leaf_data_enum = "leaf_data_enum";
@@ -46,6 +52,8 @@
 x3::rule<commit_class, commit_> const commit = "commit";
 x3::rule<command_class, command_> const command = "command";
 
+x3::rule<initializeContext_class, x3::unused_type> const initializeContext = "initializeContext";
+
 #if __clang__
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Woverloaded-shift-op-parentheses"
@@ -86,6 +94,9 @@
 auto const listElement_def =
         listPrefix > listSuffix;
 
+auto const list_def =
+        node_identifier >> !char_('[');
+
 auto const nodeup_def =
         lit("..") > x3::attr(nodeup_());
 
@@ -99,19 +110,41 @@
         node_identifier;
 
 // leaf cannot be in the middle of a path, however, I need the grammar's attribute to be a vector of variants
-auto const node_def =
-        -(module) >> x3::expect[container | listElement | nodeup | leaf];
+auto const schemaNode_def =
+        -(module) >> x3::expect[container | list | nodeup | leaf];
+
+auto const dataNode_def =
+        -(module) >> (container | listElement | nodeup | leaf);
 
 auto const absoluteStart_def =
         x3::omit['/'] >> x3::attr(Scope::Absolute);
 
 // I have to insert an empty vector to the first alternative, otherwise they won't have the same attribute
-auto const path_def =
-        absoluteStart >> x3::attr(decltype(path_::m_nodes)()) >> x3::eoi |
-        -(absoluteStart) >> node % '/';
+auto const dataPath_def =
+        absoluteStart >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::eoi |
+        -(absoluteStart) >> dataNode % '/';
+
+auto const dataNodeList_def =
+        -(module) >> list;
+
+// This intermediate rule is mandatory, because we need the first alternative
+// to be collapsed to a vector. If we didn't use the intermediate rule,
+// Spirit wouldn't know we want it to collapse.
+// https://github.com/boostorg/spirit/issues/408
+auto const dataNodesListEnd_def =
+        dataNode % '/' >> '/' >> dataNodeList |
+        initializeContext >> x3::attr(decltype(dataPath_::m_nodes)()) >> dataNodeList;
+
+auto const dataPathListEnd_def =
+        absoluteStart >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::eoi |
+        -(absoluteStart) >> dataNodesListEnd;
+
+auto const schemaPath_def =
+        absoluteStart >> x3::attr(decltype(schemaPath_::m_nodes)()) >> x3::eoi |
+        -(absoluteStart) >> schemaNode % '/';
 
 auto const leafPath_def =
-        path;
+        dataPath;
 
 auto const leaf_data_enum_def =
         +char_;
@@ -156,20 +189,24 @@
     }
 } const ls_options;
 
+// A "nothing" parser, which is used to reset the context (when trying to parse different types of paths)
+auto const initializeContext_def =
+        x3::eps;
+
 auto const ls_def =
-        lit("ls") >> *(space_separator >> ls_options) >> -(space_separator >> path);
+        lit("ls") >> *(space_separator >> ls_options) >> -(space_separator >> (dataPathListEnd | initializeContext >> dataPath));
 
 auto const cd_def =
-        lit("cd") >> space_separator > path;
+        lit("cd") >> space_separator > dataPath;
 
 auto const create_def =
-        lit("create") >> space_separator > path;
+        lit("create") >> space_separator > dataPath;
 
 auto const delete_rule_def =
-        lit("delete") >> space_separator > path;
+        lit("delete") >> space_separator > dataPath;
 
 auto const get_def =
-        lit("get") >> -path;
+        lit("get") >> -(space_separator >> (dataPathListEnd | initializeContext >> dataPath));
 
 auto const set_def =
         lit("set") >> space_separator > leafPath > leaf_data;
@@ -194,13 +231,19 @@
 BOOST_SPIRIT_DEFINE(listPrefix)
 BOOST_SPIRIT_DEFINE(listSuffix)
 BOOST_SPIRIT_DEFINE(listElement)
+BOOST_SPIRIT_DEFINE(list)
 BOOST_SPIRIT_DEFINE(nodeup)
+BOOST_SPIRIT_DEFINE(schemaNode)
+BOOST_SPIRIT_DEFINE(dataNode)
 BOOST_SPIRIT_DEFINE(container)
 BOOST_SPIRIT_DEFINE(leaf)
 BOOST_SPIRIT_DEFINE(leafPath)
-BOOST_SPIRIT_DEFINE(node)
+BOOST_SPIRIT_DEFINE(schemaPath)
+BOOST_SPIRIT_DEFINE(dataPath)
+BOOST_SPIRIT_DEFINE(dataNodeList)
+BOOST_SPIRIT_DEFINE(dataNodesListEnd)
+BOOST_SPIRIT_DEFINE(dataPathListEnd)
 BOOST_SPIRIT_DEFINE(absoluteStart)
-BOOST_SPIRIT_DEFINE(path)
 BOOST_SPIRIT_DEFINE(module)
 BOOST_SPIRIT_DEFINE(leaf_data)
 BOOST_SPIRIT_DEFINE(leaf_data_enum)
@@ -209,6 +252,7 @@
 BOOST_SPIRIT_DEFINE(leaf_data_int)
 BOOST_SPIRIT_DEFINE(leaf_data_uint)
 BOOST_SPIRIT_DEFINE(leaf_data_string)
+BOOST_SPIRIT_DEFINE(initializeContext)
 BOOST_SPIRIT_DEFINE(set)
 BOOST_SPIRIT_DEFINE(commit)
 BOOST_SPIRIT_DEFINE(get)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 452bc74..80e6195 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -84,14 +84,39 @@
         return joinPaths(m_parser.currentNode(), pathToDataString(command.m_path));
 }
 
+struct pathToStringVisitor : boost::static_visitor<std::string> {
+    std::string operator()(const schemaPath_& path) const
+    {
+        return pathToSchemaString(path);
+    }
+    std::string operator()(const dataPath_& path) const
+    {
+        return pathToDataString(path);
+    }
+};
+
+struct getPathScopeVisitor : boost::static_visitor<Scope> {
+    template <typename T>
+    Scope operator()(const T& path) const
+    {
+        return path.m_scope;
+    }
+};
+
 std::string Interpreter::absolutePathFromCommand(const get_& get) const
 {
     if (!get.m_path) {
         return m_parser.currentNode();
-    } else if (get.m_path->m_scope == Scope::Absolute) {
-        return "/" + pathToDataString(*get.m_path);
+    }
+
+    const auto path = *get.m_path;
+    std::string pathString = boost::apply_visitor(pathToStringVisitor(), path);
+    auto pathScope{boost::apply_visitor(getPathScopeVisitor(), path)};
+
+    if (pathScope == Scope::Absolute) {
+        return "/" + pathString;
     } else {
-        return joinPaths(m_parser.currentNode(), pathToDataString(*get.m_path));
+        return joinPaths(m_parser.currentNode(), pathString);
     }
 }
 
diff --git a/src/parser.cpp b/src/parser.cpp
index f25f1a3..ee0233e 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -21,7 +21,7 @@
 command_ Parser::parseCommand(const std::string& line, std::ostream& errorStream)
 {
     command_ parsedCommand;
-    ParserContext ctx(*m_schema, m_curDir);
+    ParserContext ctx(*m_schema, dataPathToSchemaPath(m_curDir));
     auto it = line.begin();
 
     boost::spirit::x3::error_handler<std::string::const_iterator> errorHandler(it, line.end(), errorStream);
@@ -39,7 +39,7 @@
     return parsedCommand;
 }
 
-void Parser::changeNode(const path_& name)
+void Parser::changeNode(const dataPath_& name)
 {
     if (name.m_scope == Scope::Absolute) {
         m_curDir = name;
@@ -58,10 +58,25 @@
     return "/" + pathToDataString(m_curDir);
 }
 
-std::set<std::string> Parser::availableNodes(const boost::optional<path_>& path, const Recursion& option) const
+struct getSchemaPathVisitor : boost::static_visitor<schemaPath_> {
+    schemaPath_ operator()(const dataPath_& path) const
+    {
+        return dataPathToSchemaPath(path);
+    }
+
+    schemaPath_ operator()(const schemaPath_& path) const
+    {
+        return path;
+    }
+};
+
+
+std::set<std::string> Parser::availableNodes(const boost::optional<boost::variant<dataPath_, schemaPath_>>& path, const Recursion& option) const
 {
-    auto pathArg = m_curDir;
-    if (path)
-        pathArg.m_nodes.insert(pathArg.m_nodes.end(), path->m_nodes.begin(), path->m_nodes.end());
+    auto pathArg = dataPathToSchemaPath(m_curDir);
+    if (path) {
+        auto schemaPath = boost::apply_visitor(getSchemaPathVisitor(), *path);
+        pathArg.m_nodes.insert(pathArg.m_nodes.end(), schemaPath.m_nodes.begin(), schemaPath.m_nodes.end());
+    }
     return m_schema->childNodes(pathArg, option);
 }
diff --git a/src/parser.hpp b/src/parser.hpp
index 0318733..343a1e5 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -27,11 +27,11 @@
 public:
     Parser(const std::shared_ptr<const Schema> schema);
     command_ parseCommand(const std::string& line, std::ostream& errorStream);
-    void changeNode(const path_& name);
+    void changeNode(const dataPath_& name);
     std::string currentNode() const;
-    std::set<std::string> availableNodes(const boost::optional<path_>& path, const Recursion& option) const;
+    std::set<std::string> availableNodes(const boost::optional<boost::variant<dataPath_, schemaPath_>>& path, const Recursion& option) const;
 
 private:
     const std::shared_ptr<const Schema> m_schema;
-    path_ m_curDir;
+    dataPath_ m_curDir;
 };
diff --git a/src/parser_context.cpp b/src/parser_context.cpp
index fa64344..c240984 100644
--- a/src/parser_context.cpp
+++ b/src/parser_context.cpp
@@ -7,11 +7,11 @@
 */
 
 #include "parser_context.hpp"
-ParserContext::ParserContext(const Schema& schema, const path_ curDir)
+ParserContext::ParserContext(const Schema& schema, const schemaPath_& curDir)
     : m_schema(schema)
+    , m_curPath(curDir)
+    , m_curPathOrig(curDir)
 {
-    m_curPath = curDir;
-
     if (!m_curPath.m_nodes.empty() && m_curPath.m_nodes.at(0).m_prefix)
         m_topLevelModulePresent = true;
 }
diff --git a/src/parser_context.hpp b/src/parser_context.hpp
index 28c5eb1..a0b8e30 100644
--- a/src/parser_context.hpp
+++ b/src/parser_context.hpp
@@ -8,9 +8,10 @@
 
 #include "schema.hpp"
 struct ParserContext {
-    ParserContext(const Schema& schema, const path_ curDir);
+    ParserContext(const Schema& schema, const schemaPath_& curDir);
     const Schema& m_schema;
-    path_ m_curPath;
+    schemaPath_ m_curPath;
+    const schemaPath_ m_curPathOrig;
     boost::optional<std::string> m_curModule;
     std::string m_errorMsg;
     std::string m_tmpListName;
diff --git a/src/schema.hpp b/src/schema.hpp
index e5827de..e1f019f 100644
--- a/src/schema.hpp
+++ b/src/schema.hpp
@@ -69,17 +69,17 @@
 public:
     virtual ~Schema();
 
-    virtual bool isContainer(const path_& location, const ModuleNodePair& node) const = 0;
-    virtual bool isLeaf(const path_& location, const ModuleNodePair& node) const = 0;
-    virtual bool isModule(const path_& location, const std::string& name) const = 0;
-    virtual bool isList(const path_& location, const ModuleNodePair& node) const = 0;
-    virtual bool isPresenceContainer(const path_& location, const ModuleNodePair& node) const = 0;
-    virtual bool leafEnumHasValue(const path_& location, const ModuleNodePair& node, const std::string& value) const = 0;
-    virtual bool listHasKey(const path_& location, const ModuleNodePair& node, const std::string& key) const = 0;
+    virtual bool isContainer(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+    virtual bool isLeaf(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+    virtual bool isModule(const schemaPath_& location, const std::string& name) const = 0;
+    virtual bool isList(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+    virtual bool isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+    virtual bool leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const = 0;
+    virtual bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const = 0;
     virtual bool nodeExists(const std::string& location, const std::string& node) const = 0;
-    virtual const std::set<std::string> listKeys(const path_& location, const ModuleNodePair& node) const = 0;
-    virtual yang::LeafDataTypes leafType(const path_& location, const ModuleNodePair& node) const = 0;
-    virtual std::set<std::string> childNodes(const path_& path, const Recursion recursion) const = 0;
+    virtual const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+    virtual yang::LeafDataTypes leafType(const schemaPath_& location, const ModuleNodePair& node) const = 0;
+    virtual std::set<std::string> childNodes(const schemaPath_& path, const Recursion recursion) const = 0;
 
 private:
     const std::unordered_map<std::string, NodeType>& children(const std::string& name) const;
diff --git a/src/static_schema.cpp b/src/static_schema.cpp
index ce94218..9be7751 100644
--- a/src/static_schema.cpp
+++ b/src/static_schema.cpp
@@ -31,12 +31,12 @@
     return childrenRef.find(node) != childrenRef.end();
 }
 
-bool StaticSchema::isModule(const path_&, const std::string& name) const
+bool StaticSchema::isModule(const schemaPath_&, const std::string& name) const
 {
     return m_modules.find(name) != m_modules.end();
 }
 
-bool StaticSchema::isContainer(const path_& location, const ModuleNodePair& node) const
+bool StaticSchema::isContainer(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::string locationString = pathToAbsoluteSchemaString(location);
     auto fullName = fullNodeName(location, node);
@@ -55,7 +55,7 @@
     m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
 }
 
-bool StaticSchema::listHasKey(const path_& location, const ModuleNodePair& node, const std::string& key) const
+bool StaticSchema::listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const
 {
     std::string locationString = pathToAbsoluteSchemaString(location);
     assert(isList(location, node));
@@ -65,7 +65,7 @@
     return list.m_keys.find(key) != list.m_keys.end();
 }
 
-const std::set<std::string> StaticSchema::listKeys(const path_& location, const ModuleNodePair& node) const
+const std::set<std::string> StaticSchema::listKeys(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::string locationString = pathToAbsoluteSchemaString(location);
     assert(isList(location, node));
@@ -75,7 +75,7 @@
     return list.m_keys;
 }
 
-bool StaticSchema::isList(const path_& location, const ModuleNodePair& node) const
+bool StaticSchema::isList(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::string locationString = pathToAbsoluteSchemaString(location);
     auto fullName = fullNodeName(location, node);
@@ -95,7 +95,7 @@
     m_nodes.emplace(name, std::unordered_map<std::string, NodeType>());
 }
 
-bool StaticSchema::isPresenceContainer(const path_& location, const ModuleNodePair& node) const
+bool StaticSchema::isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const
 {
     if (!isContainer(location, node))
         return false;
@@ -119,7 +119,7 @@
 }
 
 
-bool StaticSchema::leafEnumHasValue(const path_& location, const ModuleNodePair& node, const std::string& value) const
+bool StaticSchema::leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const
 {
     std::string locationString = pathToAbsoluteSchemaString(location);
     assert(isLeaf(location, node));
@@ -129,7 +129,7 @@
     return list.m_enumValues.find(value) != list.m_enumValues.end();
 }
 
-bool StaticSchema::isLeaf(const path_& location, const ModuleNodePair& node) const
+bool StaticSchema::isLeaf(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::string locationString = pathToAbsoluteSchemaString(location);
     auto fullName = fullNodeName(location, node);
@@ -139,7 +139,7 @@
     return children(locationString).at(fullName).type() == typeid(yang::leaf);
 }
 
-yang::LeafDataTypes StaticSchema::leafType(const path_& location, const ModuleNodePair& node) const
+yang::LeafDataTypes StaticSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::string locationString = pathToAbsoluteSchemaString(location);
     return boost::get<yang::leaf>(children(locationString).at(fullNodeName(location, node))).m_type;
@@ -147,7 +147,7 @@
 
 // We do not test StaticSchema, so we don't need to implement recursive childNodes
 // for this class.
-std::set<std::string> StaticSchema::childNodes(const path_& path, const Recursion) const
+std::set<std::string> StaticSchema::childNodes(const schemaPath_& path, const Recursion) const
 {
     std::string locationString = pathToAbsoluteSchemaString(path);
     std::set<std::string> res;
diff --git a/src/static_schema.hpp b/src/static_schema.hpp
index 68f1401..7326120 100644
--- a/src/static_schema.hpp
+++ b/src/static_schema.hpp
@@ -23,17 +23,17 @@
 public:
     StaticSchema();
 
-    bool isContainer(const path_& location, const ModuleNodePair& node) const override;
-    bool isModule(const path_& location, const std::string& name) const override;
-    bool isLeaf(const path_& location, const ModuleNodePair& node) const override;
-    bool isList(const path_& location, const ModuleNodePair& node) const override;
-    bool isPresenceContainer(const path_& location, const ModuleNodePair& node) const override;
-    bool leafEnumHasValue(const path_& location, const ModuleNodePair& node, const std::string& value) const override;
-    bool listHasKey(const path_& location, const ModuleNodePair& node, const std::string& key) const override;
+    bool isContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool isModule(const schemaPath_& location, const std::string& name) const override;
+    bool isLeaf(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool isList(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const override;
+    bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const override;
     bool nodeExists(const std::string& location, const std::string& node) const override;
-    const std::set<std::string> listKeys(const path_& location, const ModuleNodePair& node) const override;
-    yang::LeafDataTypes leafType(const path_& location, const ModuleNodePair& node) const override;
-    std::set<std::string> childNodes(const path_& path, const Recursion) const override;
+    const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const override;
+    yang::LeafDataTypes leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
+    std::set<std::string> childNodes(const schemaPath_& path, const Recursion) const override;
 
     void addContainer(const std::string& location, const std::string& name, yang::ContainerTraits isPresence = yang::ContainerTraits::None);
     void addLeaf(const std::string& location, const std::string& name, const yang::LeafDataTypes& type);
diff --git a/src/utils.cpp b/src/utils.cpp
index eb48349..f9eae06 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -26,9 +26,9 @@
     return res;
 }
 
-path_ pathWithoutLastNode(const path_& path)
+schemaPath_ pathWithoutLastNode(const schemaPath_& path)
 {
-    return path_{path.m_scope, decltype(path_::m_nodes)(path.m_nodes.begin(), path.m_nodes.end() - 1)};
+    return schemaPath_{path.m_scope, decltype(schemaPath_::m_nodes)(path.m_nodes.begin(), path.m_nodes.end() - 1)};
 }
 
 std::string leafDataTypeToString(yang::LeafDataTypes type)
@@ -51,7 +51,7 @@
     }
 }
 
-std::string fullNodeName(const path_& location, const ModuleNodePair& pair)
+std::string fullNodeName(const schemaPath_& location, const ModuleNodePair& pair)
 {
     if (!pair.first) {
         return location.m_nodes.at(0).m_prefix.value().m_name + ":" + pair.second;
@@ -59,3 +59,8 @@
         return pair.first.value() + ":" + pair.second;
     }
 }
+
+std::string fullNodeName(const dataPath_& location, const ModuleNodePair& pair)
+{
+    return fullNodeName(dataPathToSchemaPath(location), pair);
+}
diff --git a/src/utils.hpp b/src/utils.hpp
index 49b5b29..f009ccd 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -11,6 +11,8 @@
 
 std::string joinPaths(const std::string& prefix, const std::string& suffix);
 std::string stripLastNodeFromPath(const std::string& path);
-path_ pathWithoutLastNode(const path_& path);
+schemaPath_ pathWithoutLastNode(const schemaPath_& path);
+dataPath_ pathWithoutLastNode(const dataPath_& path);
 std::string leafDataTypeToString(yang::LeafDataTypes type);
-std::string fullNodeName(const path_& location, const ModuleNodePair& pair);
+std::string fullNodeName(const schemaPath_& location, const ModuleNodePair& pair);
+std::string fullNodeName(const dataPath_& location, const ModuleNodePair& pair);
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 7127082..522e58a 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -30,7 +30,8 @@
     ~InvalidSchemaQueryException() override = default;
 };
 
-std::string pathToYangAbsSchemPath(const path_& path)
+template <typename T>
+std::string pathToYangAbsSchemPath(const T& path)
 {
     std::string res = "/";
     std::string currentModule;
@@ -78,38 +79,38 @@
     }
 }
 
-bool YangSchema::isModule(const path_&, const std::string& name) const
+bool YangSchema::isModule(const schemaPath_&, const std::string& name) const
 {
     const auto set = modules();
     return set.find(name) != set.end();
 }
 
-bool YangSchema::isContainer(const path_& location, const ModuleNodePair& node) const
+bool YangSchema::isContainer(const schemaPath_& location, const ModuleNodePair& node) const
 {
     const auto schemaNode = getSchemaNode(location, node);
     return schemaNode && schemaNode->nodetype() == LYS_CONTAINER;
 }
 
-bool YangSchema::isLeaf(const path_& location, const ModuleNodePair& node) const
+bool YangSchema::isLeaf(const schemaPath_& location, const ModuleNodePair& node) const
 {
     const auto schemaNode = getSchemaNode(location, node);
     return schemaNode && schemaNode->nodetype() == LYS_LEAF;
 }
 
-bool YangSchema::isList(const path_& location, const ModuleNodePair& node) const
+bool YangSchema::isList(const schemaPath_& location, const ModuleNodePair& node) const
 {
     const auto schemaNode = getSchemaNode(location, node);
     return schemaNode && schemaNode->nodetype() == LYS_LIST;
 }
 
-bool YangSchema::isPresenceContainer(const path_& location, const ModuleNodePair& node) const
+bool YangSchema::isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const
 {
     if (!isContainer(location, node))
         return false;
     return libyang::Schema_Node_Container(getSchemaNode(location, node)).presence();
 }
 
-bool YangSchema::leafEnumHasValue(const path_& location, const ModuleNodePair& node, const std::string& value) const
+bool YangSchema::leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const
 {
     if (!isLeaf(location, node) || leafType(location, node) != yang::LeafDataTypes::Enum)
         return false;
@@ -128,7 +129,7 @@
     return std::any_of(enm.begin(), enm.end(), [=](const auto& x) { return x->name() == value; });
 }
 
-bool YangSchema::listHasKey(const path_& location, const ModuleNodePair& node, const std::string& key) const
+bool YangSchema::listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const
 {
     if (!isList(location, node))
         return false;
@@ -143,14 +144,14 @@
     return set->number() == 1;
 }
 
-libyang::S_Set YangSchema::getNodeSet(const path_& location, const ModuleNodePair& node) const
+libyang::S_Set YangSchema::getNodeSet(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::string absPath = location.m_nodes.empty() ? "" : "/";
     absPath += pathToAbsoluteSchemaString(location) + "/" + fullNodeName(location, node);
     return m_context->find_path(absPath.c_str());
 }
 
-libyang::S_Schema_Node YangSchema::getSchemaNode(const path_& location, const ModuleNodePair& node) const
+libyang::S_Schema_Node YangSchema::getSchemaNode(const schemaPath_& location, const ModuleNodePair& node) const
 {
     const auto set = getNodeSet(location, node);
     if (!set)
@@ -161,7 +162,7 @@
     return *schemaSet.begin();
 }
 
-const std::set<std::string> YangSchema::listKeys(const path_& location, const ModuleNodePair& node) const
+const std::set<std::string> YangSchema::listKeys(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::set<std::string> keys;
     if (!isList(location, node))
@@ -174,7 +175,7 @@
     return keys;
 }
 
-yang::LeafDataTypes YangSchema::leafType(const path_& location, const ModuleNodePair& node) const
+yang::LeafDataTypes YangSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
 {
     using namespace std::string_literals;
     if (!isLeaf(location, node))
@@ -210,7 +211,7 @@
     return res;
 }
 
-std::set<std::string> YangSchema::childNodes(const path_& path, const Recursion recursion) const
+std::set<std::string> YangSchema::childNodes(const schemaPath_& path, const Recursion recursion) const
 {
     using namespace std::string_view_literals;
     std::set<std::string> res;
diff --git a/src/yang_schema.hpp b/src/yang_schema.hpp
index c61232f..e4d6d5d 100644
--- a/src/yang_schema.hpp
+++ b/src/yang_schema.hpp
@@ -29,17 +29,17 @@
     YangSchema();
     ~YangSchema() override;
 
-    bool isContainer(const path_& location, const ModuleNodePair& node) const override;
-    bool isLeaf(const path_& location, const ModuleNodePair& node) const override;
-    bool isModule(const path_& location, const std::string& name) const override;
-    bool isList(const path_& location, const ModuleNodePair& node) const override;
-    bool isPresenceContainer(const path_& location, const ModuleNodePair& node) const override;
-    bool leafEnumHasValue(const path_& location, const ModuleNodePair& node, const std::string& value) const override;
-    bool listHasKey(const path_& location, const ModuleNodePair& node, const std::string& key) const override;
+    bool isContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool isLeaf(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool isModule(const schemaPath_& location, const std::string& name) const override;
+    bool isList(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool isPresenceContainer(const schemaPath_& location, const ModuleNodePair& node) const override;
+    bool leafEnumHasValue(const schemaPath_& location, const ModuleNodePair& node, const std::string& value) const override;
+    bool listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const override;
     bool nodeExists(const std::string& location, const std::string& node) const override;
-    const std::set<std::string> listKeys(const path_& location, const ModuleNodePair& node) const override;
-    yang::LeafDataTypes leafType(const path_& location, const ModuleNodePair& node) const override;
-    std::set<std::string> childNodes(const path_& path, const Recursion recursion) const override;
+    const std::set<std::string> listKeys(const schemaPath_& location, const ModuleNodePair& node) const override;
+    yang::LeafDataTypes leafType(const schemaPath_& location, const ModuleNodePair& node) const override;
+    std::set<std::string> childNodes(const schemaPath_& path, const Recursion recursion) const override;
 
     void registerModuleCallback(const std::function<std::string(const char*, const char*, const char*)>& clb);
 
@@ -57,12 +57,12 @@
 
 private:
     std::set<std::string> modules() const;
-    bool nodeExists(const path_& location, const ModuleNodePair& node) const;
+    bool nodeExists(const schemaPath_& location, const ModuleNodePair& node) const;
 
     /** @short Returns a set of nodes, that match the location and name criteria. */
-    std::shared_ptr<libyang::Set> getNodeSet(const path_& location, const ModuleNodePair& node) const;
+    std::shared_ptr<libyang::Set> getNodeSet(const schemaPath_& location, const ModuleNodePair& node) const;
 
     /** @short Returns a single Schema_Node if the criteria matches only one, otherwise nullptr. */
-    std::shared_ptr<libyang::Schema_Node> getSchemaNode(const path_& location, const ModuleNodePair& node) const;
+    std::shared_ptr<libyang::Schema_Node> getSchemaNode(const schemaPath_& location, const ModuleNodePair& node) const;
     std::shared_ptr<libyang::Context> m_context;
 };
diff --git a/tests/cd.cpp b/tests/cd.cpp
index ffa4bbf..85ea794 100644
--- a/tests/cd.cpp
+++ b/tests/cd.cpp
@@ -40,40 +40,40 @@
             SECTION("example:a")
             {
                 input = "cd example:a";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
             }
 
             SECTION("second:a")
             {
                 input = "cd second:a";
-                expected.m_path.m_nodes.push_back(node_(module_{"second"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"second"}, container_("a")));
             }
 
             SECTION("example:b")
             {
                 input = "cd example:b";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("b")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("b")));
             }
 
             SECTION("example:a/a2")
             {
                 input = "cd example:a/a2";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
-                expected.m_path.m_nodes.push_back(node_(container_("a2")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(container_("a2")));
             }
 
             SECTION("example:a/example:a2")
             {
                 input = "cd example:a/example:a2";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a2")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a2")));
             }
 
             SECTION("example:b/b2")
             {
                 input = "cd example:b/b2";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("b")));
-                expected.m_path.m_nodes.push_back(node_(container_("b2")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("b")));
+                expected.m_path.m_nodes.push_back(dataNode_(container_("b2")));
             }
         }
 
@@ -84,7 +84,7 @@
                 input = "cd example:list[number=1]";
                 auto keys = std::map<std::string, std::string>{
                     {"number", "1"}};
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, listElement_("list", keys)));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, listElement_("list", keys)));
             }
 
             SECTION("example:list[number=1]/contInList")
@@ -92,8 +92,8 @@
                 input = "cd example:list[number=1]/contInList";
                 auto keys = std::map<std::string, std::string>{
                     {"number", "1"}};
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, listElement_("list", keys)));
-                expected.m_path.m_nodes.push_back(node_(container_("contInList")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, listElement_("list", keys)));
+                expected.m_path.m_nodes.push_back(dataNode_(container_("contInList")));
             }
 
             SECTION("example:twoKeyList[number=4][name='abcd']")
@@ -102,7 +102,7 @@
                 auto keys = std::map<std::string, std::string>{
                     {"number", "4"},
                     {"name", "abcd"}};
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, listElement_("twoKeyList", keys)));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, listElement_("twoKeyList", keys)));
             }
         }
 
@@ -111,7 +111,7 @@
             SECTION("  cd   example:a     ")
             {
                 input = "  cd   example:a     ";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
             }
         }
 
@@ -120,25 +120,25 @@
             SECTION("example:a/..")
             {
                 input = "cd example:a/..";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
-                expected.m_path.m_nodes.push_back(node_(nodeup_()));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(nodeup_()));
             }
 
             SECTION("example:a/../example:a")
             {
                 input = "cd example:a/../example:a";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
-                expected.m_path.m_nodes.push_back(node_(nodeup_()));
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(nodeup_()));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
             }
 
             SECTION("example:a/../example:a/a2")
             {
                 input = "cd example:a/../example:a/a2";
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
-                expected.m_path.m_nodes.push_back(node_(nodeup_()));
-                expected.m_path.m_nodes.push_back(node_(module_{"example"}, container_("a")));
-                expected.m_path.m_nodes.push_back(node_(container_("a2")));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(nodeup_()));
+                expected.m_path.m_nodes.push_back(dataNode_(module_{"example"}, container_("a")));
+                expected.m_path.m_nodes.push_back(dataNode_(container_("a2")));
             }
         }
 
diff --git a/tests/leaf_editing.cpp b/tests/leaf_editing.cpp
index a0eeed3..757a617 100644
--- a/tests/leaf_editing.cpp
+++ b/tests/leaf_editing.cpp
@@ -36,15 +36,15 @@
         SECTION("set leafString some_data")
         {
             input = "set mod:leafString some_data";
-            expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafString")});
+            expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("leafString")});
             expected.m_data = std::string("some_data");
         }
 
         SECTION("set mod:contA/leafInCont more_data")
         {
             input = "set mod:contA/leafInCont more_data";
-            expected.m_path.m_nodes.push_back(node_{module_{"mod"}, container_("contA")});
-            expected.m_path.m_nodes.push_back(node_{leaf_("leafInCont")});
+            expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, container_("contA")});
+            expected.m_path.m_nodes.push_back(dataNode_{leaf_("leafInCont")});
             expected.m_data = std::string("more_data");
         }
 
@@ -53,8 +53,8 @@
             input = "set mod:list[number=1]/leafInList another_data";
             auto keys = std::map<std::string, std::string>{
                 {"number", "1"}};
-            expected.m_path.m_nodes.push_back(node_{module_{"mod"}, listElement_("list", keys)});
-            expected.m_path.m_nodes.push_back(node_{leaf_("leafInList")});
+            expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, listElement_("list", keys)});
+            expected.m_path.m_nodes.push_back(dataNode_{leaf_("leafInList")});
             expected.m_data = std::string("another_data");
         }
 
@@ -63,35 +63,35 @@
             SECTION("string")
             {
                 input = "set mod:leafString somedata";
-                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafString")});
+                expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("leafString")});
                 expected.m_data = std::string("somedata");
             }
 
             SECTION("int")
             {
                 input = "set mod:leafInt 2";
-                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafInt")});
+                expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("leafInt")});
                 expected.m_data = 2;
             }
 
             SECTION("decimal")
             {
                 input = "set mod:leafDecimal 3.14159";
-                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafDecimal")});
+                expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("leafDecimal")});
                 expected.m_data = 3.14159;
             }
 
             SECTION("enum")
             {
                 input = "set mod:leafEnum coze";
-                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafEnum")});
+                expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("leafEnum")});
                 expected.m_data = enum_("coze");
             }
 
             SECTION("bool")
             {
                 input = "set mod:leafBool true";
-                expected.m_path.m_nodes.push_back(node_{module_{"mod"}, leaf_("leafBool")});
+                expected.m_path.m_nodes.push_back(dataNode_{module_{"mod"}, leaf_("leafBool")});
                 expected.m_data = true;
             }
         }
diff --git a/tests/ls.cpp b/tests/ls.cpp
index 47d28ed..e42152d 100644
--- a/tests/ls.cpp
+++ b/tests/ls.cpp
@@ -17,6 +17,7 @@
     schema->addModule("example");
     schema->addModule("second");
     schema->addContainer("", "example:a");
+    schema->addList("example:a", "example:listInCont", {"number"});
     schema->addContainer("", "second:a");
     schema->addContainer("", "example:b");
     schema->addContainer("example:a", "example:a2");
@@ -51,81 +52,103 @@
             SECTION("ls example:a")
             {
                 input = "ls example:a";
-                expected.m_path = path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}};
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}};
             }
 
             SECTION("ls /example:a")
             {
                 SECTION("cwd: /") {}
-                SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+                SECTION("cwd: /example:a") {parser.changeNode(dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}});}
 
                 input = "ls /example:a";
-                expected.m_path = path_{Scope::Absolute, {node_(module_{"example"}, container_{"a"})}};
+                expected.m_path = dataPath_{Scope::Absolute, {dataNode_(module_{"example"}, container_{"a"})}};
             }
 
             SECTION("ls /")
             {
                 SECTION("cwd: /") {}
-                SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+                SECTION("cwd: /example:a") {parser.changeNode(dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}});}
                 input = "ls /";
-                expected.m_path = path_{Scope::Absolute, {}};
+                expected.m_path = dataPath_{Scope::Absolute, {}};
             }
 
             SECTION("ls example:a/a2")
             {
                 input = "ls example:a/a2";
-                expected.m_path = path_{Scope::Relative, {node_(module_{"example"}, container_{"a"}),
-                                                          node_(container_{"a2"})}};
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"}),
+                                                          dataNode_(container_{"a2"})}};
             }
 
             SECTION("ls a2")
             {
-                parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});
+                parser.changeNode(dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}});
                 input = "ls a2";
-                expected.m_path = path_{Scope::Relative, {node_(container_{"a2"})}};
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(container_{"a2"})}};
             }
 
             SECTION("ls /example:a/a2")
             {
                 SECTION("cwd: /") {}
-                SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+                SECTION("cwd: /example:a") {parser.changeNode(dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}});}
                 input = "ls /example:a/a2";
-                expected.m_path = path_{Scope::Absolute, {node_(module_{"example"}, container_{"a"}),
-                                                          node_(container_{"a2"})}};
+                expected.m_path = dataPath_{Scope::Absolute, {dataNode_(module_{"example"}, container_{"a"}),
+                                                          dataNode_(container_{"a2"})}};
             }
 
             SECTION("ls example:a/example:a2")
             {
                 input = "ls example:a/example:a2";
-                expected.m_path = path_{Scope::Relative, {node_(module_{"example"}, container_{"a"}),
-                                                          node_(module_{"example"}, container_{"a2"})}};
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"}),
+                                                          dataNode_(module_{"example"}, container_{"a2"})}};
             }
 
             SECTION("ls example:a2")
             {
-                parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});
+                parser.changeNode(dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}});
                 input = "ls example:a2";
-                expected.m_path = path_{Scope::Relative, {node_(module_{"example"}, container_{"a2"})}};
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a2"})}};
             }
 
             SECTION("ls /example:a/example:a2")
             {
                 SECTION("cwd: /") {}
-                SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+                SECTION("cwd: /example:a") {parser.changeNode(dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}});}
 
                 input = "ls /example:a/example:a2";
-                expected.m_path = path_{Scope::Absolute, {node_(module_{"example"}, container_{"a"}),
-                                                          node_(module_{"example"}, container_{"a2"})}};
+                expected.m_path = dataPath_{Scope::Absolute, {dataNode_(module_{"example"}, container_{"a"}),
+                                                          dataNode_(module_{"example"}, container_{"a2"})}};
             }
 
             SECTION("ls --recursive /example:a")
             {
                 SECTION("cwd: /") {}
-                SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+                SECTION("cwd: /example:a") {parser.changeNode(dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"})}});}
 
                 input = "ls --recursive /example:a";
                 expected.m_options.push_back(LsOption::Recursive);
-                expected.m_path = path_{Scope::Absolute, {node_(module_{"example"}, container_{"a"})}};
+                expected.m_path = dataPath_{Scope::Absolute, {dataNode_(module_{"example"}, container_{"a"})}};
+            }
+
+            SECTION("ls example:list")
+            {
+                input = "ls example:list";
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(module_{"example"}, list_{"list"})}};
+            }
+
+            SECTION("ls example:a/example:listInCont")
+            {
+                input = "ls example:a/example:listInCont";
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(module_{"example"}, container_{"a"}),
+                                                                dataNode_(module_{"example"}, list_{"listInCont"})}};
+            }
+
+            SECTION("ls example:list[number=342]/contInList")
+            {
+                input = "ls example:list[number=342]/contInList";
+                auto keys = std::map<std::string, std::string>{
+                    {"number", "342"}};
+                expected.m_path = dataPath_{Scope::Relative, {dataNode_(module_{"example"}, listElement_{"list", keys}),
+                                                                dataNode_(container_{"contInList"})}};
             }
         }
 
diff --git a/tests/presence_containers.cpp b/tests/presence_containers.cpp
index 5a43ce9..6872d1b 100644
--- a/tests/presence_containers.cpp
+++ b/tests/presence_containers.cpp
@@ -29,7 +29,7 @@
 
     SECTION("valid input")
     {
-        path_ expectedPath;
+        dataPath_ expectedPath;
 
         SECTION("mod:a")
         {
diff --git a/tests/yang.cpp b/tests/yang.cpp
index dc2286d..76b3c15 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -124,7 +124,7 @@
 {
     YangSchema ys;
     ys.addSchemaString(schema);
-    path_ path;
+    schemaPath_ path;
     ModuleNodePair node;
 
     SECTION("positive")
@@ -139,7 +139,7 @@
 
             SECTION("example-schema:a/a2")
             {
-                path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a")));
+                path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
                 node.second = "a2";
             }
 
@@ -155,7 +155,7 @@
 
             SECTION("example-schema:a/leafa")
             {
-                path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a")));
+                path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
                 node.first = "example-schema";
                 node.second = "leafa";
             }
@@ -186,8 +186,8 @@
         {
             SECTION("example-schema:a/a2/a3")
             {
-                path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a")));
-                path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a2")));
+                path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
+                path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a2")));
                 node.second = "a3";
             }
 
@@ -359,7 +359,7 @@
 
             SECTION("a")
             {
-                path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a")));
+                path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
                 set = {"example-schema:a2", "example-schema:leafa"};
             }
 
@@ -379,13 +379,13 @@
 
             SECTION("example-schema:a/nevim")
             {
-                path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a")));
+                path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
                 node.second = "nevim";
             }
 
             SECTION("modul:a/nevim")
             {
-                path.m_nodes.push_back(node_(module_{"modul"}, container_("a")));
+                path.m_nodes.push_back(schemaNode_(module_{"modul"}, container_("a")));
                 node.second = "nevim";
             }
 
@@ -405,7 +405,7 @@
 
             SECTION("example-schema:a/a2")
             {
-                path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a")));
+                path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
                 node.second = "a2";
             }
 
@@ -416,7 +416,7 @@
 
         SECTION("nodetype-specific methods called with different nodetypes")
         {
-            path.m_nodes.push_back(node_(module_{"example-schema"}, container_("a")));
+            path.m_nodes.push_back(schemaNode_(module_{"example-schema"}, container_("a")));
             node.second = "a2";
 
             REQUIRE(!ys.leafEnumHasValue(path, node, "haha"));