| // 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/config.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/type_traits/is_same.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/karma/detail/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 |
| , typename T4 = unused_type |
| > |
| struct rule |
| : proto::extends< |
| typename proto::terminal< |
| reference<rule<OutputIterator, T1, T2, T3, T4> const> |
| >::type |
| , rule<OutputIterator, T1, T2, T3, T4> |
| > |
| , generator<rule<OutputIterator, T1, T2, T3, T4> > |
| { |
| typedef mpl::int_<generator_properties::all_properties> properties; |
| |
| typedef OutputIterator iterator_type; |
| typedef rule<OutputIterator, T1, T2, T3, T4> 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, T4> 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; |
| |
| // The rule's signature |
| typedef typename |
| spirit::detail::extract_sig<template_params>::type |
| sig_type; |
| |
| // The rule's encoding type |
| typedef typename |
| spirit::detail::extract_encoding<template_params>::type |
| encoding_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; |
| |
| typedef typename |
| mpl::if_< |
| is_same<encoding_type, unused_type> |
| , unused_type |
| , tag::char_code<tag::encoding, encoding_type> |
| >::type |
| encoding_modifier_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, encoding_modifier_type())); |
| } |
| |
| 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, encoding_modifier_type())); |
| return *this; |
| } |
| |
| // VC7.1 has problems to resolve 'rule' without explicit template parameters |
| #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400) |
| // 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, encoding_modifier_type())); |
| 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); |
| } |
| #else |
| // both friend functions have to be defined out of class as VC7.1 |
| // will complain otherwise |
| template <typename OutputIterator_, typename T1_, typename T2_ |
| , typename T3_, typename T4_, typename Expr> |
| friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( |
| rule<OutputIterator_, T1_, T2_, T3_, T4_>&r, Expr const& expr); |
| |
| // non-const version needed to suppress proto's %= kicking in |
| template <typename OutputIterator_, typename T1_, typename T2_ |
| , typename T3_, typename T4_, typename Expr> |
| friend rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( |
| rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr); |
| #endif |
| |
| 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; |
| typedef traits::transform_attribute< |
| typename make_attribute::type, attr_type, domain> |
| transform; |
| |
| typename transform::type attr_ = |
| traits::pre_transform<domain, attr_type>( |
| make_attribute::call(attr)); |
| |
| // 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(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)) |
| { |
| // do a post-delimit if this is an implied verbatim |
| if (is_same<delimiter_type, unused_type>::value) |
| karma::delimit_out(sink, 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; |
| typedef traits::transform_attribute< |
| typename make_attribute::type, attr_type, domain> |
| transform; |
| |
| typename transform::type attr_ = |
| traits::pre_transform<domain, attr_type>( |
| make_attribute::call(attr)); |
| |
| // 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(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)) |
| { |
| // do a post-delimit if this is an implied verbatim |
| if (is_same<delimiter_type, unused_type>::value) |
| karma::delimit_out(sink, 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 BOOST_WORKAROUND(BOOST_MSVC, < 1400) |
| template <typename OutputIterator_, typename T1_, typename T2_ |
| , typename T3_, typename T4_, typename Expr> |
| rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( |
| rule<OutputIterator_, T1_, T2_, T3_, T4_>&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); |
| |
| typedef typename |
| rule<OutputIterator_, T1_, T2_, T3_, T4_>::encoding_modifier_type |
| encoding_modifier_type; |
| |
| r.f = detail::bind_generator<mpl::true_>( |
| compile<karma::domain>(expr, encoding_modifier_type())); |
| return r; |
| } |
| |
| // non-const version needed to suppress proto's %= kicking in |
| template <typename OutputIterator_, typename T1_, typename T2_ |
| , typename T3_, typename T4_, typename Expr> |
| rule<OutputIterator_, T1_, T2_, T3_, T4_>& operator%=( |
| rule<OutputIterator_, T1_, T2_, T3_, T4_>& r, Expr& expr) |
| { |
| return r %= static_cast<Expr const&>(expr); |
| } |
| #endif |
| }}} |
| |
| #if defined(BOOST_MSVC) |
| # pragma warning(pop) |
| #endif |
| |
| #endif |