parse_into_container.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM)
  7. #define BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM
  8. #include <type_traits>
  9. #include <boost/spirit/home/x3/support/traits/container_traits.hpp>
  10. #include <boost/spirit/home/x3/support/traits/value_traits.hpp>
  11. #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
  12. #include <boost/spirit/home/x3/support/traits/pseudo_attribute.hpp>
  13. #include <boost/spirit/home/x3/support/traits/handles_container.hpp>
  14. #include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
  15. #include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
  16. #include <boost/spirit/home/x3/support/traits/move_to.hpp>
  17. #include <boost/mpl/and.hpp>
  18. #include <boost/fusion/include/at_key.hpp>
  19. #include <boost/fusion/include/front.hpp>
  20. #include <boost/fusion/include/back.hpp>
  21. #include <boost/variant/apply_visitor.hpp>
  22. #include <iterator> // for std::make_move_iterator
  23. namespace boost { namespace spirit { namespace x3 { namespace detail
  24. {
  25. template <typename Attribute, typename Value>
  26. struct saver_visitor;
  27. // save to associative fusion container where Key is simple type
  28. template <typename Key, typename Enable = void>
  29. struct save_to_assoc_attr
  30. {
  31. template <typename Value, typename Attribute>
  32. static void call(const Key, Value& value, Attribute& attr)
  33. {
  34. traits::move_to(value, fusion::at_key<Key>(attr));
  35. }
  36. };
  37. // save to associative fusion container where Key
  38. // is variant over possible keys
  39. template <typename ...T>
  40. struct save_to_assoc_attr<variant<T...> >
  41. {
  42. typedef variant<T...> variant_t;
  43. template <typename Value, typename Attribute>
  44. static void call(const variant_t key, Value& value, Attribute& attr)
  45. {
  46. apply_visitor(saver_visitor<Attribute, Value>(attr, value), key);
  47. }
  48. };
  49. template <typename Attribute, typename Value>
  50. struct saver_visitor : boost::static_visitor<void>
  51. {
  52. saver_visitor(Attribute& attr, Value& value)
  53. : attr(attr), value(value) {};
  54. Attribute& attr;
  55. Value& value;
  56. template <typename Key>
  57. void operator()(Key) const
  58. {
  59. save_to_assoc_attr<Key>::call(Key(), value,attr);
  60. }
  61. };
  62. template <typename Parser, typename Container, typename Context>
  63. struct parser_accepts_container
  64. : traits::is_substitute<
  65. typename traits::attribute_of<Parser, Context>::type
  66. , Container
  67. >
  68. {};
  69. template <typename Parser>
  70. struct parse_into_container_base_impl
  71. {
  72. private:
  73. // Parser has attribute (synthesize; Attribute is a container)
  74. template <typename Iterator, typename Context
  75. , typename RContext, typename Attribute>
  76. static bool call_synthesize_x(
  77. Parser const& parser
  78. , Iterator& first, Iterator const& last
  79. , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
  80. {
  81. // synthesized attribute needs to be value initialized
  82. using value_type = typename traits::container_value<Attribute>::type;
  83. using pseudo = traits::pseudo_attribute<Context, value_type, Iterator>;
  84. typename pseudo::type val = pseudo::call(
  85. first, last, traits::value_initialize<value_type>::call());
  86. if (!parser.parse(first, last, context, rcontext, val))
  87. return false;
  88. // push the parsed value into our attribute
  89. traits::push_back(attr, static_cast<value_type&&>(val));
  90. return true;
  91. }
  92. // Parser has attribute (synthesize; Attribute is a container)
  93. template <typename Iterator, typename Context
  94. , typename RContext, typename Attribute>
  95. static bool call_synthesize_x(
  96. Parser const& parser
  97. , Iterator& first, Iterator const& last
  98. , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
  99. {
  100. return parser.parse(first, last, context, rcontext, attr);
  101. }
  102. // Parser has attribute (synthesize; Attribute is a container)
  103. template <typename Iterator, typename Context
  104. , typename RContext, typename Attribute>
  105. static bool call_synthesize(
  106. Parser const& parser
  107. , Iterator& first, Iterator const& last
  108. , Context const& context, RContext& rcontext, Attribute& attr)
  109. {
  110. typedef
  111. parser_accepts_container<Parser, Attribute, Context>
  112. parser_accepts_container;
  113. return call_synthesize_x(parser, first, last, context, rcontext, attr
  114. , parser_accepts_container());
  115. }
  116. // Parser has attribute (synthesize; Attribute is a single element fusion sequence)
  117. template <typename Iterator, typename Context
  118. , typename RContext, typename Attribute>
  119. static bool call_synthesize_into_fusion_seq(Parser const& parser
  120. , Iterator& first, Iterator const& last, Context const& context
  121. , RContext& rcontext, Attribute& attr, mpl::false_ /* is_associative */)
  122. {
  123. static_assert(traits::has_size<Attribute, 1>::value,
  124. "Expecting a single element fusion sequence");
  125. return call_synthesize(parser, first, last, context, rcontext,
  126. fusion::front(attr));
  127. }
  128. // Parser has attribute (synthesize; Attribute is fusion map sequence)
  129. template <typename Iterator, typename Context, typename RContext, typename Attribute>
  130. static bool call_synthesize_into_fusion_seq(
  131. Parser const& parser
  132. , Iterator& first, Iterator const& last, Context const& context
  133. , RContext& rcontext, Attribute& attr, mpl::true_ /*is_associative*/)
  134. {
  135. using attribute_type = typename traits::attribute_of<Parser, Context>::type;
  136. static_assert(traits::has_size<attribute_type, 2>::value,
  137. "To parse directly into fusion map parser must produce 2 element attr");
  138. // use type of first element of attribute as key
  139. using key = typename std::remove_reference<
  140. typename fusion::result_of::front<attribute_type>::type>::type;
  141. attribute_type attr_;
  142. if (!parser.parse(first, last, context, rcontext, attr_))
  143. return false;
  144. save_to_assoc_attr<key>::call(fusion::front(attr_), fusion::back(attr_), attr);
  145. return true;
  146. }
  147. template <typename Iterator, typename Context, typename RContext, typename Attribute>
  148. static bool call_synthesize_dispatch_by_seq(Parser const& parser
  149. , Iterator& first, Iterator const& last, Context const& context
  150. , RContext& rcontext, Attribute& attr, mpl::true_ /*is_sequence*/)
  151. {
  152. return call_synthesize_into_fusion_seq(
  153. parser, first, last, context, rcontext, attr
  154. , fusion::traits::is_associative<Attribute>());
  155. }
  156. template <typename Iterator, typename Context, typename RContext, typename Attribute>
  157. static bool call_synthesize_dispatch_by_seq(Parser const& parser
  158. , Iterator& first, Iterator const& last, Context const& context
  159. , RContext& rcontext, Attribute& attr, mpl::false_ /*is_sequence*/)
  160. {
  161. return call_synthesize(parser, first, last, context, rcontext, attr);
  162. }
  163. // Parser has attribute (synthesize)
  164. template <typename Iterator, typename Context, typename RContext, typename Attribute>
  165. static bool call(Parser const& parser
  166. , Iterator& first, Iterator const& last, Context const& context
  167. , RContext& rcontext, Attribute& attr, mpl::true_)
  168. {
  169. return call_synthesize_dispatch_by_seq(parser, first, last, context, rcontext, attr
  170. , fusion::traits::is_sequence<Attribute>());
  171. }
  172. // Parser has no attribute (pass unused)
  173. template <typename Iterator, typename Context, typename RContext, typename Attribute>
  174. static bool call(
  175. Parser const& parser
  176. , Iterator& first, Iterator const& last, Context const& context
  177. , RContext& rcontext, Attribute& /* attr */, mpl::false_)
  178. {
  179. return parser.parse(first, last, context, rcontext, unused);
  180. }
  181. public:
  182. template <typename Iterator, typename Context, typename RContext, typename Attribute>
  183. static bool call(Parser const& parser
  184. , Iterator& first, Iterator const& last, Context const& context
  185. , RContext& rcontext, Attribute& attr)
  186. {
  187. return call(parser, first, last, context, rcontext, attr
  188. , mpl::bool_<traits::has_attribute<Parser, Context>::value>());
  189. }
  190. };
  191. template <typename Parser, typename Context, typename RContext, typename Enable = void>
  192. struct parse_into_container_impl : parse_into_container_base_impl<Parser> {};
  193. template <typename Parser, typename Iterator, typename Container, typename Context>
  194. struct parser_attr_is_substitute_for_container_value
  195. : traits::is_substitute<
  196. typename traits::pseudo_attribute<
  197. Context
  198. , typename traits::attribute_of<Parser, Context>::type
  199. , Iterator
  200. >::type
  201. , typename traits::container_value<Container>::type
  202. >
  203. {};
  204. template <typename Parser, typename Context, typename RContext>
  205. struct parse_into_container_impl<Parser, Context, RContext,
  206. typename enable_if<traits::handles_container<Parser, Context>>::type>
  207. {
  208. template <typename Iterator, typename Attribute>
  209. static bool call(
  210. Parser const& parser
  211. , Iterator& first, Iterator const& last
  212. , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
  213. {
  214. return parse_into_container_base_impl<Parser>::call(
  215. parser, first, last, context, rcontext, attr);
  216. }
  217. template <typename Iterator>
  218. static bool call(
  219. Parser const& parser
  220. , Iterator& first, Iterator const& last
  221. , Context const& context, RContext& rcontext, unused_type attr, mpl::true_)
  222. {
  223. return parser.parse(first, last, context, rcontext, attr);
  224. }
  225. template <typename Iterator, typename Attribute>
  226. static bool call(
  227. Parser const& parser
  228. , Iterator& first, Iterator const& last
  229. , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
  230. {
  231. if (traits::is_empty(attr))
  232. return parser.parse(first, last, context, rcontext, attr);
  233. Attribute rest;
  234. bool r = parser.parse(first, last, context, rcontext, rest);
  235. if (r)
  236. traits::append(attr, std::make_move_iterator(rest.begin()),
  237. std::make_move_iterator(rest.end()));
  238. return r;
  239. }
  240. template <typename Iterator, typename Attribute>
  241. static bool call(Parser const& parser
  242. , Iterator& first, Iterator const& last
  243. , Context const& context, RContext& rcontext, Attribute& attr)
  244. {
  245. typedef parser_accepts_container<
  246. Parser, Attribute, Context>
  247. parser_accepts_container;
  248. typedef parser_attr_is_substitute_for_container_value<
  249. Parser, Iterator, Attribute, Context>
  250. parser_attr_is_substitute_for_container_value;
  251. typedef mpl::or_<
  252. parser_accepts_container
  253. , mpl::not_<parser_attr_is_substitute_for_container_value>>
  254. pass_attibute_as_is;
  255. return call(parser, first, last, context, rcontext, attr,
  256. pass_attibute_as_is());
  257. }
  258. };
  259. template <typename Parser, typename Iterator, typename Context
  260. , typename RContext, typename Attribute>
  261. bool parse_into_container(
  262. Parser const& parser
  263. , Iterator& first, Iterator const& last, Context const& context
  264. , RContext& rcontext, Attribute& attr)
  265. {
  266. return parse_into_container_impl<Parser, Context, RContext>::call(
  267. parser, first, last, context, rcontext, attr);
  268. }
  269. }}}}
  270. #endif