/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman 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_OR_MARCH_13_2007_1145PM) #define SPIRIT_KEYWORDS_OR_MARCH_13_2007_1145PM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace spirit { /////////////////////////////////////////////////////////////////////////// // Enablers /////////////////////////////////////////////////////////////////////////// template <> struct use_operator // enables / : mpl::true_ {}; template <> struct flatten_tree // flattens / : mpl::true_ {}; }} namespace boost { namespace spirit { namespace repository { namespace qi { // kwd directive parser type identification namespace detail { BOOST_MPL_HAS_XXX_TRAIT_DEF(kwd_parser_id) BOOST_MPL_HAS_XXX_TRAIT_DEF(complex_kwd_parser_id) } // kwd directive type query template struct is_kwd_parser : detail::has_kwd_parser_id {}; template struct is_kwd_parser > : detail::has_kwd_parser_id {}; template struct is_kwd_parser > : detail::has_kwd_parser_id {}; template struct is_complex_kwd_parser : detail::has_complex_kwd_parser_id {}; template struct is_complex_kwd_parser > : detail::has_complex_kwd_parser_id {}; template struct is_complex_kwd_parser > : detail::has_complex_kwd_parser_id {}; // Keywords operator template struct keywords : spirit::qi::nary_parser > { template struct attribute { // Put all the element attributes in a tuple typedef typename traits::build_attribute_sequence< Elements, Context, traits::sequence_attribute_transform, Iterator, spirit::qi::domain >::type all_attributes; // Now, build a fusion vector over the attributes. Note // that build_fusion_vector 1) removes all unused attributes // and 2) may return unused_type if all elements have // unused_type(s). typedef typename traits::build_fusion_vector::type type; }; /// Make sure that all subjects are of the kwd type 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 /// subject of the / operator in a kwd directive BOOST_MPL_ASSERT_RELATION( non_kwd_subject_count::value, ==, 0 ); /////////////////////////////////////////////////////////////////////////// // build_parser_tags // // Builds a boost::variant from an mpl::range_c in order to "mark" every // parser of the fusion sequence. The integer constant is used in the parser // dispatcher functor in order to use the parser corresponding to the recognised // keyword. /////////////////////////////////////////////////////////////////////////// template struct build_parser_tags { // Get the sequence size typedef typename mpl::size< Sequence >::type sequence_size; // Create an integer_c constant for every parser in the sequence typedef typename mpl::range_c::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 > >::type type; }; // Build an index mpl vector typedef typename build_parser_tags< Elements >::type parser_index_vector; template struct is_complex_kwd_parser_filter : is_complex_kwd_parser< typename mpl::at::type > {}; template struct is_kwd_parser_filter : is_kwd_parser< typename mpl::at::type > {}; // filter out the string kwd directives typedef typename mpl::filter_view< Elements, is_kwd_parser >::type string_keywords; 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; //typedef typename fusion::filter_view< Elements, is_complex_kwd_parser< mpl::_ > > complex_keywords_view; typedef typename mpl::if_< typename mpl::empty::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 // met and bail out a soon as possible typedef boost::array::value> flags_type; typedef boost::array::value> counters_type; typedef typename mpl::if_< typename mpl::empty::type, detail::empty_keywords_list, detail::string_keywords< Elements, string_keywords, string_keyword_indexes, flags_type, Modifiers> >::type string_keywords_type; keywords(Elements const& elements_) : elements(elements_) , string_keywords_inst(elements,flags_init) , complex_keywords_inst(elements,flags_init) { } template bool parse(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr_) const { // Select which parse function to call // 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 string_keywords_type::requires_one_pass() ); } template bool parse_impl(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr_,mpl::true_ /* one pass */) const { // wrap the attribute in a tuple if it is not a tuple typename traits::wrap_if_not_tuple::type attr(attr_); flags_type flags(flags_init); //flags.assign(false); counters_type counters; counters.assign(0); typedef repository::qi::detail::parse_dispatcher::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 occurred // as well as the slot of the corresponding parser to true in the flags array as soon // the minimum repetition requirement is met and keeps that value to true as long as // the maximum repetition requirement is met. // 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. for(;;) { spirit::qi::skip_over(first, last, skipper); Iterator save = first; if (string_keywords_inst.parse(first, last,parse_visitor,skipper)) { save = first; } 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) { return false; } } return true; } else save = first; } } return false; } // Handle the mixed kwd and ikwd case template bool parse_impl(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr_,mpl::false_ /* two passes */) const { // wrap the attribute in a tuple if it is not a tuple typename traits::wrap_if_not_tuple::type attr(attr_); flags_type flags(flags_init); //flags.assign(false); counters_type counters; counters.assign(0); typedef detail::parse_dispatcher::type , mpl::false_> parser_visitor_type; typedef detail::parse_dispatcher::type , mpl::true_> no_case_parser_visitor_type; parser_visitor_type parse_visitor(elements,first,last ,context,skipper,flags,counters,attr); 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 occurred // as well as the slot of the corresponding parser to true in the flags array as soon // the minimum repetition requirement is met and keeps that value to true as long as // the maximum repetition requirement is met. // 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. for(;;) { spirit::qi::skip_over(first, last, skipper); Iterator save = first; // String keywords pass if (string_keywords_inst.parse(first,last,parse_visitor,no_case_parse_visitor,skipper)) { save = first; } else { 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) { return false; } } return true; } else { save = first; } } } return false; } template info what(Context& context) const { info result("keywords"); fusion::for_each(elements, spirit::detail::what_function(result, context)); return result; } flags_type flags_init; Elements elements; string_keywords_type string_keywords_inst; complex_keywords_type complex_keywords_inst; }; }}}} namespace boost { namespace spirit { namespace qi { /////////////////////////////////////////////////////////////////////////// // Parser generators: make_xxx function (objects) /////////////////////////////////////////////////////////////////////////// template struct make_composite { typedef repository::qi::keywords result_type; result_type operator()(Elements ref, unused_type) const { return result_type(ref); } }; }}} namespace boost { namespace spirit { namespace traits { // We specialize this for keywords (see support/attributes.hpp). // For keywords, we only wrap the attribute in a tuple IFF // it is not already a fusion tuple. template struct pass_attribute, Attribute> : wrap_if_not_tuple {}; template struct has_semantic_action > : nary_has_semantic_action {}; template struct handles_container, Attribute , Context, Iterator> : nary_handles_container {}; }}} #endif