alternative.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM)
  7. #define BOOST_SPIRIT_X3_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM
  8. #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
  9. #include <boost/spirit/home/x3/support/traits/pseudo_attribute.hpp>
  10. #include <boost/spirit/home/x3/support/traits/is_variant.hpp>
  11. #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp>
  12. #include <boost/spirit/home/x3/support/traits/move_to.hpp>
  13. #include <boost/spirit/home/x3/support/traits/variant_has_substitute.hpp>
  14. #include <boost/spirit/home/x3/support/traits/variant_find_substitute.hpp>
  15. #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
  16. #include <boost/mpl/if.hpp>
  17. #include <boost/fusion/include/front.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. #include <type_traits>
  20. namespace boost { namespace spirit { namespace x3
  21. {
  22. template <typename Left, typename Right>
  23. struct alternative;
  24. }}}
  25. namespace boost { namespace spirit { namespace x3 { namespace detail
  26. {
  27. struct pass_variant_unused
  28. {
  29. typedef unused_type type;
  30. template <typename T>
  31. static unused_type
  32. call(T&)
  33. {
  34. return unused_type();
  35. }
  36. };
  37. template <typename Attribute>
  38. struct pass_variant_used
  39. {
  40. typedef Attribute& type;
  41. static Attribute&
  42. call(Attribute& v)
  43. {
  44. return v;
  45. }
  46. };
  47. template <>
  48. struct pass_variant_used<unused_type> : pass_variant_unused {};
  49. template <typename Parser, typename Attribute, typename Context
  50. , typename Enable = void>
  51. struct pass_parser_attribute
  52. {
  53. typedef typename
  54. traits::attribute_of<Parser, Context>::type
  55. attribute_type;
  56. typedef typename
  57. traits::variant_find_substitute<Attribute, attribute_type>::type
  58. substitute_type;
  59. typedef typename
  60. mpl::if_<
  61. is_same<Attribute, substitute_type>
  62. , Attribute&
  63. , substitute_type
  64. >::type
  65. type;
  66. template <typename Attribute_>
  67. static Attribute_&
  68. call(Attribute_& attribute, mpl::true_)
  69. {
  70. return attribute;
  71. }
  72. template <typename Attribute_>
  73. static type
  74. call(Attribute_&, mpl::false_)
  75. {
  76. return type();
  77. }
  78. template <typename Attribute_>
  79. static type
  80. call(Attribute_& attribute)
  81. {
  82. return call(attribute, is_same<Attribute_, typename remove_reference<type>::type>());
  83. }
  84. };
  85. // Pass non-variant attributes as-is
  86. template <typename Parser, typename Attribute, typename Context
  87. , typename Enable = void>
  88. struct pass_non_variant_attribute
  89. {
  90. typedef Attribute& type;
  91. static Attribute&
  92. call(Attribute& attribute)
  93. {
  94. return attribute;
  95. }
  96. };
  97. // Unwrap single element sequences
  98. template <typename Parser, typename Attribute, typename Context>
  99. struct pass_non_variant_attribute<Parser, Attribute, Context,
  100. typename enable_if<traits::is_size_one_sequence<Attribute>>::type>
  101. {
  102. typedef typename remove_reference<
  103. typename fusion::result_of::front<Attribute>::type>::type
  104. attr_type;
  105. typedef pass_parser_attribute<Parser, attr_type, Context> pass;
  106. typedef typename pass::type type;
  107. template <typename Attribute_>
  108. static type
  109. call(Attribute_& attr)
  110. {
  111. return pass::call(fusion::front(attr));
  112. }
  113. };
  114. template <typename Parser, typename Attribute, typename Context>
  115. struct pass_parser_attribute<Parser, Attribute, Context,
  116. typename enable_if_c<(!traits::is_variant<Attribute>::value)>::type>
  117. : pass_non_variant_attribute<Parser, Attribute, Context>
  118. {};
  119. template <typename Parser, typename Context>
  120. struct pass_parser_attribute<Parser, unused_type, Context>
  121. : pass_variant_unused {};
  122. template <typename Parser, typename Attribute, typename Context>
  123. struct pass_variant_attribute :
  124. mpl::if_c<traits::has_attribute<Parser, Context>::value
  125. , pass_parser_attribute<Parser, Attribute, Context>
  126. , pass_variant_unused>::type
  127. {
  128. };
  129. template <typename L, typename R, typename Attribute, typename Context>
  130. struct pass_variant_attribute<alternative<L, R>, Attribute, Context> :
  131. mpl::if_c<traits::has_attribute<alternative<L, R>, Context>::value
  132. , pass_variant_used<Attribute>
  133. , pass_variant_unused>::type
  134. {
  135. };
  136. template <bool Condition>
  137. struct move_if
  138. {
  139. template<typename T1, typename T2>
  140. static void call(T1& /* attr_ */, T2& /* attr */) {}
  141. };
  142. template <>
  143. struct move_if<true>
  144. {
  145. template<typename T1, typename T2>
  146. static void call(T1& attr_, T2& attribute)
  147. {
  148. traits::move_to(attr_, attribute);
  149. }
  150. };
  151. template <typename Parser, typename Iterator, typename Context
  152. , typename RContext, typename Attribute>
  153. bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last
  154. , Context const& context, RContext& rcontext, Attribute& attribute)
  155. {
  156. using pass = detail::pass_variant_attribute<Parser, Attribute, Context>;
  157. using pseudo = traits::pseudo_attribute<Context, typename pass::type, Iterator>;
  158. typename pseudo::type attr_ = pseudo::call(first, last, pass::call(attribute));
  159. if (p.parse(first, last, context, rcontext, attr_))
  160. {
  161. move_if<!std::is_reference<decltype(attr_)>::value>::call(attr_, attribute);
  162. return true;
  163. }
  164. return false;
  165. }
  166. template <typename Subject>
  167. struct alternative_helper : unary_parser<Subject, alternative_helper<Subject>>
  168. {
  169. static bool const is_pass_through_unary = true;
  170. using unary_parser<Subject, alternative_helper<Subject>>::unary_parser;
  171. template <typename Iterator, typename Context
  172. , typename RContext, typename Attribute>
  173. bool parse(Iterator& first, Iterator const& last
  174. , Context const& context, RContext& rcontext, Attribute& attr) const
  175. {
  176. return detail::parse_alternative(this->subject, first, last, context, rcontext, attr);
  177. }
  178. };
  179. template <typename Left, typename Right, typename Context, typename RContext>
  180. struct parse_into_container_impl<alternative<Left, Right>, Context, RContext>
  181. {
  182. typedef alternative<Left, Right> parser_type;
  183. template <typename Iterator, typename Attribute>
  184. static bool call(
  185. parser_type const& parser
  186. , Iterator& first, Iterator const& last
  187. , Context const& context, RContext& rcontext, Attribute& attribute, mpl::false_)
  188. {
  189. return detail::parse_into_container(parser.left, first, last, context, rcontext, attribute)
  190. || detail::parse_into_container(parser.right, first, last, context, rcontext, attribute);
  191. }
  192. template <typename Iterator, typename Attribute>
  193. static bool call(
  194. parser_type const& parser
  195. , Iterator& first, Iterator const& last
  196. , Context const& context, RContext& rcontext, Attribute& attribute, mpl::true_)
  197. {
  198. return detail::parse_into_container(alternative_helper<Left>{parser.left}, first, last, context, rcontext, attribute)
  199. || detail::parse_into_container(alternative_helper<Right>{parser.right}, first, last, context, rcontext, attribute);
  200. }
  201. template <typename Iterator, typename Attribute>
  202. static bool call(
  203. parser_type const& parser
  204. , Iterator& first, Iterator const& last
  205. , Context const& context, RContext& rcontext, Attribute& attribute)
  206. {
  207. return call(parser, first, last, context, rcontext, attribute,
  208. typename traits::is_variant<typename traits::container_value<Attribute>::type>::type{});
  209. }
  210. };
  211. }}}}
  212. #endif