On 10/4/2010 12:20 PM, Thomas Heller wrote: > On Mon, Oct 4, 2010 at 8:53 PM, joel falcou wrote: >> On 04/10/10 20:45, Eric Niebler wrote: >>> >>> I'm not opposed to such a thing being in Proto, but I >>> (personally) don't feel a strong need. I'd be more willing if I >>> saw a more strongly motivating example. I believe Joel Falcou >>> invented something similar. Joel, what was your use scenario? >> >> NT2 ;) >> >> More specifically, all our transform are built the same way: visit >> the tree, dispatch on visitor type + tag and act accordignly. It >> was needed for us cause the grammar could NOT have been written by >> hand as we supprot 200+ functions on nt2 terminal. All our code is >> somethign like "for each node, do Foo" with variable Foo depending >> on the pass and duplicating the grammar was a no-no.
Fair 'nuf. But I haven't yet reached the conclusion that visitor is the appropriate solution. >> We ended up with somethign like this, except without switch_ (which >> I like btw), so we can easily add new transform on the AST from the >> external view point of user who didn't have to know much proto. As >> I only had to define one grammar (the visitor) This is something I have trouble with. A visitor is a grammar? That doesn't make sense to me. >> and only specialisation of the visitor for some tag, it compiled >> fast and that was what we wanted. >> >> Thomas, why not showign the split example ? It's far better than >> this one and I remember I and Eric weren't able to write it usign >> grammar/transform back in the day. Joel, I don't recall this particular problem or being unable to solve it with Proto transforms. > The split example was one of the motivating examples, that is > correct, though it suffers the exact points Eric is criticizing. The > split example was possible because i added some new transforms which > proto currently misses, but i didn't want to shoot out all my > ammunition just yet :P > > But since you ask for it: > > http://github.com/sithhell/boosties/blob/master/proto/libs/proto/test/splitter.cpp > > the new thing i added is transform_expr, which works like > fusion::transform: It creates the expression again, with transformed > child nodes (the child nodes get transformed according to the > transform you specify as template parameter If the theory is that this particular problem cannot be implemented with existing Proto grammars and transforms, then I submit the attached solution as contrary evidence. I'll admit that it doesn't have the property that the transforms can be substituted post-hoc into an existing Proto algorithm, but is that really necessary? There is no grammar to speak of; *every* expression is a valid split expression. This solution is much, much simpler than Thomas' solution that uses a visitor. Heck, it took me longer to understand Thomas' code than it did for me to write the solution using standard Proto components. Still not seeing the big picture with visitors, -- Eric Niebler BoostPro Computing http://www.boostpro.com
#include <iostream> #include <boost/proto/proto.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> namespace proto = boost::proto; namespace fusion = boost::fusion; namespace mpl = boost::mpl; using proto::_; // For display_expr debugging purposes namespace boost { namespace mpl { template<int N> std::ostream & operator<<(std::ostream & sout, mpl::int_<N>) { return std::cout << "mpl::int_<" << N << ">"; } }} namespace tag { struct split {}; } template <typename Expr> struct make_split : proto::result_of::make_expr<tag::split, proto::default_domain, Expr> {}; template <typename Expr> typename make_split<Expr>::type const split(Expr const& expr) { typename make_split<Expr>::type const e = {expr}; return e; } struct push_back { BOOST_PROTO_CALLABLE() template <typename Sig> struct result; template <typename This, typename Seq, typename T> struct result<This(Seq, T)> : boost::add_const< typename 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 >::type > {}; template <typename Seq, typename T> typename fusion::result_of::push_back<Seq const, T>::type const operator()(Seq const& seq, T const& t) const { return fusion::push_back(seq, t); } }; #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) #define push_back(x,y) proto::call<push_back(x,y)> #endif // Given an expression that (maybe) contains split expressions, // replace the expressions with mpl::int_<0> terminals. struct Substitute : proto::or_< proto::when< proto::unary_expr<tag::split, _> , proto::terminal<mpl::int_<0> >::type(mpl::int_<0>()) > , proto::terminal<_> , proto::nary_expr<_, proto::vararg<Substitute> > > {}; // Walk an expression recursively. Collect into the state // vector the split expressions. Return the collected // replacements. struct Replacements : proto::or_< proto::when<proto::terminal<_>, proto::_state> , proto::when< proto::unary_expr<tag::split, _> , Replacements( proto::_child , push_back(proto::_state, Substitute(proto::_child)) ) > , proto::otherwise<proto::fold<_, proto::_state, Replacements> > > {}; // Start the recursive replacement collection on an expression // that may have split expressions. struct Splitter : proto::otherwise< Replacements(_, push_back(proto::_state, Substitute)) > {}; #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) #undef push_back #endif int main() { typedef proto::terminal<char>::type char_; char_ const a = {'a'}; char_ const b = {'b'}; char_ const c = {'c'}; char_ const d = {'d'}; char_ const e = {'e'}; char_ const f = {'f'}; fusion::vector0<> const res = fusion::vector0<>(); fusion::for_each(Splitter()(split(a) + split(b), res), proto::functional::display_expr()); std::cout << "\n\n"; fusion::for_each(Splitter()(a + b, res), proto::functional::display_expr()); std::cout << "\n\n"; fusion::for_each(Splitter()(split(a) + b, res), proto::functional::display_expr()); std::cout << "\n\n"; fusion::for_each(Splitter()(a + split(b), res), proto::functional::display_expr()); std::cout << "\n\n"; fusion::for_each(Splitter()(a + split(b + c), res), proto::functional::display_expr()); std::cout << "\n\n"; fusion::for_each(Splitter()(a+b+split( c*d + split(e-f)), res), proto::functional::display_expr()); std::cout << "\n\n"; Splitter()(split(a) + split(b), res); Splitter()(a + b, res); Splitter()(split(a) + b, res); Splitter()(a + split(b), res); Splitter()(a + split(b + c), res); }
_______________________________________________ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto