]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
75 | 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 | |
87 | 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_& | |
100 | call(Attribute_& attr) | |
101 | { | |
102 | return attr; | |
103 | } | |
104 | }; | |
105 | ||
106 | template <typename Parser, typename Attribute, bool pass_through> | |
107 | struct pass_sequence_attribute_used : | |
108 | mpl::if_c< | |
109 | (!pass_through && traits::is_size_one_sequence<Attribute>::value) | |
110 | , pass_sequence_attribute_front<Attribute> | |
111 | , pass_through_sequence_attribute<Attribute>>::type {}; | |
112 | ||
113 | template <typename Parser, typename Attribute, bool pass_through = false, 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, pass_through>>::type {}; | |
119 | ||
120 | template <typename L, typename R, typename Attribute, bool pass_through> | |
121 | struct pass_sequence_attribute<sequence<L, R>, Attribute, pass_through> | |
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, bool pass_through> | |
129 | struct pass_sequence_attribute<Parser, Attribute, pass_through | |
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, false> l_pass; | |
154 | typedef pass_sequence_attribute<R, r_part, false> r_pass; | |
155 | ||
156 | 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 | ||
162 | 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, true> r_pass; | |
179 | ||
180 | static unused_type left(Attribute&) | |
181 | { | |
182 | return unused; | |
183 | } | |
184 | ||
185 | 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, true> l_pass; | |
199 | typedef pass_sequence_attribute_unused r_pass; | |
200 | ||
201 | static Attribute& left(Attribute& s) | |
202 | { | |
203 | return s; | |
204 | } | |
205 | ||
206 | 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 | ||
222 | static unused_type left(Attribute&) | |
223 | { | |
224 | return unused; | |
225 | } | |
226 | ||
227 | 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> | |
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> | |
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> | |
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> | |
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> | |
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> | |
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> | |
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> | |
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> | |
449 | 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> | |
473 | 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> | |
483 | 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 |