[ create a new paste ] login | about

Link: http://codepad.org/K0TZamPb    [ raw code | fork ]

C++, pasted on Nov 18:
#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);
}


Create a new paste based on this one


Comments: