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