Boost logo

Proto :

Subject: Re: [proto] Thoughts on traversing proto expressions and reusing grammar
From: Eric Niebler (eric_at_[hidden])
Date: 2010-10-12 16:24:25

On 10/4/2010 10:57 PM, Thomas Heller wrote:
> Eric Niebler wrote:
>> On 10/4/2010 12:20 PM, Thomas Heller wrote:
>>> 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
>> How is that different than what the pass_through transform does?
> It works slightly different than pass_through:
> transform_expr calls
> when<_, Fun>::template impl<typename result_of::child_c<Expr, N>::type,
> State, Data>
> while pass_through calls
> Grammar::proto_childN::template impl<typename result_of::child_c<Expr,
> N>::type, State, Data>
> Truth is, I could not see how I could use pass_through to do what I wanted,
> and still fail to see what pass_through really does. Another truth is, that
> i initially wanted to call transform_expr pass_through until I realized that
> it is already there.
> Perhaps you can sched some light on why pass_through is implemented that
> way.

Getting caught up on this discussion and realized I never responded to this.

It seems to me that:

    transform_expr< Fun >

is equivalent to:

    nary_expr< _, vararg< when<_,Fun> > >

with some extra handling for terminals. (The default transform of the
nary_expr grammar is implemented in terms of pass_through.)
Transform_expr applies the Fun transform to terminals also, but
pass_through doesn't do anything to terminals. That's because, in my
experience, transforms that work for non-terminals rarely work as-is for
terminals. Is your experience different?

So it really seems to me that transform_expr is not necessary, but I may
be wrong.

As to why pass_through is implemented as it is, the idea is to make it
as easy as possible to apply global transformations to specific
sub-expressions while leaving the rest of the tree structure unmodified.
For instance, if you want to change all ints to floats in an expression
tree, you would do (untested):

  struct Int2Float
    : or_<
          when< terminal<int>, terminal<float>::type(_value) >
        , nary_expr< _, vararg< Int2Float > >

This takes an expression tree and produces a new one where all int
terminals have been converted to float terminals. IIUC, using
transform_expr, it would look like this:

  struct Int2Float
    : or_<
          when< terminal<int>, terminal<float>::type(_value) >
        , otherwise< transform_expr< Int2Float > >

Is that right? If so, Proto's pass_through transform is more flexible,
because it allows different transforms to be applied to different
children. For instance:

  plus< Alg0, Alg1 >

is a grammar that matches plus nodes in the expected way, and an
algorithm that builds a new plus node where the 0th child is the result
of applying Alg0 to the left child and Alg1 to the right. IIUC,
transform_expr doesn't allow this flexibility.

Eric Niebler
BoostPro Computing

Proto list run by eric at