123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- #include <boost/detail/lightweight_test.hpp>
- #include <boost/spirit/home/x3.hpp>
- #include <boost/fusion/include/vector.hpp>
- #include <boost/fusion/include/make_vector.hpp>
- #include <boost/fusion/include/equal_to.hpp>
- #include <boost/type_traits/is_same.hpp>
- #include <boost/optional.hpp>
- #include <string>
- namespace x3 = boost::spirit::x3;
- // just an `attr` with added type checker
- template <typename Value, typename Expected>
- struct checked_attr_parser : x3::attr_parser<Value>
- {
- using base_t = x3::attr_parser<Value>;
- checked_attr_parser(Value const& value) : base_t(value) {}
- checked_attr_parser(Value&& value) : base_t(std::move(value)) {}
- template <typename Iterator, typename Context
- , typename RuleContext, typename Attribute>
- bool parse(Iterator& first, Iterator const& last
- , Context const& ctx, RuleContext& rctx, Attribute& attr_) const
- {
- static_assert(boost::is_same<Expected, Attribute>::value,
- "attribute type check failed");
- return base_t::parse(first, last, ctx, rctx, attr_);
- }
- };
- template <typename Expected, typename Value>
- static inline checked_attr_parser<boost::decay_t<Value>, Expected>
- checked_attr(Value&& value) { return { std::forward<Value>(value) }; }
- // instantiate our type checker
- // (checks attribute value just to be sure we are ok)
- template <typename Value, typename Expr>
- static void test_expr(Value const& v, Expr&& expr)
- {
- char const* it = "";
- Value r;
- BOOST_TEST((x3::parse(it, it, std::forward<Expr>(expr), r)));
- BOOST_TEST((r == v));
- }
- template <typename Expr, typename Attribute>
- static void gen_sequence(Attribute const& attribute, Expr&& expr)
- {
- test_expr(attribute, expr);
- test_expr(attribute, expr >> x3::eps);
- }
- template <typename Expected, typename... ExpectedTail, typename Attribute, typename Expr, typename Value, typename... Tail>
- static void gen_sequence(Attribute const& attribute, Expr&& expr, Value const& v, Tail const&... tail)
- {
- gen_sequence<ExpectedTail...>(attribute, expr >> checked_attr<Expected>(v), tail...);
- gen_sequence<ExpectedTail...>(attribute, expr >> x3::eps >> checked_attr<Expected>(v), tail...);
- gen_sequence<ExpectedTail...>(attribute, expr >> (x3::eps >> checked_attr<Expected>(v)), tail...);
- }
- template <typename Expected, typename... ExpectedTail, typename Attribute, typename Value, typename... Tail>
- static void gen_sequence_tests(Attribute const& attribute, Value const& v, Tail const&... tail)
- {
- gen_sequence<ExpectedTail...>(attribute, checked_attr<Expected>(v), tail...);
- gen_sequence<ExpectedTail...>(attribute, x3::eps >> checked_attr<Expected>(v), tail...);
- }
- template <typename Expected, typename Value>
- static void gen_single_item_tests(Value const& v)
- {
- Expected attribute(v);
- gen_sequence(attribute, checked_attr<Expected>(v));
- gen_sequence(attribute, x3::eps >> checked_attr<Expected>(v));
- }
- template <typename Expected, typename... ExpectedTail, typename Value, typename... Tail>
- static void gen_single_item_tests(Value const& v, Tail const&... tail)
- {
- gen_single_item_tests<Expected>(v);
- gen_single_item_tests<ExpectedTail...>(tail...);
- }
- template <typename... Expected, typename... Values>
- static void gen_tests(Values const&... values)
- {
- gen_single_item_tests<Expected...>(values...);
- boost::fusion::vector<Expected...> attribute = boost::fusion::make_vector(values...);
- gen_sequence_tests<Expected...>(attribute, values...);
- }
- template <typename... Attributes>
- void make_test(Attributes const&... attrs)
- {
- // I would like to place all of this in a single call
- // but it requires tremendous amount of heap to compile
- gen_tests<Attributes...>(attrs...);
- gen_tests<
- boost::optional<Attributes>...
- , boost::fusion::vector<Attributes>...
- >(attrs..., attrs...);
- gen_tests<
- boost::optional<boost::fusion::vector<Attributes>>...
- , boost::fusion::vector<boost::optional<Attributes>>...
- >(boost::fusion::vector<Attributes>(attrs)..., attrs...);
- }
- int main()
- {
- make_test<int, std::string>(123, "hello");
- return boost::report_errors();
- }
|