rule.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*=============================================================================
  2. Copyright (c) 2001-2014 Joel de Guzman
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. ==============================================================================*/
  6. #if !defined(BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM)
  7. #define BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM
  8. #include <boost/spirit/home/x3/nonterminal/detail/rule.hpp>
  9. #include <boost/type_traits/is_same.hpp>
  10. #include <boost/spirit/home/x3/support/context.hpp>
  11. #include <boost/preprocessor/variadic/to_seq.hpp>
  12. #include <boost/preprocessor/variadic/elem.hpp>
  13. #include <boost/preprocessor/seq/for_each.hpp>
  14. #include <type_traits>
  15. #if !defined(BOOST_SPIRIT_X3_NO_RTTI)
  16. #include <typeinfo>
  17. #endif
  18. namespace boost { namespace spirit { namespace x3
  19. {
  20. // default parse_rule implementation
  21. template <typename ID, typename Iterator
  22. , typename Context, typename ActualAttribute>
  23. inline detail::default_parse_rule_result
  24. parse_rule(
  25. detail::rule_id<ID>
  26. , Iterator& first, Iterator const& last
  27. , Context const& context, ActualAttribute& attr)
  28. {
  29. static_assert(!is_same<decltype(x3::get<ID>(context)), unused_type>::value,
  30. "BOOST_SPIRIT_DEFINE undefined for this rule.");
  31. return x3::get<ID>(context).parse(first, last, context, unused, attr);
  32. }
  33. template <typename ID, typename RHS, typename Attribute, bool force_attribute_, bool skip_definition_injection = false>
  34. struct rule_definition : parser<rule_definition<ID, RHS, Attribute, force_attribute_>>
  35. {
  36. typedef rule_definition<ID, RHS, Attribute, force_attribute_, skip_definition_injection> this_type;
  37. typedef ID id;
  38. typedef RHS rhs_type;
  39. typedef rule<ID, Attribute, force_attribute_> lhs_type;
  40. typedef Attribute attribute_type;
  41. static bool const has_attribute =
  42. !is_same<Attribute, unused_type>::value;
  43. static bool const handles_container =
  44. traits::is_container<Attribute>::value;
  45. static bool const force_attribute =
  46. force_attribute_;
  47. constexpr rule_definition(RHS const& rhs, char const* name)
  48. : rhs(rhs), name(name) {}
  49. template <typename Iterator, typename Context, typename Attribute_>
  50. bool parse(Iterator& first, Iterator const& last
  51. , Context const& context, unused_type, Attribute_& attr) const
  52. {
  53. return detail::rule_parser<attribute_type, ID, skip_definition_injection>
  54. ::call_rule_definition(
  55. rhs, name, first, last
  56. , context
  57. , attr
  58. , mpl::bool_<force_attribute>());
  59. }
  60. RHS rhs;
  61. char const* name;
  62. };
  63. template <typename ID, typename Attribute, bool force_attribute_>
  64. struct rule : parser<rule<ID, Attribute, force_attribute_>>
  65. {
  66. static_assert(!std::is_reference<Attribute>::value,
  67. "Reference qualifier on rule attribute type is meaningless");
  68. typedef ID id;
  69. typedef Attribute attribute_type;
  70. static bool const has_attribute =
  71. !std::is_same<std::remove_const_t<Attribute>, unused_type>::value;
  72. static bool const handles_container =
  73. traits::is_container<Attribute>::value;
  74. static bool const force_attribute = force_attribute_;
  75. #if !defined(BOOST_SPIRIT_X3_NO_RTTI)
  76. rule() : name(typeid(rule).name()) {}
  77. #else
  78. constexpr rule() : name("unnamed") {}
  79. #endif
  80. constexpr rule(char const* name)
  81. : name(name) {}
  82. constexpr rule(rule const& r)
  83. : name(r.name)
  84. {
  85. // Assert that we are not copying an unitialized static rule. If
  86. // the static is in another TU, it may be initialized after we copy
  87. // it. If so, its name member will be nullptr.
  88. BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco
  89. }
  90. template <typename RHS>
  91. constexpr rule_definition<
  92. ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_>
  93. operator=(RHS const& rhs) const&
  94. {
  95. return { as_parser(rhs), name };
  96. }
  97. template <typename RHS>
  98. constexpr rule_definition<
  99. ID, typename extension::as_parser<RHS>::value_type, Attribute, true>
  100. operator%=(RHS const& rhs) const&
  101. {
  102. return { as_parser(rhs), name };
  103. }
  104. // When a rule placeholder constructed and immediately consumed it cannot be used recursively,
  105. // that's why the rule definition injection into a parser context can be skipped.
  106. // This optimization has a huge impact on compile times because immediate rules are commonly
  107. // used to cast an attribute like `as`/`attr_cast` does in Qi.
  108. template <typename RHS>
  109. constexpr rule_definition<
  110. ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_, true>
  111. operator=(RHS const& rhs) const&&
  112. {
  113. return { as_parser(rhs), name };
  114. }
  115. template <typename RHS>
  116. constexpr rule_definition<
  117. ID, typename extension::as_parser<RHS>::value_type, Attribute, true, true>
  118. operator%=(RHS const& rhs) const&&
  119. {
  120. return { as_parser(rhs), name };
  121. }
  122. template <typename Iterator, typename Context, typename Attribute_>
  123. bool parse(Iterator& first, Iterator const& last
  124. , Context const& context, unused_type, Attribute_& attr) const
  125. {
  126. static_assert(has_attribute,
  127. "The rule does not have an attribute. Check your parser.");
  128. using transform = traits::transform_attribute<
  129. Attribute_, attribute_type, parser_id>;
  130. using transform_attr = typename transform::type;
  131. transform_attr attr_ = transform::pre(attr);
  132. if (parse_rule(detail::rule_id<ID>{}, first, last, context, attr_)) {
  133. transform::post(attr, std::forward<transform_attr>(attr_));
  134. return true;
  135. }
  136. return false;
  137. }
  138. template <typename Iterator, typename Context>
  139. bool parse(Iterator& first, Iterator const& last
  140. , Context const& context, unused_type, unused_type) const
  141. {
  142. // make sure we pass exactly the rule attribute type
  143. attribute_type no_attr{};
  144. return parse_rule(detail::rule_id<ID>{}, first, last, context, no_attr);
  145. }
  146. char const* name;
  147. };
  148. namespace traits
  149. {
  150. template <typename T, typename Enable = void>
  151. struct is_rule : mpl::false_ {};
  152. template <typename ID, typename Attribute, bool force_attribute>
  153. struct is_rule<rule<ID, Attribute, force_attribute>> : mpl::true_ {};
  154. template <typename ID, typename Attribute, typename RHS, bool force_attribute, bool skip_definition_injection>
  155. struct is_rule<rule_definition<ID, RHS, Attribute, force_attribute, skip_definition_injection>> : mpl::true_ {};
  156. }
  157. template <typename T>
  158. struct get_info<T, typename enable_if<traits::is_rule<T>>::type>
  159. {
  160. typedef std::string result_type;
  161. std::string operator()(T const& r) const
  162. {
  163. BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco
  164. return r.name? r.name : "uninitialized";
  165. }
  166. };
  167. #define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \
  168. template <typename Iterator, typename Context> \
  169. bool parse_rule( \
  170. ::boost::spirit::x3::detail::rule_id<rule_type::id> \
  171. , Iterator& first, Iterator const& last \
  172. , Context const& context, rule_type::attribute_type& attr); \
  173. /***/
  174. #define BOOST_SPIRIT_DECLARE(...) BOOST_PP_SEQ_FOR_EACH( \
  175. BOOST_SPIRIT_DECLARE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
  176. /***/
  177. #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
  178. #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \
  179. using BOOST_PP_CAT(rule_name, _synonym) = decltype(rule_name); \
  180. template <typename Iterator, typename Context> \
  181. inline bool parse_rule( \
  182. ::boost::spirit::x3::detail::rule_id<BOOST_PP_CAT(rule_name, _synonym)::id> \
  183. , Iterator& first, Iterator const& last \
  184. , Context const& context, BOOST_PP_CAT(rule_name, _synonym)::attribute_type& attr) \
  185. { \
  186. using rule_t = BOOST_JOIN(rule_name, _synonym); \
  187. return ::boost::spirit::x3::detail \
  188. ::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \
  189. ::call_rule_definition( \
  190. BOOST_JOIN(rule_name, _def), rule_name.name \
  191. , first, last, context, attr \
  192. , ::boost::mpl::bool_<rule_t::force_attribute>()); \
  193. } \
  194. /***/
  195. #else
  196. #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \
  197. template <typename Iterator, typename Context> \
  198. inline bool parse_rule( \
  199. ::boost::spirit::x3::detail::rule_id<decltype(rule_name)::id> \
  200. , Iterator& first, Iterator const& last \
  201. , Context const& context, decltype(rule_name)::attribute_type& attr) \
  202. { \
  203. using rule_t = decltype(rule_name); \
  204. return ::boost::spirit::x3::detail \
  205. ::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \
  206. ::call_rule_definition( \
  207. BOOST_JOIN(rule_name, _def), rule_name.name \
  208. , first, last, context, attr \
  209. , ::boost::mpl::bool_<rule_t::force_attribute>()); \
  210. } \
  211. /***/
  212. #endif
  213. #define BOOST_SPIRIT_DEFINE(...) BOOST_PP_SEQ_FOR_EACH( \
  214. BOOST_SPIRIT_DEFINE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
  215. /***/
  216. #define BOOST_SPIRIT_INSTANTIATE(rule_type, Iterator, Context) \
  217. template bool parse_rule<Iterator, Context>( \
  218. ::boost::spirit::x3::detail::rule_id<rule_type::id> \
  219. , Iterator& first, Iterator const& last \
  220. , Context const& context, rule_type::attribute_type&); \
  221. /***/
  222. }}}
  223. #endif