Chris@16: /*============================================================================= Chris@16: Copyright (c) 2001-2011 Joel de Guzman Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: ==============================================================================*/ Chris@16: #if !defined(BOOST_SPIRIT_RULE_FEBRUARY_12_2007_1020AM) Chris@16: #define BOOST_SPIRIT_RULE_FEBRUARY_12_2007_1020AM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #if defined(BOOST_MSVC) Chris@16: # pragma warning(push) Chris@16: # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning Chris@101: # pragma warning(disable: 4127) // conditional expression is constant Chris@16: #endif Chris@16: Chris@16: namespace boost { namespace spirit { namespace qi Chris@16: { Chris@16: BOOST_PP_REPEAT(SPIRIT_ATTRIBUTES_LIMIT, SPIRIT_USING_ATTRIBUTE, _) Chris@16: Chris@16: using spirit::_pass_type; Chris@16: using spirit::_val_type; Chris@16: using spirit::_a_type; Chris@16: using spirit::_b_type; Chris@16: using spirit::_c_type; Chris@16: using spirit::_d_type; Chris@16: using spirit::_e_type; Chris@16: using spirit::_f_type; Chris@16: using spirit::_g_type; Chris@16: using spirit::_h_type; Chris@16: using spirit::_i_type; Chris@16: using spirit::_j_type; Chris@16: Chris@16: #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS Chris@16: Chris@16: using spirit::_pass; Chris@16: using spirit::_val; Chris@16: using spirit::_a; Chris@16: using spirit::_b; Chris@16: using spirit::_c; Chris@16: using spirit::_d; Chris@16: using spirit::_e; Chris@16: using spirit::_f; Chris@16: using spirit::_g; Chris@16: using spirit::_h; Chris@16: using spirit::_i; Chris@16: using spirit::_j; Chris@16: Chris@16: #endif Chris@16: Chris@16: using spirit::info; Chris@16: using spirit::locals; Chris@16: Chris@16: template < Chris@16: typename Iterator, typename T1, typename T2, typename T3 Chris@16: , typename T4> Chris@16: struct rule Chris@16: : proto::extends< Chris@16: typename proto::terminal< Chris@16: reference const> Chris@16: >::type Chris@16: , rule Chris@16: > Chris@16: , parser > Chris@16: { Chris@16: typedef Iterator iterator_type; Chris@16: typedef rule this_type; Chris@16: typedef reference reference_; Chris@16: typedef typename proto::terminal::type terminal; Chris@16: typedef proto::extends base_type; Chris@16: typedef mpl::vector template_params; Chris@16: Chris@16: // The rule's locals_type: a sequence of types to be used as local variables Chris@16: typedef typename Chris@16: spirit::detail::extract_locals::type Chris@16: locals_type; Chris@16: Chris@16: // The rule's skip-parser type Chris@16: typedef typename Chris@16: spirit::detail::extract_component< Chris@16: qi::domain, template_params>::type Chris@16: skipper_type; Chris@16: Chris@16: // The rule's signature Chris@16: typedef typename Chris@16: spirit::detail::extract_sig::type Chris@16: sig_type; Chris@16: Chris@16: // The rule's encoding type Chris@16: typedef typename Chris@16: spirit::detail::extract_encoding::type Chris@16: encoding_type; Chris@16: Chris@16: // This is the rule's attribute type Chris@16: typedef typename Chris@16: spirit::detail::attr_from_sig::type Chris@16: attr_type; Chris@16: typedef typename add_reference::type attr_reference_type; Chris@16: Chris@16: // parameter_types is a sequence of types passed as parameters to the rule Chris@16: typedef typename Chris@16: spirit::detail::params_from_sig::type Chris@16: parameter_types; Chris@16: Chris@16: static size_t const params_size = Chris@16: fusion::result_of::size::type::value; Chris@16: Chris@16: typedef context< Chris@16: fusion::cons Chris@16: , locals_type> Chris@16: context_type; Chris@16: Chris@16: typedef function< Chris@16: bool(Iterator& first, Iterator const& last Chris@16: , context_type& context Chris@16: , skipper_type const& skipper Chris@16: )> Chris@16: function_type; Chris@16: Chris@16: typedef typename Chris@16: mpl::if_< Chris@16: is_same Chris@16: , unused_type Chris@16: , tag::char_code Chris@16: >::type Chris@16: encoding_modifier_type; Chris@16: Chris@16: explicit rule(std::string const& name = "unnamed-rule") Chris@16: : base_type(terminal::make(reference_(*this))) Chris@16: , name_(name) Chris@16: { Chris@16: } Chris@16: Chris@16: rule(rule const& rhs) Chris@16: : base_type(terminal::make(reference_(*this))) Chris@16: , name_(rhs.name_) Chris@16: , f(rhs.f) Chris@16: { Chris@16: } Chris@16: Chris@16: template Chris@16: static void define(rule& /*lhs*/, Expr const& /*expr*/, mpl::false_) Chris@16: { Chris@16: // Report invalid expression error as early as possible. Chris@16: // If you got an error_invalid_expression error message here, Chris@16: // then the expression (expr) is not a valid spirit qi expression. Chris@16: BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr); Chris@16: } Chris@16: Chris@16: template Chris@16: static void define(rule& lhs, Expr const& expr, mpl::true_) Chris@16: { Chris@16: lhs.f = detail::bind_parser( Chris@16: compile(expr, encoding_modifier_type())); Chris@16: } Chris@16: Chris@16: template Chris@16: rule(Expr const& expr, std::string const& name = "unnamed-rule") Chris@16: : base_type(terminal::make(reference_(*this))) Chris@16: , name_(name) Chris@16: { Chris@16: define(*this, expr, traits::matches()); Chris@16: } Chris@16: Chris@16: rule& operator=(rule const& rhs) Chris@16: { Chris@16: // The following assertion fires when you try to initialize a rule Chris@16: // from an uninitialized one. Did you mean to refer to the right Chris@16: // hand side rule instead of assigning from it? In this case you Chris@16: // should write lhs = rhs.alias(); Chris@16: BOOST_ASSERT(rhs.f && "Did you mean rhs.alias() instead of rhs?"); Chris@16: Chris@16: f = rhs.f; Chris@16: name_ = rhs.name_; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: std::string const& name() const Chris@16: { Chris@16: return name_; Chris@16: } Chris@16: Chris@16: void name(std::string const& str) Chris@16: { Chris@16: name_ = str; Chris@16: } Chris@16: Chris@16: template Chris@16: rule& operator=(Expr const& expr) Chris@16: { Chris@16: define(*this, expr, traits::matches()); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: // VC7.1 has problems to resolve 'rule' without explicit template parameters Chris@16: #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400) Chris@16: // g++ 3.3 barfs if this is a member function :( Chris@16: template Chris@16: friend rule& operator%=(rule& r, Expr const& expr) Chris@16: { Chris@16: define(r, expr, traits::matches()); Chris@16: return r; Chris@16: } Chris@16: Chris@16: #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) Chris@16: // non-const version needed to suppress proto's %= kicking in Chris@16: template Chris@16: friend rule& operator%=(rule& r, Expr& expr) Chris@16: { Chris@16: return r %= static_cast(expr); Chris@16: } Chris@16: #else Chris@16: // for rvalue references Chris@16: template Chris@16: friend rule& operator%=(rule& r, Expr&& expr) Chris@16: { Chris@16: define(r, expr, traits::matches()); Chris@16: return r; Chris@16: } Chris@16: #endif Chris@16: Chris@16: #else Chris@16: // both friend functions have to be defined out of class as VC7.1 Chris@16: // will complain otherwise Chris@16: template Chris@16: friend rule& operator%=( Chris@16: rule& r, Expr const& expr); Chris@16: Chris@16: // non-const version needed to suppress proto's %= kicking in Chris@16: template Chris@16: friend rule& operator%=( Chris@16: rule& r, Expr& expr); Chris@16: #endif Chris@16: Chris@16: template Chris@16: struct attribute Chris@16: { Chris@16: typedef attr_type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: bool parse(Iterator& first, Iterator const& last Chris@16: , Context& /*context*/, Skipper const& skipper Chris@16: , Attribute& attr_param) const Chris@16: { Chris@16: if (f) Chris@16: { Chris@16: // do a preskip if this is an implied lexeme Chris@16: if (is_same::value) Chris@16: qi::skip_over(first, last, skipper); Chris@16: Chris@16: typedef traits::make_attribute make_attribute; Chris@16: Chris@16: // do down-stream transformation, provides attribute for Chris@16: // rhs parser Chris@16: typedef traits::transform_attribute< Chris@16: typename make_attribute::type, attr_type, domain> Chris@16: transform; Chris@16: Chris@16: typename make_attribute::type made_attr = make_attribute::call(attr_param); Chris@16: typename transform::type attr_ = transform::pre(made_attr); Chris@16: Chris@16: // If you are seeing a compilation error here, you are probably Chris@16: // trying to use a rule or a grammar which has inherited Chris@16: // attributes, without passing values for them. Chris@16: context_type context(attr_); Chris@16: Chris@16: // If you are seeing a compilation error here stating that the Chris@16: // fourth parameter can't be converted to a required target type Chris@16: // then you are probably trying to use a rule or a grammar with Chris@16: // an incompatible skipper type. Chris@16: if (f(first, last, context, skipper)) Chris@16: { Chris@16: // do up-stream transformation, this integrates the results Chris@16: // back into the original attribute value, if appropriate Chris@16: traits::post_transform(attr_param, attr_); Chris@16: return true; Chris@16: } Chris@16: Chris@16: // inform attribute transformation of failed rhs Chris@16: traits::fail_transform(attr_param, attr_); Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: bool parse(Iterator& first, Iterator const& last Chris@16: , Context& caller_context, Skipper const& skipper Chris@16: , Attribute& attr_param, Params const& params) const Chris@16: { Chris@16: if (f) Chris@16: { Chris@16: // do a preskip if this is an implied lexeme Chris@16: if (is_same::value) Chris@16: qi::skip_over(first, last, skipper); Chris@16: Chris@16: typedef traits::make_attribute make_attribute; Chris@16: Chris@16: // do down-stream transformation, provides attribute for Chris@16: // rhs parser Chris@16: typedef traits::transform_attribute< Chris@16: typename make_attribute::type, attr_type, domain> Chris@16: transform; Chris@16: Chris@16: typename make_attribute::type made_attr = make_attribute::call(attr_param); Chris@16: typename transform::type attr_ = transform::pre(made_attr); Chris@16: Chris@16: // If you are seeing a compilation error here, you are probably Chris@16: // trying to use a rule or a grammar which has inherited Chris@16: // attributes, passing values of incompatible types for them. Chris@16: context_type context(attr_, params, caller_context); Chris@16: Chris@16: // If you are seeing a compilation error here stating that the Chris@16: // fourth parameter can't be converted to a required target type Chris@16: // then you are probably trying to use a rule or a grammar with Chris@16: // an incompatible skipper type. Chris@16: if (f(first, last, context, skipper)) Chris@16: { Chris@16: // do up-stream transformation, this integrates the results Chris@16: // back into the original attribute value, if appropriate Chris@16: traits::post_transform(attr_param, attr_); Chris@16: return true; Chris@16: } Chris@16: Chris@16: // inform attribute transformation of failed rhs Chris@16: traits::fail_transform(attr_param, attr_); Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: info what(Context& /*context*/) const Chris@16: { Chris@16: return info(name_); Chris@16: } Chris@16: Chris@16: reference_ alias() const Chris@16: { Chris@16: return reference_(*this); Chris@16: } Chris@16: Chris@16: typename proto::terminal::type copy() const Chris@16: { Chris@16: typename proto::terminal::type result = {*this}; Chris@16: return result; Chris@16: } Chris@16: Chris@16: // bring in the operator() overloads Chris@16: rule const& get_parameterized_subject() const { return *this; } Chris@16: typedef rule parameterized_subject_type; Chris@16: #include Chris@16: Chris@16: std::string name_; Chris@16: function_type f; Chris@16: }; Chris@16: Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, < 1400) Chris@16: template Chris@16: rule& operator%=( Chris@16: rule& r, Expr const& expr) Chris@16: { Chris@16: // Report invalid expression error as early as possible. Chris@16: // If you got an error_invalid_expression error message here, Chris@16: // then the expression (expr) is not a valid spirit qi expression. Chris@16: BOOST_SPIRIT_ASSERT_MATCH(qi::domain, Expr); Chris@16: Chris@16: typedef typename Chris@16: rule::encoding_modifier_type Chris@16: encoding_modifier_type; Chris@16: Chris@16: r.f = detail::bind_parser( Chris@16: compile(expr, encoding_modifier_type())); Chris@16: return r; Chris@16: } Chris@16: Chris@16: template Chris@16: rule& operator%=( Chris@16: rule& r, Expr& expr) Chris@16: { Chris@16: return r %= static_cast(expr); Chris@16: } Chris@16: #endif Chris@16: }}} Chris@16: Chris@16: namespace boost { namespace spirit { namespace traits Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template < Chris@16: typename IteratorA, typename IteratorB, typename Attribute Chris@16: , typename Context, typename T1, typename T2, typename T3, typename T4> Chris@16: struct handles_container< Chris@16: qi::rule, Attribute, Context, IteratorB> Chris@16: : traits::is_container< Chris@16: typename attribute_of< Chris@16: qi::rule, Context, IteratorB Chris@16: >::type Chris@16: > Chris@16: {}; Chris@16: }}} Chris@16: Chris@16: #if defined(BOOST_MSVC) Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #endif