diff options
Diffstat (limited to 'boost/spirit/repository')
-rw-r--r-- | boost/spirit/repository/home/qi/directive/kwd.hpp | 689 | ||||
-rw-r--r-- | boost/spirit/repository/home/qi/operator/detail/keywords.hpp | 634 | ||||
-rw-r--r-- | boost/spirit/repository/home/qi/operator/keywords.hpp | 420 | ||||
-rw-r--r-- | boost/spirit/repository/home/support/kwd.hpp | 2 |
4 files changed, 1365 insertions, 380 deletions
diff --git a/boost/spirit/repository/home/qi/directive/kwd.hpp b/boost/spirit/repository/home/qi/directive/kwd.hpp index 79fdc2f6dc..bba1a78448 100644 --- a/boost/spirit/repository/home/qi/directive/kwd.hpp +++ b/boost/spirit/repository/home/qi/directive/kwd.hpp @@ -35,50 +35,98 @@ namespace boost { namespace spirit struct use_directive<qi::domain , terminal_ex<repository::tag::kwd // enables kwd(key)[p] , fusion::vector1<T > > - > : traits::is_string<T> {}; + > : mpl::true_ {}; template < typename T> struct use_directive<qi::domain , terminal_ex<repository::tag::ikwd // enables ikwd(key)[p] , fusion::vector1<T > > - > : traits::is_string<T> {}; + > : mpl::true_ {}; + template < typename T> + struct use_directive<qi::domain + , terminal_ex<repository::tag::dkwd // enables dkwd(key)[p] + , fusion::vector1<T > > + > : mpl::true_ {}; + template < typename T> + struct use_directive<qi::domain + , terminal_ex<repository::tag::idkwd // enables idkwd(key)[p] + , fusion::vector1<T > > + > : mpl::true_ {}; + + template < typename T1, typename T2> struct use_directive<qi::domain , terminal_ex<repository::tag::kwd // enables kwd(key,exact)[p] , fusion::vector2< T1, T2 > > - > : traits::is_string<T1> {}; + > : mpl::true_ {}; template < typename T1, typename T2> struct use_directive<qi::domain , terminal_ex<repository::tag::ikwd // enables ikwd(key,exact)[p] , fusion::vector2< T1, T2 > > - > : traits::is_string<T1> {}; + > : mpl::true_ {}; template < typename T1, typename T2> struct use_directive<qi::domain + , terminal_ex<repository::tag::dkwd // enables dkwd(key,exact)[p] + , fusion::vector2< T1, T2 > > + > : mpl::true_ {}; + + template < typename T1, typename T2> + struct use_directive<qi::domain + , terminal_ex<repository::tag::idkwd // enables idkwd(key,exact)[p] + , fusion::vector2< T1, T2 > > + > : mpl::true_ {}; + + template < typename T1, typename T2> + struct use_directive<qi::domain , terminal_ex<repository::tag::kwd // enables kwd(min, max)[p] , fusion::vector3< T1, T2, T2 > > - > : traits::is_string<T1> {}; + > : mpl::true_ {}; template < typename T1, typename T2> struct use_directive<qi::domain , terminal_ex<repository::tag::ikwd // enables ikwd(min, max)[p] , fusion::vector3< T1, T2, T2 > > - > : traits::is_string<T1> {}; + > : mpl::true_ {}; + + template < typename T1, typename T2> + struct use_directive<qi::domain + , terminal_ex<repository::tag::dkwd // enables dkwd(min, max)[p] + , fusion::vector3< T1, T2, T2 > > + > : mpl::true_ {}; template < typename T1, typename T2> struct use_directive<qi::domain + , terminal_ex<repository::tag::idkwd // enables idkwd(min, max)[p] + , fusion::vector3< T1, T2, T2 > > + > : mpl::true_ {}; + + template < typename T1, typename T2> + struct use_directive<qi::domain , terminal_ex<repository::tag::kwd // enables kwd(min, inf)[p] , fusion::vector3<T1, T2, inf_type > > - > : traits::is_string<T1> {}; + > : mpl::true_ {}; template < typename T1, typename T2> struct use_directive<qi::domain , terminal_ex<repository::tag::ikwd // enables ikwd(min, inf)[p] , fusion::vector3<T1, T2, inf_type > > - > : traits::is_string<T1> {}; + > : mpl::true_ {}; + + template < typename T1, typename T2> + struct use_directive<qi::domain + , terminal_ex<repository::tag::dkwd // enables dkwd(min, inf)[p] + , fusion::vector3<T1, T2, inf_type > > + > : mpl::true_ {}; + + template < typename T1, typename T2> + struct use_directive<qi::domain + , terminal_ex<repository::tag::idkwd // enables idkwd(min, inf)[p] + , fusion::vector3<T1, T2, inf_type > > + > : mpl::true_ {}; /* template <> // enables *lazy* kwd(exact)[p] @@ -102,6 +150,8 @@ namespace boost { namespace spirit { namespace repository { namespace qi { using repository::kwd; using repository::ikwd; + using repository::dkwd; + using repository::idkwd; using spirit::inf; using spirit::inf_type; @@ -225,13 +275,14 @@ template <typename T> int &counter; }; - template <typename Subject, typename KeywordType, typename LoopIter , typename NoCase > - struct kwd_parser : spirit::qi::unary_parser<kwd_parser<Subject, KeywordType, LoopIter , NoCase > > + template <typename Subject, typename KeywordType, typename LoopIter , typename NoCase, typename Distinct > + struct kwd_parser : spirit::qi::unary_parser<kwd_parser<Subject, KeywordType, LoopIter , NoCase, Distinct > > { struct kwd_parser_id; typedef Subject subject_type; typedef NoCase no_case_keyword; + typedef Distinct distinct; typedef typename remove_const<typename traits::char_type_of<KeywordType>::type>::type @@ -256,6 +307,13 @@ template <typename T> , LoopIter const& iter) : subject(subject), iter(iter), keyword(keyword) {} + template<typename CharEncoding> + kwd_parser(Subject const& subject + , typename add_reference<KeywordType>::type keyword + , LoopIter const& iter, CharEncoding encoding) + : subject(subject), iter(iter), keyword(keyword,encoding) {} + + // Call the subject parser on a non container attribute template <typename Iterator, typename Context , typename Skipper, typename Attribute> @@ -329,12 +387,14 @@ template <typename T> , mpl::not_< traits::is_weak_substitute< subject_attribute,Attribute > > >::type predicate; + // Parse the keyword bool flag = iter.flag_init(); int counter = 0; Iterator save = first; spirit::qi::skip_over(first, last, skipper); if(keyword.parse(first,last,context,skipper,unused)){ + if((!distinct::value) || skipper.parse(first,last,unused,unused,unused)){ // Followed by the subject parser spirit::qi::skip_over(first, last, skipper); if(parse_impl(first,last,context,skipper,attr, predicate())) @@ -342,6 +402,7 @@ template <typename T> return iter.register_successful_parse(flag,counter); } } + } first = save; return flag; } @@ -350,16 +411,29 @@ template <typename T> template <typename Context> info what(Context& context) const { + if(distinct::value){ if(no_case_keyword::value) + return info("idkwd", subject.what(context)); + else + return info("dkwd", subject.what(context)); + } + else + { + if(no_case_keyword::value) return info("ikwd", subject.what(context)); else return info("kwd", subject.what(context)); } + } Subject subject; LoopIter iter; - spirit::qi::literal_string<KeywordType, true> keyword; + typedef typename mpl::if_< + no_case_keyword, + spirit::qi::no_case_literal_string< KeywordType, true>, + spirit::qi::literal_string<KeywordType, true> >::type keyword_string_type; + keyword_string_type keyword; private: // silence MSVC warning C4512: assignment operator could not be generated kwd_parser& operator= (kwd_parser const&); @@ -376,6 +450,151 @@ template <typename T> }; + +template <typename Subject, typename KeywordType, typename LoopIter, typename Distinct> + struct complex_kwd_parser : spirit::qi::unary_parser<complex_kwd_parser<Subject, KeywordType, LoopIter, Distinct > > + { + struct complex_kwd_parser_id; + typedef Subject subject_type; + typedef Distinct distinct; + + template <typename Context, typename Iterator> + struct attribute + { + typedef typename + traits::build_std_vector< + typename traits::attribute_of< + Subject, Context, Iterator>::type + >::type + type; + }; + + + complex_kwd_parser(Subject const& subject + , typename add_reference<KeywordType>::type keyword + , LoopIter const& iter) + : subject(subject), iter(iter), keyword(keyword) {} + + // Call the subject parser on a non container attribute + template <typename Iterator, typename Context + , typename Skipper, typename Attribute> + bool parse_impl(Iterator& first, Iterator const& last + , Context& context, Skipper const& skipper + , Attribute& attr,mpl::false_) const + { + return subject.parse(first,last,context,skipper,attr); + } + + // Call the subject parser on a container attribute + template <typename Iterator, typename Context + , typename Skipper, typename Attribute> + bool parse_impl(Iterator& first, Iterator const& last + , Context& context, Skipper const& skipper + , Attribute& attr,mpl::true_) const + { + + // synthesized attribute needs to be default constructed + typename traits::container_value<Attribute>::type val = + typename traits::container_value<Attribute>::type(); + + Iterator save = first; + bool r = subject.parse(first,last,context,skipper, val); + if (r) + { + // push the parsed value into our attribute + r = traits::push_back(attr, val); + if (!r) + first = save; + } + return r; + } + + template <typename Iterator, typename Context + , typename Skipper, typename Attribute,typename NoCasePass> + bool parse(Iterator& first, Iterator const& last + , Context& context, skipper_keyword_marker<Skipper,NoCasePass> const& skipper + , Attribute &attr) const + { + + typedef typename traits::attribute_of< + Subject, Context, Iterator>::type + subject_attribute; + + typedef typename mpl::and_< + traits::is_container<Attribute> + , mpl::not_< traits::is_weak_substitute< subject_attribute,Attribute > > + >::type predicate; + + if(parse_impl(first,last,context,skipper.skipper,attr, predicate())) + return iter.register_successful_parse(skipper.flag,skipper.counter); + return false; + } + + template <typename Iterator, typename Context + , typename Skipper, typename Attribute> + bool parse(Iterator& first, Iterator const& last + , Context& context, Skipper const& skipper + , Attribute& attr) const + { + typedef typename traits::attribute_of< + Subject, Context, Iterator>::type + subject_attribute; + + typedef typename mpl::and_< + traits::is_container<Attribute> + , mpl::not_< traits::is_weak_substitute< subject_attribute,Attribute > > + >::type predicate; + + + // Parse the keyword + bool flag = iter.flag_init(); + int counter = 0; + Iterator save = first; + spirit::qi::skip_over(first, last, skipper); + if(keyword.parse(first,last,context,skipper,unused)){ + if( !distinct::value || skipper.parse(first,last,unused,unused,unused)){ + // Followed by the subject parser + spirit::qi::skip_over(first, last, skipper); + if(parse_impl(first,last,context,skipper,attr, predicate())) + { + return iter.register_successful_parse(flag,counter); + } + } + } + first = save; + return flag; + } + + + template <typename Context> + info what(Context& context) const + { + if(distinct::value) + return info("dkwd", subject.what(context)); + else + return info("kwd", subject.what(context)); + } + + Subject subject; + LoopIter iter; + + KeywordType keyword; + private: + // silence MSVC warning C4512: assignment operator could not be generated + complex_kwd_parser& operator= (complex_kwd_parser const&); + + template <typename Iterator, typename Context, typename Skipper> + static spirit::qi::detail::fail_function<Iterator, Context, Skipper> + fail_function( + Iterator& first, Iterator const& last + , Context& context, Skipper const& skipper) + { + return spirit::qi::detail::fail_function<Iterator, Context, Skipper> + (first, last, context, skipper); + } + + }; + }}}} /////////////////////////////////////////////////////////////////////////////// @@ -386,177 +605,546 @@ namespace boost { namespace spirit { namespace qi // Parser generators: make_xxx function (objects) /////////////////////////////////////////////////////////////////////////// + template <typename T1, typename T2, typename Subject, typename Modifiers, typename Distinct, typename MakeDirectiveHelper> + struct make_directive_internal_2_args + { + + // is the keyword a string keyword ? + typedef typename traits::is_string<T1> is_string_kwd_type; + // make the keyword type + typedef typename mpl::if_< is_string_kwd_type , + T1 , + typename result_of::compile<qi::domain, T1>::type + >::type keyword_type; + + typedef typename add_const<keyword_type>::type const_keyword; + // select the pass iterator type + typedef typename MakeDirectiveHelper::iterator_type iterator_type; + // determine if a no case modifier applies to the context + typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case; + // Determine the full type of the kwd / complex_kwd directive + typedef typename + mpl::if_< + is_string_kwd_type, + repository::qi::kwd_parser<Subject, const_keyword, iterator_type, no_case, Distinct >, + repository::qi::complex_kwd_parser<Subject, const_keyword, iterator_type, Distinct > + >::type result_type; + + // Return a kwd parser object + template <typename Terminal> + result_type create_kwd_string(Terminal const &term, Subject const & subject, boost::mpl::true_ ) const + { + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; + return result_type(subject + ,MakeDirectiveHelper::make_iterator(term.args) + ,encoding + ); + } + template <typename Terminal> + result_type create_kwd_string(Terminal const &term, Subject const & subject, boost::mpl::false_ ) const + { + return result_type(subject + ,fusion::at_c<0>(term.args) + ,MakeDirectiveHelper::make_iterator(term.args) + ); + } + template <typename Terminal> + result_type create_kwd(Terminal const &term, Subject const & subject, Modifiers const& modifiers, boost::mpl::true_ ) const + { + return create_kwd_string(term,subject,no_case()); + } + // Return a complex_kwd parser object + template <typename Terminal> + result_type create_kwd(Terminal const &term , Subject const & subject, Modifiers const& modifiers, boost::mpl::false_ ) const + { + return result_type(subject + ,compile<qi::domain>(fusion::at_c<0>(term.args),modifiers) + ,MakeDirectiveHelper::make_iterator(term.args) + ); + } + // Select which object type to return + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const + { + return create_kwd(term, subject, modifiers, is_string_kwd_type()); + } + + }; + // Directive kwd(key)[p] + template <typename T1, typename Subject, typename Modifiers, typename Distinct> + struct make_directive_internal + { + // is the keyword a string keyword ? + typedef typename traits::is_string<T1> is_string_kwd_type; + // make the keyword type + typedef typename mpl::if_< is_string_kwd_type , + T1 , + typename result_of::compile<qi::domain, T1, Modifiers>::type + >::type keyword_type; + + typedef typename add_const<keyword_type>::type const_keyword; + // select the pass iterator type + typedef repository::qi::kwd_pass_iterator<int> iterator_type; + // determine if a no case modifier applies to the context + typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case; + // Determine the full type of the kwd / complex_kwd directive + typedef typename + mpl::if_< + is_string_kwd_type, + repository::qi::kwd_parser<Subject, const_keyword, iterator_type, no_case, Distinct >, + repository::qi::complex_kwd_parser<Subject, const_keyword, iterator_type, Distinct> + >::type result_type; + + // Return a kwd parser object + template <typename Terminal> + result_type create_kwd_string(Terminal const &term, Subject const & subject, boost::mpl::true_) const + { + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; + + return result_type(subject + ,fusion::at_c<0>(term.args) + ,iterator_type() + ,encoding + ); + + } + template <typename Terminal> + result_type create_kwd_string(Terminal const &term, Subject const & subject, boost::mpl::false_) const + { + return result_type(subject + ,fusion::at_c<0>(term.args) + ,iterator_type() + ); + } + template <typename Terminal> + result_type create_kwd(Terminal const &term, Subject const & subject, Modifiers const& modifiers, boost::mpl::true_ ) const + { + return create_kwd_string(term,subject,no_case()); + } + // Return a complex_kwd parser object + template <typename Terminal> + result_type create_kwd(Terminal const &term , Subject const & subject, Modifiers const& modifiers, boost::mpl::false_ ) const + { + return result_type(subject + ,compile<qi::domain>(fusion::at_c<0>(term.args),modifiers) + ,iterator_type() + ); + } + // Select which object type to return + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers ) const + { + return create_kwd(term, subject, modifiers, is_string_kwd_type()); + } + }; + template <typename T1, typename Subject, typename Modifiers> struct make_directive< terminal_ex<repository::tag::kwd, fusion::vector1<T1> >, Subject, Modifiers> { + typedef make_directive_internal<T1, Subject, Modifiers, mpl::false_> make_directive_type; + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const + { + + return make_directive_type()(term, subject, modifiers); + } + + }; + + template <typename T1, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::dkwd, fusion::vector1<T1> >, Subject, Modifiers> + { + typedef make_directive_internal<T1, Subject, Modifiers, mpl::true_> make_directive_type; + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const + { + + return make_directive_type()(term, subject, modifiers); + } + + }; + + + + // Directive ikwd(key)[p] + template <typename T1, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::ikwd, fusion::vector1<T1> >, Subject, Modifiers> + { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_pass_iterator<int> iterator_type; - typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::false_ > result_type; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, no_case > result_type; - template <typename Terminal> result_type operator()( Terminal const& term, Subject const& subject, unused_type) const { + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; + return result_type(subject ,fusion::at_c<0>(term.args) ,iterator_type() + ,encoding ); } }; - // Directive ikwd(key)[p] template <typename T1, typename Subject, typename Modifiers> struct make_directive< - terminal_ex<repository::tag::ikwd, fusion::vector1<T1> >, Subject, Modifiers> + terminal_ex<repository::tag::idkwd, fusion::vector1<T1> >, Subject, Modifiers> { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_pass_iterator<int> iterator_type; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_ > result_type; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::true_ > result_type; template <typename Terminal> result_type operator()( Terminal const& term, Subject const& subject, unused_type) const { - /* typename spirit::detail::get_encoding<Modifiers, - spirit::char_encoding::standard>::type encoding;*/ + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; return result_type(subject ,fusion::at_c<0>(term.args) ,iterator_type() + ,encoding ); } }; // Directive kwd(key,exact)[p] + template <typename T> + struct make_exact_helper + { + typedef repository::qi::kwd_exact_iterator<T> iterator_type; + template<typename Args> + static iterator_type make_iterator(Args const& args) + { + return iterator_type(fusion::at_c<1>(args)); + } + }; + template <typename T1, typename T2, typename Subject, typename Modifiers> struct make_directive< terminal_ex<repository::tag::kwd, fusion::vector2<T1,T2> >, Subject, Modifiers> { + typedef make_directive_internal_2_args< T1 + , T2 + , Subject + , Modifiers + , mpl::false_ + , make_exact_helper<T2> + > make_directive_type; + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const + { + + return make_directive_type()(term,subject, modifiers); + } + + }; + + template <typename T1, typename T2, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::dkwd, fusion::vector2<T1,T2> >, Subject, Modifiers> + { + typedef make_directive_internal_2_args< T1 + , T2 + , Subject + , Modifiers + , mpl::true_ + , make_exact_helper<T2> + > make_directive_type; + + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const + { + + return make_directive_type()(term, subject, modifiers); + } + + }; + + + // Directive ikwd(key,exact)[p] + template <typename T1, typename T2, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::ikwd, fusion::vector2<T1,T2> >, Subject, Modifiers> + { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_exact_iterator<T2> iterator_type; - typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, no_case > result_type; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::false_ > result_type; template <typename Terminal> result_type operator()( - Terminal const& term, Subject const& subject, unused_type) const + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const { + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; return result_type(subject ,fusion::at_c<0>(term.args) ,fusion::at_c<1>(term.args) + , encoding ); } }; - // Directive ikwd(key,exact)[p] template <typename T1, typename T2, typename Subject, typename Modifiers> struct make_directive< - terminal_ex<repository::tag::ikwd, fusion::vector2<T1,T2> >, Subject, Modifiers> + terminal_ex<repository::tag::idkwd, fusion::vector2<T1,T2> >, Subject, Modifiers> { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_exact_iterator<T2> iterator_type; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_ > result_type; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::true_ > result_type; template <typename Terminal> result_type operator()( - Terminal const& term, Subject const& subject, unused_type) const + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const { + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; return result_type(subject , fusion::at_c<0>(term.args) , fusion::at_c<1>(term.args) + , encoding ); } }; + // Directive kwd(min, max)[p] + + template <typename T> + struct make_finite_helper + { + typedef repository::qi::kwd_finite_iterator<T> iterator_type; + template<typename Args> + static iterator_type make_iterator(Args const& args) + { + return iterator_type(fusion::at_c<1>(args),fusion::at_c<2>(args)); + } + + }; + template <typename T1, typename T2, typename Subject, typename Modifiers> struct make_directive< terminal_ex<repository::tag::kwd, fusion::vector3< T1, T2, T2> >, Subject, Modifiers> { + typedef make_directive_internal_2_args< T1 + , T2 + , Subject + , Modifiers + , mpl::false_ + , make_finite_helper<T2> + > make_directive_type; + + + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const + { + + return make_directive_type()(term,subject, modifiers); + } + + }; + + template <typename T1, typename T2, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::dkwd, fusion::vector3<T1,T2,T2> >, Subject, Modifiers> + { + + typedef make_directive_internal_2_args< T1 + , T2 + , Subject + , Modifiers + , mpl::true_ + , make_finite_helper<T2> + > make_directive_type; + + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, Modifiers const& modifiers) const + { + + return make_directive_type()(term,subject, modifiers); + } + + }; + + // Directive ikwd(min, max)[p] + template <typename T1, typename T2, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::ikwd, fusion::vector3< T1, T2, T2> >, Subject, Modifiers> + { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_finite_iterator<T2> iterator_type; - typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, no_case > result_type; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::false_ > result_type; template <typename Terminal> result_type operator()( Terminal const& term, Subject const& subject, unused_type) const { + + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; return result_type(subject, fusion::at_c<0>(term.args), iterator_type( fusion::at_c<1>(term.args) , fusion::at_c<2>(term.args) + , encoding ) ); } }; - // Directive ikwd(min, max)[p] template <typename T1, typename T2, typename Subject, typename Modifiers> struct make_directive< - terminal_ex<repository::tag::ikwd, fusion::vector3< T1, T2, T2> >, Subject, Modifiers> + terminal_ex<repository::tag::idkwd, fusion::vector3< T1, T2, T2> >, Subject, Modifiers> { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_finite_iterator<T2> iterator_type; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_ > result_type; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::true_ > result_type; template <typename Terminal> result_type operator()( Terminal const& term, Subject const& subject, unused_type) const { + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; return result_type(subject, fusion::at_c<0>(term.args), iterator_type( fusion::at_c<1>(term.args) , fusion::at_c<2>(term.args) + , encoding ) ); } }; + // Directive kwd(min, inf)[p] + + template <typename T> + struct make_infinite_helper + { + typedef repository::qi::kwd_infinite_iterator<T> iterator_type; + template<typename Args> + static iterator_type make_iterator(Args const& args) + { + return iterator_type(fusion::at_c<1>(args)); + } + + }; + + template <typename T1, typename T2, typename Subject, typename Modifiers> struct make_directive< - terminal_ex<repository::tag::kwd + terminal_ex<repository::tag::kwd, fusion::vector3<T1,T2,inf_type> >, Subject, Modifiers> + { + typedef make_directive_internal_2_args< T1 + , T2 + , Subject + , Modifiers + , mpl::false_ + , make_infinite_helper<T2> + > make_directive_type; + + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, unused_type) const + { + + return make_directive_type()(term,subject, unused_type()); + } + + }; + + template <typename T1, typename T2, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::dkwd, fusion::vector3<T1,T2,inf_type> >, Subject, Modifiers> + { + typedef make_directive_internal_2_args< T1 + , T2 + , Subject + , Modifiers + , mpl::false_ + , make_infinite_helper<T2> + > make_directive_type; + + typedef typename make_directive_type::result_type result_type; + template <typename Terminal> + result_type operator()( + Terminal const& term, Subject const& subject, unused_type) const + { + + return make_directive_type()(term,subject, unused_type()); + } + + }; + + + // Directive ikwd(min, inf)[p] + template <typename T1, typename T2, typename Subject, typename Modifiers> + struct make_directive< + terminal_ex<repository::tag::ikwd , fusion::vector3<T1, T2, inf_type> >, Subject, Modifiers> { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_infinite_iterator<T2> iterator_type; - typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, no_case > result_type; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::false_ > result_type; template <typename Terminal> result_type operator()( Terminal const& term, Subject const& subject, unused_type) const { + typename spirit::detail::get_encoding<Modifiers, + spirit::char_encoding::standard>::type encoding; + return result_type(subject , fusion::at_c<0>(term.args) , fusion::at_c<1>(term.args) + , encoding ); } }; - // Directive ikwd(min, inf)[p] template <typename T1, typename T2, typename Subject, typename Modifiers> struct make_directive< - terminal_ex<repository::tag::ikwd + terminal_ex<repository::tag::idkwd , fusion::vector3<T1, T2, inf_type> >, Subject, Modifiers> { typedef typename add_const<T1>::type const_keyword; typedef repository::qi::kwd_infinite_iterator<T2> iterator_type; - typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_ > result_type; + typedef repository::qi::kwd_parser<Subject, const_keyword, iterator_type, mpl::true_, mpl::true_ > result_type; template <typename Terminal> result_type operator()( @@ -568,6 +1156,7 @@ namespace boost { namespace spirit { namespace qi return result_type(subject , fusion::at_c<0>(term.args) , fusion::at_c<1>(term.args) + , encoding ); } }; @@ -578,10 +1167,32 @@ namespace boost { namespace spirit { namespace qi namespace boost { namespace spirit { namespace traits { template <typename Subject, typename KeywordType - , typename LoopIter, typename NoCase > + , typename LoopIter, typename NoCase , typename Distinct> struct has_semantic_action< - repository::qi::kwd_parser< Subject, KeywordType, LoopIter, NoCase > > + repository::qi::kwd_parser< Subject, KeywordType, LoopIter, NoCase, Distinct > > + : unary_has_semantic_action<Subject> {}; + + template <typename Subject, typename KeywordType + , typename LoopIter, typename Distinct > + struct has_semantic_action< + repository::qi::complex_kwd_parser< Subject, KeywordType, LoopIter, Distinct > > : unary_has_semantic_action<Subject> {}; + + template <typename Subject, typename KeywordType + , typename LoopIter, typename NoCase, typename Attribute, typename Context + , typename Iterator, typename Distinct> + struct handles_container<repository::qi::kwd_parser<Subject, KeywordType, LoopIter, NoCase, Distinct>, Attribute + , Context, Iterator> + : unary_handles_container<Subject, Attribute, Context, Iterator> {}; + + template <typename Subject, typename KeywordType + , typename LoopIter + , typename Attribute, typename Context + , typename Iterator, typename Distinct> + struct handles_container<repository::qi::complex_kwd_parser<Subject, KeywordType, LoopIter, Distinct>, Attribute + , Context, Iterator> + : unary_handles_container<Subject, Attribute, Context, Iterator> {}; + }}} #endif 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 diff --git a/boost/spirit/repository/home/qi/operator/keywords.hpp b/boost/spirit/repository/home/qi/operator/keywords.hpp index c32c55c7af..f0382371fa 100644 --- a/boost/spirit/repository/home/qi/operator/keywords.hpp +++ b/boost/spirit/repository/home/qi/operator/keywords.hpp @@ -1,6 +1,6 @@ /*============================================================================= 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) @@ -22,6 +22,7 @@ #include <boost/fusion/include/iter_fold.hpp> #include <boost/fusion/include/at.hpp> #include <boost/fusion/include/value_at.hpp> +#include <boost/fusion/include/mpl.hpp> #include <boost/optional.hpp> #include <boost/foreach.hpp> #include <boost/array.hpp> @@ -35,10 +36,14 @@ #include <boost/mpl/size.hpp> #include <boost/mpl/equal_to.hpp> #include <boost/mpl/back_inserter.hpp> +#include <boost/mpl/filter_view.hpp> +#include <boost/fusion/include/zip_view.hpp> +#include <boost/fusion/include/as_vector.hpp> #include <boost/variant/static_visitor.hpp> #include <boost/type_traits/remove_const.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/spirit/repository/home/qi/operator/detail/keywords.hpp> +#include <boost/fusion/include/any.hpp> namespace boost { namespace spirit @@ -62,6 +67,7 @@ namespace boost { namespace spirit { namespace repository { namespace qi namespace detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(kwd_parser_id) + BOOST_MPL_HAS_XXX_TRAIT_DEF(complex_kwd_parser_id) } @@ -76,6 +82,16 @@ namespace boost { namespace spirit { namespace repository { namespace qi template <typename Subject> struct is_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_kwd_parser_id<Subject> {}; + template <typename T> + struct is_complex_kwd_parser : detail::has_complex_kwd_parser_id<T> {}; + + template <typename Subject, typename Action> + struct is_complex_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_complex_kwd_parser_id<Subject> {}; + + template <typename Subject> + struct is_complex_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_complex_kwd_parser_id<Subject> {}; + + // Keywords operator template <typename Elements, typename Modifiers> struct keywords : spirit::qi::nary_parser<keywords<Elements,Modifiers> > @@ -101,10 +117,15 @@ namespace boost { namespace spirit { namespace repository { namespace qi typedef typename mpl::count_if< Elements, mpl::not_< + mpl::or_< is_kwd_parser< mpl::_1 + > , + is_complex_kwd_parser< + mpl::_1 > > + > > non_kwd_subject_count; /// If the assertion fails here then you probably forgot to wrap a @@ -130,208 +151,38 @@ namespace boost { namespace spirit { namespace repository { namespace qi typedef typename mpl::range_c<int, 0, sequence_size::value>::type int_range; // Transform the range_c to an mpl vector in order to be able to transform it into a variant - typedef typename mpl::copy<int_range, mpl::back_inserter<mpl::vector<> > >::type int_vector; - - // Build the variant type containing the indexes of the parsers - typedef typename - spirit::detail::as_variant< - int_vector >::type type; - }; - - // Create a variant type to be able to store parser indexes in the embedded symbols parser - typedef typename build_parser_tags< Elements >::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; + typedef typename mpl::copy<int_range, mpl::back_inserter<mpl::vector<> > >::type type; - // 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< Elements >::type char_types; - typedef typename get_keyword_char_type< char_types >::type char_type; + // Build an index mpl vector + typedef typename build_parser_tags< Elements >::type parser_index_vector; - /// Our symbols container - typedef spirit::qi::tst< char_type, parser_index_type> keywords_type; + template <typename idx> + struct is_complex_kwd_parser_filter : is_complex_kwd_parser< typename mpl::at<Elements, idx>::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 idx> + struct is_kwd_parser_filter : is_kwd_parser< typename mpl::at<Elements, idx>::type > + {}; - template <typename F, typename Element> - struct result<F(Element)> - { - typedef typename Element::no_case_keyword type; + // filter out the string kwd directives + typedef typename mpl::filter_view< Elements, is_kwd_parser<mpl_::_> >::type string_keywords; - }; - 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; - }; + typedef typename mpl::filter_view< parser_index_vector , + is_kwd_parser_filter< mpl::_ > + >::type string_keyword_indexes; + // filter out the complex keywords + typedef typename mpl::filter_view< parser_index_vector , + is_complex_kwd_parser_filter< mpl::_ > + >::type complex_keywords_indexes; - // never called, but needed for decltype-based result_of (C++0x) - template <typename Element> - typename result<element_case_type(Element)>::type - operator()(Element&) const; - }; + //typedef typename fusion::filter_view< Elements, is_complex_kwd_parser< mpl::_ > > complex_keywords_view; - // 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<Elements>::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<Elements>::type nb_elements; - // Determine if all the kwd directive are case sensitive/insensitive - typedef typename mpl::equal_to< ikwd_count, nb_elements>::type all_ikwd; - typedef typename mpl::equal_to< kwd_count, nb_elements>::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 - filter_type; - + typename mpl::empty<complex_keywords_indexes>::type, + detail::empty_keywords_list, + detail::complex_keywords< complex_keywords_indexes > + >::type complex_keywords_type; // build a bool array and an integer array which will be used to // check that the repetition constraints of the kwd parsers are @@ -339,91 +190,24 @@ namespace boost { namespace spirit { namespace repository { namespace qi typedef boost::array<bool, fusion::result_of::size<Elements>::value> flags_type; typedef boost::array<int, fusion::result_of::size<Elements>::value> counters_type; + typedef typename mpl::if_< + typename mpl::empty<string_keyword_indexes>::type, + detail::empty_keywords_list, + detail::string_keywords< + Elements, + string_keywords, + string_keyword_indexes, + flags_type, + Modifiers> + >::type string_keywords_type; - - // Functor which adds all the keywords/subject parser indexes - // collected from the subject kwd directives to the keyword tst parser - template< typename Sequence > - struct keyword_entry_adder + keywords(Elements const& elements_) : + elements(elements_) + , string_keywords_inst(elements,flags_init) + , complex_keywords_inst(elements,flags_init) { - typedef int result_type; - - keyword_entry_adder(shared_ptr<keywords_type> lookup,flags_type &flags) : - lookup(lookup) - ,flags(flags) - {} - - typedef typename fusion::result_of::begin< Sequence >::type sequence_begin; - - template <typename T> - int operator()(const int i, const T &parser) const - { - // Determine the current position being handled - typedef typename fusion::result_of::distance< sequence_begin, T >::type position_raw; - // Transform the position to a parser index tag - typedef typename mpl::integral_c<int,position_raw::value> position; - - return call(i,fusion::deref(parser),position()); } - template <typename T, typename Position, typename Action> - int call( const int i, 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 int i, const T & parser, const Position position) const - { - // Make the keyword/parse index entry in the tst parser - lookup->add( - traits::get_begin<char_type>(parser.keyword.str), - traits::get_end<char_type>(parser.keyword.str), - 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 int i, 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; - } - - - shared_ptr<keywords_type> lookup; - flags_type & flags; - }; - - - keywords(Elements const& elements) : - elements(elements) - , lookup(new keywords_type()) - { - // Loop through all the subject parsers to build the keyword parser symbol parser - keyword_entry_adder<Elements> f1(lookup,flags_init); - fusion::iter_fold(this->elements,0,f1); - } - template <typename Iterator, typename Context , typename Skipper, typename Attribute> bool parse(Iterator& first, Iterator const& last @@ -434,7 +218,7 @@ namespace boost { namespace spirit { namespace repository { namespace qi // We need to handle the case where kwd / ikwd directives have been mixed // This is where we decide which function should be called. return parse_impl(first, last, context, skipper, attr_, - typename mpl::or_<all_directives_of_same_type, no_case>::type() + typename string_keywords_type::requires_one_pass() ); } @@ -442,7 +226,7 @@ namespace boost { namespace spirit { namespace repository { namespace qi , typename Skipper, typename Attribute> bool parse_impl(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper - , Attribute& attr_,mpl::true_ /* no ikwd */) const + , Attribute& attr_,mpl::true_ /* one pass */) const { // wrap the attribute in a tuple if it is not a tuple @@ -458,10 +242,16 @@ namespace boost { namespace spirit { namespace repository { namespace qi , flags_type, counters_type , typename traits::wrap_if_not_tuple<Attribute>::type , mpl::false_ > parser_visitor_type; + parser_visitor_type parse_visitor(elements, first, last , context, skipper, flags , counters, attr); + typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type; + + complex_kwd_function_type + complex_function(first,last,context,skipper,parse_visitor); + // We have a bool array 'flags' with one flag for each parser as well as a 'counter' // array. // The kwd directive sets and increments the counter when a successeful parse occured @@ -471,35 +261,36 @@ namespace boost { namespace spirit { namespace repository { namespace qi // The parsing takes place here in two steps: // 1) parse a keyword and fetch the parser index associated with that keyword // 2) call the associated parser and store the parsed value in the matching attribute. - Iterator save = first; + while(true) { spirit::qi::skip_over(first, last, skipper); - if (parser_index_type* val_ptr - = lookup->find(first, last, filter_type())) + Iterator save = first; + if (string_keywords_inst.parse(first, last,parse_visitor,skipper)) { - spirit::qi::skip_over(first, last, skipper); - if(!apply_visitor(parse_visitor,*val_ptr)){ - first = save; - return false; - } save = first; } - else + else { + // restore the position to the last successful keyword parse + first = save; + if(!complex_keywords_inst.parse(complex_function)) { + first = save; // Check that we are leaving the keywords parser in a successfull state BOOST_FOREACH(bool &valid,flags) { if(!valid) { - first = save; return false; } } return true; } + else + save = first; } + } return false; } @@ -508,7 +299,7 @@ namespace boost { namespace spirit { namespace repository { namespace qi , typename Skipper, typename Attribute> bool parse_impl(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper - , Attribute& attr_,mpl::false_) const + , Attribute& attr_,mpl::false_ /* two passes */) const { // wrap the attribute in a tuple if it is not a tuple @@ -536,6 +327,12 @@ namespace boost { namespace spirit { namespace repository { namespace qi no_case_parser_visitor_type no_case_parse_visitor(elements,first,last ,context,skipper,flags,counters,attr); + typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type; + + complex_kwd_function_type + complex_function(first,last,context,skipper,parse_visitor); + + // We have a bool array 'flags' with one flag for each parser as well as a 'counter' // array. // The kwd directive sets and increments the counter when a successeful parse occured @@ -545,47 +342,37 @@ namespace boost { namespace spirit { namespace repository { namespace qi // The parsing takes place here in two steps: // 1) parse a keyword and fetch the parser index associated with that keyword // 2) call the associated parser and store the parsed value in the matching attribute. - Iterator save = first; + while(true) { spirit::qi::skip_over(first, last, skipper); - // First pass case sensitive - Iterator saved_first = first; - if (parser_index_type* val_ptr - = lookup->find(first, last, spirit::qi::tst_pass_through())) + Iterator save = first; + // String keywords pass + if (string_keywords_inst.parse(first,last,parse_visitor,no_case_parse_visitor,skipper)) { - spirit::qi::skip_over(first, last, skipper); - if(!apply_visitor(parse_visitor,*val_ptr)){ - first = save; - return false; - } save = first; } - // Second pass case insensitive - else if(parser_index_type* val_ptr - = lookup->find(saved_first,last,nc_filter())) + else { + first = save; + + if(!complex_keywords_inst.parse(complex_function)) { - first = saved_first; - spirit::qi::skip_over(first, last, skipper); - if(!apply_visitor(no_case_parse_visitor,*val_ptr)){ first = save; - return false; - } - save = first; - } - else - { // Check that we are leaving the keywords parser in a successfull state BOOST_FOREACH(bool &valid,flags) { if(!valid) { - first = save; return false; } } return true; } + else + { + save = first; + } + } } return false; } @@ -600,7 +387,8 @@ namespace boost { namespace spirit { namespace repository { namespace qi } flags_type flags_init; Elements elements; - shared_ptr<keywords_type> lookup; + string_keywords_type string_keywords_inst; + complex_keywords_type complex_keywords_inst; }; }}}} @@ -634,6 +422,14 @@ namespace boost { namespace spirit { namespace traits template <typename Elements, typename Modifiers> struct has_semantic_action<repository::qi::keywords<Elements, Modifiers> > : nary_has_semantic_action<Elements> {}; + + template <typename Elements, typename Attribute, typename Context + , typename Iterator, typename Modifiers> + struct handles_container<repository::qi::keywords<Elements,Modifiers>, Attribute + , Context, Iterator> + : nary_handles_container<Elements, Attribute, Context, Iterator> {}; + + }}} #endif diff --git a/boost/spirit/repository/home/support/kwd.hpp b/boost/spirit/repository/home/support/kwd.hpp index efe756d3e0..e723cec8c6 100644 --- a/boost/spirit/repository/home/support/kwd.hpp +++ b/boost/spirit/repository/home/support/kwd.hpp @@ -15,7 +15,7 @@ namespace boost { namespace spirit { namespace repository { // The distinct extended terminal - BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(( kwd, kwd_type )( ikwd, ikwd_type ) ) + BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(( kwd, kwd_type )( ikwd, ikwd_type )(dkwd, dkwd_type)(idkwd, idkwd_type) ) }}} |