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(SPIRIT_SEQUENCE_DETAIL_JAN_06_2013_1015AM)
8 #define SPIRIT_SEQUENCE_DETAIL_JAN_06_2013_1015AM
9 
10 #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
11 #include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
12 #include <boost/spirit/home/x3/support/traits/make_attribute.hpp>
13 #include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
14 #include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
15 #include <boost/spirit/home/x3/support/traits/container_traits.hpp>
16 #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp>
17 
18 #include <boost/fusion/include/begin.hpp>
19 #include <boost/fusion/include/end.hpp>
20 #include <boost/fusion/include/advance.hpp>
21 #include <boost/fusion/include/empty.hpp>
22 #include <boost/fusion/include/front.hpp>
23 #include <boost/fusion/include/iterator_range.hpp>
24 #include <boost/fusion/include/as_deque.hpp>
25 #include <boost/fusion/include/mpl.hpp>
26 
27 #include <boost/mpl/copy_if.hpp>
28 #include <boost/mpl/not.hpp>
29 #include <boost/mpl/if.hpp>
30 #include <boost/mpl/insert_range.hpp>
31 #include <boost/mpl/eval_if.hpp>
32 #include <boost/mpl/vector.hpp>
33 #include <boost/mpl/identity.hpp>
34 
35 #include <boost/type_traits/add_reference.hpp>
36 #include <boost/type_traits/is_same.hpp>
37 
38 namespace boost { namespace spirit { namespace x3
39 {
40     template <typename Left, typename Right>
41     struct sequence;
42 }}}
43 
44 namespace boost { namespace spirit { namespace x3 { namespace detail
45 {
46     template <typename Parser, typename Context, typename Enable = void>
47     struct sequence_size
48     {
49         static int const value = traits::has_attribute<Parser, Context>::value;
50     };
51 
52     template <typename Parser, typename Context>
53     struct sequence_size_subject
54       : sequence_size<typename Parser::subject_type, Context> {};
55 
56     template <typename Parser, typename Context>
57     struct sequence_size<Parser, Context
58       , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
59       : sequence_size_subject<Parser, Context> {};
60 
61     template <typename L, typename R, typename Context>
62     struct sequence_size<sequence<L, R>, Context>
63     {
64         static int const value =
65             sequence_size<L, Context>::value +
66             sequence_size<R, Context>::value;
67     };
68 
69     struct pass_sequence_attribute_unused
70     {
71         typedef unused_type type;
72 
73         template <typename T>
74         static unused_type
callboost::spirit::x3::detail::pass_sequence_attribute_unused75         call(T&)
76         {
77             return unused_type();
78         }
79     };
80 
81     template <typename Attribute>
82     struct pass_sequence_attribute_front
83     {
84         typedef typename fusion::result_of::front<Attribute>::type type;
85 
86         static typename add_reference<type>::type
callboost::spirit::x3::detail::pass_sequence_attribute_front87         call(Attribute& attr)
88         {
89             return fusion::front(attr);
90         }
91     };
92 
93     template <typename Attribute>
94     struct pass_through_sequence_attribute
95     {
96         typedef Attribute& type;
97 
98         template <typename Attribute_>
99         static Attribute_&
callboost::spirit::x3::detail::pass_through_sequence_attribute100         call(Attribute_& attr)
101         {
102             return attr;
103         }
104     };
105 
106     template <typename Parser, typename Attribute>
107     struct pass_sequence_attribute_used :
108         mpl::if_<
109             traits::is_size_one_sequence<Attribute>
110           , pass_sequence_attribute_front<Attribute>
111           , pass_through_sequence_attribute<Attribute>>::type {};
112 
113     template <typename Parser, typename Attribute, typename Enable = void>
114     struct pass_sequence_attribute :
115         mpl::if_<
116             fusion::result_of::empty<Attribute>
117           , pass_sequence_attribute_unused
118           , pass_sequence_attribute_used<Parser, Attribute>>::type {};
119 
120     template <typename L, typename R, typename Attribute>
121     struct pass_sequence_attribute<sequence<L, R>, Attribute>
122       : pass_through_sequence_attribute<Attribute> {};
123 
124     template <typename Parser, typename Attribute>
125     struct pass_sequence_attribute_subject :
126         pass_sequence_attribute<typename Parser::subject_type, Attribute> {};
127 
128     template <typename Parser, typename Attribute>
129     struct pass_sequence_attribute<Parser, Attribute
130       , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
131       : pass_sequence_attribute_subject<Parser, Attribute> {};
132 
133     template <typename L, typename R, typename Attribute, typename Context
134       , typename Enable = void>
135     struct partition_attribute
136     {
137         static int const l_size = sequence_size<L, Context>::value;
138         static int const r_size = sequence_size<R, Context>::value;
139 
140         // If you got an error here, then you are trying to pass
141         // a fusion sequence with the wrong number of elements
142         // as that expected by the (sequence) parser.
143         static_assert(
144             fusion::result_of::size<Attribute>::value == (l_size + r_size)
145           , "Attribute does not have the expected size."
146         );
147 
148         typedef typename fusion::result_of::begin<Attribute>::type l_begin;
149         typedef typename fusion::result_of::advance_c<l_begin, l_size>::type l_end;
150         typedef typename fusion::result_of::end<Attribute>::type r_end;
151         typedef fusion::iterator_range<l_begin, l_end> l_part;
152         typedef fusion::iterator_range<l_end, r_end> r_part;
153         typedef pass_sequence_attribute<L, l_part> l_pass;
154         typedef pass_sequence_attribute<R, r_part> r_pass;
155 
leftboost::spirit::x3::detail::partition_attribute156         static l_part left(Attribute& s)
157         {
158             auto i = fusion::begin(s);
159             return l_part(i, fusion::advance_c<l_size>(i));
160         }
161 
rightboost::spirit::x3::detail::partition_attribute162         static r_part right(Attribute& s)
163         {
164             return r_part(
165                 fusion::advance_c<l_size>(fusion::begin(s))
166               , fusion::end(s));
167         }
168     };
169 
170     template <typename L, typename R, typename Attribute, typename Context>
171     struct partition_attribute<L, R, Attribute, Context,
172         typename enable_if_c<(!traits::has_attribute<L, Context>::value &&
173             traits::has_attribute<R, Context>::value)>::type>
174     {
175         typedef unused_type l_part;
176         typedef Attribute& r_part;
177         typedef pass_sequence_attribute_unused l_pass;
178         typedef pass_sequence_attribute<R, Attribute> r_pass;
179 
leftboost::spirit::x3::detail::partition_attribute180         static unused_type left(Attribute&)
181         {
182             return unused;
183         }
184 
rightboost::spirit::x3::detail::partition_attribute185         static Attribute& right(Attribute& s)
186         {
187             return s;
188         }
189     };
190 
191     template <typename L, typename R, typename Attribute, typename Context>
192     struct partition_attribute<L, R, Attribute, Context,
193         typename enable_if_c<(traits::has_attribute<L, Context>::value &&
194             !traits::has_attribute<R, Context>::value)>::type>
195     {
196         typedef Attribute& l_part;
197         typedef unused_type r_part;
198         typedef pass_sequence_attribute<L, Attribute> l_pass;
199         typedef pass_sequence_attribute_unused r_pass;
200 
leftboost::spirit::x3::detail::partition_attribute201         static Attribute& left(Attribute& s)
202         {
203             return s;
204         }
205 
rightboost::spirit::x3::detail::partition_attribute206         static unused_type right(Attribute&)
207         {
208             return unused;
209         }
210     };
211 
212     template <typename L, typename R, typename Attribute, typename Context>
213     struct partition_attribute<L, R, Attribute, Context,
214         typename enable_if_c<(!traits::has_attribute<L, Context>::value &&
215             !traits::has_attribute<R, Context>::value)>::type>
216     {
217         typedef unused_type l_part;
218         typedef unused_type r_part;
219         typedef pass_sequence_attribute_unused l_pass;
220         typedef pass_sequence_attribute_unused r_pass;
221 
leftboost::spirit::x3::detail::partition_attribute222         static unused_type left(Attribute&)
223         {
224             return unused;
225         }
226 
rightboost::spirit::x3::detail::partition_attribute227         static unused_type right(Attribute&)
228         {
229             return unused;
230         }
231     };
232 
233     template <typename L, typename R, typename C>
234     struct get_sequence_types
235     {
236         typedef
237             mpl::vector<
238                 typename traits::attribute_of<L, C>::type
239               , typename traits::attribute_of<R, C>::type
240             >
241         type;
242     };
243 
244     template <typename LL, typename LR, typename R, typename C>
245     struct get_sequence_types<sequence<LL, LR>, R, C>
246         : mpl::push_back< typename get_sequence_types<LL, LR, C>::type
247                         , typename traits::attribute_of<R, C>::type> {};
248 
249     template <typename L, typename RL, typename RR, typename C>
250     struct get_sequence_types<L, sequence<RL, RR>, C>
251         : mpl::push_front< typename get_sequence_types<RL, RR, C>::type
252                          , typename traits::attribute_of<L, C>::type> {};
253 
254     template <typename LL, typename LR, typename RL, typename RR, typename C>
255     struct get_sequence_types<sequence<LL, LR>, sequence<RL, RR>, C>
256     {
257         typedef typename get_sequence_types<LL, LR, C>::type left;
258         typedef typename get_sequence_types<RL, RR, C>::type right;
259         typedef typename
260             mpl::insert_range<left, typename mpl::end<left>::type, right>::type
261         type;
262     };
263 
264     template <typename L, typename R, typename C>
265     struct attribute_of_sequence
266     {
267         // Get all sequence attribute types
268         typedef typename get_sequence_types<L, R, C>::type all_types;
269 
270         // Filter all unused_types
271         typedef typename
272             mpl::copy_if<
273                 all_types
274               , mpl::not_<is_same<mpl::_1, unused_type>>
275               , mpl::back_inserter<mpl::vector<>>
276             >::type
277         filtered_types;
278 
279         // Build a fusion::deque if filtered_types is not empty,
280         // else just return unused_type
281         typedef typename
282             mpl::eval_if<
283                 mpl::empty<filtered_types>
284 	    , mpl::identity<unused_type>
285 	    , mpl::if_<mpl::equal_to<mpl::size<filtered_types>, mpl::int_<1> >,
286 	    typename mpl::front<filtered_types>::type
287 		      , typename fusion::result_of::as_deque<filtered_types>::type >
288             >::type
289         type;
290     };
291 
292     template <typename Parser, typename Iterator, typename Context
293       , typename RContext, typename Attribute>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::tuple_attribute)294     bool parse_sequence(
295         Parser const& parser, Iterator& first, Iterator const& last
296       , Context const& context, RContext& rcontext, Attribute& attr
297       , traits::tuple_attribute)
298     {
299         typedef typename Parser::left_type Left;
300         typedef typename Parser::right_type Right;
301         typedef partition_attribute<Left, Right, Attribute, Context> partition;
302         typedef typename partition::l_pass l_pass;
303         typedef typename partition::r_pass r_pass;
304 
305         typename partition::l_part l_part = partition::left(attr);
306         typename partition::r_part r_part = partition::right(attr);
307         typename l_pass::type l_attr = l_pass::call(l_part);
308         typename r_pass::type r_attr = r_pass::call(r_part);
309 
310         Iterator save = first;
311         if (parser.left.parse(first, last, context, rcontext, l_attr)
312             && parser.right.parse(first, last, context, rcontext, r_attr))
313             return true;
314         first = save;
315         return false;
316     }
317 
318     template <typename Parser, typename Iterator, typename Context
319       , typename RContext, typename Attribute>
parse_sequence_plain(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr)320     bool parse_sequence_plain(
321         Parser const& parser, Iterator& first, Iterator const& last
322       , Context const& context, RContext& rcontext, Attribute& attr)
323     {
324         typedef typename Parser::left_type Left;
325         typedef typename Parser::right_type Right;
326         typedef typename traits::attribute_of<Left, Context>::type l_attr_type;
327         typedef typename traits::attribute_of<Right, Context>::type r_attr_type;
328         typedef traits::make_attribute<l_attr_type, Attribute> l_make_attribute;
329         typedef traits::make_attribute<r_attr_type, Attribute> r_make_attribute;
330 
331         typename l_make_attribute::type l_attr = l_make_attribute::call(attr);
332         typename r_make_attribute::type r_attr = r_make_attribute::call(attr);
333 
334         Iterator save = first;
335         if (parser.left.parse(first, last, context, rcontext, l_attr)
336             && parser.right.parse(first, last, context, rcontext, r_attr))
337             return true;
338         first = save;
339         return false;
340     }
341 
342     template <typename Parser, typename Iterator, typename Context
343       , typename RContext, typename Attribute>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::plain_attribute)344     bool parse_sequence(
345         Parser const& parser, Iterator& first, Iterator const& last
346       , Context const& context, RContext& rcontext, Attribute& attr
347       , traits::plain_attribute)
348     {
349         return parse_sequence_plain(parser, first, last, context, rcontext, attr);
350     }
351 
352     template <typename Parser, typename Iterator, typename Context
353       , typename RContext, typename Attribute>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::variant_attribute)354     bool parse_sequence(
355         Parser const& parser, Iterator& first, Iterator const& last
356       , Context const& context, RContext& rcontext, Attribute& attr
357       , traits::variant_attribute)
358     {
359         return parse_sequence_plain(parser, first, last, context, rcontext, attr);
360     }
361 
362     template <typename Left, typename Right, typename Iterator
363       , typename Context, typename RContext, typename Attribute>
364     bool parse_sequence(
365         Left const& left, Right const& right
366       , Iterator& first, Iterator const& last
367       , Context const& context, RContext& rcontext, Attribute& attr
368       , traits::container_attribute);
369 
370     template <typename Parser, typename Iterator, typename Context
371       , typename RContext, typename Attribute>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::container_attribute)372     bool parse_sequence(
373         Parser const& parser , Iterator& first, Iterator const& last
374       , Context const& context, RContext& rcontext, Attribute& attr
375       , traits::container_attribute)
376     {
377         Iterator save = first;
378         if (parse_into_container(parser.left, first, last, context, rcontext, attr)
379             && parse_into_container(parser.right, first, last, context, rcontext, attr))
380             return true;
381         first = save;
382         return false;
383     }
384 
385     template <typename Parser, typename Iterator, typename Context
386       , typename RContext, typename Attribute>
parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::false_)387     bool parse_sequence_assoc(
388         Parser const& parser , Iterator& first, Iterator const& last
389 	  , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_ /*should_split*/)
390     {
391 	    return parse_into_container(parser, first, last, context, rcontext, attr);
392     }
393 
394     template <typename Parser, typename Iterator, typename Context
395       , typename RContext, typename Attribute>
parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::true_)396     bool parse_sequence_assoc(
397         Parser const& parser , Iterator& first, Iterator const& last
398 	  , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_ /*should_split*/)
399     {
400         Iterator save = first;
401         if (parser.left.parse( first, last, context, rcontext, attr)
402             && parser.right.parse(first, last, context, rcontext, attr))
403             return true;
404         first = save;
405         return false;
406     }
407 
408     template <typename Parser, typename Iterator, typename Context
409       , typename RContext, typename Attribute>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::associative_attribute)410     bool parse_sequence(
411         Parser const& parser, Iterator& first, Iterator const& last
412       , Context const& context, RContext& rcontext, Attribute& attr
413       , traits::associative_attribute)
414     {
415         // we can come here in 2 cases:
416         // - when sequence is key >> value and therefore must
417         // be parsed with tuple synthesized attribute and then
418         // that tuple is used to save into associative attribute provided here.
419         // Example:  key >> value;
420         //
421         // - when either this->left or this->right provides full key-value
422         // pair (like in case 1) and another one provides nothing.
423         // Example:  eps >> rule<class x; fusion::map<...> >
424         //
425         // first case must be parsed as whole, and second one should
426         // be parsed separately for left and right.
427 
428         typedef typename traits::attribute_of<
429             decltype(parser.left), Context>::type l_attr_type;
430         typedef typename traits::attribute_of<
431             decltype(parser.right), Context>::type r_attr_type;
432 
433         typedef typename
434             mpl::or_<
435                 is_same<l_attr_type, unused_type>
436               , is_same<r_attr_type, unused_type> >
437         should_split;
438 
439         return parse_sequence_assoc(parser, first, last, context, rcontext, attr
440           , should_split());
441     }
442 
443     template <typename Left, typename Right, typename Context, typename RContext>
444     struct parse_into_container_impl<sequence<Left, Right>, Context, RContext>
445     {
446         typedef sequence<Left, Right> parser_type;
447 
448         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl449         static bool call(
450             parser_type const& parser
451           , Iterator& first, Iterator const& last
452           , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
453         {
454             // inform user what went wrong if we jumped here in attempt to
455             // parse incompatible sequence into fusion::map
456             static_assert(!is_same< typename traits::attribute_category<Attribute>::type,
457                   traits::associative_attribute>::value,
458                   "To parse directly into fusion::map sequence must produce tuple attribute "
459                   "where type of first element is existing key in fusion::map and second element "
460                   "is value to be stored under that key");
461 
462             Attribute attr_;
463             if (!parse_sequence(parser
464 			       , first, last, context, rcontext, attr_, traits::container_attribute()))
465             {
466                 return false;
467             }
468             traits::append(attr, traits::begin(attr_), traits::end(attr_));
469             return true;
470         }
471 
472         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl473         static bool call(
474             parser_type const& parser
475           , Iterator& first, Iterator const& last
476           , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
477         {
478             return parse_into_container_base_impl<parser_type>::call(
479                 parser, first, last, context, rcontext, attr);
480         }
481 
482         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl483         static bool call(
484             parser_type const& parser
485           , Iterator& first, Iterator const& last
486           , Context const& context, RContext& rcontext, Attribute& attr)
487         {
488             typedef typename
489                 traits::attribute_of<parser_type, Context>::type
490             attribute_type;
491 
492             typedef typename
493                 traits::container_value<Attribute>::type
494             value_type;
495 
496             return call(parser, first, last, context, rcontext, attr
497 	        , typename traits::is_substitute<attribute_type, value_type>::type());
498         }
499     };
500 
501 }}}}
502 
503 #endif
504