attribute_type_check.cpp 4.0 KB

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