]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/spirit/repository/home/qi/operator/keywords.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / spirit / repository / home / qi / operator / keywords.hpp
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