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