Commits

David Mugnai committed cced286

slam/parser: parser for attributes delimiter fixed

Comments (0)

Files changed (2)

     qi::rule<Iterator, string()> attribute_value;
 
     qi::rule<Iterator, string(), qi::locals<char>> quoted_string;
-    qi::symbols<char const, char const> escape_chars;
     qi::rule<Iterator, string()> identifier;
+    qi::symbols<char const, char const> escape_chars;
+    qi::symbols<char const, char> delimiters;
 
     XSlamGrammar() : XSlamGrammar::base_type(expression) {
 
         // matches at least _r1 spaces -> expose the number of matched spaces
         indent = (qi::repeat(_r1, qi::inf)[qi::blank])[_val = phx::size(_1)];
 
-        attributes_list =
-            qi::omit[qi::char_(" ({[")[_a = _1] | qi::eps[_a = 0]]
-            >> *attribute
-            >> qi::lit(_a);
+        attributes_list = qi::skip(qi::space)[
+            (
+                qi::omit[delimiters[_a = _1]]
+                >> *attribute
+                > qi::omit[qi::char_(_a)]
+            )
+            | *attribute];
         attribute = qi::skip(qi::space)[attribute_name >> "=" >> attribute_value];
         attribute_name = identifier.alias();
         attribute_value = quoted_string.alias();
             >> qi::lexeme[(*(escape_chars | (qi::char_ - qi::char_(_a)) ))]
             >> qi::lit(_a);
 
+        identifier = +qi::alpha >> *qi::alnum;
+
         escape_chars.add
             ("\\a", '\a')
             ("\\b", '\b')
             ("\\\'", '\'')
             ("\\\"", '\"');
 
-        identifier = +qi::alpha >> *qi::alnum;
+        delimiters.add
+            ("(", ')')
+            ("[", ']')
+            ("{", '}');
 
         this->expression.name("expression");
         this->block.name("block");

tests/test_slam_parser.cpp

     template<typename T>
     tuple<bool, typename T::attr_type> parse(string const& input, T rule) {
         typename T::attr_type result;
-        auto parsed = qi::parse(input.begin(), input.end(), rule, result);
+        bool parsed = false;
+        try {
+            parsed = qi::parse(input.begin(), input.end(), rule, result);
+        } catch(qi::expectation_failure<string::const_iterator>& e) {
+            result = typename T::attr_type{};
+        }
         return make_tuple(parsed, result);
     }
 
             auto result = this->parse(get<0>(test), rule);
             auto expected = get<1>(test);
             auto success = get<0>(result);
-            EXPECT_EQ(expected, success);
+            EXPECT_EQ(expected, success) << " input --> " << get<0>(test);
             if(expected && success) {
                 EXPECT_EQ(get<2>(test), get<1>(result));
             }
     std::vector<tuple<string, bool, RType>> tests_list = {
         make_tuple("html", true, RType{"html"}),
         make_tuple("h1", true, RType{"h1"}),
-        make_tuple("1h", false, RType{})
+        make_tuple("1h", false, RType{}),
+        make_tuple("(h", false, RType{})
     };
 };
 TEST_F(IdentifierRuleTest, test) {
 struct AttributesListRuleTest : SingleGrammarRuleTest {
     using RType = std::map<string, string>;
     std::vector<tuple<string, bool, RType>> tests_list = {
+        make_tuple("", true, RType{}),
+        make_tuple("()", true, RType{}),
+        make_tuple("[]", true, RType{}),
+        make_tuple("{}", true, RType{}),
         make_tuple(
-            "class=\"title selected\"", true,
-            RType{{"class", "title selected"}}),
-
+            R"(class="title")", true,
+            RType{{"class", "title"}}),
         make_tuple(
-            "id=\"page\" class=\"title selected\"", true,
-            RType{{"id", "page"}, {"class", "title selected"}}),
-
+            R"(id="page" class="title")", true,
+            RType{{"id", "page"}, {"class", "title"}}),
         make_tuple(
-            "(class=\"title selected\")", true,
-            RType{{"class", "title selected"}}),
-
-        make_tuple("(class=\"title selected\"", false, RType())
+            R"(class='title')", true,
+            RType{{"class", "title"}}),
+        make_tuple(
+            R"(class="title \"quoted\"")", true,
+            RType{{"class", "title \"quoted\""}}),
+        make_tuple(
+            R"((class="title"))", true,
+            RType{{"class", "title"}}),
+        make_tuple(
+            R"([class="title"])", true,
+            RType{{"class", "title"}}),
+        make_tuple(
+            R"({class="title"})", true,
+            RType{{"class", "title"}}),
+        make_tuple(
+            R"(( class = "title" ))", true,
+            RType{{"class", "title"}}),
+        make_tuple(
+            R"((class="title")", false,
+            RType{}),
+        make_tuple(
+            R"([class="title")", false,
+            RType{}),
+        make_tuple(
+            R"({class="title")", false,
+            RType{})
     };
 };
 TEST_F(AttributesListRuleTest, test) {
     run_test(tests_list, grammar.attributes_list);
 }
 
-
 TEST(Parsing, just_one_tag) {
     auto result = static_cast<Tag*>(parse("html"));
     ASSERT_NE(result, nullptr);