// Copyright (c) 2001-2011 Joel de Guzman | |
// Copyright (c) 2001-2011 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/nonterminal_fwd.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, typename T2, typename T3 | |
, typename T4> | |
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 && "Did you mean rhs.alias() instead of rhs?"); | |
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 | |
}}} | |
namespace boost { namespace spirit { namespace traits | |
{ | |
namespace detail | |
{ | |
template <typename RuleAttribute, typename Attribute> | |
struct nonterminal_handles_container | |
: mpl::and_< | |
traits::is_container<RuleAttribute> | |
, is_convertible<Attribute, RuleAttribute> > | |
{}; | |
} | |
/////////////////////////////////////////////////////////////////////////// | |
template < | |
typename IteratorA, typename IteratorB, typename Attribute | |
, typename Context, typename T1, typename T2, typename T3, typename T4> | |
struct handles_container< | |
karma::rule<IteratorA, T1, T2, T3, T4>, Attribute, Context | |
, IteratorB> | |
: detail::nonterminal_handles_container< | |
typename attribute_of< | |
karma::rule<IteratorA, T1, T2, T3, T4> | |
, Context, IteratorB | |
>::type, Attribute> | |
{}; | |
}}} | |
#if defined(BOOST_MSVC) | |
# pragma warning(pop) | |
#endif | |
#endif |