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