| 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 | |
| 166 | explicit rule(std::string const& name = "unnamed-rule" ) |
| 167 | : base_type(terminal::make(reference_(*this))) |
| 168 | , name_(name) |
| 169 | { |
| 170 | } |
| 171 | |
| 172 | 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> |
| 180 | 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> |
| 189 | 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> |
| 196 | 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 | |
| 203 | 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 | |
| 216 | std::string const& name() const |
| 217 | { |
| 218 | return name_; |
| 219 | } |
| 220 | |
| 221 | void name(std::string const& str) |
| 222 | { |
| 223 | name_ = str; |
| 224 | } |
| 225 | |
| 226 | template <typename Expr> |
| 227 | 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> |
| 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> |
| 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> |
| 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> |
| 282 | 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> |
| 333 | 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> |
| 383 | info what(Context& /*context*/) const |
| 384 | { |
| 385 | return info(name_); |
| 386 | } |
| 387 | |
| 388 | reference_ alias() const |
| 389 | { |
| 390 | return reference_(*this); |
| 391 | } |
| 392 | |
| 393 | 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 |
| 400 | 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> |
| 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> |
| 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 | |