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