Change syntax for multi-key list indexing

List instances are now dereferenced by listing each key-value in
separate brackets. Value can be enclosed either in single quotes or in
double quotes.

Change-Id: Iad72b1002d4655249ecd7bfc7109814b45c7b16b
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 686ae30..580ea86 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -53,6 +53,8 @@
     }
 };
 
+struct key_identifier_class;
+
 struct module_identifier_class;
 
 struct listPrefix_class {
diff --git a/src/grammars.hpp b/src/grammars.hpp
index fddd409..688394e 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -13,6 +13,7 @@
 
 
 x3::rule<keyValue_class, keyValue_> const keyValue = "keyValue";
+x3::rule<key_identifier_class, std::string> const key_identifier = "key_identifier";
 x3::rule<node_identifier_class, std::string> const node_identifier = "node_identifier";
 x3::rule<module_identifier_class, std::string> const module_identifier = "module_identifier";
 x3::rule<listPrefix_class, std::string> const listPrefix = "listPrefix";
@@ -49,8 +50,20 @@
 #pragma GCC diagnostic ignored "-Woverloaded-shift-op-parentheses"
 #endif
 
+auto const key_identifier_def =
+        lexeme[
+                ((alpha | char_("_")) >> *(alnum | char_("_") | char_("-") | char_(".")))
+        ];
+
+auto const quotedValue =
+        ('\'' > +(char_-'\'') > '\'') |
+        ('\"' > +(char_-'\"') > '\"');
+
+auto const number =
+        +x3::digit;
+
 auto const keyValue_def =
-        lexeme[+alnum > '=' > +alnum];
+        lexeme['[' > key_identifier > '=' > (quotedValue | number) > ']'];
 
 auto const module_identifier_def =
         lexeme[
@@ -63,11 +76,11 @@
         ];
 
 auto const listPrefix_def =
-        node_identifier >> '[';
+        node_identifier >> &char_('[');
 
 // even though we don't allow no keys to be supplied, the star allows me to check which keys are missing
 auto const listSuffix_def =
-        *keyValue > ']';
+        *keyValue;
 
 auto const listElement_def =
         listPrefix > listSuffix;
@@ -171,6 +184,7 @@
 #endif
 
 BOOST_SPIRIT_DEFINE(keyValue)
+BOOST_SPIRIT_DEFINE(key_identifier)
 BOOST_SPIRIT_DEFINE(node_identifier)
 BOOST_SPIRIT_DEFINE(module_identifier)
 BOOST_SPIRIT_DEFINE(listPrefix)
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 6f34ad1..57e66e5 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -221,7 +221,7 @@
 
     for (const auto node : nodes) {
         if (node->module()->name() == "ietf-yang-library"sv)
-                continue;
+            continue;
         if (recursion == Recursion::Recursive) {
             for (auto it : node->tree_dfs()) {
                 res.insert(it->path(LYS_PATH_FIRST_PREFIX));
diff --git a/tests/cd.cpp b/tests/cd.cpp
index 5bf0172..bcc1dab 100644
--- a/tests/cd.cpp
+++ b/tests/cd.cpp
@@ -96,9 +96,9 @@
                 expected.m_path.m_nodes.push_back(node_(container_("contInList")));
             }
 
-            SECTION("example:twoKeyList[number=4 name=abcd]")
+            SECTION("example:twoKeyList[number=4][name='abcd']")
             {
-                input = "cd example:twoKeyList[number=4 name=abcd]";
+                input = "cd example:twoKeyList[number=4][name='abcd']";
                 auto keys = std::map<std::string, std::string>{
                     {"number", "4"},
                     {"name", "abcd"}};
@@ -250,25 +250,30 @@
                 input = "cd example:list[]";
             }
 
-            SECTION("example:twoKeyList[invalidKey=4]")
+            SECTION("example:twoKeyList[invalidKey='4']")
             {
-                input = "cd example:twoKeyList[invalidKey=4]";
+                input = "cd example:twoKeyList[invalidKey='4']";
             }
 
-            SECTION("example:twoKeyList[number=4 number=5]")
+            SECTION("example:twoKeyList[number=4][number=5]")
             {
-                input = "cd example:twoKeyList[number=4 number=5]";
+                input = "cd example:twoKeyList[number=4][number=5]";
             }
 
-            SECTION("example:twoKeyList[number=4 name=lol number=7]")
+            SECTION("example:twoKeyList[number=4][name='lol'][number=7]")
             {
-                input = "cd example:twoKeyList[number=4 name=lol number=7]";
+                input = "cd example:twoKeyList[number=4][name='lol'][number=7]";
             }
 
             SECTION("example:twoKeyList[number=4]")
             {
                 input = "cd example:twoKeyList[number=4]";
             }
+
+            SECTION("strings must be quoted")
+            {
+                input = "cd example:twoKeyList[number=4][name=abcd]";
+            }
         }
         REQUIRE_THROWS(parser.parseCommand(input, errorStream));
     }
diff --git a/tests/presence_containers.cpp b/tests/presence_containers.cpp
index 9683daf..20e1d48 100644
--- a/tests/presence_containers.cpp
+++ b/tests/presence_containers.cpp
@@ -49,9 +49,9 @@
             expectedPath.m_nodes = {{{module_{"mod"}}, container_("a")}, {container_("a2")}, {container_("a3")}};
         }
 
-        SECTION("mod:list[quote=lol]/contInList")
+        SECTION("mod:list[quote='lol']/contInList")
         {
-            input = "mod:list[quote=lol]/contInList";
+            input = "mod:list[quote='lol']/contInList";
             auto keys = std::map<std::string, std::string>{
                 {"quote", "lol"}};
             expectedPath.m_nodes = {{{module_{"mod"}}, listElement_("list", keys)}, {container_("contInList")}};
@@ -83,9 +83,9 @@
             input = "a/a2";
         }
 
-        SECTION("list[quote=lol]")
+        SECTION("list[quote='lol']")
         {
-            input = "list[quote=lol]";
+            input = "list[quote='lol']";
         }
 
         REQUIRE_THROWS(parser.parseCommand("create " + input, errorStream));