Commits

David Mugnai committed 6fb6d8a

slam: using the ExprGrammar::expression inside an XGrammar

  • Participants
  • Parent commits a3ee386
  • Branches f_mixed_grammars

Comments (0)

Files changed (3)

File slam/parser.h

 #include <boost/spirit/include/phoenix_stl.hpp>
 #include <boost/spirit/include/phoenix_operator.hpp>
 
+#include "expr/ast.h"
+#include "expr/parser.h"
 #include "slam/ast.h"
 
 namespace slam { namespace parser {
 
     qi::rule<Iterator, string()> text_content;
 
-    qi::rule<Iterator, std::map<string, string>(), qi::locals<char>> attributes_list;
-    qi::rule<Iterator, std::pair<string, string>()> attribute;
+    qi::rule<Iterator, std::map<string, expr::ast::Node const*>(), qi::locals<char>> attributes_list;
+    qi::rule<Iterator, std::pair<string, expr::ast::Node const*>()> attribute;
     qi::rule<Iterator, string()> attribute_name;
-    qi::rule<Iterator, string()> attribute_value;
+    qi::rule<Iterator, expr::ast::Node const*()> attribute_value;
 
     qi::rule<Iterator, string(), qi::locals<char>> quoted_string;
     qi::rule<Iterator, string()> identifier;
     qi::symbols<char const, char> delimiters;
 
     XSlamGrammar() : XSlamGrammar::base_type(expression) {
+        expr::parser::ExprGrammar<Iterator> expr_grammar;
 
         // html         0 Node1
         //   head       2 Node1->Node2
         node %= (tag >> (qi::eol | qi::eoi));
 
         {
-            using AttrType = boost::optional<std::map<string, string>>;
+            using AttrType = boost::optional<std::map<string, expr::ast::Node const*>>;
             using TextType = boost::optional<string>;
             tag = (identifier >> -attributes_list >> -text_content) [
                 _val = bind([](string const& name, AttrType const& attrs, TextType const& text) -> Tag* {
-                    return new Tag{name, attrs ? *attrs : std::map<string, string>() };
+                    return new Tag{name};//, attrs ? *attrs : std::map<string, string>() };
+                    //return new Tag{name, attrs ? *attrs : std::map<string, string>() };
                 }, _1, qi::_2, qi::_3)
             ];
         }
         ];
         attribute = qi::skip(qi::space)[attribute_name >> "=" >> attribute_value];
         attribute_name = identifier.alias();
-        attribute_value = quoted_string.alias();
+        attribute_value %= qi::skip(qi::space)[expr_grammar.expression];
+        //attribute_value = quoted_string.alias();
 
         quoted_string =
             qi::omit[qi::char_("'\"")[_a = _1]]

File tests/test_slam_parser.cpp

 #include "slam.h"
 #include "gtest/gtest.h"
 #include <boost/spirit/include/qi.hpp>
+#include "tests/utils.h"
 
 namespace qi = boost::spirit::qi;
 
         }
     }
 };
+struct AttributeRuleTest : slam::test::SingleGrammarRuleTest2<XSlamGrammar<string::const_iterator>> {
+};
+TEST_F(AttributeRuleTest, test1) {
+    match(grammar.attribute, "title='hello world'", "hello world");
+}
+/*
 
 struct QuotedStringRuleTest : SingleGrammarRuleTest {
     using RType = string;
     EXPECT_EQ(result->attribs.size(), 1);
     EXPECT_EQ(result->attribs["id"], "42");
 }
+*/

File tests/utils.h

 #pragma once
 #include <string>
 #include <tuple>
+#include <type_traits>
 #include "gtest/gtest.h"
 #include <boost/spirit/include/qi.hpp>
 #include "expr.h"
     }
 };
 
+template<typename TGrammar>
+struct SingleGrammarRuleTest2 : ::testing::Test {
+    TGrammar grammar;
+    expr::context::Context* context;
+
+    struct are_strict_equals : boost::static_visitor<bool>
+    {
+        template<typename T>
+        bool operator()( T const& lhs, T const& rhs ) const {
+            EXPECT_EQ(lhs, rhs);
+            return lhs == rhs;
+        }
+
+        template<typename T, typename U>
+        bool operator()(T const&, U const&) const {
+            ADD_FAILURE() << "cannot compare different types";
+            return false;
+        }
+
+        template<typename T>
+        bool operator()(T const&, expr::types::callable const&) const {
+            ADD_FAILURE() << "callable cannot be compared";
+            return false;
+        }
+
+        template<typename T>
+        bool operator()(expr::types::callable const&, T const&) const {
+            ADD_FAILURE() << "callable cannot be compared";
+            return false;
+        }
+
+        bool operator()(expr::types::callable const&, expr::types::callable const&) const {
+            ADD_FAILURE() << "callable cannot be compared";
+            return false;
+        }
+    };
+
+    virtual void SetUp() {
+        context = new expr::context::Context();
+    }
+    virtual void TearDown() {
+        delete context;
+        context = nullptr;
+    }
+
+    template<typename T, typename std::enable_if<!std::is_same<typename T::skipper_type, boost::spirit::qi::unused_type>::value, int>::type = 0>
+    tuple<bool, typename T::attr_type> parse(string const& input, T rule) {
+        typename T::attr_type result;
+        bool parsed = false;
+
+        namespace qi = boost::spirit::qi;
+        try {
+            parsed = qi::phrase_parse(input.begin(), input.end(), rule, qi::space, result);
+        } catch(qi::expectation_failure<string::const_iterator>& e) {
+            result = typename T::attr_type{};
+        }
+        return make_tuple(parsed, result);
+    }
+
+    template<typename T, typename std::enable_if<std::is_same<typename T::skipper_type, boost::spirit::qi::unused_type>::value, int>::type = 0>
+    tuple<bool, typename T::attr_type> parse(string const& input, T rule) {
+        typename T::attr_type result;
+        bool parsed = false;
+
+        namespace qi = boost::spirit::qi;
+        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);
+    }
+
+    template<typename R, typename T>
+    void match(R const& rule, string const& input, T const& expected_result) {
+        auto parsing_result = this->parse(input, rule);
+        auto success = get<0>(parsing_result);
+        ASSERT_TRUE(success) << " input --> " << input;
+
+        auto node = get<1>(parsing_result);
+        auto value = node->evaluate(*this->context);
+        boost::apply_visitor(are_strict_equals(), value, expected_result);
+    }
+};
 }};