]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/spirit/repository/home/qi/operator/detail/keywords.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / spirit / repository / home / qi / operator / detail / keywords.hpp
CommitLineData
7c673cae
FG
1/*=============================================================================
2 Copyright (c) 2011-2012 Thomas Bernard
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 =============================================================================*/
7#if !defined(SPIRIT_KEYWORDS_DETAIL_MARCH_13_2007_1145PM)
8#define SPIRIT_KEYWORDS_DETAIL_MARCH_13_2007_1145PM
9
10#if defined(_MSC_VER)
11#pragma once
12#endif
13#include <boost/fusion/include/nview.hpp>
14#include <boost/spirit/home/qi/string/lit.hpp>
15#include <boost/fusion/include/at.hpp>
16namespace boost { namespace spirit { namespace repository { namespace qi { namespace detail {
17 // Variant visitor class which handles dispatching the parsing to the selected parser
18 // This also handles passing the correct attributes and flags/counters to the subject parsers
19 template<typename T>
20 struct is_distinct : T::distinct { };
21
22 template<typename T, typename Action>
23 struct is_distinct< spirit::qi::action<T,Action> > : T::distinct { };
24
25 template<typename T>
26 struct is_distinct< spirit::qi::hold_directive<T> > : T::distinct { };
27
28
29
30 template < typename Elements, typename Iterator ,typename Context ,typename Skipper
31 ,typename Flags ,typename Counters ,typename Attribute, typename NoCasePass>
32 struct parse_dispatcher
33 : public boost::static_visitor<bool>
34 {
35
36 typedef Iterator iterator_type;
37 typedef Context context_type;
38 typedef Skipper skipper_type;
39 typedef Elements elements_type;
40
41 typedef typename add_reference<Attribute>::type attr_reference;
42 public:
43 parse_dispatcher(const Elements &elements,Iterator& first, Iterator const& last
44 , Context& context, Skipper const& skipper
45 , Flags &flags, Counters &counters, attr_reference attr) :
46 elements(elements), first(first), last(last)
47 , context(context), skipper(skipper)
48 , flags(flags),counters(counters), attr(attr)
49 {}
50
51 template<typename T> bool operator()(T& idx) const
52 {
53 return call(idx,typename traits::not_is_unused<Attribute>::type());
54 }
55
56 template <typename Subject,typename Index>
57 bool call_subject_unused(
58 Subject const &subject, Iterator &first, Iterator const &last
59 , Context& context, Skipper const& skipper
11fdf7f2 60 , Index& /*idx*/ ) const
7c673cae
FG
61 {
62 Iterator save = first;
63 skipper_keyword_marker<Skipper,NoCasePass>
64 marked_skipper(skipper,flags[Index::value],counters[Index::value]);
65
66 if(subject.parse(first,last,context,marked_skipper,unused))
67 {
68 return true;
69 }
92f5a8d4 70 first = save;
7c673cae
FG
71 return false;
72 }
73
74
75 template <typename Subject,typename Index>
76 bool call_subject(
77 Subject const &subject, Iterator &first, Iterator const &last
78 , Context& context, Skipper const& skipper
11fdf7f2 79 , Index& /*idx*/ ) const
7c673cae
FG
80 {
81
82 Iterator save = first;
83 skipper_keyword_marker<Skipper,NoCasePass>
84 marked_skipper(skipper,flags[Index::value],counters[Index::value]);
85 if(subject.parse(first,last,context,marked_skipper,fusion::at_c<Index::value>(attr)))
86 {
87 return true;
88 }
92f5a8d4 89 first = save;
7c673cae
FG
90 return false;
91 }
92
92f5a8d4
TL
93#if defined(_MSC_VER)
94# pragma warning(push)
95# pragma warning(disable: 4127) // conditional expression is constant
96#endif
7c673cae
FG
97 // Handle unused attributes
98 template <typename T> bool call(T &idx, mpl::false_) const{
99
100 typedef typename mpl::at<Elements,T>::type ElementType;
101 if(
102 (!is_distinct<ElementType>::value)
103 || skipper.parse(first,last,unused,unused,unused)
104 ){
105 spirit::qi::skip_over(first, last, skipper);
106 return call_subject_unused(fusion::at_c<T::value>(elements), first, last, context, skipper, idx );
107 }
108 return false;
109 }
110 // Handle normal attributes
111 template <typename T> bool call(T &idx, mpl::true_) const{
112 typedef typename mpl::at<Elements,T>::type ElementType;
113 if(
114 (!is_distinct<ElementType>::value)
115 || skipper.parse(first,last,unused,unused,unused)
116 ){
117 return call_subject(fusion::at_c<T::value>(elements), first, last, context, skipper, idx);
118 }
119 return false;
120 }
92f5a8d4
TL
121#if defined(_MSC_VER)
122# pragma warning(pop)
123#endif
7c673cae
FG
124
125 const Elements &elements;
126 Iterator &first;
127 const Iterator &last;
128 Context & context;
129 const Skipper &skipper;
130 Flags &flags;
131 Counters &counters;
132 attr_reference attr;
133 };
134 // string keyword loop handler
135 template <typename Elements, typename StringKeywords, typename IndexList, typename FlagsType, typename Modifiers>
136 struct string_keywords
137 {
138 // Create a variant type to be able to store parser indexes in the embedded symbols parser
139 typedef typename
140 spirit::detail::as_variant<
141 IndexList >::type parser_index_type;
142
143 ///////////////////////////////////////////////////////////////////////////
144 // build_char_type_sequence
145 //
146 // Build a fusion sequence from the kwd directive specified character type.
147 ///////////////////////////////////////////////////////////////////////////
148 template <typename Sequence >
149 struct build_char_type_sequence
150 {
151 struct element_char_type
152 {
153 template <typename T>
154 struct result;
155
156 template <typename F, typename Element>
157 struct result<F(Element)>
158 {
159 typedef typename Element::char_type type;
160
161 };
162 template <typename F, typename Element,typename Action>
163 struct result<F(spirit::qi::action<Element,Action>) >
164 {
165 typedef typename Element::char_type type;
166 };
167 template <typename F, typename Element>
168 struct result<F(spirit::qi::hold_directive<Element>)>
169 {
170 typedef typename Element::char_type type;
171 };
172
173 // never called, but needed for decltype-based result_of (C++0x)
11fdf7f2 174#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
7c673cae
FG
175 template <typename Element>
176 typename result<element_char_type(Element)>::type
11fdf7f2
TL
177 operator()(Element&&) const;
178#endif
7c673cae
FG
179 };
180
181 // Compute the list of character types of the child kwd directives
182 typedef typename
183 fusion::result_of::transform<Sequence, element_char_type>::type
184 type;
185 };
186
187
188 ///////////////////////////////////////////////////////////////////////////
189 // get_keyword_char_type
190 //
191 // Collapses the character type comming from the subject kwd parsers and
192 // and checks that they are all identical (necessary in order to be able
193 // to build a tst parser to parse the keywords.
194 ///////////////////////////////////////////////////////////////////////////
195 template <typename Sequence>
196 struct get_keyword_char_type
197 {
198 // Make sure each of the types occur only once in the type list
199 typedef typename
200 mpl::fold<
201 Sequence, mpl::vector<>,
202 mpl::if_<
203 mpl::contains<mpl::_1, mpl::_2>,
204 mpl::_1, mpl::push_back<mpl::_1, mpl::_2>
205 >
206 >::type
207 no_duplicate_char_types;
208
209 // If the compiler traps here this means you mixed
210 // character type for the keywords specified in the
211 // kwd directive sequence.
212 BOOST_MPL_ASSERT_RELATION( mpl::size<no_duplicate_char_types>::value, ==, 1 );
213
214 typedef typename mpl::front<no_duplicate_char_types>::type type;
215
216 };
217
218 // Get the character type for the tst parser
219 typedef typename build_char_type_sequence< StringKeywords >::type char_types;
220 typedef typename get_keyword_char_type<
221 typename mpl::if_<
222 mpl::equal_to<
223 typename mpl::size < char_types >::type
224 , mpl::int_<0>
225 >
226 , mpl::vector< boost::spirit::standard::char_type >
227 , char_types >::type
228 >::type char_type;
229
230 // Our symbols container
231 typedef spirit::qi::tst< char_type, parser_index_type> keywords_type;
232
233 // Filter functor used for case insensitive parsing
234 template <typename CharEncoding>
235 struct no_case_filter
236 {
237 char_type operator()(char_type ch) const
238 {
239 return static_cast<char_type>(CharEncoding::tolower(ch));
240 }
241 };
242
243 ///////////////////////////////////////////////////////////////////////////
244 // build_case_type_sequence
245 //
246 // Build a fusion sequence from the kwd/ikwd directives
247 // in order to determine if case sensitive and case insensitive
248 // keywords have been mixed.
249 ///////////////////////////////////////////////////////////////////////////
250 template <typename Sequence >
251 struct build_case_type_sequence
252 {
253 struct element_case_type
254 {
255 template <typename T>
256 struct result;
257
258 template <typename F, typename Element>
259 struct result<F(Element)>
260 {
261 typedef typename Element::no_case_keyword type;
262
263 };
264 template <typename F, typename Element,typename Action>
265 struct result<F(spirit::qi::action<Element,Action>) >
266 {
267 typedef typename Element::no_case_keyword type;
268 };
269 template <typename F, typename Element>
270 struct result<F(spirit::qi::hold_directive<Element>)>
271 {
272 typedef typename Element::no_case_keyword type;
273 };
274
275 // never called, but needed for decltype-based result_of (C++0x)
11fdf7f2 276#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
7c673cae
FG
277 template <typename Element>
278 typename result<element_case_type(Element)>::type
11fdf7f2
TL
279 operator()(Element&&) const;
280#endif
7c673cae
FG
281 };
282
283 // Compute the list of character types of the child kwd directives
284 typedef typename
285 fusion::result_of::transform<Sequence, element_case_type>::type
286 type;
287 };
288
289 ///////////////////////////////////////////////////////////////////////////
290 // get_nb_case_types
291 //
292 // Counts the number of entries in the case type sequence matching the
293 // CaseType parameter (mpl::true_ -> case insensitve
294 // , mpl::false_ -> case sensitive
295 ///////////////////////////////////////////////////////////////////////////
296 template <typename Sequence,typename CaseType>
297 struct get_nb_case_types
298 {
299 // Make sure each of the types occur only once in the type list
300 typedef typename
301 mpl::count_if<
302 Sequence, mpl::equal_to<mpl::_,CaseType>
303 >::type type;
304
305
306 };
307 // Build the case type sequence
308 typedef typename build_case_type_sequence< StringKeywords >::type case_type_sequence;
309 // Count the number of case sensitive entries and case insensitve entries
310 typedef typename get_nb_case_types<case_type_sequence,mpl::true_>::type ikwd_count;
311 typedef typename get_nb_case_types<case_type_sequence,mpl::false_>::type kwd_count;
312 // Get the size of the original sequence
313 typedef typename mpl::size<IndexList>::type nb_elements;
314 // Determine if all the kwd directive are case sensitive/insensitive
315 typedef typename mpl::and_<
316 typename mpl::greater< nb_elements, mpl::int_<0> >::type
317 , typename mpl::equal_to< ikwd_count, nb_elements>::type
318 >::type all_ikwd;
319
320 typedef typename mpl::and_<
321 typename mpl::greater< nb_elements, mpl::int_<0> >::type
322 , typename mpl::equal_to< kwd_count, nb_elements>::type
323 >::type all_kwd;
324
325 typedef typename mpl::or_< all_kwd, all_ikwd >::type all_directives_of_same_type;
326
327 // Do we have a no case modifier
328 typedef has_modifier<Modifiers, spirit::tag::char_code_base<spirit::tag::no_case> > no_case_modifier;
329
330 // Should the no_case filter always be used ?
331 typedef typename mpl::or_<
332 no_case_modifier,
333 mpl::and_<
334 all_directives_of_same_type
335 ,all_ikwd
336 >
337 >::type
338 no_case;
339
340 typedef no_case_filter<
341 typename spirit::detail::get_encoding_with_case<
342 Modifiers
343 , char_encoding::standard
344 , no_case::value>::type>
345 nc_filter;
346 // Determine the standard case filter type
347 typedef typename mpl::if_<
348 no_case
349 , nc_filter
350 , spirit::qi::tst_pass_through >::type
351 first_pass_filter_type;
352
353 typedef typename mpl::or_<
354 all_directives_of_same_type
355 , no_case_modifier
356 >::type requires_one_pass;
357
358
359 // Functor which adds all the keywords/subject parser indexes
360 // collected from the subject kwd directives to the keyword tst parser
361 struct keyword_entry_adder
362 {
363 typedef int result_type;
364
365 keyword_entry_adder(shared_ptr<keywords_type> lookup,FlagsType &flags, Elements &elements) :
366 lookup(lookup)
367 ,flags(flags)
368 ,elements(elements)
369 {}
370
371 template <typename T>
372 int operator()(const T &index) const
373 {
374 return call(fusion::at_c<T::value>(elements),index);
375 }
376
377 template <typename T, typename Position, typename Action>
378 int call(const spirit::qi::action<T,Action> &parser, const Position position ) const
379 {
380
381 // Make the keyword/parse index entry in the tst parser
382 lookup->add(
383 traits::get_begin<char_type>(get_string(parser.subject.keyword)),
384 traits::get_end<char_type>(get_string(parser.subject.keyword)),
385 position
386 );
387 // Get the initial state of the flags array and store it in the flags initializer
388 flags[Position::value]=parser.subject.iter.flag_init();
389 return 0;
390 }
391
392 template <typename T, typename Position>
393 int call( const T & parser, const Position position) const
394 {
395 // Make the keyword/parse index entry in the tst parser
396 lookup->add(
397 traits::get_begin<char_type>(get_string(parser.keyword)),
398 traits::get_end<char_type>(get_string(parser.keyword)),
399 position
400 );
401 // Get the initial state of the flags array and store it in the flags initializer
402 flags[Position::value]=parser.iter.flag_init();
403 return 0;
404 }
405
406 template <typename T, typename Position>
407 int call( const spirit::qi::hold_directive<T> & parser, const Position position) const
408 {
409 // Make the keyword/parse index entry in the tst parser
410 lookup->add(
411 traits::get_begin<char_type>(get_string(parser.subject.keyword)),
412 traits::get_end<char_type>(get_string(parser.subject.keyword)),
413 position
414 );
415 // Get the initial state of the flags array and store it in the flags initializer
416 flags[Position::value]=parser.subject.iter.flag_init();
417 return 0;
418 }
419
420
421 template <typename String, bool no_attribute>
422 const String get_string(const boost::spirit::qi::literal_string<String,no_attribute> &parser) const
423 {
424 return parser.str;
425 }
426
427 template <typename String, bool no_attribute>
428 const typename boost::spirit::qi::no_case_literal_string<String,no_attribute>::string_type &
429 get_string(const boost::spirit::qi::no_case_literal_string<String,no_attribute> &parser) const
430 {
431 return parser.str_lo;
432 }
433
434
435
436 shared_ptr<keywords_type> lookup;
437 FlagsType & flags;
438 Elements &elements;
439 };
440
441 string_keywords(Elements &elements,FlagsType &flags_init) : lookup(new keywords_type())
442 {
443 // Loop through all the subject parsers to build the keyword parser symbol parser
444 IndexList indexes;
445 keyword_entry_adder f1(lookup,flags_init,elements);
446 fusion::for_each(indexes,f1);
447
448 }
449 template <typename Iterator,typename ParseVisitor, typename Skipper>
450 bool parse(
451 Iterator &first,
452 const Iterator &last,
453 const ParseVisitor &parse_visitor,
11fdf7f2 454 const Skipper &/*skipper*/) const
7c673cae
FG
455 {
456 if(parser_index_type* val_ptr =
457 lookup->find(first,last,first_pass_filter_type()))
458 {
459 if(!apply_visitor(parse_visitor,*val_ptr)){
460 return false;
461 }
462 return true;
463 }
464 return false;
465 }
466
467 template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper>
468 bool parse(
469 Iterator &first,
470 const Iterator &last,
471 const ParseVisitor &parse_visitor,
472 const NoCaseParseVisitor &no_case_parse_visitor,
11fdf7f2 473 const Skipper &/*skipper*/) const
7c673cae
FG
474 {
475 Iterator saved_first = first;
476 if(parser_index_type* val_ptr =
477 lookup->find(first,last,first_pass_filter_type()))
478 {
479 if(!apply_visitor(parse_visitor,*val_ptr)){
480 return false;
481 }
482 return true;
483 }
484 // Second pass case insensitive
485 else if(parser_index_type* val_ptr
486 = lookup->find(saved_first,last,nc_filter()))
487 {
488 first = saved_first;
489 if(!apply_visitor(no_case_parse_visitor,*val_ptr)){
490 return false;
491 }
492 return true;
493 }
494 return false;
495 }
496 shared_ptr<keywords_type> lookup;
497
498
499 };
500
501 struct empty_keywords_list
502 {
503 typedef mpl::true_ requires_one_pass;
504
505 empty_keywords_list()
506 {}
507 template<typename Elements>
508 empty_keywords_list(const Elements &)
509 {}
510
511 template<typename Elements, typename FlagsInit>
512 empty_keywords_list(const Elements &, const FlagsInit &)
513 {}
514
515 template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper>
516 bool parse(
11fdf7f2
TL
517 Iterator &/*first*/,
518 const Iterator &/*last*/,
519 const ParseVisitor &/*parse_visitor*/,
520 const NoCaseParseVisitor &/*no_case_parse_visitor*/,
521 const Skipper &/*skipper*/) const
7c673cae
FG
522 {
523 return false;
524 }
525
526 template <typename Iterator,typename ParseVisitor, typename Skipper>
527 bool parse(
11fdf7f2
TL
528 Iterator &/*first*/,
529 const Iterator &/*last*/,
530 const ParseVisitor &/*parse_visitor*/,
531 const Skipper &/*skipper*/) const
7c673cae
FG
532 {
533 return false;
534 }
535
536 template <typename ParseFunction>
11fdf7f2 537 bool parse( ParseFunction &/*function*/ ) const
7c673cae
FG
538 {
539 return false;
540 }
541 };
542
543 template<typename ComplexKeywords>
544 struct complex_keywords
545 {
546 // Functor which performs the flag initialization for the complex keyword parsers
547 template <typename FlagsType, typename Elements>
548 struct flag_init_value_setter
549 {
550 typedef int result_type;
551
552 flag_init_value_setter(Elements &elements,FlagsType &flags)
553 :flags(flags)
554 ,elements(elements)
555 {}
556
557 template <typename T>
558 int operator()(const T &index) const
559 {
560 return call(fusion::at_c<T::value>(elements),index);
561 }
562
563 template <typename T, typename Position, typename Action>
11fdf7f2 564 int call(const spirit::qi::action<T,Action> &parser, const Position /*position*/ ) const
7c673cae
FG
565 {
566 // Get the initial state of the flags array and store it in the flags initializer
567 flags[Position::value]=parser.subject.iter.flag_init();
568 return 0;
569 }
570
571 template <typename T, typename Position>
11fdf7f2 572 int call( const T & parser, const Position /*position*/) const
7c673cae
FG
573 {
574 // Get the initial state of the flags array and store it in the flags initializer
575 flags[Position::value]=parser.iter.flag_init();
576 return 0;
577 }
578
579 template <typename T, typename Position>
11fdf7f2 580 int call( const spirit::qi::hold_directive<T> & parser, const Position /*position*/) const
7c673cae
FG
581 {
582 // Get the initial state of the flags array and store it in the flags initializer
583 flags[Position::value]=parser.subject.iter.flag_init();
584 return 0;
585 }
586
587 FlagsType & flags;
588 Elements &elements;
589 };
590
591 template <typename Elements, typename Flags>
592 complex_keywords(Elements &elements, Flags &flags)
593 {
594 flag_init_value_setter<Flags,Elements> flag_initializer(elements,flags);
595 fusion::for_each(complex_keywords_inst,flag_initializer);
596 }
597
598 template <typename ParseFunction>
599 bool parse( ParseFunction &function ) const
600 {
601 return fusion::any(complex_keywords_inst,function);
602 }
603
604 ComplexKeywords complex_keywords_inst;
605 };
606 // This helper class enables jumping over intermediate directives
607 // down the kwd parser iteration count checking policy
608 struct register_successful_parse
609 {
610 template <typename Subject>
611 static bool call(Subject const &subject,bool &flag, int &counter)
612 {
613 return subject.iter.register_successful_parse(flag,counter);
614 }
615 template <typename Subject, typename Action>
616 static bool call(spirit::qi::action<Subject, Action> const &subject,bool &flag, int &counter)
617 {
618 return subject.subject.iter.register_successful_parse(flag,counter);
619 }
620 template <typename Subject>
621 static bool call(spirit::qi::hold_directive<Subject> const &subject,bool &flag, int &counter)
622 {
623 return subject.subject.iter.register_successful_parse(flag,counter);
624 }
625 };
626
627 // This helper class enables jumping over intermediate directives
628 // down the kwd parser
629 struct extract_keyword
630 {
631 template <typename Subject>
632 static Subject const& call(Subject const &subject)
633 {
634 return subject;
635 }
636 template <typename Subject, typename Action>
637 static Subject const& call(spirit::qi::action<Subject, Action> const &subject)
638 {
639 return subject.subject;
640 }
641 template <typename Subject>
642 static Subject const& call(spirit::qi::hold_directive<Subject> const &subject)
643 {
644 return subject.subject;
645 }
646 };
647
648 template <typename ParseDispatcher>
649 struct complex_kwd_function
650 {
651 typedef typename ParseDispatcher::iterator_type Iterator;
652 typedef typename ParseDispatcher::context_type Context;
653 typedef typename ParseDispatcher::skipper_type Skipper;
654 complex_kwd_function(
655 Iterator& first, Iterator const& last
656 , Context& context, Skipper const& skipper, ParseDispatcher &dispatcher)
657 : first(first)
658 , last(last)
659 , context(context)
660 , skipper(skipper)
661 , dispatcher(dispatcher)
662 {
663 }
664
665 template <typename Component>
666 bool operator()(Component const& component)
667 {
668 Iterator save = first;
669 if(
670 extract_keyword::call(
671 fusion::at_c<
672 Component::value
673 ,typename ParseDispatcher::elements_type
674 >(dispatcher.elements)
675 )
676 .keyword.parse(
677 first
678 ,last
679 ,context
680 ,skipper
681 ,unused)
682 )
683 {
684 if(!dispatcher(component)){
685 first = save;
686 return false;
687 }
688 return true;
689 }
690 return false;
691 }
692
693 Iterator& first;
694 Iterator const& last;
695 Context& context;
696 Skipper const& skipper;
697 ParseDispatcher const& dispatcher;
698
7c673cae 699 // silence MSVC warning C4512: assignment operator could not be generated
92f5a8d4 700 BOOST_DELETED_FUNCTION(complex_kwd_function& operator= (complex_kwd_function const&))
7c673cae
FG
701 };
702
703
704}}}}}
705
706#endif