Support absolute paths
Change-Id: Ibe087d2bad0c6c9f1619d8811103415bcb3b4906
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 2953dad..aa37574 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -189,6 +189,15 @@
}
};
+struct absoluteStart_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.m_nodes.clear();
+ }
+};
+
struct path_class {
template <typename Iterator, typename Exception, typename Context>
x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
diff --git a/src/ast_path.hpp b/src/ast_path.hpp
index 029d33f..8827a38 100644
--- a/src/ast_path.hpp
+++ b/src/ast_path.hpp
@@ -68,8 +68,15 @@
bool operator==(const node_& b) const;
};
+enum class Scope
+{
+ Absolute,
+ Relative
+};
+
struct path_ {
bool operator==(const path_& b) const;
+ Scope m_scope = Scope::Relative;
std::vector<node_> m_nodes;
};
@@ -83,4 +90,4 @@
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_nodes)
+BOOST_FUSION_ADAPT_STRUCT(path_, m_scope, m_nodes)
diff --git a/src/grammars.hpp b/src/grammars.hpp
index 06e1bf8..ffe6e8b 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -23,6 +23,7 @@
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<absoluteStart_class, Scope> const absoluteStart = "absoluteStart";
x3::rule<path_class, path_> const path = "path";
x3::rule<leaf_path_class, path_> const leafPath = "leafPath";
@@ -85,8 +86,13 @@
auto const node_def =
-(module) >> x3::expect[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 =
- node % '/';
+ absoluteStart >> x3::attr(decltype(path_::m_nodes)()) >> x3::eoi |
+ -(absoluteStart) >> node % '/';
auto const leafPath_def =
path;
@@ -159,6 +165,7 @@
BOOST_SPIRIT_DEFINE(leaf)
BOOST_SPIRIT_DEFINE(leafPath)
BOOST_SPIRIT_DEFINE(node)
+BOOST_SPIRIT_DEFINE(absoluteStart)
BOOST_SPIRIT_DEFINE(path)
BOOST_SPIRIT_DEFINE(module)
BOOST_SPIRIT_DEFINE(leaf_data)
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index 24c48c4..e3113dd 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -55,7 +55,10 @@
template <typename T>
std::string Interpreter::absolutePathFromCommand(const T& command) const
{
- return joinPaths(m_parser.currentNode(), pathToDataString(command.m_path));
+ if (command.m_path.m_scope == Scope::Absolute)
+ return "/" + pathToDataString(command.m_path);
+ else
+ return joinPaths(m_parser.currentNode(), pathToDataString(command.m_path));
}
Interpreter::Interpreter(Parser& parser, DatastoreAccess& datastore)
diff --git a/src/parser.cpp b/src/parser.cpp
index a3550a6..c56b561 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -41,11 +41,15 @@
void Parser::changeNode(const path_& name)
{
- for (const auto& it : name.m_nodes) {
- if (it.m_suffix.type() == typeid(nodeup_))
- m_curDir.m_nodes.pop_back();
- else
- m_curDir.m_nodes.push_back(it);
+ if (name.m_scope == Scope::Absolute) {
+ m_curDir = name;
+ } else {
+ for (const auto& it : name.m_nodes) {
+ if (it.m_suffix.type() == typeid(nodeup_))
+ m_curDir.m_nodes.pop_back();
+ else
+ m_curDir.m_nodes.push_back(it);
+ }
}
}
diff --git a/src/utils.cpp b/src/utils.cpp
index 9f9fd25..eb48349 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -28,7 +28,7 @@
path_ pathWithoutLastNode(const path_& path)
{
- return path_{decltype(path_::m_nodes)(path.m_nodes.begin(), path.m_nodes.end() - 1)};
+ return path_{path.m_scope, decltype(path_::m_nodes)(path.m_nodes.begin(), path.m_nodes.end() - 1)};
}
std::string leafDataTypeToString(yang::LeafDataTypes type)
diff --git a/tests/ls.cpp b/tests/ls.cpp
index c2cc5fe..9356c69 100644
--- a/tests/ls.cpp
+++ b/tests/ls.cpp
@@ -41,8 +41,75 @@
SECTION("with path argument")
{
- input = "ls example:a";
- expected.m_path = path_{{node_(module_{"example"}, container_{"a"})}};
+ SECTION("ls example:a")
+ {
+ input = "ls example:a";
+ expected.m_path = path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}};
+ }
+
+ SECTION("ls /example:a")
+ {
+ SECTION("cwd: /") {}
+ SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+
+ input = "ls /example:a";
+ expected.m_path = path_{Scope::Absolute, {node_(module_{"example"}, container_{"a"})}};
+ }
+
+ SECTION("ls /")
+ {
+ SECTION("cwd: /") {}
+ SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+ input = "ls /";
+ expected.m_path = path_{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"})}};
+ }
+
+ SECTION("ls a2")
+ {
+ parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});
+ input = "ls a2";
+ expected.m_path = path_{Scope::Relative, {node_(container_{"a2"})}};
+ }
+
+ SECTION("ls /example:a/a2")
+ {
+ SECTION("cwd: /") {}
+ SECTION("cwd: /example:a") {parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});}
+ input = "ls /example:a/a2";
+ expected.m_path = path_{Scope::Absolute, {node_(module_{"example"}, container_{"a"}),
+ node_(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"})}};
+ }
+
+ SECTION("ls example:a2")
+ {
+ parser.changeNode(path_{Scope::Relative, {node_(module_{"example"}, container_{"a"})}});
+ input = "ls example:a2";
+ expected.m_path = path_{Scope::Relative, {node_(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"})}});}
+
+ input = "ls /example:a/example:a2";
+ expected.m_path = path_{Scope::Absolute, {node_(module_{"example"}, container_{"a"}),
+ node_(module_{"example"}, container_{"a2"})}};
+ }
}
command_ command = parser.parseCommand(input, errorStream);
@@ -53,7 +120,20 @@
{
SECTION("invalid path")
{
- input = "ls example:nonexistent";
+ SECTION("ls example:nonexistent")
+ input = "ls example:nonexistent";
+
+ SECTION("ls /example:nonexistent")
+ input = "ls /example:nonexistent";
+
+ SECTION("ls /bad:nonexistent")
+ input = "ls /bad:nonexistent";
+
+ SECTION( "ls example:a/nonexistent")
+ input = "ls example:a/nonexistent";
+
+ SECTION( "ls /example:a/nonexistent")
+ input = "ls /example:a/nonexistent";
}
REQUIRE_THROWS(parser.parseCommand(input, errorStream));