• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <boost/detail/lightweight_test.hpp>
2 #include <boost/spirit/home/x3.hpp>
3 #include <boost/fusion/include/vector.hpp>
4 #include <boost/fusion/include/make_vector.hpp>
5 #include <boost/fusion/include/equal_to.hpp>
6 #include <boost/type_traits/is_same.hpp>
7 #include <boost/optional.hpp>
8 #include <string>
9 
10 namespace x3 = boost::spirit::x3;
11 
12 // just an `attr` with added type checker
13 template <typename Value, typename Expected>
14 struct checked_attr_parser : x3::attr_parser<Value>
15 {
16     using base_t = x3::attr_parser<Value>;
17 
checked_attr_parserchecked_attr_parser18     checked_attr_parser(Value const& value) : base_t(value) {}
checked_attr_parserchecked_attr_parser19     checked_attr_parser(Value&& value) : base_t(std::move(value)) {}
20 
21     template <typename Iterator, typename Context
22       , typename RuleContext, typename Attribute>
parsechecked_attr_parser23     bool parse(Iterator& first, Iterator const& last
24       , Context const& ctx, RuleContext& rctx, Attribute& attr_) const
25     {
26         static_assert(boost::is_same<Expected, Attribute>::value,
27             "attribute type check failed");
28         return base_t::parse(first, last, ctx, rctx, attr_);
29     }
30 };
31 
32 template <typename Expected, typename Value>
33 static inline checked_attr_parser<boost::decay_t<Value>, Expected>
checked_attr(Value && value)34 checked_attr(Value&& value) { return { std::forward<Value>(value) }; }
35 
36 // instantiate our type checker
37 // (checks attribute value just to be sure we are ok)
38 template <typename Value, typename Expr>
test_expr(Value const & v,Expr && expr)39 static void test_expr(Value const& v, Expr&& expr)
40 {
41     char const* it = "";
42     Value r;
43     BOOST_TEST((x3::parse(it, it, std::forward<Expr>(expr), r)));
44     BOOST_TEST((r == v));
45 }
46 
47 template <typename Expr, typename Attribute>
gen_sequence(Attribute const & attribute,Expr && expr)48 static void gen_sequence(Attribute const& attribute, Expr&& expr)
49 {
50     test_expr(attribute, expr);
51     test_expr(attribute, expr >> x3::eps);
52 }
53 
54 template <typename Expected, typename... ExpectedTail, typename Attribute, typename Expr, typename Value, typename... Tail>
gen_sequence(Attribute const & attribute,Expr && expr,Value const & v,Tail const &...tail)55 static void gen_sequence(Attribute const& attribute, Expr&& expr, Value const& v, Tail const&... tail)
56 {
57     gen_sequence<ExpectedTail...>(attribute, expr >> checked_attr<Expected>(v), tail...);
58     gen_sequence<ExpectedTail...>(attribute, expr >> x3::eps >> checked_attr<Expected>(v), tail...);
59     gen_sequence<ExpectedTail...>(attribute, expr >> (x3::eps >> checked_attr<Expected>(v)), tail...);
60 }
61 
62 template <typename Expected, typename... ExpectedTail, typename Attribute, typename Value, typename... Tail>
gen_sequence_tests(Attribute const & attribute,Value const & v,Tail const &...tail)63 static void gen_sequence_tests(Attribute const& attribute, Value const& v, Tail const&... tail)
64 {
65     gen_sequence<ExpectedTail...>(attribute, checked_attr<Expected>(v), tail...);
66     gen_sequence<ExpectedTail...>(attribute, x3::eps >> checked_attr<Expected>(v), tail...);
67 }
68 
69 template <typename Expected, typename Value>
gen_single_item_tests(Value const & v)70 static void gen_single_item_tests(Value const& v)
71 {
72     Expected attribute(v);
73     gen_sequence(attribute, checked_attr<Expected>(v));
74     gen_sequence(attribute, x3::eps >> checked_attr<Expected>(v));
75 }
76 
77 template <typename Expected, typename... ExpectedTail, typename Value, typename... Tail>
gen_single_item_tests(Value const & v,Tail const &...tail)78 static void gen_single_item_tests(Value const& v, Tail const&... tail)
79 {
80     gen_single_item_tests<Expected>(v);
81     gen_single_item_tests<ExpectedTail...>(tail...);
82 }
83 
84 template <typename... Expected, typename... Values>
gen_tests(Values const &...values)85 static void gen_tests(Values const&... values)
86 {
87     gen_single_item_tests<Expected...>(values...);
88 
89     boost::fusion::vector<Expected...> attribute = boost::fusion::make_vector(values...);
90     gen_sequence_tests<Expected...>(attribute, values...);
91 }
92 
93 template <typename... Attributes>
make_test(Attributes const &...attrs)94 void make_test(Attributes const&... attrs)
95 {
96     // I would like to place all of this in a single call
97     // but it requires tremendous amount of heap to compile
98     gen_tests<Attributes...>(attrs...);
99     gen_tests<
100         boost::optional<Attributes>...
101       , boost::fusion::vector<Attributes>...
102     >(attrs..., attrs...);
103     gen_tests<
104         boost::optional<boost::fusion::vector<Attributes>>...
105       , boost::fusion::vector<boost::optional<Attributes>>...
106     >(boost::fusion::vector<Attributes>(attrs)..., attrs...);
107 }
108 
main()109 int main()
110 {
111     make_test<int, std::string>(123, "hello");
112     return boost::report_errors();
113 }
114