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
#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

    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 
              , typename boost::remove_const<typename 

    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);

#define push_back(x,y) proto::call<push_back(x,y)>

// Given an expression that (maybe) contains split expressions,
// replace the expressions with mpl::int_<0> terminals.
struct Substitute
  : proto::or_<
            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(
              , 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))

#undef push_back

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

Reply via email to