alternative.hpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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/variant/variant.hpp>
  17. #include <boost/mpl/copy_if.hpp>
  18. #include <boost/mpl/not.hpp>
  19. #include <boost/mpl/if.hpp>
  20. #include <boost/mpl/insert_range.hpp>
  21. #include <boost/mpl/eval_if.hpp>
  22. #include <boost/mpl/vector.hpp>
  23. #include <boost/fusion/include/front.hpp>
  24. #include <boost/type_traits/is_same.hpp>
  25. namespace boost { namespace spirit { namespace x3
  26. {
  27. template <typename Left, typename Right>
  28. struct alternative;
  29. }}}
  30. namespace boost { namespace spirit { namespace x3 { namespace detail
  31. {
  32. struct pass_variant_unused
  33. {
  34. typedef unused_type type;
  35. template <typename T>
  36. static unused_type
  37. call(T&)
  38. {
  39. return unused_type();
  40. }
  41. };
  42. template <typename Attribute>
  43. struct pass_variant_used
  44. {
  45. typedef Attribute& type;
  46. static Attribute&
  47. call(Attribute& v)
  48. {
  49. return v;
  50. }
  51. };
  52. template <>
  53. struct pass_variant_used<unused_type> : pass_variant_unused {};
  54. template <typename Parser, typename Attribute, typename Context
  55. , typename Enable = void>
  56. struct pass_parser_attribute
  57. {
  58. typedef typename
  59. traits::attribute_of<Parser, Context>::type
  60. attribute_type;
  61. typedef typename
  62. traits::variant_find_substitute<Attribute, attribute_type>::type
  63. substitute_type;
  64. typedef typename
  65. mpl::if_<
  66. is_same<Attribute, substitute_type>
  67. , Attribute&
  68. , substitute_type
  69. >::type
  70. type;
  71. template <typename Attribute_>
  72. static Attribute_&
  73. call(Attribute_& attr, mpl::true_)
  74. {
  75. return attr;
  76. }
  77. template <typename Attribute_>
  78. static type
  79. call(Attribute_&, mpl::false_)
  80. {
  81. return type();
  82. }
  83. template <typename Attribute_>
  84. static type
  85. call(Attribute_& attr)
  86. {
  87. return call(attr, is_same<Attribute_, typename remove_reference<type>::type>());
  88. }
  89. };
  90. // Pass non-variant attributes as-is
  91. template <typename Parser, typename Attribute, typename Context
  92. , typename Enable = void>
  93. struct pass_non_variant_attribute
  94. {
  95. typedef Attribute& type;
  96. static Attribute&
  97. call(Attribute& attr)
  98. {
  99. return attr;
  100. }
  101. };
  102. // Unwrap single element sequences
  103. template <typename Parser, typename Attribute, typename Context>
  104. struct pass_non_variant_attribute<Parser, Attribute, Context,
  105. typename enable_if<traits::is_size_one_sequence<Attribute>>::type>
  106. {
  107. typedef typename remove_reference<
  108. typename fusion::result_of::front<Attribute>::type>::type
  109. attr_type;
  110. typedef pass_parser_attribute<Parser, attr_type, Context> pass;
  111. typedef typename pass::type type;
  112. template <typename Attribute_>
  113. static type
  114. call(Attribute_& attr)
  115. {
  116. return pass::call(fusion::front(attr));
  117. }
  118. };
  119. template <typename Parser, typename Attribute, typename Context>
  120. struct pass_parser_attribute<Parser, Attribute, Context,
  121. typename enable_if_c<(!traits::is_variant<Attribute>::value)>::type>
  122. : pass_non_variant_attribute<Parser, Attribute, Context>
  123. {};
  124. template <typename Parser, typename Context>
  125. struct pass_parser_attribute<Parser, unused_type, Context>
  126. : pass_variant_unused {};
  127. template <typename Parser, typename Attribute, typename Context>
  128. struct pass_variant_attribute :
  129. mpl::if_c<traits::has_attribute<Parser, Context>::value
  130. , pass_parser_attribute<Parser, Attribute, Context>
  131. , pass_variant_unused>::type
  132. {
  133. typedef typename mpl::false_ is_alternative;
  134. };
  135. template <typename L, typename R, typename Attribute, typename Context>
  136. struct pass_variant_attribute<alternative<L, R>, Attribute, Context> :
  137. mpl::if_c<traits::has_attribute<alternative<L, R>, Context>::value
  138. , pass_variant_used<Attribute>
  139. , pass_variant_unused>::type
  140. {
  141. typedef typename mpl::true_ is_alternative;
  142. };
  143. template <typename L, typename R, typename C>
  144. struct get_alternative_types
  145. {
  146. typedef
  147. mpl::vector<
  148. typename traits::attribute_of<L, C>::type
  149. , typename traits::attribute_of<R, C>::type
  150. >
  151. type;
  152. };
  153. template <typename LL, typename LR, typename R, typename C>
  154. struct get_alternative_types<alternative<LL, LR>, R, C>
  155. : mpl::push_back< typename get_alternative_types<LL, LR, C>::type
  156. , typename traits::attribute_of<R, C>::type> {};
  157. template <typename L, typename RL, typename RR, typename C>
  158. struct get_alternative_types<L, alternative<RL, RR>, C>
  159. : mpl::push_front< typename get_alternative_types<RL, RR, C>::type
  160. , typename traits::attribute_of<L, C>::type> {};
  161. template <typename LL, typename LR, typename RL, typename RR, typename C>
  162. struct get_alternative_types<alternative<LL, LR>, alternative<RL, RR>, C>
  163. {
  164. typedef typename get_alternative_types<LL, LR, C>::type left;
  165. typedef typename get_alternative_types<RL, RR, C>::type right;
  166. typedef typename
  167. mpl::insert_range<left, typename mpl::end<left>::type, right>::type
  168. type;
  169. };
  170. template <typename L, typename R, typename C>
  171. struct attribute_of_alternative
  172. {
  173. // Get all alternative attribute types
  174. typedef typename get_alternative_types<L, R, C>::type all_types;
  175. // Filter all unused_types
  176. typedef typename
  177. mpl::copy_if<
  178. all_types
  179. , mpl::not_<is_same<mpl::_1, unused_type>>
  180. , mpl::back_inserter<mpl::vector<>>
  181. >::type
  182. filtered_types;
  183. // Build a variant if filtered_types is not empty,
  184. // else just return unused_type
  185. typedef typename
  186. mpl::eval_if<
  187. mpl::empty<filtered_types>
  188. , mpl::identity<unused_type>
  189. , make_variant_over<filtered_types>
  190. >::type
  191. type;
  192. };
  193. template <typename IsAlternative>
  194. struct move_if_not_alternative
  195. {
  196. template<typename T1, typename T2>
  197. static void call(T1& /* attr_ */, T2& /* attr */) {}
  198. };
  199. template <>
  200. struct move_if_not_alternative<mpl::false_ /*is alternative*/>
  201. {
  202. template<typename T1, typename T2>
  203. static void call(T1& attr_, T2& attr)
  204. {
  205. traits::move_to(attr_, attr);
  206. }
  207. };
  208. template <typename Parser, typename Iterator, typename Context
  209. , typename RContext, typename Attribute>
  210. bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last
  211. , Context const& context, RContext& rcontext, Attribute& attr)
  212. {
  213. using pass = detail::pass_variant_attribute<Parser, Attribute, Context>;
  214. using pseudo = traits::pseudo_attribute<Context, typename pass::type, Iterator>;
  215. typename pseudo::type attr_ = pseudo::call(first, last, pass::call(attr));
  216. if (p.parse(first, last, context, rcontext, attr_))
  217. {
  218. move_if_not_alternative<typename pass::is_alternative>::call(attr_, attr);
  219. return true;
  220. }
  221. return false;
  222. }
  223. template <typename Left, typename Right, typename Context, typename RContext>
  224. struct parse_into_container_impl<alternative<Left, Right>, Context, RContext>
  225. {
  226. typedef alternative<Left, Right> parser_type;
  227. template <typename Iterator, typename Attribute>
  228. static bool call(
  229. parser_type const& parser
  230. , Iterator& first, Iterator const& last
  231. , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
  232. {
  233. return parse_alternative(parser, first, last, context, rcontext, attr);
  234. }
  235. template <typename Iterator, typename Attribute>
  236. static bool call(
  237. parser_type const& parser
  238. , Iterator& first, Iterator const& last
  239. , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
  240. {
  241. return parse_into_container_base_impl<parser_type>::call(
  242. parser, first, last, context, rcontext, attr);
  243. }
  244. template <typename Iterator, typename Attribute>
  245. static bool call(
  246. parser_type const& parser
  247. , Iterator& first, Iterator const& last
  248. , Context const& context, RContext& rcontext, Attribute& attr)
  249. {
  250. typedef typename
  251. traits::attribute_of<parser_type, Context>::type
  252. attribute_type;
  253. return call(parser, first, last, context, rcontext, attr
  254. , traits::variant_has_substitute<attribute_type, Attribute>());
  255. }
  256. };
  257. }}}}
  258. #endif