1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 4 Distributed under the Boost Software License, Version 1.0. (See accompanying 5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 ==============================================================================*/ 7 #if !defined(BOOST_SPIRIT_RULE_FEBRUARY_12_2007_1020AM) 8 #define BOOST_SPIRIT_RULE_FEBRUARY_12_2007_1020AM 9 10 #if defined(_MSC_VER) 11 #pragma once 12 #endif 13 14 #include <boost/assert.hpp> 15 #include <boost/static_assert.hpp> 16 #include <boost/config.hpp> 17 #include <boost/function.hpp> 18 #include <boost/mpl/vector.hpp> 19 #include <boost/type_traits/is_convertible.hpp> 20 #include <boost/type_traits/is_same.hpp> 21 22 #include <boost/fusion/include/vector.hpp> 23 #include <boost/fusion/include/size.hpp> 24 #include <boost/fusion/include/make_vector.hpp> 25 #include <boost/fusion/include/cons.hpp> 26 #include <boost/fusion/include/as_list.hpp> 27 #include <boost/fusion/include/as_vector.hpp> 28 29 #include <boost/spirit/home/support/unused.hpp> 30 #include <boost/spirit/home/support/argument.hpp> 31 #include <boost/spirit/home/support/context.hpp> 32 #include <boost/spirit/home/support/info.hpp> 33 #include <boost/spirit/home/qi/detail/attributes.hpp> 34 #include <boost/spirit/home/support/nonterminal/extract_param.hpp> 35 #include <boost/spirit/home/support/nonterminal/locals.hpp> 36 #include <boost/spirit/home/qi/reference.hpp> 37 #include <boost/spirit/home/qi/nonterminal/detail/parameterized.hpp> 38 #include <boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp> 39 #include <boost/spirit/home/qi/nonterminal/nonterminal_fwd.hpp> 40 #include <boost/spirit/home/qi/skip_over.hpp> 41 42 #include <boost/proto/extends.hpp> 43 #include <boost/proto/traits.hpp> 44 #include <boost/type_traits/is_reference.hpp> 45 46 #if defined(BOOST_MSVC) 47 # pragma warning(push) 48 # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning 49 # pragma warning(disable: 4127) // conditional expression is constant 50 #endif 51 52 namespace boost { namespace spirit { namespace qi 53 { 54 BOOST_PP_REPEAT(SPIRIT_ATTRIBUTES_LIMIT, SPIRIT_USING_ATTRIBUTE, _) 55 56 using spirit::_pass_type; 57 using spirit::_val_type; 58 using spirit::_a_type; 59 using spirit::_b_type; 60 using spirit::_c_type; 61 using spirit::_d_type; 62 using spirit::_e_type; 63 using spirit::_f_type; 64 using spirit::_g_type; 65 using spirit::_h_type; 66 using spirit::_i_type; 67 using spirit::_j_type; 68 69 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 70 71 using spirit::_pass; 72 using spirit::_val; 73 using spirit::_a; 74 using spirit::_b; 75 using spirit::_c; 76 using spirit::_d; 77 using spirit::_e; 78 using spirit::_f; 79 using spirit::_g; 80 using spirit::_h; 81 using spirit::_i; 82 using spirit::_j; 83 84 #endif 85 86 using spirit::info; 87 using spirit::locals; 88 89 template < 90 typename Iterator, typename T1, typename T2, typename T3 91 , typename T4> 92 struct rule 93 : proto::extends< 94 typename proto::terminal< 95 reference<rule<Iterator, T1, T2, T3, T4> const> 96 >::type 97 , rule<Iterator, T1, T2, T3, T4> 98 > 99 , parser<rule<Iterator, T1, T2, T3, T4> > 100 { 101 typedef Iterator iterator_type; 102 typedef rule<Iterator, T1, T2, T3, T4> this_type; 103 typedef reference<this_type const> reference_; 104 typedef typename proto::terminal<reference_>::type terminal; 105 typedef proto::extends<terminal, this_type> base_type; 106 typedef mpl::vector<T1, T2, T3, T4> template_params; 107 108 // The rule's locals_type: a sequence of types to be used as local variables 109 typedef typename 110 spirit::detail::extract_locals<template_params>::type 111 locals_type; 112 113 // The rule's skip-parser type 114 typedef typename 115 spirit::detail::extract_component< 116 qi::domain, template_params>::type 117 skipper_type; 118 119 // The rule's encoding type 120 typedef typename 121 spirit::detail::extract_encoding<template_params>::type 122 encoding_type; 123 124 // The rule's signature 125 typedef typename 126 spirit::detail::extract_sig<template_params, encoding_type, qi::domain>::type 127 sig_type; 128 129 // This is the rule's attribute type 130 typedef typename 131 spirit::detail::attr_from_sig<sig_type>::type 132 attr_type; 133 BOOST_STATIC_ASSERT_MSG( 134 !is_reference<attr_type>::value, 135 "Reference qualifier on Qi rule attribute is meaningless"); 136 typedef attr_type& attr_reference_type; 137 138 // parameter_types is a sequence of types passed as parameters to the rule 139 typedef typename 140 spirit::detail::params_from_sig<sig_type>::type 141 parameter_types; 142 143 static size_t const params_size = 144 fusion::result_of::size<parameter_types>::type::value; 145 146 typedef context< 147 fusion::cons<attr_reference_type, parameter_types> 148 , locals_type> 149 context_type; 150 151 typedef function< 152 bool(Iterator& first, Iterator const& last 153 , context_type& context 154 , skipper_type const& skipper 155 )> 156 function_type; 157 158 typedef typename 159 mpl::if_< 160 is_same<encoding_type, unused_type> 161 , unused_type 162 , tag::char_code<tag::encoding, encoding_type> 163 >::type 164 encoding_modifier_type; 165 ruleboost::spirit::qi::rule166 explicit rule(std::string const& name = "unnamed-rule") 167 : base_type(terminal::make(reference_(*this))) 168 , name_(name) 169 { 170 } 171 ruleboost::spirit::qi::rule172 rule(rule const& rhs) 173 : base_type(terminal::make(reference_(*this))) 174 , name_(rhs.name_) 175 , f(rhs.f) 176 { 177 } 178 179 template <typename Auto, typename Expr> defineboost::spirit::qi::rule180 static void define(rule& /*lhs*/, Expr const& /*expr*/, mpl::false_) 181 { 182 // Report invalid expression error as early as possible. 183 // If you got an error_invalid_expression error message here, 184 // then the expression (expr) is not a valid spirit qi expression. 185 BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr); 186 } 187 188 template <typename Auto, typename Expr> defineboost::spirit::qi::rule189 static void define(rule& lhs, Expr const& expr, mpl::true_) 190 { 191 lhs.f = detail::bind_parser<Auto>( 192 compile<qi::domain>(expr, encoding_modifier_type())); 193 } 194 195 template <typename Expr> ruleboost::spirit::qi::rule196 rule(Expr const& expr, std::string const& name = "unnamed-rule") 197 : base_type(terminal::make(reference_(*this))) 198 , name_(name) 199 { 200 define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>()); 201 } 202 operator =boost::spirit::qi::rule203 rule& operator=(rule const& rhs) 204 { 205 // The following assertion fires when you try to initialize a rule 206 // from an uninitialized one. Did you mean to refer to the right 207 // hand side rule instead of assigning from it? In this case you 208 // should write lhs = rhs.alias(); 209 BOOST_ASSERT(rhs.f && "Did you mean rhs.alias() instead of rhs?"); 210 211 f = rhs.f; 212 name_ = rhs.name_; 213 return *this; 214 } 215 nameboost::spirit::qi::rule216 std::string const& name() const 217 { 218 return name_; 219 } 220 nameboost::spirit::qi::rule221 void name(std::string const& str) 222 { 223 name_ = str; 224 } 225 226 template <typename Expr> operator =boost::spirit::qi::rule227 rule& operator=(Expr const& expr) 228 { 229 define<mpl::false_>(*this, expr, traits::matches<qi::domain, Expr>()); 230 return *this; 231 } 232 233 // VC7.1 has problems to resolve 'rule' without explicit template parameters 234 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400) 235 // g++ 3.3 barfs if this is a member function :( 236 template <typename Expr> operator %=(rule & r,Expr const & expr)237 friend rule& operator%=(rule& r, Expr const& expr) 238 { 239 define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>()); 240 return r; 241 } 242 243 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) 244 // non-const version needed to suppress proto's %= kicking in 245 template <typename Expr> operator %=(rule & r,Expr & expr)246 friend rule& operator%=(rule& r, Expr& expr) 247 { 248 return r %= static_cast<Expr const&>(expr); 249 } 250 #else 251 // for rvalue references 252 template <typename Expr> operator %=(rule & r,Expr && expr)253 friend rule& operator%=(rule& r, Expr&& expr) 254 { 255 define<mpl::true_>(r, expr, traits::matches<qi::domain, Expr>()); 256 return r; 257 } 258 #endif 259 260 #else 261 // both friend functions have to be defined out of class as VC7.1 262 // will complain otherwise 263 template <typename OutputIterator_, typename T1_, typename T2_ 264 , typename T3_, typename T4_, typename Expr> 265 friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( 266 rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr const& expr); 267 268 // non-const version needed to suppress proto's %= kicking in 269 template <typename OutputIterator_, typename T1_, typename T2_ 270 , typename T3_, typename T4_, typename Expr> 271 friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( 272 rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr); 273 #endif 274 275 template <typename Context, typename Iterator_> 276 struct attribute 277 { 278 typedef attr_type type; 279 }; 280 281 template <typename Context, typename Skipper, typename Attribute> parseboost::spirit::qi::rule282 bool parse(Iterator& first, Iterator const& last 283 , Context& /*context*/, Skipper const& skipper 284 , Attribute& attr_param) const 285 { 286 BOOST_STATIC_ASSERT_MSG((is_same<skipper_type, unused_type>::value || 287 !is_same<Skipper, unused_type>::value), 288 "The rule was instantiated with a skipper type but you have not pass any. " 289 "Did you use `parse` instead of `phrase_parse`?"); 290 BOOST_STATIC_ASSERT_MSG( 291 (is_convertible<Skipper const&, skipper_type>::value), 292 "The passed skipper is not compatible/convertible to one " 293 "that the rule was instantiated with"); 294 if (f) 295 { 296 // do a preskip if this is an implied lexeme 297 if (is_same<skipper_type, unused_type>::value) 298 qi::skip_over(first, last, skipper); 299 300 // do down-stream transformation, provides attribute for 301 // rhs parser 302 typedef traits::transform_attribute< 303 Attribute, attr_type, domain> 304 transform; 305 306 typename transform::type attr_ = transform::pre(attr_param); 307 308 // If you are seeing a compilation error here, you are probably 309 // trying to use a rule or a grammar which has inherited 310 // attributes, without passing values for them. 311 context_type context(attr_); 312 313 // If you are seeing a compilation error here stating that the 314 // fourth parameter can't be converted to a required target type 315 // then you are probably trying to use a rule or a grammar with 316 // an incompatible skipper type. 317 if (f(first, last, context, skipper)) 318 { 319 // do up-stream transformation, this integrates the results 320 // back into the original attribute value, if appropriate 321 transform::post(attr_param, attr_); 322 return true; 323 } 324 325 // inform attribute transformation of failed rhs 326 transform::fail(attr_param); 327 } 328 return false; 329 } 330 331 template <typename Context, typename Skipper 332 , typename Attribute, typename Params> parseboost::spirit::qi::rule333 bool parse(Iterator& first, Iterator const& last 334 , Context& caller_context, Skipper const& skipper 335 , Attribute& attr_param, Params const& params) const 336 { 337 BOOST_STATIC_ASSERT_MSG((is_same<skipper_type, unused_type>::value || 338 !is_same<Skipper, unused_type>::value), 339 "The rule was instantiated with a skipper type but you have not pass any. " 340 "Did you use `parse` instead of `phrase_parse`?"); 341 BOOST_STATIC_ASSERT_MSG( 342 (is_convertible<Skipper const&, skipper_type>::value), 343 "The passed skipper is not compatible/convertible to one " 344 "that the rule was instantiated with"); 345 if (f) 346 { 347 // do a preskip if this is an implied lexeme 348 if (is_same<skipper_type, unused_type>::value) 349 qi::skip_over(first, last, skipper); 350 351 // do down-stream transformation, provides attribute for 352 // rhs parser 353 typedef traits::transform_attribute< 354 Attribute, attr_type, domain> 355 transform; 356 357 typename transform::type attr_ = transform::pre(attr_param); 358 359 // If you are seeing a compilation error here, you are probably 360 // trying to use a rule or a grammar which has inherited 361 // attributes, passing values of incompatible types for them. 362 context_type context(attr_, params, caller_context); 363 364 // If you are seeing a compilation error here stating that the 365 // fourth parameter can't be converted to a required target type 366 // then you are probably trying to use a rule or a grammar with 367 // an incompatible skipper type. 368 if (f(first, last, context, skipper)) 369 { 370 // do up-stream transformation, this integrates the results 371 // back into the original attribute value, if appropriate 372 transform::post(attr_param, attr_); 373 return true; 374 } 375 376 // inform attribute transformation of failed rhs 377 transform::fail(attr_param); 378 } 379 return false; 380 } 381 382 template <typename Context> whatboost::spirit::qi::rule383 info what(Context& /*context*/) const 384 { 385 return info(name_); 386 } 387 aliasboost::spirit::qi::rule388 reference_ alias() const 389 { 390 return reference_(*this); 391 } 392 copyboost::spirit::qi::rule393 typename proto::terminal<this_type>::type copy() const 394 { 395 typename proto::terminal<this_type>::type result = {*this}; 396 return result; 397 } 398 399 // bring in the operator() overloads get_parameterized_subjectboost::spirit::qi::rule400 rule const& get_parameterized_subject() const { return *this; } 401 typedef rule parameterized_subject_type; 402 #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp> 403 404 std::string name_; 405 function_type f; 406 }; 407 408 #if BOOST_WORKAROUND(BOOST_MSVC, < 1400) 409 template <typename OutputIterator_, typename T1_, typename T2_ 410 , typename T3_, typename T4_, typename Expr> operator %=(rule<OutputIterator_,T1_,T2_,T3_,T4_> & r,Expr const & expr)411 rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( 412 rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr const& expr) 413 { 414 // Report invalid expression error as early as possible. 415 // If you got an error_invalid_expression error message here, 416 // then the expression (expr) is not a valid spirit qi expression. 417 BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr); 418 419 typedef typename 420 rule<OutputIterator_, T1_, T2_, T3_, T4_>::encoding_modifier_type 421 encoding_modifier_type; 422 423 r.f = detail::bind_parser<mpl::true_>( 424 compile<qi::domain>(expr, encoding_modifier_type())); 425 return r; 426 } 427 428 template <typename Iterator_, typename T1_, typename T2_ 429 , typename T3_, typename T4_, typename Expr> operator %=(rule<Iterator_,T1_,T2_,T3_,T4_> & r,Expr & expr)430 rule<Iterator_, T1_, T2_, T3_, T4_>& operator%=( 431 rule<Iterator_, T1_, T2_, T3_, T4_>& r, Expr& expr) 432 { 433 return r %= static_cast<Expr const&>(expr); 434 } 435 #endif 436 }}} 437 438 namespace boost { namespace spirit { namespace traits 439 { 440 /////////////////////////////////////////////////////////////////////////// 441 template < 442 typename IteratorA, typename IteratorB, typename Attribute 443 , typename Context, typename T1, typename T2, typename T3, typename T4> 444 struct handles_container< 445 qi::rule<IteratorA, T1, T2, T3, T4>, Attribute, Context, IteratorB> 446 : traits::is_container< 447 typename attribute_of< 448 qi::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB 449 >::type 450 > 451 {}; 452 }}} 453 454 #if defined(BOOST_MSVC) 455 # pragma warning(pop) 456 #endif 457 458 #endif 459