1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2011-2012 Thomas Bernard 4 5 Distributed under the Boost Software License, Version 1.0. (See accompanying 6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 =============================================================================*/ 8 #ifndef BOOST_SPIRIT_REPOSITORY_QI_OPERATOR_KEYWORDS_HPP 9 #define BOOST_SPIRIT_REPOSITORY_QI_OPERATOR_KEYWORDS_HPP 10 11 #if defined(_MSC_VER) 12 #pragma once 13 #endif 14 15 #include <boost/spirit/home/qi/meta_compiler.hpp> 16 #include <boost/spirit/home/qi/domain.hpp> 17 #include <boost/spirit/home/qi/detail/permute_function.hpp> 18 #include <boost/spirit/home/qi/detail/attributes.hpp> 19 #include <boost/spirit/home/support/detail/what_function.hpp> 20 #include <boost/spirit/home/support/info.hpp> 21 #include <boost/spirit/home/support/unused.hpp> 22 #include <boost/fusion/include/iter_fold.hpp> 23 #include <boost/fusion/include/at.hpp> 24 #include <boost/fusion/include/value_at.hpp> 25 #include <boost/fusion/include/mpl.hpp> 26 #include <boost/optional.hpp> 27 #include <boost/foreach.hpp> 28 #include <boost/array.hpp> 29 #include <boost/spirit/home/qi/string/symbols.hpp> 30 #include <boost/spirit/home/qi/string/lit.hpp> 31 #include <boost/spirit/home/qi/action/action.hpp> 32 #include <boost/spirit/home/qi/directive/hold.hpp> 33 #include <boost/mpl/count_if.hpp> 34 #include <boost/mpl/greater.hpp> 35 #include <boost/mpl/range_c.hpp> 36 #include <boost/mpl/copy.hpp> 37 #include <boost/mpl/size.hpp> 38 #include <boost/mpl/equal_to.hpp> 39 #include <boost/mpl/back_inserter.hpp> 40 #include <boost/mpl/filter_view.hpp> 41 #include <boost/fusion/include/zip_view.hpp> 42 #include <boost/fusion/include/as_vector.hpp> 43 #include <boost/variant/static_visitor.hpp> 44 #include <boost/proto/operators.hpp> 45 #include <boost/proto/tags.hpp> 46 #include <boost/type_traits/remove_const.hpp> 47 #include <boost/type_traits/is_same.hpp> 48 #include <boost/spirit/repository/home/qi/operator/detail/keywords.hpp> 49 #include <boost/fusion/include/any.hpp> 50 51 52 namespace boost { namespace spirit 53 { 54 /////////////////////////////////////////////////////////////////////////// 55 // Enablers 56 /////////////////////////////////////////////////////////////////////////// 57 template <> 58 struct use_operator<qi::domain, proto::tag::divides > // enables / 59 : mpl::true_ {}; 60 61 template <> 62 struct flatten_tree<qi::domain, proto::tag::divides> // flattens / 63 : mpl::true_ {}; 64 }} 65 66 namespace boost { namespace spirit { namespace repository { namespace qi 67 { 68 69 // kwd directive parser type identification 70 namespace detail 71 { 72 BOOST_MPL_HAS_XXX_TRAIT_DEF(kwd_parser_id) 73 BOOST_MPL_HAS_XXX_TRAIT_DEF(complex_kwd_parser_id) 74 75 76 } 77 78 // kwd directive type query 79 template <typename T> 80 struct is_kwd_parser : detail::has_kwd_parser_id<T> {}; 81 82 template <typename Subject, typename Action> 83 struct is_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_kwd_parser_id<Subject> {}; 84 85 template <typename Subject> 86 struct is_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_kwd_parser_id<Subject> {}; 87 88 template <typename T> 89 struct is_complex_kwd_parser : detail::has_complex_kwd_parser_id<T> {}; 90 91 template <typename Subject, typename Action> 92 struct is_complex_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_complex_kwd_parser_id<Subject> {}; 93 94 template <typename Subject> 95 struct is_complex_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_complex_kwd_parser_id<Subject> {}; 96 97 98 // Keywords operator 99 template <typename Elements, typename Modifiers> 100 struct keywords : spirit::qi::nary_parser<keywords<Elements,Modifiers> > 101 { 102 template <typename Context, typename Iterator> 103 struct attribute 104 { 105 // Put all the element attributes in a tuple 106 typedef typename traits::build_attribute_sequence< 107 Elements, Context, traits::sequence_attribute_transform, Iterator, spirit::qi::domain >::type 108 all_attributes; 109 110 // Now, build a fusion vector over the attributes. Note 111 // that build_fusion_vector 1) removes all unused attributes 112 // and 2) may return unused_type if all elements have 113 // unused_type(s). 114 typedef typename 115 traits::build_fusion_vector<all_attributes>::type 116 type; 117 }; 118 119 /// Make sure that all subjects are of the kwd type 120 typedef typename mpl::count_if< 121 Elements, 122 mpl::not_< 123 mpl::or_< 124 is_kwd_parser< 125 mpl::_1 126 > , 127 is_complex_kwd_parser< 128 mpl::_1 129 > 130 > 131 > 132 > non_kwd_subject_count; 133 134 /// If the assertion fails here then you probably forgot to wrap a 135 /// subject of the / operator in a kwd directive 136 BOOST_MPL_ASSERT_RELATION( non_kwd_subject_count::value, ==, 0 ); 137 138 /////////////////////////////////////////////////////////////////////////// 139 // build_parser_tags 140 // 141 // Builds a boost::variant from an mpl::range_c in order to "mark" every 142 // parser of the fusion sequence. The integer constant is used in the parser 143 // dispatcher functor in order to use the parser corresponding to the recognised 144 // keyword. 145 /////////////////////////////////////////////////////////////////////////// 146 147 template <typename Sequence> 148 struct build_parser_tags 149 { 150 // Get the sequence size 151 typedef typename mpl::size< Sequence >::type sequence_size; 152 153 // Create an integer_c constant for every parser in the sequence 154 typedef typename mpl::range_c<int, 0, sequence_size::value>::type int_range; 155 156 // Transform the range_c to an mpl vector in order to be able to transform it into a variant 157 typedef typename mpl::copy<int_range, mpl::back_inserter<mpl::vector<> > >::type type; 158 159 }; 160 // Build an index mpl vector 161 typedef typename build_parser_tags< Elements >::type parser_index_vector; 162 163 template <typename idx> 164 struct is_complex_kwd_parser_filter : is_complex_kwd_parser< typename mpl::at<Elements, idx>::type > 165 {}; 166 167 template <typename idx> 168 struct is_kwd_parser_filter : is_kwd_parser< typename mpl::at<Elements, idx>::type > 169 {}; 170 171 // filter out the string kwd directives 172 typedef typename mpl::filter_view< Elements, is_kwd_parser<mpl::_> >::type string_keywords; 173 174 typedef typename mpl::filter_view< parser_index_vector , 175 is_kwd_parser_filter< mpl::_ > 176 >::type string_keyword_indexes; 177 // filter out the complex keywords 178 typedef typename mpl::filter_view< parser_index_vector , 179 is_complex_kwd_parser_filter< mpl::_ > 180 >::type complex_keywords_indexes; 181 182 //typedef typename fusion::filter_view< Elements, is_complex_kwd_parser< mpl::_ > > complex_keywords_view; 183 184 typedef typename mpl::if_< 185 typename mpl::empty<complex_keywords_indexes>::type, 186 detail::empty_keywords_list, 187 detail::complex_keywords< complex_keywords_indexes > 188 >::type complex_keywords_type; 189 190 // build a bool array and an integer array which will be used to 191 // check that the repetition constraints of the kwd parsers are 192 // met and bail out a soon as possible 193 typedef boost::array<bool, fusion::result_of::size<Elements>::value> flags_type; 194 typedef boost::array<int, fusion::result_of::size<Elements>::value> counters_type; 195 196 typedef typename mpl::if_< 197 typename mpl::empty<string_keyword_indexes>::type, 198 detail::empty_keywords_list, 199 detail::string_keywords< 200 Elements, 201 string_keywords, 202 string_keyword_indexes, 203 flags_type, 204 Modifiers> 205 >::type string_keywords_type; 206 keywordsboost::spirit::repository::qi::keywords207 keywords(Elements const& elements_) : 208 elements(elements_) 209 , string_keywords_inst(elements,flags_init) 210 , complex_keywords_inst(elements,flags_init) 211 { 212 } 213 214 template <typename Iterator, typename Context 215 , typename Skipper, typename Attribute> parseboost::spirit::repository::qi::keywords216 bool parse(Iterator& first, Iterator const& last 217 , Context& context, Skipper const& skipper 218 , Attribute& attr_) const 219 { 220 // Select which parse function to call 221 // We need to handle the case where kwd / ikwd directives have been mixed 222 // This is where we decide which function should be called. 223 return parse_impl(first, last, context, skipper, attr_, 224 typename string_keywords_type::requires_one_pass() 225 ); 226 } 227 228 template <typename Iterator, typename Context 229 , typename Skipper, typename Attribute> parse_implboost::spirit::repository::qi::keywords230 bool parse_impl(Iterator& first, Iterator const& last 231 , Context& context, Skipper const& skipper 232 , Attribute& attr_,mpl::true_ /* one pass */) const 233 { 234 235 // wrap the attribute in a tuple if it is not a tuple 236 typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_); 237 238 flags_type flags(flags_init); 239 //flags.assign(false); 240 241 counters_type counters; 242 counters.assign(0); 243 244 typedef repository::qi::detail::parse_dispatcher<Elements,Iterator, Context, Skipper 245 , flags_type, counters_type 246 , typename traits::wrap_if_not_tuple<Attribute>::type 247 , mpl::false_ > parser_visitor_type; 248 249 parser_visitor_type parse_visitor(elements, first, last 250 , context, skipper, flags 251 , counters, attr); 252 253 typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type; 254 255 complex_kwd_function_type 256 complex_function(first,last,context,skipper,parse_visitor); 257 258 // We have a bool array 'flags' with one flag for each parser as well as a 'counter' 259 // array. 260 // The kwd directive sets and increments the counter when a successeful parse occurred 261 // as well as the slot of the corresponding parser to true in the flags array as soon 262 // the minimum repetition requirement is met and keeps that value to true as long as 263 // the maximum repetition requirement is met. 264 // The parsing takes place here in two steps: 265 // 1) parse a keyword and fetch the parser index associated with that keyword 266 // 2) call the associated parser and store the parsed value in the matching attribute. 267 268 for(;;) 269 { 270 271 spirit::qi::skip_over(first, last, skipper); 272 Iterator save = first; 273 if (string_keywords_inst.parse(first, last,parse_visitor,skipper)) 274 { 275 save = first; 276 } 277 else { 278 // restore the position to the last successful keyword parse 279 first = save; 280 if(!complex_keywords_inst.parse(complex_function)) 281 { 282 first = save; 283 // Check that we are leaving the keywords parser in a successful state 284 BOOST_FOREACH(bool &valid,flags) 285 { 286 if(!valid) 287 { 288 return false; 289 } 290 } 291 return true; 292 } 293 else 294 save = first; 295 } 296 } 297 BOOST_UNREACHABLE_RETURN(false) 298 } 299 300 // Handle the mixed kwd and ikwd case 301 template <typename Iterator, typename Context 302 , typename Skipper, typename Attribute> parse_implboost::spirit::repository::qi::keywords303 bool parse_impl(Iterator& first, Iterator const& last 304 , Context& context, Skipper const& skipper 305 , Attribute& attr_,mpl::false_ /* two passes */) const 306 { 307 308 // wrap the attribute in a tuple if it is not a tuple 309 typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_); 310 311 flags_type flags(flags_init); 312 //flags.assign(false); 313 314 counters_type counters; 315 counters.assign(0); 316 317 typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper 318 , flags_type, counters_type 319 , typename traits::wrap_if_not_tuple<Attribute>::type 320 , mpl::false_> parser_visitor_type; 321 322 typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper 323 , flags_type, counters_type 324 , typename traits::wrap_if_not_tuple<Attribute>::type 325 , mpl::true_> no_case_parser_visitor_type; 326 327 328 parser_visitor_type parse_visitor(elements,first,last 329 ,context,skipper,flags,counters,attr); 330 no_case_parser_visitor_type no_case_parse_visitor(elements,first,last 331 ,context,skipper,flags,counters,attr); 332 333 typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type; 334 335 complex_kwd_function_type 336 complex_function(first,last,context,skipper,parse_visitor); 337 338 339 // We have a bool array 'flags' with one flag for each parser as well as a 'counter' 340 // array. 341 // The kwd directive sets and increments the counter when a successeful parse occurred 342 // as well as the slot of the corresponding parser to true in the flags array as soon 343 // the minimum repetition requirement is met and keeps that value to true as long as 344 // the maximum repetition requirement is met. 345 // The parsing takes place here in two steps: 346 // 1) parse a keyword and fetch the parser index associated with that keyword 347 // 2) call the associated parser and store the parsed value in the matching attribute. 348 349 for(;;) 350 { 351 spirit::qi::skip_over(first, last, skipper); 352 Iterator save = first; 353 // String keywords pass 354 if (string_keywords_inst.parse(first,last,parse_visitor,no_case_parse_visitor,skipper)) 355 { 356 save = first; 357 } 358 else { 359 first = save; 360 361 if(!complex_keywords_inst.parse(complex_function)) 362 { 363 first = save; 364 // Check that we are leaving the keywords parser in a successful state 365 BOOST_FOREACH(bool &valid,flags) 366 { 367 if(!valid) 368 { 369 return false; 370 } 371 } 372 return true; 373 } 374 else 375 { 376 save = first; 377 } 378 } 379 } 380 BOOST_UNREACHABLE_RETURN(false) 381 } 382 383 template <typename Context> whatboost::spirit::repository::qi::keywords384 info what(Context& context) const 385 { 386 info result("keywords"); 387 fusion::for_each(elements, 388 spirit::detail::what_function<Context>(result, context)); 389 return result; 390 } 391 flags_type flags_init; 392 Elements elements; 393 string_keywords_type string_keywords_inst; 394 complex_keywords_type complex_keywords_inst; 395 396 }; 397 }}}} 398 399 namespace boost { namespace spirit { namespace qi { 400 /////////////////////////////////////////////////////////////////////////// 401 // Parser generators: make_xxx function (objects) 402 /////////////////////////////////////////////////////////////////////////// 403 template <typename Elements, typename Modifiers > 404 struct make_composite<proto::tag::divides, Elements, Modifiers > 405 { 406 typedef repository::qi::keywords<Elements,Modifiers> result_type; operator ()boost::spirit::qi::make_composite407 result_type operator()(Elements ref, unused_type) const 408 { 409 return result_type(ref); 410 } 411 }; 412 413 414 }}} 415 416 namespace boost { namespace spirit { namespace traits 417 { 418 // We specialize this for keywords (see support/attributes.hpp). 419 // For keywords, we only wrap the attribute in a tuple IFF 420 // it is not already a fusion tuple. 421 template <typename Elements, typename Modifiers,typename Attribute> 422 struct pass_attribute<repository::qi::keywords<Elements,Modifiers>, Attribute> 423 : wrap_if_not_tuple<Attribute> {}; 424 425 template <typename Elements, typename Modifiers> 426 struct has_semantic_action<repository::qi::keywords<Elements, Modifiers> > 427 : nary_has_semantic_action<Elements> {}; 428 429 template <typename Elements, typename Attribute, typename Context 430 , typename Iterator, typename Modifiers> 431 struct handles_container<repository::qi::keywords<Elements,Modifiers>, Attribute 432 , Context, Iterator> 433 : nary_handles_container<Elements, Attribute, Context, Iterator> {}; 434 435 436 }}} 437 438 #endif 439 440