summaryrefslogtreecommitdiff
path: root/boost/spirit/repository/home/qi/operator/detail/keywords.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/spirit/repository/home/qi/operator/detail/keywords.hpp')
-rw-r--r--boost/spirit/repository/home/qi/operator/detail/keywords.hpp634
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