]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/spirit/repository/home/qi/operator/keywords.hpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / boost / boost / spirit / repository / home / qi / operator / keywords.hpp
CommitLineData
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
52namespace 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
66namespace 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
399namespace 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
416namespace 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