]>
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 | =============================================================================*/ | |
11fdf7f2 TL |
7 | #if !defined(BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM) |
8 | #define BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM | |
7c673cae FG |
9 | |
10 | #include <boost/spirit/home/x3/support/traits/attribute_of.hpp> | |
11 | #include <boost/spirit/home/x3/support/traits/attribute_category.hpp> | |
7c673cae FG |
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> | |
11fdf7f2 | 15 | #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp> |
7c673cae FG |
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> | |
11fdf7f2 | 21 | #include <boost/fusion/include/deref.hpp> |
7c673cae FG |
22 | #include <boost/fusion/include/empty.hpp> |
23 | #include <boost/fusion/include/front.hpp> | |
24 | #include <boost/fusion/include/iterator_range.hpp> | |
7c673cae | 25 | |
7c673cae | 26 | #include <boost/mpl/if.hpp> |
7c673cae FG |
27 | |
28 | #include <boost/type_traits/add_reference.hpp> | |
29 | #include <boost/type_traits/is_same.hpp> | |
30 | ||
92f5a8d4 TL |
31 | #include <iterator> // for std::make_move_iterator |
32 | ||
7c673cae FG |
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 | |
70 | call(T&) | |
71 | { | |
72 | return unused_type(); | |
73 | } | |
74 | }; | |
75 | ||
76 | template <typename Attribute> | |
11fdf7f2 | 77 | struct pass_sequence_attribute_size_one_view |
7c673cae | 78 | { |
11fdf7f2 TL |
79 | typedef typename fusion::result_of::deref< |
80 | typename fusion::result_of::begin<Attribute>::type | |
81 | >::type type; | |
7c673cae | 82 | |
1e59de90 | 83 | static type call(Attribute& attribute) |
7c673cae | 84 | { |
1e59de90 | 85 | return fusion::deref(fusion::begin(attribute)); |
7c673cae FG |
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_& | |
1e59de90 | 96 | call(Attribute_& attribute) |
7c673cae | 97 | { |
1e59de90 | 98 | return attribute; |
7c673cae FG |
99 | } |
100 | }; | |
101 | ||
92f5a8d4 TL |
102 | template <typename Parser, typename Attribute, typename Enable = void> |
103 | struct pass_sequence_attribute : | |
11fdf7f2 TL |
104 | mpl::if_< |
105 | traits::is_size_one_view<Attribute> | |
106 | , pass_sequence_attribute_size_one_view<Attribute> | |
7c673cae FG |
107 | , pass_through_sequence_attribute<Attribute>>::type {}; |
108 | ||
11fdf7f2 TL |
109 | template <typename L, typename R, typename Attribute> |
110 | struct pass_sequence_attribute<sequence<L, R>, Attribute> | |
7c673cae FG |
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 | ||
11fdf7f2 TL |
117 | template <typename Parser, typename Attribute> |
118 | struct pass_sequence_attribute<Parser, Attribute | |
7c673cae FG |
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 | { | |
92f5a8d4 TL |
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 | ||
7c673cae FG |
130 | static int const l_size = sequence_size<L, Context>::value; |
131 | static int const r_size = sequence_size<R, Context>::value; | |
132 | ||
92f5a8d4 TL |
133 | static int constexpr actual_size = fusion::result_of::size<Attribute>::value; |
134 | static int constexpr expected_size = l_size + r_size; | |
135 | ||
7c673cae FG |
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( | |
92f5a8d4 TL |
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." | |
7c673cae FG |
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; | |
11fdf7f2 TL |
153 | typedef pass_sequence_attribute<L, l_part> l_pass; |
154 | typedef pass_sequence_attribute<R, r_part> r_pass; | |
7c673cae FG |
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; | |
11fdf7f2 | 178 | typedef pass_sequence_attribute<R, Attribute> r_pass; |
7c673cae FG |
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; | |
11fdf7f2 | 198 | typedef pass_sequence_attribute<L, Attribute> l_pass; |
7c673cae FG |
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 | ||
7c673cae | 233 | template <typename Parser, typename Iterator, typename Context |
92f5a8d4 | 234 | , typename RContext, typename Attribute, typename AttributeCategory> |
7c673cae FG |
235 | bool parse_sequence( |
236 | Parser const& parser, Iterator& first, Iterator const& last | |
237 | , Context const& context, RContext& rcontext, Attribute& attr | |
92f5a8d4 | 238 | , AttributeCategory) |
7c673cae | 239 | { |
92f5a8d4 TL |
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; | |
7c673cae FG |
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 | ||
92f5a8d4 TL |
259 | template <typename Parser, typename Context> |
260 | constexpr bool pass_sequence_container_attribute | |
261 | = sequence_size<Parser, Context>::value > 1; | |
7c673cae | 262 | |
11fdf7f2 TL |
263 | template <typename Parser, typename Iterator, typename Context |
264 | , typename RContext, typename Attribute> | |
92f5a8d4 TL |
265 | typename enable_if_c<pass_sequence_container_attribute<Parser, Context>, bool>::type |
266 | parse_sequence_container( | |
267 | Parser const& parser | |
268 | , Iterator& first, Iterator const& last, Context const& context | |
269 | , RContext& rcontext, Attribute& attr) | |
11fdf7f2 | 270 | { |
92f5a8d4 | 271 | return parser.parse(first, last, context, rcontext, attr); |
11fdf7f2 TL |
272 | } |
273 | ||
274 | template <typename Parser, typename Iterator, typename Context | |
275 | , typename RContext, typename Attribute> | |
92f5a8d4 TL |
276 | typename disable_if_c<pass_sequence_container_attribute<Parser, Context>, bool>::type |
277 | parse_sequence_container( | |
278 | Parser const& parser | |
279 | , Iterator& first, Iterator const& last, Context const& context | |
280 | , RContext& rcontext, Attribute& attr) | |
11fdf7f2 | 281 | { |
92f5a8d4 | 282 | return parse_into_container(parser, first, last, context, rcontext, attr); |
11fdf7f2 TL |
283 | } |
284 | ||
7c673cae FG |
285 | template <typename Parser, typename Iterator, typename Context |
286 | , typename RContext, typename 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; | |
92f5a8d4 TL |
293 | if (parse_sequence_container(parser.left, first, last, context, rcontext, attr) |
294 | && parse_sequence_container(parser.right, first, last, context, rcontext, attr)) | |
7c673cae FG |
295 | return true; |
296 | first = save; | |
297 | return false; | |
298 | } | |
299 | ||
300 | template <typename Parser, typename Iterator, typename Context | |
301 | , typename RContext, typename Attribute> | |
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> | |
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> | |
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> | |
364 | 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 | ||
f67539c2 | 377 | Attribute attr_{}; |
7c673cae FG |
378 | if (!parse_sequence(parser |
379 | , first, last, context, rcontext, attr_, traits::container_attribute())) | |
380 | { | |
381 | return false; | |
382 | } | |
92f5a8d4 TL |
383 | traits::append(attr, std::make_move_iterator(traits::begin(attr_)), |
384 | std::make_move_iterator(traits::end(attr_))); | |
7c673cae FG |
385 | return true; |
386 | } | |
387 | ||
388 | template <typename Iterator, typename Attribute> | |
389 | 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> | |
399 | 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 |