blob: 43aa13346873354c5a8d0d7cbc740ac48e17abb1 [file] [log] [blame]
/*=============================================================================
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;
}
save = 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;
}
save = save;
return false;
}
// 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;
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)
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>(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;
private:
// silence MSVC warning C4512: assignment operator could not be generated
complex_kwd_function& operator= (complex_kwd_function const&);
};
}}}}}
#endif