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

source code of boost/libs/spirit/test/x3/attribute_type_check.cpp