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 
26 #include <boost/mpl/if.hpp>
27 
28 #include <boost/type_traits/add_reference.hpp>
29 #include <boost/type_traits/is_same.hpp>
30 
31 #include <iterator> // for std::make_move_iterator
32 
33 namespace boost { namespace spirit { namespace x3
34 {
35     template <typename Left, typename Right>
36     struct sequence;
37 }}}
38 
39 namespace boost { namespace spirit { namespace x3 { namespace detail
40 {
41     template <typename Parser, typename Context, typename Enable = void>
42     struct sequence_size
43     {
44         static int const value = traits::has_attribute<Parser, Context>::value;
45     };
46 
47     template <typename Parser, typename Context>
48     struct sequence_size_subject
49       : sequence_size<typename Parser::subject_type, Context> {};
50 
51     template <typename Parser, typename Context>
52     struct sequence_size<Parser, Context
53       , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
54       : sequence_size_subject<Parser, Context> {};
55 
56     template <typename L, typename R, typename Context>
57     struct sequence_size<sequence<L, R>, Context>
58     {
59         static int const value =
60             sequence_size<L, Context>::value +
61             sequence_size<R, Context>::value;
62     };
63 
64     struct pass_sequence_attribute_unused
65     {
66         typedef unused_type type;
67 
68         template <typename T>
69         static unused_type
callboost::spirit::x3::detail::pass_sequence_attribute_unused70         call(T&)
71         {
72             return unused_type();
73         }
74     };
75 
76     template <typename Attribute>
77     struct pass_sequence_attribute_size_one_view
78     {
79         typedef typename fusion::result_of::deref<
80             typename fusion::result_of::begin<Attribute>::type
81         >::type type;
82 
callboost::spirit::x3::detail::pass_sequence_attribute_size_one_view83         static type call(Attribute& attribute)
84         {
85             return fusion::deref(fusion::begin(attribute));
86         }
87     };
88 
89     template <typename Attribute>
90     struct pass_through_sequence_attribute
91     {
92         typedef Attribute& type;
93 
94         template <typename Attribute_>
95         static Attribute_&
callboost::spirit::x3::detail::pass_through_sequence_attribute96         call(Attribute_& attribute)
97         {
98             return attribute;
99         }
100     };
101 
102     template <typename Parser, typename Attribute, typename Enable = void>
103     struct pass_sequence_attribute :
104         mpl::if_<
105             traits::is_size_one_view<Attribute>
106           , pass_sequence_attribute_size_one_view<Attribute>
107           , pass_through_sequence_attribute<Attribute>>::type {};
108 
109     template <typename L, typename R, typename Attribute>
110     struct pass_sequence_attribute<sequence<L, R>, Attribute>
111       : pass_through_sequence_attribute<Attribute> {};
112 
113     template <typename Parser, typename Attribute>
114     struct pass_sequence_attribute_subject :
115         pass_sequence_attribute<typename Parser::subject_type, Attribute> {};
116 
117     template <typename Parser, typename Attribute>
118     struct pass_sequence_attribute<Parser, Attribute
119       , typename enable_if_c<(Parser::is_pass_through_unary)>::type>
120       : pass_sequence_attribute_subject<Parser, Attribute> {};
121 
122     template <typename L, typename R, typename Attribute, typename Context
123       , typename Enable = void>
124     struct partition_attribute
125     {
126         using attr_category = typename traits::attribute_category<Attribute>::type;
127         static_assert(is_same<traits::tuple_attribute, attr_category>::value,
128             "The parser expects tuple-like attribute type");
129 
130         static int const l_size = sequence_size<L, Context>::value;
131         static int const r_size = sequence_size<R, Context>::value;
132 
133         static int constexpr actual_size = fusion::result_of::size<Attribute>::value;
134         static int constexpr expected_size = l_size + r_size;
135 
136         // If you got an error here, then you are trying to pass
137         // a fusion sequence with the wrong number of elements
138         // as that expected by the (sequence) parser.
139         static_assert(
140             actual_size >= expected_size
141           , "Size of the passed attribute is less than expected."
142         );
143         static_assert(
144             actual_size <= expected_size
145           , "Size of the passed attribute is bigger than expected."
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 Parser, typename Iterator, typename Context
234       , typename RContext, typename Attribute, typename AttributeCategory>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,AttributeCategory)235     bool parse_sequence(
236         Parser const& parser, Iterator& first, Iterator const& last
237       , Context const& context, RContext& rcontext, Attribute& attr
238       , AttributeCategory)
239     {
240         using Left = typename Parser::left_type;
241         using Right = typename Parser::right_type;
242         using partition = partition_attribute<Left, Right, Attribute, Context>;
243         using l_pass = typename partition::l_pass;
244         using r_pass = typename partition::r_pass;
245 
246         typename partition::l_part l_part = partition::left(attr);
247         typename partition::r_part r_part = partition::right(attr);
248         typename l_pass::type l_attr = l_pass::call(l_part);
249         typename r_pass::type r_attr = r_pass::call(r_part);
250 
251         Iterator save = first;
252         if (parser.left.parse(first, last, context, rcontext, l_attr)
253             && parser.right.parse(first, last, context, rcontext, r_attr))
254             return true;
255         first = save;
256         return false;
257     }
258 
259     template <typename Parser, typename Context>
260     constexpr bool pass_sequence_container_attribute
261         = sequence_size<Parser, Context>::value > 1;
262 
263     template <typename Parser, typename Iterator, typename Context
264       , typename RContext, typename Attribute>
265     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)266     parse_sequence_container(
267         Parser const& parser
268       , Iterator& first, Iterator const& last, Context const& context
269       , RContext& rcontext, Attribute& attr)
270     {
271         return parser.parse(first, last, context, rcontext, attr);
272     }
273 
274     template <typename Parser, typename Iterator, typename Context
275       , typename RContext, typename Attribute>
276     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)277     parse_sequence_container(
278         Parser const& parser
279       , Iterator& first, Iterator const& last, Context const& context
280       , RContext& rcontext, Attribute& attr)
281     {
282         return parse_into_container(parser, first, last, context, rcontext, attr);
283     }
284 
285     template <typename Parser, typename Iterator, typename Context
286       , typename RContext, typename Attribute>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::container_attribute)287     bool parse_sequence(
288         Parser const& parser , Iterator& first, Iterator const& last
289       , Context const& context, RContext& rcontext, Attribute& attr
290       , traits::container_attribute)
291     {
292         Iterator save = first;
293         if (parse_sequence_container(parser.left, first, last, context, rcontext, attr)
294             && parse_sequence_container(parser.right, first, last, context, rcontext, attr))
295             return true;
296         first = save;
297         return false;
298     }
299 
300     template <typename Parser, typename Iterator, typename Context
301       , typename RContext, typename Attribute>
parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::false_)302     bool parse_sequence_assoc(
303         Parser const& parser , Iterator& first, Iterator const& last
304 	  , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_ /*should_split*/)
305     {
306 	    return parse_into_container(parser, first, last, context, rcontext, attr);
307     }
308 
309     template <typename Parser, typename Iterator, typename Context
310       , typename RContext, typename Attribute>
parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::true_)311     bool parse_sequence_assoc(
312         Parser const& parser , Iterator& first, Iterator const& last
313 	  , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_ /*should_split*/)
314     {
315         Iterator save = first;
316         if (parser.left.parse( first, last, context, rcontext, attr)
317             && parser.right.parse(first, last, context, rcontext, attr))
318             return true;
319         first = save;
320         return false;
321     }
322 
323     template <typename Parser, typename Iterator, typename Context
324       , typename RContext, typename Attribute>
parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::associative_attribute)325     bool parse_sequence(
326         Parser const& parser, Iterator& first, Iterator const& last
327       , Context const& context, RContext& rcontext, Attribute& attr
328       , traits::associative_attribute)
329     {
330         // we can come here in 2 cases:
331         // - when sequence is key >> value and therefore must
332         // be parsed with tuple synthesized attribute and then
333         // that tuple is used to save into associative attribute provided here.
334         // Example:  key >> value;
335         //
336         // - when either this->left or this->right provides full key-value
337         // pair (like in case 1) and another one provides nothing.
338         // Example:  eps >> rule<class x; fusion::map<...> >
339         //
340         // first case must be parsed as whole, and second one should
341         // be parsed separately for left and right.
342 
343         typedef typename traits::attribute_of<
344             decltype(parser.left), Context>::type l_attr_type;
345         typedef typename traits::attribute_of<
346             decltype(parser.right), Context>::type r_attr_type;
347 
348         typedef typename
349             mpl::or_<
350                 is_same<l_attr_type, unused_type>
351               , is_same<r_attr_type, unused_type> >
352         should_split;
353 
354         return parse_sequence_assoc(parser, first, last, context, rcontext, attr
355           , should_split());
356     }
357 
358     template <typename Left, typename Right, typename Context, typename RContext>
359     struct parse_into_container_impl<sequence<Left, Right>, Context, RContext>
360     {
361         typedef sequence<Left, Right> parser_type;
362 
363         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl364         static bool call(
365             parser_type const& parser
366           , Iterator& first, Iterator const& last
367           , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
368         {
369             // inform user what went wrong if we jumped here in attempt to
370             // parse incompatible sequence into fusion::map
371             static_assert(!is_same< typename traits::attribute_category<Attribute>::type,
372                   traits::associative_attribute>::value,
373                   "To parse directly into fusion::map sequence must produce tuple attribute "
374                   "where type of first element is existing key in fusion::map and second element "
375                   "is value to be stored under that key");
376 
377             Attribute attr_{};
378             if (!parse_sequence(parser
379 			       , first, last, context, rcontext, attr_, traits::container_attribute()))
380             {
381                 return false;
382             }
383             traits::append(attr, std::make_move_iterator(traits::begin(attr_)),
384                                  std::make_move_iterator(traits::end(attr_)));
385             return true;
386         }
387 
388         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl389         static bool call(
390             parser_type const& parser
391           , Iterator& first, Iterator const& last
392           , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
393         {
394             return parse_into_container_base_impl<parser_type>::call(
395                 parser, first, last, context, rcontext, attr);
396         }
397 
398         template <typename Iterator, typename Attribute>
callboost::spirit::x3::detail::parse_into_container_impl399         static bool call(
400             parser_type const& parser
401           , Iterator& first, Iterator const& last
402           , Context const& context, RContext& rcontext, Attribute& attr)
403         {
404             typedef typename
405                 traits::attribute_of<parser_type, Context>::type
406             attribute_type;
407 
408             typedef typename
409                 traits::container_value<Attribute>::type
410             value_type;
411 
412             return call(parser, first, last, context, rcontext, attr
413 	        , typename traits::is_substitute<attribute_type, value_type>::type());
414         }
415     };
416 
417 }}}}
418 
419 #endif
420