|
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 http://www.boostpro.com
Proto list run by eric at boostpro.com