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