boost/spirit/home/karma/nonterminal/rule.hpp
// Copyright (c) 2001-2010 Joel de Guzman // Copyright (c) 2001-2010 Hartmut Kaiser // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #if !defined(BOOST_SPIRIT_KARMA_RULE_MAR_05_2007_0455PM) #define BOOST_SPIRIT_KARMA_RULE_MAR_05_2007_0455PM #if defined(_MSC_VER) #pragma once #endif #include <boost/assert.hpp> #include <boost/function.hpp> #include <boost/mpl/vector.hpp> #include <boost/type_traits/add_const.hpp> #include <boost/type_traits/add_reference.hpp> #include <boost/utility/enable_if.hpp> #include <boost/fusion/include/vector.hpp> #include <boost/fusion/include/size.hpp> #include <boost/fusion/include/make_vector.hpp> #include <boost/fusion/include/cons.hpp> #include <boost/fusion/include/as_list.hpp> #include <boost/fusion/include/as_vector.hpp> #include <boost/spirit/home/support/unused.hpp> #include <boost/spirit/home/support/argument.hpp> #include <boost/spirit/home/support/context.hpp> #include <boost/spirit/home/support/info.hpp> #include <boost/spirit/home/support/attributes.hpp> #include <boost/spirit/home/support/nonterminal/extract_param.hpp> #include <boost/spirit/home/support/nonterminal/locals.hpp> #include <boost/spirit/home/karma/reference.hpp> #include <boost/spirit/home/karma/detail/output_iterator.hpp> #include <boost/spirit/home/karma/nonterminal/detail/generator_binder.hpp> #include <boost/spirit/home/karma/nonterminal/detail/parameterized.hpp> #if defined(BOOST_MSVC) # pragma warning(push) # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning #endif namespace boost { namespace spirit { namespace karma { BOOST_PP_REPEAT(SPIRIT_ATTRIBUTES_LIMIT, SPIRIT_USING_ATTRIBUTE, _) using spirit::_pass; using spirit::_val; using spirit::_a; using spirit::_b; using spirit::_c; using spirit::_d; using spirit::_e; using spirit::_f; using spirit::_g; using spirit::_h; using spirit::_i; using spirit::_j; using spirit::info; using spirit::locals; template < typename OutputIterator , typename T1 = unused_type , typename T2 = unused_type , typename T3 = unused_type > struct rule : proto::extends< typename proto::terminal< reference<rule<OutputIterator, T1, T2, T3> const> >::type , rule<OutputIterator, T1, T2, T3> > , generator<rule<OutputIterator, T1, T2, T3> > { typedef mpl::int_<generator_properties::all_properties> properties; typedef OutputIterator iterator_type; typedef rule<OutputIterator, T1, T2, T3> this_type; typedef reference<this_type const> reference_; typedef typename proto::terminal<reference_>::type terminal; typedef proto::extends<terminal, this_type> base_type; typedef mpl::vector<T1, T2, T3> template_params; // the output iterator is always wrapped by karma typedef detail::output_iterator<OutputIterator, properties> output_iterator; // locals_type is a sequence of types to be used as local variables typedef typename spirit::detail::extract_locals<template_params>::type locals_type; // The delimiter-generator type typedef typename spirit::detail::extract_component< karma::domain, template_params>::type delimiter_type; typedef typename spirit::detail::extract_sig<template_params>::type sig_type; // This is the rule's attribute type typedef typename spirit::detail::attr_from_sig<sig_type>::type attr_type; typedef typename add_reference< typename add_const<attr_type>::type>::type attr_reference_type; // parameter_types is a sequence of types passed as parameters to the rule typedef typename spirit::detail::params_from_sig<sig_type>::type parameter_types; static size_t const params_size = fusion::result_of::size<parameter_types>::type::value; // the context passed to the right hand side of a rule contains // the attribute and the parameters for this particular rule invocation typedef context< fusion::cons<attr_reference_type, parameter_types> , locals_type> context_type; typedef function< bool(output_iterator&, context_type&, delimiter_type const&)> function_type; explicit rule(std::string const& name_ = "unnamed-rule") : base_type(terminal::make(reference_(*this))) , name_(name_) { } rule(rule const& rhs) : base_type(terminal::make(reference_(*this))) , name_(rhs.name_) , f(rhs.f) { } template <typename Expr> rule (Expr const& expr, std::string const& name_ = "unnamed-rule") : base_type(terminal::make(reference_(*this))) , name_(name_) { // Report invalid expression error as early as possible. // If you got an error_invalid_expression error message here, then // the expression (expr) is not a valid spirit karma expression. BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); f = detail::bind_generator<mpl::false_>(compile<karma::domain>(expr)); } rule& operator=(rule const& rhs) { // The following assertion fires when you try to initialize a rule // from an uninitialized one. Did you mean to refer to the right // hand side rule instead of assigning from it? In this case you // should write lhs = rhs.alias(); BOOST_ASSERT(rhs.f); f = rhs.f; name_ = rhs.name_; return *this; } std::string const& name() const { return name_; } void name(std::string const& str) { name_ = str; } template <typename Expr> rule& operator=(Expr const& expr) { // Report invalid expression error as early as possible. // If you got an error_invalid_expression error message here, then // the expression (expr) is not a valid spirit karma expression. BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); f = detail::bind_generator<mpl::false_>(compile<karma::domain>(expr)); return *this; } // g++ 3.3 barfs if this is a member function :( template <typename Expr> friend rule& operator%=(rule& r, Expr const& expr) { // Report invalid expression error as early as possible. // If you got an error_invalid_expression error message here, then // the expression (expr) is not a valid spirit karma expression. BOOST_SPIRIT_ASSERT_MATCH(karma::domain, Expr); r.f = detail::bind_generator<mpl::true_>(compile<karma::domain>(expr)); return r; } // non-const version needed to suppress proto's %= kicking in template <typename Expr> friend rule& operator%=(rule& r, Expr& expr) { return r %= static_cast<Expr const&>(expr); } template <typename Context, typename Unused> struct attribute { typedef attr_type type; }; template <typename Context, typename Delimiter, typename Attribute> bool generate(output_iterator& sink, Context&, Delimiter const& delim , Attribute const& attr) const { if (f) { // Create an attribute if none is supplied. typedef traits::make_attribute<attr_type, Attribute> make_attribute; // If you are seeing a compilation error here, you are probably // trying to use a rule or a grammar which has inherited // attributes, without passing values for them. context_type context(traits::pre_transform<attr_type>( make_attribute::call(attr))); // If you are seeing a compilation error here stating that the // third parameter can't be converted to a karma::reference // then you are probably trying to use a rule or a grammar with // an incompatible delimiter type. if (f(sink, context, delim)) { return true; } } return false; } template <typename Context, typename Delimiter, typename Attribute , typename Params> bool generate(output_iterator& sink, Context& caller_context , Delimiter const& delim, Attribute const& attr , Params const& params) const { if (f) { // Create an attribute if none is supplied. typedef traits::make_attribute<attr_type, Attribute> make_attribute; // If you are seeing a compilation error here, you are probably // trying to use a rule or a grammar which has inherited // attributes, passing values of incompatible types for them. context_type context(traits::pre_transform<attr_type>( make_attribute::call(attr)), params, caller_context); // If you are seeing a compilation error here stating that the // third parameter can't be converted to a karma::reference // then you are probably trying to use a rule or a grammar with // an incompatible delimiter type. if (f(sink, context, delim)) { return true; } } return false; } template <typename Context> info what(Context& /*context*/) const { return info(name_); } reference_ alias() const { return reference_(*this); } typename proto::terminal<this_type>::type copy() const { typename proto::terminal<this_type>::type result = {*this}; return result; } // bring in the operator() overloads rule const& get_parameterized_subject() const { return *this; } typedef rule parameterized_subject_type; #include <boost/spirit/home/karma/nonterminal/detail/fcall.hpp> std::string name_; function_type f; }; }}} #if defined(BOOST_MSVC) # pragma warning(pop) #endif #endif