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
[email protected]
http://lists.boost.org/mailman/listinfo.cgi/proto