• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3 
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 =============================================================================*/
7 #if !defined(BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM)
8 #define BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM
9 
10 #include <type_traits>
11 
12 #include <boost/spirit/home/x3/support/traits/container_traits.hpp>
13 #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
14 #include <boost/spirit/home/x3/support/traits/pseudo_attribute.hpp>
15 #include <boost/spirit/home/x3/support/traits/handles_container.hpp>
16 #include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
17 #include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
18 #include <boost/spirit/home/x3/support/traits/move_to.hpp>
19 #include <boost/mpl/and.hpp>
20 #include <boost/fusion/include/at_key.hpp>
21 #include <boost/fusion/include/front.hpp>
22 #include <boost/fusion/include/back.hpp>
23 #include <boost/variant/apply_visitor.hpp>
24 #include <iterator> // for std::make_move_iterator
25 
26 namespace boost { namespace spirit { namespace x3 { namespace detail
27 {
28     template <typename Attribute, typename Value>
29     struct saver_visitor;
30 
31     // save to associative fusion container where Key is simple type
32     template <typename Key, typename Enable = void>
33     struct save_to_assoc_attr
34     {
35         template <typename Value, typename Attribute>
callboost::spirit::x3::detail::save_to_assoc_attr36         static void call(const Key, Value& value, Attribute& attr)
37         {
38             traits::move_to(value, fusion::at_key<Key>(attr));
39         }
40     };
41 
42     // save to associative fusion container where Key
43     // is variant over possible keys
44     template <typename ...T>
45     struct save_to_assoc_attr<variant<T...> >
46     {
47         typedef variant<T...> variant_t;
48 
49         template <typename Value, typename Attribute>
callboost::spirit::x3::detail::save_to_assoc_attr50         static void call(const variant_t key, Value& value, Attribute& attr)
51         {
52             apply_visitor(saver_visitor<Attribute, Value>(attr, value), key);
53         }
54     };
55 
56     template <typename Attribute, typename Value>
57     struct saver_visitor  : boost::static_visitor<void>
58     {
saver_visitorboost::spirit::x3::detail::saver_visitor59         saver_visitor(Attribute& attr, Value& value)
60             : attr(attr), value(value) {};
61 
62         Attribute& attr;
63         Value& value;
64 
65         template <typename Key>
operator ()boost::spirit::x3::detail::saver_visitor66         void operator()(Key) const
67         {
68             save_to_assoc_attr<Key>::call(Key(), value,attr);
69         }
70     };
71 
72     template <typename Parser, typename Container, typename Context>
73     struct parser_accepts_container
74         : traits::is_substitute<
75                 typename traits::attribute_of<Parser, Context>::type
76               , Container
77             >
78     {};
79 
80     template <typename Parser>
81     struct parse_into_container_base_impl
82     {
83     private:
84 
85         // Parser has attribute (synthesize; Attribute is a container)
86         template <typename Iterator, typename Context
87           , typename RContext, typename Attribute>
call_synthesize_xboost::spirit::x3::detail::parse_into_container_base_impl88         static bool call_synthesize_x(
89             Parser const& parser
90           , Iterator& first, Iterator const& last
91           , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
92         {
93             // synthesized attribute needs to be value initialized
94             using value_type = typename traits::container_value<Attribute>::type;
95             value_type val{};
96 
97             if (!parser.parse(first, last, context, rcontext, val))
98                 return false;
99 
100             // push the parsed value into our attribute
101             traits::push_back(attr, static_cast<value_type&&>(val));
102             return true;
103         }
104 
105         // Parser has attribute (synthesize; Attribute is a container)
106         template <typename Iterator, typename Context
107           , typename RContext, typename Attribute>
call_synthesize_xboost::spirit::x3::detail::parse_into_container_base_impl108         static bool call_synthesize_x(
109             Parser const& parser
110           , Iterator& first, Iterator const& last
111           , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
112         {
113             return parser.parse(first, last, context, rcontext, attr);
114         }
115 
116         // Parser has attribute (synthesize; Attribute is a container)
117         template <typename Iterator, typename Context
118           , typename RContext, typename Attribute>
call_synthesizeboost::spirit::x3::detail::parse_into_container_base_impl119         static bool call_synthesize(
120             Parser const& parser
121           , Iterator& first, Iterator const& last
122           , Context const& context, RContext& rcontext, Attribute& attr)
123         {
124             typedef
125                 parser_accepts_container<Parser, Attribute, Context>
126             parser_accepts_container;
127 
128             return call_synthesize_x(parser, first, last, context, rcontext, attr
129                 , parser_accepts_container());
130         }
131 
132         // Parser has attribute (synthesize; Attribute is a single element fusion sequence)
133         template <typename Iterator, typename Context
134           , typename RContext, typename Attribute>
call_synthesize_into_fusion_seqboost::spirit::x3::detail::parse_into_container_base_impl135         static bool call_synthesize_into_fusion_seq(Parser const& parser
136           , Iterator& first, Iterator const& last, Context const& context
137           , RContext& rcontext, Attribute& attr, mpl::false_ /* is_associative */)
138         {
139             static_assert(traits::has_size<Attribute, 1>::value,
140                 "Expecting a single element fusion sequence");
141             return call_synthesize(parser, first, last, context, rcontext,
142                 fusion::front(attr));
143         }
144 
145         // Parser has attribute (synthesize; Attribute is fusion map sequence)
146         template <typename Iterator, typename Context, typename RContext, typename Attribute>
call_synthesize_into_fusion_seqboost::spirit::x3::detail::parse_into_container_base_impl147         static bool call_synthesize_into_fusion_seq(
148             Parser const& parser
149           , Iterator& first, Iterator const& last, Context const& context
150           , RContext& rcontext, Attribute& attr, mpl::true_ /*is_associative*/)
151         {
152             using attribute_type = typename traits::attribute_of<Parser, Context>::type;
153             static_assert(traits::has_size<attribute_type, 2>::value,
154                 "To parse directly into fusion map parser must produce 2 element attr");
155 
156             // use type of  first element of attribute as key
157             using key = typename std::remove_reference<
158             typename fusion::result_of::front<attribute_type>::type>::type;
159 
160             attribute_type attr_;
161             if (!parser.parse(first, last, context, rcontext, attr_))
162                 return false;
163 
164             save_to_assoc_attr<key>::call(fusion::front(attr_), fusion::back(attr_), attr);
165             return true;
166         }
167 
168         template <typename Iterator, typename Context, typename RContext, typename Attribute>
call_synthesize_dispatch_by_seqboost::spirit::x3::detail::parse_into_container_base_impl169         static bool call_synthesize_dispatch_by_seq(Parser const& parser
170           , Iterator& first, Iterator const& last, Context const& context
171           , RContext& rcontext, Attribute& attr, mpl::true_ /*is_sequence*/)
172         {
173             return call_synthesize_into_fusion_seq(
174                 parser, first, last, context, rcontext, attr
175               , fusion::traits::is_associative<Attribute>());
176         }
177 
178         template <typename Iterator, typename Context, typename RContext, typename Attribute>
call_synthesize_dispatch_by_seqboost::spirit::x3::detail::parse_into_container_base_impl179         static bool call_synthesize_dispatch_by_seq(Parser const& parser
180           , Iterator& first, Iterator const& last, Context const& context
181           , RContext& rcontext, Attribute& attr, mpl::false_ /*is_sequence*/)
182         {
183             return call_synthesize(parser, first, last, context, rcontext, attr);
184         }
185 
186         // Parser has attribute (synthesize)
187         template <typename Iterator, typename Context, typename RContext, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_base_impl188         static bool call(Parser const& parser
189           , Iterator& first, Iterator const& last, Context const& context
190           , RContext& rcontext, Attribute& attr, mpl::true_)
191         {
192             return call_synthesize_dispatch_by_seq(parser, first, last, context, rcontext, attr
193                 , fusion::traits::is_sequence<Attribute>());
194         }
195 
196         // Parser has no attribute (pass unused)
197         template <typename Iterator, typename Context, typename RContext, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_base_impl198         static bool call(
199             Parser const& parser
200           , Iterator& first, Iterator const& last, Context const& context
201           , RContext& rcontext, Attribute& /* attr */, mpl::false_)
202         {
203             return parser.parse(first, last, context, rcontext, unused);
204         }
205 
206 
207     public:
208 
209         template <typename Iterator, typename Context, typename RContext, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_base_impl210         static bool call(Parser const& parser
211           , Iterator& first, Iterator const& last, Context const& context
212           , RContext& rcontext, Attribute& attr)
213         {
214             return call(parser, first, last, context, rcontext, attr
215               , mpl::bool_<traits::has_attribute<Parser, Context>::value>());
216         }
217     };
218 
219     template <typename Parser, typename Context, typename RContext, typename Enable = void>
220     struct parse_into_container_impl : parse_into_container_base_impl<Parser> {};
221 
222     template <typename Parser, typename Iterator, typename Container, typename Context>
223     struct parser_attr_is_substitute_for_container_value
224         : traits::is_substitute<
225             typename traits::pseudo_attribute<
226                 Context
227               , typename traits::attribute_of<Parser, Context>::type
228               , Iterator
229             >::type
230           , typename traits::container_value<Container>::type
231         >
232     {};
233 
234     template <typename Parser, typename Context, typename RContext>
235     struct parse_into_container_impl<Parser, Context, RContext,
236         typename enable_if<traits::handles_container<Parser, Context>>::type>
237     {
238         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl239         static bool call(
240             Parser const& parser
241           , Iterator& first, Iterator const& last
242           , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
243         {
244             return parse_into_container_base_impl<Parser>::call(
245                 parser, first, last, context, rcontext, attr);
246         }
247 
248         template <typename Iterator>
callboost::spirit::x3::detail::parse_into_container_impl249         static bool call(
250             Parser const& parser
251           , Iterator& first, Iterator const& last
252           , Context const& context, RContext& rcontext, unused_type attr, mpl::true_)
253         {
254             return parser.parse(first, last, context, rcontext, attr);
255         }
256 
257         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl258         static bool call(
259             Parser const& parser
260           , Iterator& first, Iterator const& last
261           , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
262         {
263             if (traits::is_empty(attr))
264                 return parser.parse(first, last, context, rcontext, attr);
265             Attribute rest;
266             bool r = parser.parse(first, last, context, rcontext, rest);
267             if (r)
268                 traits::append(attr, std::make_move_iterator(rest.begin()),
269                                      std::make_move_iterator(rest.end()));
270             return r;
271         }
272 
273         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl274         static bool call(Parser const& parser
275           , Iterator& first, Iterator const& last
276           , Context const& context, RContext& rcontext, Attribute& attr)
277         {
278             typedef parser_accepts_container<
279                     Parser, Attribute, Context>
280             parser_accepts_container;
281 
282             typedef parser_attr_is_substitute_for_container_value<
283                     Parser, Iterator, Attribute, Context>
284             parser_attr_is_substitute_for_container_value;
285 
286             typedef mpl::or_<
287                 parser_accepts_container
288               , mpl::not_<parser_attr_is_substitute_for_container_value>>
289             pass_attibute_as_is;
290 
291             return call(parser, first, last, context, rcontext, attr,
292                 pass_attibute_as_is());
293         }
294     };
295 
296     template <typename Parser, typename Iterator, typename Context
297       , typename RContext, typename Attribute>
parse_into_container(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr)298     bool parse_into_container(
299         Parser const& parser
300       , Iterator& first, Iterator const& last, Context const& context
301       , RContext& rcontext, Attribute& attr)
302     {
303         return parse_into_container_impl<Parser, Context, RContext>::call(
304             parser, first, last, context, rcontext, attr);
305     }
306 
307 }}}}
308 
309 #endif
310