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