Allow data path to end with a list for get and ls

Change-Id: I3facc8315fa6192da4318012a85121de37e7314b
diff --git a/src/grammars.hpp b/src/grammars.hpp
index 7f76ac7..7caa45c 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -28,6 +28,9 @@
 x3::rule<schemaNode_class, schemaNode_> const schemaNode = "schemaNode";
 x3::rule<absoluteStart_class, Scope> const absoluteStart = "absoluteStart";
 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";
 
@@ -49,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"
@@ -90,7 +95,7 @@
         listPrefix > listSuffix;
 
 auto const list_def =
-        node_identifier;
+        node_identifier >> !char_('[');
 
 auto const nodeup_def =
         lit("..") > x3::attr(nodeup_());
@@ -109,7 +114,7 @@
         -(module) >> x3::expect[container | list | nodeup | leaf];
 
 auto const dataNode_def =
-        -(module) >> x3::expect[container | listElement | nodeup | leaf];
+        -(module) >> (container | listElement | nodeup | leaf);
 
 auto const absoluteStart_def =
         x3::omit['/'] >> x3::attr(Scope::Absolute);
@@ -119,6 +124,21 @@
         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 % '/';
@@ -169,8 +189,12 @@
     }
 } 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 >> dataPath);
+        lit("ls") >> *(space_separator >> ls_options) >> -(space_separator >> (dataPathListEnd | initializeContext >> dataPath));
 
 auto const cd_def =
         lit("cd") >> space_separator > dataPath;
@@ -182,7 +206,7 @@
         lit("delete") >> space_separator > dataPath;
 
 auto const get_def =
-        lit("get") >> -dataPath;
+        lit("get") >> -(space_separator >> (dataPathListEnd | initializeContext >> dataPath));
 
 auto const set_def =
         lit("set") >> space_separator > leafPath > leaf_data;
@@ -216,6 +240,9 @@
 BOOST_SPIRIT_DEFINE(leafPath)
 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(module)
 BOOST_SPIRIT_DEFINE(leaf_data)
@@ -225,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)