123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- /*=============================================================================
- Copyright (c) 2011-2012 Thomas Bernard
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- =============================================================================*/
- #if !defined(SPIRIT_KEYWORDS_DETAIL_MARCH_13_2007_1145PM)
- #define SPIRIT_KEYWORDS_DETAIL_MARCH_13_2007_1145PM
- #if defined(_MSC_VER)
- #pragma once
- #endif
- #include <boost/fusion/include/nview.hpp>
- #include <boost/spirit/home/qi/string/lit.hpp>
- #include <boost/fusion/include/at.hpp>
- namespace boost { namespace spirit { namespace repository { namespace qi { namespace detail {
- // Variant visitor class which handles dispatching the parsing to the selected parser
- // This also handles passing the correct attributes and flags/counters to the subject parsers
- template<typename T>
- struct is_distinct : T::distinct { };
-
- template<typename T, typename Action>
- struct is_distinct< spirit::qi::action<T,Action> > : T::distinct { };
- template<typename T>
- struct is_distinct< spirit::qi::hold_directive<T> > : T::distinct { };
- template < typename Elements, typename Iterator ,typename Context ,typename Skipper
- ,typename Flags ,typename Counters ,typename Attribute, typename NoCasePass>
- struct parse_dispatcher
- : public boost::static_visitor<bool>
- {
- typedef Iterator iterator_type;
- typedef Context context_type;
- typedef Skipper skipper_type;
- typedef Elements elements_type;
- typedef typename add_reference<Attribute>::type attr_reference;
- public:
- parse_dispatcher(const Elements &elements,Iterator& first, Iterator const& last
- , Context& context, Skipper const& skipper
- , Flags &flags, Counters &counters, attr_reference attr) :
- elements(elements), first(first), last(last)
- , context(context), skipper(skipper)
- , flags(flags),counters(counters), attr(attr)
- {}
- template<typename T> bool operator()(T& idx) const
- {
- return call(idx,typename traits::not_is_unused<Attribute>::type());
- }
- template <typename Subject,typename Index>
- bool call_subject_unused(
- Subject const &subject, Iterator &first, Iterator const &last
- , Context& context, Skipper const& skipper
- , Index& /*idx*/ ) const
- {
- Iterator save = first;
- skipper_keyword_marker<Skipper,NoCasePass>
- marked_skipper(skipper,flags[Index::value],counters[Index::value]);
- if(subject.parse(first,last,context,marked_skipper,unused))
- {
- return true;
- }
- first = save;
- return false;
- }
- template <typename Subject,typename Index>
- bool call_subject(
- Subject const &subject, Iterator &first, Iterator const &last
- , Context& context, Skipper const& skipper
- , Index& /*idx*/ ) const
- {
- Iterator save = first;
- skipper_keyword_marker<Skipper,NoCasePass>
- marked_skipper(skipper,flags[Index::value],counters[Index::value]);
- if(subject.parse(first,last,context,marked_skipper,fusion::at_c<Index::value>(attr)))
- {
- return true;
- }
- first = save;
- return false;
- }
- #if defined(_MSC_VER)
- # pragma warning(push)
- # pragma warning(disable: 4127) // conditional expression is constant
- #endif
- // Handle unused attributes
- template <typename T> bool call(T &idx, mpl::false_) const{
-
- typedef typename mpl::at<Elements,T>::type ElementType;
- if(
- (!is_distinct<ElementType>::value)
- || skipper.parse(first,last,unused,unused,unused)
- ){
- spirit::qi::skip_over(first, last, skipper);
- return call_subject_unused(fusion::at_c<T::value>(elements), first, last, context, skipper, idx );
- }
- return false;
- }
- // Handle normal attributes
- template <typename T> bool call(T &idx, mpl::true_) const{
- typedef typename mpl::at<Elements,T>::type ElementType;
- if(
- (!is_distinct<ElementType>::value)
- || skipper.parse(first,last,unused,unused,unused)
- ){
- return call_subject(fusion::at_c<T::value>(elements), first, last, context, skipper, idx);
- }
- return false;
- }
- #if defined(_MSC_VER)
- # pragma warning(pop)
- #endif
- const Elements &elements;
- Iterator &first;
- const Iterator &last;
- Context & context;
- const Skipper &skipper;
- Flags &flags;
- Counters &counters;
- attr_reference attr;
- };
- // string keyword loop handler
- template <typename Elements, typename StringKeywords, typename IndexList, typename FlagsType, typename Modifiers>
- struct string_keywords
- {
- // Create a variant type to be able to store parser indexes in the embedded symbols parser
- typedef typename
- spirit::detail::as_variant<
- IndexList >::type parser_index_type;
- ///////////////////////////////////////////////////////////////////////////
- // build_char_type_sequence
- //
- // Build a fusion sequence from the kwd directive specified character type.
- ///////////////////////////////////////////////////////////////////////////
- template <typename Sequence >
- struct build_char_type_sequence
- {
- struct element_char_type
- {
- template <typename T>
- struct result;
- template <typename F, typename Element>
- struct result<F(Element)>
- {
- typedef typename Element::char_type type;
- };
- template <typename F, typename Element,typename Action>
- struct result<F(spirit::qi::action<Element,Action>) >
- {
- typedef typename Element::char_type type;
- };
- template <typename F, typename Element>
- struct result<F(spirit::qi::hold_directive<Element>)>
- {
- typedef typename Element::char_type type;
- };
- // never called, but needed for decltype-based result_of (C++0x)
- #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
- template <typename Element>
- typename result<element_char_type(Element)>::type
- operator()(Element&&) const;
- #endif
- };
- // Compute the list of character types of the child kwd directives
- typedef typename
- fusion::result_of::transform<Sequence, element_char_type>::type
- type;
- };
- ///////////////////////////////////////////////////////////////////////////
- // get_keyword_char_type
- //
- // Collapses the character type comming from the subject kwd parsers and
- // and checks that they are all identical (necessary in order to be able
- // to build a tst parser to parse the keywords.
- ///////////////////////////////////////////////////////////////////////////
- template <typename Sequence>
- struct get_keyword_char_type
- {
- // Make sure each of the types occur only once in the type list
- typedef typename
- mpl::fold<
- Sequence, mpl::vector<>,
- mpl::if_<
- mpl::contains<mpl::_1, mpl::_2>,
- mpl::_1, mpl::push_back<mpl::_1, mpl::_2>
- >
- >::type
- no_duplicate_char_types;
- // If the compiler traps here this means you mixed
- // character type for the keywords specified in the
- // kwd directive sequence.
- BOOST_MPL_ASSERT_RELATION( mpl::size<no_duplicate_char_types>::value, ==, 1 );
- typedef typename mpl::front<no_duplicate_char_types>::type type;
- };
- // Get the character type for the tst parser
- typedef typename build_char_type_sequence< StringKeywords >::type char_types;
- typedef typename get_keyword_char_type<
- typename mpl::if_<
- mpl::equal_to<
- typename mpl::size < char_types >::type
- , mpl::int_<0>
- >
- , mpl::vector< boost::spirit::standard::char_type >
- , char_types >::type
- >::type char_type;
- // Our symbols container
- typedef spirit::qi::tst< char_type, parser_index_type> keywords_type;
- // Filter functor used for case insensitive parsing
- template <typename CharEncoding>
- struct no_case_filter
- {
- char_type operator()(char_type ch) const
- {
- return static_cast<char_type>(CharEncoding::tolower(ch));
- }
- };
- ///////////////////////////////////////////////////////////////////////////
- // build_case_type_sequence
- //
- // Build a fusion sequence from the kwd/ikwd directives
- // in order to determine if case sensitive and case insensitive
- // keywords have been mixed.
- ///////////////////////////////////////////////////////////////////////////
- template <typename Sequence >
- struct build_case_type_sequence
- {
- struct element_case_type
- {
- template <typename T>
- struct result;
- template <typename F, typename Element>
- struct result<F(Element)>
- {
- typedef typename Element::no_case_keyword type;
- };
- template <typename F, typename Element,typename Action>
- struct result<F(spirit::qi::action<Element,Action>) >
- {
- typedef typename Element::no_case_keyword type;
- };
- template <typename F, typename Element>
- struct result<F(spirit::qi::hold_directive<Element>)>
- {
- typedef typename Element::no_case_keyword type;
- };
- // never called, but needed for decltype-based result_of (C++0x)
- #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
- template <typename Element>
- typename result<element_case_type(Element)>::type
- operator()(Element&&) const;
- #endif
- };
- // Compute the list of character types of the child kwd directives
- typedef typename
- fusion::result_of::transform<Sequence, element_case_type>::type
- type;
- };
- ///////////////////////////////////////////////////////////////////////////
- // get_nb_case_types
- //
- // Counts the number of entries in the case type sequence matching the
- // CaseType parameter (mpl::true_ -> case insensitve
- // , mpl::false_ -> case sensitive
- ///////////////////////////////////////////////////////////////////////////
- template <typename Sequence,typename CaseType>
- struct get_nb_case_types
- {
- // Make sure each of the types occur only once in the type list
- typedef typename
- mpl::count_if<
- Sequence, mpl::equal_to<mpl::_,CaseType>
- >::type type;
- };
- // Build the case type sequence
- typedef typename build_case_type_sequence< StringKeywords >::type case_type_sequence;
- // Count the number of case sensitive entries and case insensitve entries
- typedef typename get_nb_case_types<case_type_sequence,mpl::true_>::type ikwd_count;
- typedef typename get_nb_case_types<case_type_sequence,mpl::false_>::type kwd_count;
- // Get the size of the original sequence
- typedef typename mpl::size<IndexList>::type nb_elements;
- // Determine if all the kwd directive are case sensitive/insensitive
- typedef typename mpl::and_<
- typename mpl::greater< nb_elements, mpl::int_<0> >::type
- , typename mpl::equal_to< ikwd_count, nb_elements>::type
- >::type all_ikwd;
- typedef typename mpl::and_<
- typename mpl::greater< nb_elements, mpl::int_<0> >::type
- , typename mpl::equal_to< kwd_count, nb_elements>::type
- >::type all_kwd;
- typedef typename mpl::or_< all_kwd, all_ikwd >::type all_directives_of_same_type;
- // Do we have a no case modifier
- typedef has_modifier<Modifiers, spirit::tag::char_code_base<spirit::tag::no_case> > no_case_modifier;
- // Should the no_case filter always be used ?
- typedef typename mpl::or_<
- no_case_modifier,
- mpl::and_<
- all_directives_of_same_type
- ,all_ikwd
- >
- >::type
- no_case;
- typedef no_case_filter<
- typename spirit::detail::get_encoding_with_case<
- Modifiers
- , char_encoding::standard
- , no_case::value>::type>
- nc_filter;
- // Determine the standard case filter type
- typedef typename mpl::if_<
- no_case
- , nc_filter
- , spirit::qi::tst_pass_through >::type
- first_pass_filter_type;
- typedef typename mpl::or_<
- all_directives_of_same_type
- , no_case_modifier
- >::type requires_one_pass;
- // Functor which adds all the keywords/subject parser indexes
- // collected from the subject kwd directives to the keyword tst parser
- struct keyword_entry_adder
- {
- typedef int result_type;
- keyword_entry_adder(shared_ptr<keywords_type> lookup,FlagsType &flags, Elements &elements) :
- lookup(lookup)
- ,flags(flags)
- ,elements(elements)
- {}
- template <typename T>
- int operator()(const T &index) const
- {
- return call(fusion::at_c<T::value>(elements),index);
- }
- template <typename T, typename Position, typename Action>
- int call(const spirit::qi::action<T,Action> &parser, const Position position ) const
- {
- // Make the keyword/parse index entry in the tst parser
- lookup->add(
- traits::get_begin<char_type>(get_string(parser.subject.keyword)),
- traits::get_end<char_type>(get_string(parser.subject.keyword)),
- position
- );
- // Get the initial state of the flags array and store it in the flags initializer
- flags[Position::value]=parser.subject.iter.flag_init();
- return 0;
- }
- template <typename T, typename Position>
- int call( const T & parser, const Position position) const
- {
- // Make the keyword/parse index entry in the tst parser
- lookup->add(
- traits::get_begin<char_type>(get_string(parser.keyword)),
- traits::get_end<char_type>(get_string(parser.keyword)),
- position
- );
- // Get the initial state of the flags array and store it in the flags initializer
- flags[Position::value]=parser.iter.flag_init();
- return 0;
- }
- template <typename T, typename Position>
- int call( const spirit::qi::hold_directive<T> & parser, const Position position) const
- {
- // Make the keyword/parse index entry in the tst parser
- lookup->add(
- traits::get_begin<char_type>(get_string(parser.subject.keyword)),
- traits::get_end<char_type>(get_string(parser.subject.keyword)),
- position
- );
- // Get the initial state of the flags array and store it in the flags initializer
- flags[Position::value]=parser.subject.iter.flag_init();
- return 0;
- }
- template <typename String, bool no_attribute>
- const String get_string(const boost::spirit::qi::literal_string<String,no_attribute> &parser) const
- {
- return parser.str;
- }
- template <typename String, bool no_attribute>
- const typename boost::spirit::qi::no_case_literal_string<String,no_attribute>::string_type &
- get_string(const boost::spirit::qi::no_case_literal_string<String,no_attribute> &parser) const
- {
- return parser.str_lo;
- }
-
- shared_ptr<keywords_type> lookup;
- FlagsType & flags;
- Elements &elements;
- };
- string_keywords(Elements &elements,FlagsType &flags_init) : lookup(new keywords_type())
- {
- // Loop through all the subject parsers to build the keyword parser symbol parser
- IndexList indexes;
- keyword_entry_adder f1(lookup,flags_init,elements);
- fusion::for_each(indexes,f1);
- }
- template <typename Iterator,typename ParseVisitor, typename Skipper>
- bool parse(
- Iterator &first,
- const Iterator &last,
- const ParseVisitor &parse_visitor,
- const Skipper &/*skipper*/) const
- {
- if(parser_index_type* val_ptr =
- lookup->find(first,last,first_pass_filter_type()))
- {
- if(!apply_visitor(parse_visitor,*val_ptr)){
- return false;
- }
- return true;
- }
- return false;
- }
- template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper>
- bool parse(
- Iterator &first,
- const Iterator &last,
- const ParseVisitor &parse_visitor,
- const NoCaseParseVisitor &no_case_parse_visitor,
- const Skipper &/*skipper*/) const
- {
- Iterator saved_first = first;
- if(parser_index_type* val_ptr =
- lookup->find(first,last,first_pass_filter_type()))
- {
- if(!apply_visitor(parse_visitor,*val_ptr)){
- return false;
- }
- return true;
- }
- // Second pass case insensitive
- else if(parser_index_type* val_ptr
- = lookup->find(saved_first,last,nc_filter()))
- {
- first = saved_first;
- if(!apply_visitor(no_case_parse_visitor,*val_ptr)){
- return false;
- }
- return true;
- }
- return false;
- }
- shared_ptr<keywords_type> lookup;
- };
- struct empty_keywords_list
- {
- typedef mpl::true_ requires_one_pass;
- empty_keywords_list()
- {}
- template<typename Elements>
- empty_keywords_list(const Elements &)
- {}
- template<typename Elements, typename FlagsInit>
- empty_keywords_list(const Elements &, const FlagsInit &)
- {}
- template <typename Iterator,typename ParseVisitor, typename NoCaseParseVisitor,typename Skipper>
- bool parse(
- Iterator &/*first*/,
- const Iterator &/*last*/,
- const ParseVisitor &/*parse_visitor*/,
- const NoCaseParseVisitor &/*no_case_parse_visitor*/,
- const Skipper &/*skipper*/) const
- {
- return false;
- }
- template <typename Iterator,typename ParseVisitor, typename Skipper>
- bool parse(
- Iterator &/*first*/,
- const Iterator &/*last*/,
- const ParseVisitor &/*parse_visitor*/,
- const Skipper &/*skipper*/) const
- {
- return false;
- }
- template <typename ParseFunction>
- bool parse( ParseFunction &/*function*/ ) const
- {
- return false;
- }
- };
- template<typename ComplexKeywords>
- struct complex_keywords
- {
- // Functor which performs the flag initialization for the complex keyword parsers
- template <typename FlagsType, typename Elements>
- struct flag_init_value_setter
- {
- typedef int result_type;
- flag_init_value_setter(Elements &elements,FlagsType &flags)
- :flags(flags)
- ,elements(elements)
- {}
- template <typename T>
- int operator()(const T &index) const
- {
- return call(fusion::at_c<T::value>(elements),index);
- }
- template <typename T, typename Position, typename Action>
- int call(const spirit::qi::action<T,Action> &parser, const Position /*position*/ ) const
- {
- // Get the initial state of the flags array and store it in the flags initializer
- flags[Position::value]=parser.subject.iter.flag_init();
- return 0;
- }
- template <typename T, typename Position>
- int call( const T & parser, const Position /*position*/) const
- {
- // Get the initial state of the flags array and store it in the flags initializer
- flags[Position::value]=parser.iter.flag_init();
- return 0;
- }
- template <typename T, typename Position>
- int call( const spirit::qi::hold_directive<T> & parser, const Position /*position*/) const
- {
- // Get the initial state of the flags array and store it in the flags initializer
- flags[Position::value]=parser.subject.iter.flag_init();
- return 0;
- }
- FlagsType & flags;
- Elements &elements;
- };
- template <typename Elements, typename Flags>
- complex_keywords(Elements &elements, Flags &flags)
- {
- flag_init_value_setter<Flags,Elements> flag_initializer(elements,flags);
- fusion::for_each(complex_keywords_inst,flag_initializer);
- }
- template <typename ParseFunction>
- bool parse( ParseFunction &function ) const
- {
- return fusion::any(complex_keywords_inst,function);
- }
- ComplexKeywords complex_keywords_inst;
- };
- // This helper class enables jumping over intermediate directives
- // down the kwd parser iteration count checking policy
- struct register_successful_parse
- {
- template <typename Subject>
- static bool call(Subject const &subject,bool &flag, int &counter)
- {
- return subject.iter.register_successful_parse(flag,counter);
- }
- template <typename Subject, typename Action>
- static bool call(spirit::qi::action<Subject, Action> const &subject,bool &flag, int &counter)
- {
- return subject.subject.iter.register_successful_parse(flag,counter);
- }
- template <typename Subject>
- static bool call(spirit::qi::hold_directive<Subject> const &subject,bool &flag, int &counter)
- {
- return subject.subject.iter.register_successful_parse(flag,counter);
- }
- };
- // This helper class enables jumping over intermediate directives
- // down the kwd parser
- struct extract_keyword
- {
- template <typename Subject>
- static Subject const& call(Subject const &subject)
- {
- return subject;
- }
- template <typename Subject, typename Action>
- static Subject const& call(spirit::qi::action<Subject, Action> const &subject)
- {
- return subject.subject;
- }
- template <typename Subject>
- static Subject const& call(spirit::qi::hold_directive<Subject> const &subject)
- {
- return subject.subject;
- }
- };
- template <typename ParseDispatcher>
- struct complex_kwd_function
- {
- typedef typename ParseDispatcher::iterator_type Iterator;
- typedef typename ParseDispatcher::context_type Context;
- typedef typename ParseDispatcher::skipper_type Skipper;
- complex_kwd_function(
- Iterator& first, Iterator const& last
- , Context& context, Skipper const& skipper, ParseDispatcher &dispatcher)
- : first(first)
- , last(last)
- , context(context)
- , skipper(skipper)
- , dispatcher(dispatcher)
- {
- }
- template <typename Component>
- bool operator()(Component const& component)
- {
- Iterator save = first;
- if(
- extract_keyword::call(
- fusion::at_c<
- Component::value
- ,typename ParseDispatcher::elements_type
- >(dispatcher.elements)
- )
- .keyword.parse(
- first
- ,last
- ,context
- ,skipper
- ,unused)
- )
- {
- if(!dispatcher(component)){
- first = save;
- return false;
- }
- return true;
- }
- return false;
- }
- Iterator& first;
- Iterator const& last;
- Context& context;
- Skipper const& skipper;
- ParseDispatcher const& dispatcher;
- // silence MSVC warning C4512: assignment operator could not be generated
- BOOST_DELETED_FUNCTION(complex_kwd_function& operator= (complex_kwd_function const&))
- };
- }}}}}
- #endif
|