1 /*=============================================================================
2 Copyright (c) 2011-2012 Thomas Bernard
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
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
20 struct is_distinct : T::distinct { };
22 template<typename T, typename Action>
23 struct is_distinct< spirit::qi::action<T,Action> > : T::distinct { };
26 struct is_distinct< spirit::qi::hold_directive<T> > : T::distinct { };
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>
36 typedef Iterator iterator_type;
37 typedef Context context_type;
38 typedef Skipper skipper_type;
39 typedef Elements elements_type;
41 typedef typename add_reference<Attribute>::type attr_reference;
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)
51 template<typename T> bool operator()(T& idx) const
53 return call(idx,typename traits::not_is_unused<Attribute>::type());
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
60 , Index& /*idx*/ ) const
62 Iterator save = first;
63 skipper_keyword_marker<Skipper,NoCasePass>
64 marked_skipper(skipper,flags[Index::value],counters[Index::value]);
66 if(subject.parse(first,last,context,marked_skipper,unused))
75 template <typename Subject,typename Index>
77 Subject const &subject, Iterator &first, Iterator const &last
78 , Context& context, Skipper const& skipper
79 , Index& /*idx*/ ) const
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)))
94 # pragma warning(push)
95 # pragma warning(disable: 4127) // conditional expression is constant
97 // Handle unused attributes
98 template <typename T> bool call(T &idx, mpl::false_) const{
100 typedef typename mpl::at<Elements,T>::type ElementType;
102 (!is_distinct<ElementType>::value)
103 || skipper.parse(first,last,unused,unused,unused)
105 spirit::qi::skip_over(first, last, skipper);
106 return call_subject_unused(fusion::at_c<T::value>(elements), first, last, context, skipper, idx );
110 // Handle normal attributes
111 template <typename T> bool call(T &idx, mpl::true_) const{
112 typedef typename mpl::at<Elements,T>::type ElementType;
114 (!is_distinct<ElementType>::value)
115 || skipper.parse(first,last,unused,unused,unused)
117 return call_subject(fusion::at_c<T::value>(elements), first, last, context, skipper, idx);
121 #if defined(_MSC_VER)
122 # pragma warning(pop)
125 const Elements &elements;
127 const Iterator &last;
129 const Skipper &skipper;
134 // string keyword loop handler
135 template <typename Elements, typename StringKeywords, typename IndexList, typename FlagsType, typename Modifiers>
136 struct string_keywords
138 // Create a variant type to be able to store parser indexes in the embedded symbols parser
140 spirit::detail::as_variant<
141 IndexList >::type parser_index_type;
143 ///////////////////////////////////////////////////////////////////////////
144 // build_char_type_sequence
146 // Build a fusion sequence from the kwd directive specified character type.
147 ///////////////////////////////////////////////////////////////////////////
148 template <typename Sequence >
149 struct build_char_type_sequence
151 struct element_char_type
153 template <typename T>
156 template <typename F, typename Element>
157 struct result<F(Element)>
159 typedef typename Element::char_type type;
162 template <typename F, typename Element,typename Action>
163 struct result<F(spirit::qi::action<Element,Action>) >
165 typedef typename Element::char_type type;
167 template <typename F, typename Element>
168 struct result<F(spirit::qi::hold_directive<Element>)>
170 typedef typename Element::char_type type;
173 // never called, but needed for decltype-based result_of (C++0x)
174 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
175 template <typename Element>
176 typename result<element_char_type(Element)>::type
177 operator()(Element&&) const;
181 // Compute the list of character types of the child kwd directives
183 fusion::result_of::transform<Sequence, element_char_type>::type
188 ///////////////////////////////////////////////////////////////////////////
189 // get_keyword_char_type
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
198 // Make sure each of the types occur only once in the type list
201 Sequence, mpl::vector<>,
203 mpl::contains<mpl::_1, mpl::_2>,
204 mpl::_1, mpl::push_back<mpl::_1, mpl::_2>
207 no_duplicate_char_types;
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 );
214 typedef typename mpl::front<no_duplicate_char_types>::type type;
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<
223 typename mpl::size < char_types >::type
226 , mpl::vector< boost::spirit::standard::char_type >
230 // Our symbols container
231 typedef spirit::qi::tst< char_type, parser_index_type> keywords_type;
233 // Filter functor used for case insensitive parsing
234 template <typename CharEncoding>
235 struct no_case_filter
237 char_type operator()(char_type ch) const
239 return static_cast<char_type>(CharEncoding::tolower(ch));
243 ///////////////////////////////////////////////////////////////////////////
244 // build_case_type_sequence
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
253 struct element_case_type
255 template <typename T>
258 template <typename F, typename Element>
259 struct result<F(Element)>
261 typedef typename Element::no_case_keyword type;
264 template <typename F, typename Element,typename Action>
265 struct result<F(spirit::qi::action<Element,Action>) >
267 typedef typename Element::no_case_keyword type;
269 template <typename F, typename Element>
270 struct result<F(spirit::qi::hold_directive<Element>)>
272 typedef typename Element::no_case_keyword type;
275 // never called, but needed for decltype-based result_of (C++0x)
276 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
277 template <typename Element>
278 typename result<element_case_type(Element)>::type
279 operator()(Element&&) const;
283 // Compute the list of character types of the child kwd directives
285 fusion::result_of::transform<Sequence, element_case_type>::type
289 ///////////////////////////////////////////////////////////////////////////
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
299 // Make sure each of the types occur only once in the type list
302 Sequence, mpl::equal_to<mpl::_,CaseType>
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
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
325 typedef typename mpl::or_< all_kwd, all_ikwd >::type all_directives_of_same_type;
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;
330 // Should the no_case filter always be used ?
331 typedef typename mpl::or_<
334 all_directives_of_same_type
340 typedef no_case_filter<
341 typename spirit::detail::get_encoding_with_case<
343 , char_encoding::standard
344 , no_case::value>::type>
346 // Determine the standard case filter type
347 typedef typename mpl::if_<
350 , spirit::qi::tst_pass_through >::type
351 first_pass_filter_type;
353 typedef typename mpl::or_<
354 all_directives_of_same_type
356 >::type requires_one_pass;
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
363 typedef int result_type;
365 keyword_entry_adder(shared_ptr<keywords_type> lookup,FlagsType &flags, Elements &elements) :
371 template <typename T>
372 int operator()(const T &index) const
374 return call(fusion::at_c<T::value>(elements),index);
377 template <typename T, typename Position, typename Action>
378 int call(const spirit::qi::action<T,Action> &parser, const Position position ) const
381 // Make the keyword/parse index entry in the tst parser
383 traits::get_begin<char_type>(get_string(parser.subject.keyword)),
384 traits::get_end<char_type>(get_string(parser.subject.keyword)),
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();
392 template <typename T, typename Position>
393 int call( const T & parser, const Position position) const
395 // Make the keyword/parse index entry in the tst parser
397 traits::get_begin<char_type>(get_string(parser.keyword)),
398 traits::get_end<char_type>(get_string(parser.keyword)),
401 // Get the initial state of the flags array and store it in the flags initializer
402 flags[Position::value]=parser.iter.flag_init();
406 template <typename T, typename Position>
407 int call( const spirit::qi::hold_directive<T> & parser, const Position position) const
409 // Make the keyword/parse index entry in the tst parser
411 traits::get_begin<char_type>(get_string(parser.subject.keyword)),
412 traits::get_end<char_type>(get_string(parser.subject.keyword)),
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();
421 template <typename String, bool no_attribute>
422 const String get_string(const boost::spirit::qi::literal_string<String,no_attribute> &parser) const
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
431 return parser.str_lo;
436 shared_ptr<keywords_type> lookup;
441 string_keywords(Elements &elements,FlagsType &flags_init) : lookup(new keywords_type())
443 // Loop through all the subject parsers to build the keyword parser symbol parser
445 keyword_entry_adder f1(lookup,flags_init,elements);
446 fusion::for_each(indexes,f1);
449 template <typename Iterator,typename ParseVisitor, typename Skipper>
452 const Iterator &last,
453 const ParseVisitor &parse_visitor,
454 const Skipper &/*skipper*/) const
456 if(parser_index_type* val_ptr =
457 lookup->find(first,last,first_pass_filter_type()))
459 if(!apply_visitor(parse_visitor,*val_ptr)){
467 template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper>
470 const Iterator &last,
471 const ParseVisitor &parse_visitor,
472 const NoCaseParseVisitor &no_case_parse_visitor,
473 const Skipper &/*skipper*/) const
475 Iterator saved_first = first;
476 if(parser_index_type* val_ptr =
477 lookup->find(first,last,first_pass_filter_type()))
479 if(!apply_visitor(parse_visitor,*val_ptr)){
484 // Second pass case insensitive
485 else if(parser_index_type* val_ptr
486 = lookup->find(saved_first,last,nc_filter()))
489 if(!apply_visitor(no_case_parse_visitor,*val_ptr)){
496 shared_ptr<keywords_type> lookup;
501 struct empty_keywords_list
503 typedef mpl::true_ requires_one_pass;
505 empty_keywords_list()
507 template<typename Elements>
508 empty_keywords_list(const Elements &)
511 template<typename Elements, typename FlagsInit>
512 empty_keywords_list(const Elements &, const FlagsInit &)
515 template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper>
518 const Iterator &/*last*/,
519 const ParseVisitor &/*parse_visitor*/,
520 const NoCaseParseVisitor &/*no_case_parse_visitor*/,
521 const Skipper &/*skipper*/) const
526 template <typename Iterator,typename ParseVisitor, typename Skipper>
529 const Iterator &/*last*/,
530 const ParseVisitor &/*parse_visitor*/,
531 const Skipper &/*skipper*/) const
536 template <typename ParseFunction>
537 bool parse( ParseFunction &/*function*/ ) const
543 template<typename ComplexKeywords>
544 struct complex_keywords
546 // Functor which performs the flag initialization for the complex keyword parsers
547 template <typename FlagsType, typename Elements>
548 struct flag_init_value_setter
550 typedef int result_type;
552 flag_init_value_setter(Elements &elements,FlagsType &flags)
557 template <typename T>
558 int operator()(const T &index) const
560 return call(fusion::at_c<T::value>(elements),index);
563 template <typename T, typename Position, typename Action>
564 int call(const spirit::qi::action<T,Action> &parser, const Position /*position*/ ) const
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();
571 template <typename T, typename Position>
572 int call( const T & parser, const Position /*position*/) const
574 // Get the initial state of the flags array and store it in the flags initializer
575 flags[Position::value]=parser.iter.flag_init();
579 template <typename T, typename Position>
580 int call( const spirit::qi::hold_directive<T> & parser, const Position /*position*/) const
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();
591 template <typename Elements, typename Flags>
592 complex_keywords(Elements &elements, Flags &flags)
594 flag_init_value_setter<Flags,Elements> flag_initializer(elements,flags);
595 fusion::for_each(complex_keywords_inst,flag_initializer);
598 template <typename ParseFunction>
599 bool parse( ParseFunction &function ) const
601 return fusion::any(complex_keywords_inst,function);
604 ComplexKeywords complex_keywords_inst;
606 // This helper class enables jumping over intermediate directives
607 // down the kwd parser iteration count checking policy
608 struct register_successful_parse
610 template <typename Subject>
611 static bool call(Subject const &subject,bool &flag, int &counter)
613 return subject.iter.register_successful_parse(flag,counter);
615 template <typename Subject, typename Action>
616 static bool call(spirit::qi::action<Subject, Action> const &subject,bool &flag, int &counter)
618 return subject.subject.iter.register_successful_parse(flag,counter);
620 template <typename Subject>
621 static bool call(spirit::qi::hold_directive<Subject> const &subject,bool &flag, int &counter)
623 return subject.subject.iter.register_successful_parse(flag,counter);
627 // This helper class enables jumping over intermediate directives
628 // down the kwd parser
629 struct extract_keyword
631 template <typename Subject>
632 static Subject const& call(Subject const &subject)
636 template <typename Subject, typename Action>
637 static Subject const& call(spirit::qi::action<Subject, Action> const &subject)
639 return subject.subject;
641 template <typename Subject>
642 static Subject const& call(spirit::qi::hold_directive<Subject> const &subject)
644 return subject.subject;
648 template <typename ParseDispatcher>
649 struct complex_kwd_function
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)
661 , dispatcher(dispatcher)
665 template <typename Component>
666 bool operator()(Component const& component)
668 Iterator save = first;
670 extract_keyword::call(
673 ,typename ParseDispatcher::elements_type
674 >(dispatcher.elements)
684 if(!dispatcher(component)){
694 Iterator const& last;
696 Skipper const& skipper;
697 ParseDispatcher const& dispatcher;
699 // silence MSVC warning C4512: assignment operator could not be generated
700 BOOST_DELETED_FUNCTION(complex_kwd_function& operator= (complex_kwd_function const&))