diff options
Diffstat (limited to 'boost/spirit/repository/home/qi/operator/detail/keywords.hpp')
-rw-r--r-- | boost/spirit/repository/home/qi/operator/detail/keywords.hpp | 634 |
1 files changed, 606 insertions, 28 deletions
diff --git a/boost/spirit/repository/home/qi/operator/detail/keywords.hpp b/boost/spirit/repository/home/qi/operator/detail/keywords.hpp index 81e17715df..06836f7746 100644 --- a/boost/spirit/repository/home/qi/operator/detail/keywords.hpp +++ b/boost/spirit/repository/home/qi/operator/detail/keywords.hpp @@ -1,6 +1,5 @@ /*============================================================================= - Copyright (c) 2001-2011 Joel de Guzman - Copyright (c) 2011 Thomas Bernard + 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) @@ -11,39 +10,35 @@ #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 { - - // 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); - } - }; // 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> - class parse_dispatcher + 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 @@ -65,7 +60,8 @@ namespace boost { namespace spirit { namespace repository { namespace qi { names , Index& idx ) const { Iterator save = first; - skipper_keyword_marker<Skipper,NoCasePass> marked_skipper(skipper,flags[Index::value],counters[Index::value]); + skipper_keyword_marker<Skipper,NoCasePass> + marked_skipper(skipper,flags[Index::value],counters[Index::value]); if(subject.parse(first,last,context,marked_skipper,unused)) { @@ -84,7 +80,8 @@ namespace boost { namespace spirit { namespace repository { namespace qi { names { Iterator save = first; - skipper_keyword_marker<Skipper,NoCasePass> marked_skipper(skipper,flags[Index::value],counters[Index::value]); + 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; @@ -95,12 +92,28 @@ namespace boost { namespace spirit { namespace repository { namespace qi { names // 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; + } const Elements &elements; Iterator &first; @@ -111,7 +124,572 @@ namespace boost { namespace spirit { namespace repository { namespace qi { names 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) + template <typename Element> + typename result<element_char_type(Element)>::type + operator()(Element&) const; + }; + + // 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) + template <typename Element> + typename result<element_case_type(Element)>::type + operator()(Element&) const; + }; + + // 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>(parser.subject.keyword.str), + traits::get_end<char_type>(parser.subject.keyword.str), + 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>(parser.subject.keyword.str), + traits::get_end<char_type>(parser.subject.keyword.str), + 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; + + private: + // silence MSVC warning C4512: assignment operator could not be generated + complex_kwd_function& operator= (complex_kwd_function const&); + }; + + }}}}} #endif |