]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 Joel de Guzman | |
3 | Copyright (c) 2011-2012 Thomas Bernard | |
4 | ||
5 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
6 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | =============================================================================*/ | |
f67539c2 TL |
8 | #ifndef BOOST_SPIRIT_REPOSITORY_QI_OPERATOR_KEYWORDS_HPP |
9 | #define BOOST_SPIRIT_REPOSITORY_QI_OPERATOR_KEYWORDS_HPP | |
7c673cae FG |
10 | |
11 | #if defined(_MSC_VER) | |
12 | #pragma once | |
13 | #endif | |
14 | ||
15 | #include <boost/spirit/home/qi/meta_compiler.hpp> | |
16 | #include <boost/spirit/home/qi/domain.hpp> | |
17 | #include <boost/spirit/home/qi/detail/permute_function.hpp> | |
18 | #include <boost/spirit/home/qi/detail/attributes.hpp> | |
19 | #include <boost/spirit/home/support/detail/what_function.hpp> | |
20 | #include <boost/spirit/home/support/info.hpp> | |
21 | #include <boost/spirit/home/support/unused.hpp> | |
22 | #include <boost/fusion/include/iter_fold.hpp> | |
23 | #include <boost/fusion/include/at.hpp> | |
24 | #include <boost/fusion/include/value_at.hpp> | |
25 | #include <boost/fusion/include/mpl.hpp> | |
26 | #include <boost/optional.hpp> | |
27 | #include <boost/foreach.hpp> | |
28 | #include <boost/array.hpp> | |
29 | #include <boost/spirit/home/qi/string/symbols.hpp> | |
30 | #include <boost/spirit/home/qi/string/lit.hpp> | |
31 | #include <boost/spirit/home/qi/action/action.hpp> | |
32 | #include <boost/spirit/home/qi/directive/hold.hpp> | |
33 | #include <boost/mpl/count_if.hpp> | |
11fdf7f2 | 34 | #include <boost/mpl/greater.hpp> |
7c673cae FG |
35 | #include <boost/mpl/range_c.hpp> |
36 | #include <boost/mpl/copy.hpp> | |
37 | #include <boost/mpl/size.hpp> | |
38 | #include <boost/mpl/equal_to.hpp> | |
39 | #include <boost/mpl/back_inserter.hpp> | |
40 | #include <boost/mpl/filter_view.hpp> | |
41 | #include <boost/fusion/include/zip_view.hpp> | |
42 | #include <boost/fusion/include/as_vector.hpp> | |
43 | #include <boost/variant/static_visitor.hpp> | |
f67539c2 TL |
44 | #include <boost/proto/operators.hpp> |
45 | #include <boost/proto/tags.hpp> | |
7c673cae FG |
46 | #include <boost/type_traits/remove_const.hpp> |
47 | #include <boost/type_traits/is_same.hpp> | |
48 | #include <boost/spirit/repository/home/qi/operator/detail/keywords.hpp> | |
49 | #include <boost/fusion/include/any.hpp> | |
50 | ||
51 | ||
52 | namespace boost { namespace spirit | |
53 | { | |
54 | /////////////////////////////////////////////////////////////////////////// | |
55 | // Enablers | |
56 | /////////////////////////////////////////////////////////////////////////// | |
57 | template <> | |
58 | struct use_operator<qi::domain, proto::tag::divides > // enables / | |
59 | : mpl::true_ {}; | |
60 | ||
61 | template <> | |
62 | struct flatten_tree<qi::domain, proto::tag::divides> // flattens / | |
63 | : mpl::true_ {}; | |
64 | }} | |
65 | ||
66 | namespace boost { namespace spirit { namespace repository { namespace qi | |
67 | { | |
68 | ||
69 | // kwd directive parser type identification | |
70 | namespace detail | |
71 | { | |
72 | BOOST_MPL_HAS_XXX_TRAIT_DEF(kwd_parser_id) | |
73 | BOOST_MPL_HAS_XXX_TRAIT_DEF(complex_kwd_parser_id) | |
74 | ||
75 | ||
76 | } | |
77 | ||
78 | // kwd directive type query | |
79 | template <typename T> | |
80 | struct is_kwd_parser : detail::has_kwd_parser_id<T> {}; | |
81 | ||
82 | template <typename Subject, typename Action> | |
83 | struct is_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_kwd_parser_id<Subject> {}; | |
84 | ||
85 | template <typename Subject> | |
86 | struct is_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_kwd_parser_id<Subject> {}; | |
87 | ||
88 | template <typename T> | |
89 | struct is_complex_kwd_parser : detail::has_complex_kwd_parser_id<T> {}; | |
90 | ||
91 | template <typename Subject, typename Action> | |
92 | struct is_complex_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_complex_kwd_parser_id<Subject> {}; | |
93 | ||
94 | template <typename Subject> | |
95 | struct is_complex_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_complex_kwd_parser_id<Subject> {}; | |
96 | ||
97 | ||
98 | // Keywords operator | |
99 | template <typename Elements, typename Modifiers> | |
100 | struct keywords : spirit::qi::nary_parser<keywords<Elements,Modifiers> > | |
101 | { | |
102 | template <typename Context, typename Iterator> | |
103 | struct attribute | |
104 | { | |
105 | // Put all the element attributes in a tuple | |
106 | typedef typename traits::build_attribute_sequence< | |
107 | Elements, Context, traits::sequence_attribute_transform, Iterator, spirit::qi::domain >::type | |
108 | all_attributes; | |
109 | ||
110 | // Now, build a fusion vector over the attributes. Note | |
111 | // that build_fusion_vector 1) removes all unused attributes | |
112 | // and 2) may return unused_type if all elements have | |
113 | // unused_type(s). | |
114 | typedef typename | |
115 | traits::build_fusion_vector<all_attributes>::type | |
116 | type; | |
117 | }; | |
118 | ||
119 | /// Make sure that all subjects are of the kwd type | |
120 | typedef typename mpl::count_if< | |
121 | Elements, | |
122 | mpl::not_< | |
123 | mpl::or_< | |
124 | is_kwd_parser< | |
125 | mpl::_1 | |
126 | > , | |
127 | is_complex_kwd_parser< | |
128 | mpl::_1 | |
129 | > | |
130 | > | |
131 | > | |
132 | > non_kwd_subject_count; | |
133 | ||
134 | /// If the assertion fails here then you probably forgot to wrap a | |
135 | /// subject of the / operator in a kwd directive | |
136 | BOOST_MPL_ASSERT_RELATION( non_kwd_subject_count::value, ==, 0 ); | |
137 | ||
138 | /////////////////////////////////////////////////////////////////////////// | |
139 | // build_parser_tags | |
140 | // | |
141 | // Builds a boost::variant from an mpl::range_c in order to "mark" every | |
142 | // parser of the fusion sequence. The integer constant is used in the parser | |
143 | // dispatcher functor in order to use the parser corresponding to the recognised | |
144 | // keyword. | |
145 | /////////////////////////////////////////////////////////////////////////// | |
146 | ||
147 | template <typename Sequence> | |
148 | struct build_parser_tags | |
149 | { | |
150 | // Get the sequence size | |
151 | typedef typename mpl::size< Sequence >::type sequence_size; | |
152 | ||
153 | // Create an integer_c constant for every parser in the sequence | |
154 | typedef typename mpl::range_c<int, 0, sequence_size::value>::type int_range; | |
155 | ||
156 | // Transform the range_c to an mpl vector in order to be able to transform it into a variant | |
157 | typedef typename mpl::copy<int_range, mpl::back_inserter<mpl::vector<> > >::type type; | |
158 | ||
159 | }; | |
160 | // Build an index mpl vector | |
161 | typedef typename build_parser_tags< Elements >::type parser_index_vector; | |
162 | ||
163 | template <typename idx> | |
164 | struct is_complex_kwd_parser_filter : is_complex_kwd_parser< typename mpl::at<Elements, idx>::type > | |
165 | {}; | |
166 | ||
167 | template <typename idx> | |
168 | struct is_kwd_parser_filter : is_kwd_parser< typename mpl::at<Elements, idx>::type > | |
169 | {}; | |
170 | ||
171 | // filter out the string kwd directives | |
172 | typedef typename mpl::filter_view< Elements, is_kwd_parser<mpl::_> >::type string_keywords; | |
173 | ||
174 | typedef typename mpl::filter_view< parser_index_vector , | |
175 | is_kwd_parser_filter< mpl::_ > | |
176 | >::type string_keyword_indexes; | |
177 | // filter out the complex keywords | |
178 | typedef typename mpl::filter_view< parser_index_vector , | |
179 | is_complex_kwd_parser_filter< mpl::_ > | |
180 | >::type complex_keywords_indexes; | |
181 | ||
182 | //typedef typename fusion::filter_view< Elements, is_complex_kwd_parser< mpl::_ > > complex_keywords_view; | |
183 | ||
184 | typedef typename mpl::if_< | |
185 | typename mpl::empty<complex_keywords_indexes>::type, | |
186 | detail::empty_keywords_list, | |
187 | detail::complex_keywords< complex_keywords_indexes > | |
188 | >::type complex_keywords_type; | |
189 | ||
190 | // build a bool array and an integer array which will be used to | |
191 | // check that the repetition constraints of the kwd parsers are | |
192 | // met and bail out a soon as possible | |
193 | typedef boost::array<bool, fusion::result_of::size<Elements>::value> flags_type; | |
194 | typedef boost::array<int, fusion::result_of::size<Elements>::value> counters_type; | |
195 | ||
196 | typedef typename mpl::if_< | |
197 | typename mpl::empty<string_keyword_indexes>::type, | |
198 | detail::empty_keywords_list, | |
199 | detail::string_keywords< | |
200 | Elements, | |
201 | string_keywords, | |
202 | string_keyword_indexes, | |
203 | flags_type, | |
204 | Modifiers> | |
205 | >::type string_keywords_type; | |
206 | ||
207 | keywords(Elements const& elements_) : | |
208 | elements(elements_) | |
209 | , string_keywords_inst(elements,flags_init) | |
210 | , complex_keywords_inst(elements,flags_init) | |
211 | { | |
212 | } | |
213 | ||
214 | template <typename Iterator, typename Context | |
215 | , typename Skipper, typename Attribute> | |
216 | bool parse(Iterator& first, Iterator const& last | |
217 | , Context& context, Skipper const& skipper | |
218 | , Attribute& attr_) const | |
219 | { | |
220 | // Select which parse function to call | |
221 | // We need to handle the case where kwd / ikwd directives have been mixed | |
222 | // This is where we decide which function should be called. | |
223 | return parse_impl(first, last, context, skipper, attr_, | |
224 | typename string_keywords_type::requires_one_pass() | |
225 | ); | |
226 | } | |
227 | ||
228 | template <typename Iterator, typename Context | |
229 | , typename Skipper, typename Attribute> | |
230 | bool parse_impl(Iterator& first, Iterator const& last | |
231 | , Context& context, Skipper const& skipper | |
232 | , Attribute& attr_,mpl::true_ /* one pass */) const | |
233 | { | |
234 | ||
235 | // wrap the attribute in a tuple if it is not a tuple | |
236 | typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_); | |
237 | ||
238 | flags_type flags(flags_init); | |
239 | //flags.assign(false); | |
240 | ||
241 | counters_type counters; | |
242 | counters.assign(0); | |
243 | ||
244 | typedef repository::qi::detail::parse_dispatcher<Elements,Iterator, Context, Skipper | |
245 | , flags_type, counters_type | |
246 | , typename traits::wrap_if_not_tuple<Attribute>::type | |
247 | , mpl::false_ > parser_visitor_type; | |
248 | ||
249 | parser_visitor_type parse_visitor(elements, first, last | |
250 | , context, skipper, flags | |
251 | , counters, attr); | |
252 | ||
253 | typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type; | |
254 | ||
255 | complex_kwd_function_type | |
256 | complex_function(first,last,context,skipper,parse_visitor); | |
257 | ||
258 | // We have a bool array 'flags' with one flag for each parser as well as a 'counter' | |
259 | // array. | |
260 | // The kwd directive sets and increments the counter when a successeful parse occurred | |
261 | // as well as the slot of the corresponding parser to true in the flags array as soon | |
262 | // the minimum repetition requirement is met and keeps that value to true as long as | |
263 | // the maximum repetition requirement is met. | |
264 | // The parsing takes place here in two steps: | |
265 | // 1) parse a keyword and fetch the parser index associated with that keyword | |
266 | // 2) call the associated parser and store the parsed value in the matching attribute. | |
267 | ||
92f5a8d4 | 268 | for(;;) |
7c673cae FG |
269 | { |
270 | ||
271 | spirit::qi::skip_over(first, last, skipper); | |
272 | Iterator save = first; | |
273 | if (string_keywords_inst.parse(first, last,parse_visitor,skipper)) | |
274 | { | |
275 | save = first; | |
276 | } | |
277 | else { | |
278 | // restore the position to the last successful keyword parse | |
279 | first = save; | |
280 | if(!complex_keywords_inst.parse(complex_function)) | |
281 | { | |
282 | first = save; | |
f67539c2 | 283 | // Check that we are leaving the keywords parser in a successful state |
7c673cae FG |
284 | BOOST_FOREACH(bool &valid,flags) |
285 | { | |
286 | if(!valid) | |
287 | { | |
288 | return false; | |
289 | } | |
290 | } | |
291 | return true; | |
292 | } | |
293 | else | |
294 | save = first; | |
295 | } | |
296 | } | |
297 | return false; | |
298 | } | |
299 | ||
300 | // Handle the mixed kwd and ikwd case | |
301 | template <typename Iterator, typename Context | |
302 | , typename Skipper, typename Attribute> | |
303 | bool parse_impl(Iterator& first, Iterator const& last | |
304 | , Context& context, Skipper const& skipper | |
305 | , Attribute& attr_,mpl::false_ /* two passes */) const | |
306 | { | |
307 | ||
308 | // wrap the attribute in a tuple if it is not a tuple | |
309 | typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_); | |
310 | ||
311 | flags_type flags(flags_init); | |
312 | //flags.assign(false); | |
313 | ||
314 | counters_type counters; | |
315 | counters.assign(0); | |
316 | ||
317 | typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper | |
318 | , flags_type, counters_type | |
319 | , typename traits::wrap_if_not_tuple<Attribute>::type | |
320 | , mpl::false_> parser_visitor_type; | |
321 | ||
322 | typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper | |
323 | , flags_type, counters_type | |
324 | , typename traits::wrap_if_not_tuple<Attribute>::type | |
325 | , mpl::true_> no_case_parser_visitor_type; | |
326 | ||
327 | ||
328 | parser_visitor_type parse_visitor(elements,first,last | |
329 | ,context,skipper,flags,counters,attr); | |
330 | no_case_parser_visitor_type no_case_parse_visitor(elements,first,last | |
331 | ,context,skipper,flags,counters,attr); | |
332 | ||
333 | typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type; | |
334 | ||
335 | complex_kwd_function_type | |
336 | complex_function(first,last,context,skipper,parse_visitor); | |
337 | ||
338 | ||
339 | // We have a bool array 'flags' with one flag for each parser as well as a 'counter' | |
340 | // array. | |
341 | // The kwd directive sets and increments the counter when a successeful parse occurred | |
342 | // as well as the slot of the corresponding parser to true in the flags array as soon | |
343 | // the minimum repetition requirement is met and keeps that value to true as long as | |
344 | // the maximum repetition requirement is met. | |
345 | // The parsing takes place here in two steps: | |
346 | // 1) parse a keyword and fetch the parser index associated with that keyword | |
347 | // 2) call the associated parser and store the parsed value in the matching attribute. | |
348 | ||
92f5a8d4 | 349 | for(;;) |
7c673cae FG |
350 | { |
351 | spirit::qi::skip_over(first, last, skipper); | |
352 | Iterator save = first; | |
353 | // String keywords pass | |
354 | if (string_keywords_inst.parse(first,last,parse_visitor,no_case_parse_visitor,skipper)) | |
355 | { | |
356 | save = first; | |
357 | } | |
358 | else { | |
359 | first = save; | |
360 | ||
361 | if(!complex_keywords_inst.parse(complex_function)) | |
362 | { | |
363 | first = save; | |
f67539c2 | 364 | // Check that we are leaving the keywords parser in a successful state |
7c673cae FG |
365 | BOOST_FOREACH(bool &valid,flags) |
366 | { | |
367 | if(!valid) | |
368 | { | |
369 | return false; | |
370 | } | |
371 | } | |
372 | return true; | |
373 | } | |
374 | else | |
375 | { | |
376 | save = first; | |
377 | } | |
378 | } | |
379 | } | |
380 | return false; | |
381 | } | |
382 | ||
383 | template <typename Context> | |
384 | info what(Context& context) const | |
385 | { | |
386 | info result("keywords"); | |
387 | fusion::for_each(elements, | |
388 | spirit::detail::what_function<Context>(result, context)); | |
389 | return result; | |
390 | } | |
391 | flags_type flags_init; | |
392 | Elements elements; | |
393 | string_keywords_type string_keywords_inst; | |
394 | complex_keywords_type complex_keywords_inst; | |
395 | ||
396 | }; | |
397 | }}}} | |
398 | ||
399 | namespace boost { namespace spirit { namespace qi { | |
400 | /////////////////////////////////////////////////////////////////////////// | |
401 | // Parser generators: make_xxx function (objects) | |
402 | /////////////////////////////////////////////////////////////////////////// | |
403 | template <typename Elements, typename Modifiers > | |
404 | struct make_composite<proto::tag::divides, Elements, Modifiers > | |
405 | { | |
406 | typedef repository::qi::keywords<Elements,Modifiers> result_type; | |
407 | result_type operator()(Elements ref, unused_type) const | |
408 | { | |
409 | return result_type(ref); | |
410 | } | |
411 | }; | |
412 | ||
413 | ||
414 | }}} | |
415 | ||
416 | namespace boost { namespace spirit { namespace traits | |
417 | { | |
418 | // We specialize this for keywords (see support/attributes.hpp). | |
419 | // For keywords, we only wrap the attribute in a tuple IFF | |
420 | // it is not already a fusion tuple. | |
421 | template <typename Elements, typename Modifiers,typename Attribute> | |
422 | struct pass_attribute<repository::qi::keywords<Elements,Modifiers>, Attribute> | |
423 | : wrap_if_not_tuple<Attribute> {}; | |
424 | ||
425 | template <typename Elements, typename Modifiers> | |
426 | struct has_semantic_action<repository::qi::keywords<Elements, Modifiers> > | |
427 | : nary_has_semantic_action<Elements> {}; | |
428 | ||
429 | template <typename Elements, typename Attribute, typename Context | |
430 | , typename Iterator, typename Modifiers> | |
431 | struct handles_container<repository::qi::keywords<Elements,Modifiers>, Attribute | |
432 | , Context, Iterator> | |
433 | : nary_handles_container<Elements, Attribute, Context, Iterator> {}; | |
434 | ||
435 | ||
436 | }}} | |
437 | ||
438 | #endif | |
439 |