#include <iostream>
#include <utility>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/push_front.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/next.hpp>
#include <boost/proto/proto.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;
using proto::_;
namespace detail
{
template<typename Transform, typename LocalName, typename LocalTransform>
struct replace_local
: mpl::if_<
boost::is_same<Transform, LocalName>
, LocalTransform
, Transform
>
{};
#define M1(Z, N, DATA) \
typename replace_local< \
BOOST_PP_CAT(A, N) \
, LocalName \
, LocalTransform \
>::type \
/**/
#define M0(Z, N, DATA) \
template< \
template < \
BOOST_PP_ENUM_PARAMS(N, typename BOOST_PP_INTERCEPT) \
> class Transform \
, BOOST_PP_ENUM_PARAMS(N, typename A) \
, typename LocalName \
, typename LocalTransform \
> \
struct replace_local< \
Transform<BOOST_PP_ENUM_PARAMS(N, A)> \
, LocalName \
, LocalTransform \
> \
{ \
typedef \
Transform< \
BOOST_PP_ENUM(N, M1, _) \
> type; \
}; \
/**/
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0, _)
#undef M0
#define M0(Z, N, DATA) \
template< \
typename Transform \
BOOST_PP_ENUM_TRAILING_PARAMS(N, typename A) \
, typename LocalName \
, typename LocalTransform \
> \
struct replace_local< \
Transform(BOOST_PP_ENUM_PARAMS(N, A)) \
, LocalName \
, LocalTransform \
> \
: mpl::identity< \
typename replace_local< \
Transform \
, LocalName \
, LocalTransform \
>::type( \
BOOST_PP_ENUM(N, M1, _) \
) \
> \
{}; \
/**/
BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, M0, _)
#undef M0
#undef M1
template<typename Transform, typename LocalName, typename LocalTransform>
struct replace_local<Transform *, LocalName, LocalTransform>
: replace_local<Transform, LocalName, LocalTransform>
{};
}
template <typename Local0, typename Transform>
struct let;
template <typename LocalName0, typename LocalTransform0, typename Transform>
struct let<LocalName0(LocalTransform0), Transform>
: proto::transform<let<LocalName0(LocalTransform0), Transform> >
{
struct local_transform0
: proto::when<proto::_, LocalTransform0>
{};
template <typename Expr, typename State, typename Data>
struct impl
: proto::when<
proto::_
, typename detail::replace_local<Transform, LocalName0, local_transform0>::type
>::template impl<Expr, State, Data>
{};
};
#define M1(_, N, __) BOOST_PP_CAT(LocalName, N)(BOOST_PP_CAT(LocalTransform, N))
#define M2(Z, N, DATA) \
typedef \
typename detail::replace_local< \
BOOST_PP_CAT(replaced_transform, BOOST_PP_SUB(DATA, N)) \
, BOOST_PP_CAT(LocalName, BOOST_PP_DEC(BOOST_PP_SUB(DATA, N))) \
, BOOST_PP_CAT(local_transform, BOOST_PP_DEC(BOOST_PP_SUB(DATA, N))) \
>::type \
BOOST_PP_CAT(replaced_transform, BOOST_PP_DEC(BOOST_PP_SUB(DATA, N))); \
#define M3(Z, N, DATA) \
struct BOOST_PP_CAT(local_transform, N) : proto::when<proto::_, BOOST_PP_CAT(LocalTransform, N)> {};
#define M0(Z, N, DATA) \
template <BOOST_PP_ENUM_PARAMS(N, typename LocalName), BOOST_PP_ENUM_PARAMS(N, typename LocalTransform), typename Transform> \
struct let<proto::and_<BOOST_PP_ENUM(N, M1, _)>, Transform> \
{ \
BOOST_PP_REPEAT(N, M3, _) \
\
typedef \
typename detail::replace_local< \
Transform \
, BOOST_PP_CAT(LocalName, BOOST_PP_DEC(N)) \
, BOOST_PP_CAT(local_transform, BOOST_PP_DEC(N)) \
>::type \
BOOST_PP_CAT(replaced_transform, BOOST_PP_DEC(N)); \
\
BOOST_PP_REPEAT(BOOST_PP_DEC(N), M2, BOOST_PP_DEC(N)) \
\
typedef replaced_transform0 replaced_transform; \
\
template <typename Expr, typename State, typename Data> \
struct impl \
: proto::when< \
proto::_ \
, replaced_transform \
>::template impl<Expr, State, Data> \
{}; \
}; \
BOOST_PP_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_LOGICAL_ARITY, M0, _)
struct _a {};
struct _b {};
struct term
{
friend std::ostream &operator<<(std::ostream &sout, term const &)
{
return sout << "term";
}
};
template<typename I>
struct newterm
{
friend std::ostream &operator<<(std::ostream &sout, newterm<I> const &)
{
return sout << "newterm<" << I::value << ">";
}
};
proto::terminal<term>::type const a = {{}};
proto::terminal<term>::type const b = {{}};
proto::terminal<term>::type const c = {{}};
struct make_pair : proto::callable
{
template<typename Sig>
struct result;
template<typename This, typename First, typename Second>
struct result<This(First, Second)>
{
typedef std::pair<First, Second> type;
};
template<typename First, typename Second>
std::pair<First, Second> operator()(First const &first, Second const &second) const
{
return std::make_pair(first, second);
}
};
struct first : proto::callable
{
template<typename Sig>
struct result;
template<typename This, typename Pair>
struct result<This(Pair)>
{
typedef typename Pair::first_type type;
};
template<typename Pair>
typename Pair::first_type operator()(Pair const &pair) const
{
return pair.first;
}
};
struct second : proto::callable
{
template<typename Sig>
struct result;
template<typename This, typename Pair>
struct result<This(Pair)>
{
typedef typename Pair::second_type type;
};
template<typename Pair>
typename Pair::second_type operator()(Pair const &pair) const
{
return pair.second;
}
};
struct push_back : proto::callable
{
template<typename Sig>
struct result;
template<typename This, typename Seq, typename T>
struct result<This(Seq, T)>
: fusion::result_of::push_back<
typename boost::add_const<typename boost::remove_reference<Seq>::type>::type
, typename boost::remove_const<typename boost::remove_reference<T>::type>::type
>
{};
template<typename Seq, typename T>
typename fusion::result_of::push_back<Seq const, T>::type
operator ()(Seq const &seq, T const &t) const
{
return fusion::push_back(seq, t);
}
};
struct unpack_expr : proto::callable
{
template<typename Sig>
struct result;
template<typename This, typename Tag, typename Seq>
struct result<This(Tag, Seq)>
: proto::result_of::unpack_expr<Tag, Seq>
{};
template<typename Tag, typename Seq>
typename proto::result_of::unpack_expr<Tag, Seq const>::type
operator ()(Tag, Seq const &seq) const
{
return proto::unpack_expr<Tag>(seq);
}
};
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
#define _make_terminal(x) call<proto::_make_terminal(x) >
#define Renumber(x,y) proto::call<Renumber(x,y) >
#define push_back(x,y) proto::call<push_back(x,y) >
#define make_pair(x,y) proto::call<make_pair(x,y) >
#define unpack_expr(x,y) proto::call<unpack_expr(x,y) >
#define first(x) proto::call<first(x) >
#define second(x) proto::call<second(x) >
#endif
struct Renumber;
// don't evaluate T at runtime, but default-construct an object
// of T's result type.
template<typename T>
struct type_of
: proto::make<proto::call<T> >
{};
struct RenumberFun
: proto::fold<
_
, make_pair(fusion::vector<>(), proto::_state)
, let<
_a(Renumber(_, second(proto::_state)))
, make_pair(
push_back(
first(proto::_state)
, first(_a)
)
, type_of<second(_a) >
)
>
>
{};
struct Renumber
: proto::or_<
proto::when<
proto::terminal<term>
, make_pair(
proto::_make_terminal(newterm<proto::_state>())
, mpl::next<proto::_state>()
)
>
, proto::when<
proto::terminal<_>
, make_pair(proto::_byval(_), proto::_state)
>
, proto::otherwise<
make_pair(
unpack_expr(proto::make<proto::tag_of<_> >, first(RenumberFun))
, type_of<second(RenumberFun) >
)
>
>
{};
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
#undef _make_terminal
#undef Renumber
#undef push_back
#undef make_pair
#undef unpack_expr
#undef first
#undef second
#endif
int main()
{
proto::display_expr((a + 1) + (b - c));
proto::display_expr(Renumber()((a + 1) + (b - c), mpl::int_<0>()).first);
}