On 11/17/2010 1:47 AM, Manjunath Kudlur wrote:
> I am trying to create a transform where I replace occurrences of
> proto::terminal<term> with proto::terminal<newterm<mpl::int_<N> > >. I
> want N to increment for every proto::terminal<term> encountered. So
> far I have the following code :

<snip>

> I pass in mpl::int_<0>() as the initial state and call mpl::next when
> I match proto::terminal<term>. As the output would indicate, this is
> not working. Every time I think I understand proto transforms,
> something basic like this stumps me. I will be grateful for any hints
> on how to accomplish this.

Don't feel bad. This is EXTREMELY hard to do in Proto. :-( Most
algorithms only return one piece of information at each step. This task
requires returning two: the transformed expression and the new state.
Worse, after transforming a left child, the new state needs to be used
as input while transforming the right. Like I said, EXTREMELY hard.

Since your algorithm needs to return two pieces of information, it needs
to return a std::pair containing the new expression and the updated
state variable. And when transforming a non-terminal, you need to use
the fold algorithm to propagate the state from one invocation to the
next (again, bundling and unbundling into a pair as necessary). Fold can
build a fusion::vector of transformed children, which then needs to be
unpacked into an expression. (This step wouldn't be necessary if Proto
expressions were extensible Fusion sequences. <sigh>)

See the attached code. I wish I had a better answer. It sure would be
nice to generalize this for other times when new state needs to bubble
up and back down.

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com
//#include "stdafx.h"
#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::_;

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)
      , make_pair(
            push_back(
                first(proto::_state)
              , first(Renumber(_, second(proto::_state)))
            )
          , type_of<second(Renumber(_, second(proto::_state))) >
        )
    >
{};

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);
}
_______________________________________________
proto mailing list
proto@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/proto

Reply via email to