![]() |
Home | Libraries | People | FAQ | More |
Primitive transforms are the building blocks for more interesting composite transforms. Proto defines a bunch of generally useful primitive transforms. They are summarized below.
proto::_value
Given a terminal expression, return the value of the terminal.
proto::_child_c<>
Given a non-terminal expression, proto::_child_c<
returns the N
>N
-th
child.
proto::_child
A synonym for proto::_child_c<0>
.
proto::_left
A synonym for proto::_child_c<0>
.
proto::_right
A synonym for proto::_child_c<1>
.
proto::_expr
Returns the current expression unmodified.
proto::_state
Returns the current state unmodified.
proto::_data
Returns the current data unmodified.
proto::call<>
For a given callable transform
,
CT
proto::call<
turns the callable transform
into a primitive transform. This is useful for disambiguating callable
transforms from object transforms, and also for working around
compiler bugs with nested function types.
CT
>
proto::make<>
For a given object transform
,
OT
proto::make<
turns the object transform
into a primitive transform. This is useful for disambiguating object
transforms from callable transforms, and also for working around
compiler bugs with nested function types.
OT
>
proto::_default<>
Given a grammar G
, proto::_default<
evaluates the current node
according to the standard C++ meaning of the operation the node
represents. For instance, if the current node is a binary plus
node, the two children will both be evaluated according to G
>
and the results will be added and returned. The return type is
deduced with the help of the Boost.Typeof library.
G
proto::fold<>
Given three transforms
,
ET
, and ST
,
FT
proto::fold<
first evaluates ET
, ST
, FT
>
to obtain a Fusion sequence and ET
to obtain an initial state for the fold, and then evaluates ST
for each element in the sequence to generate the next state from
the previous.
FT
proto::reverse_fold<>
Like proto::fold<>
, except the
elements in the Fusion sequence are iterated in reverse order.
proto::fold_tree<>
Like proto::fold<
, except that the result of
the ET
, ST
, FT
>
transform is treated
as an expression tree that is flattened to
generate the sequence to be folded. Flattening an expression tree
causes child nodes with the same tag type as the parent to be put
into sequence. For instance, ET
a
>> b
>> c
would be flattened to the sequence [a
,
b
, c
], and this is the sequence
that would be folded.
proto::reverse_fold_tree<>
Like proto::fold_tree<>
, except that
the flattened sequence is iterated in reverse order.
proto::lazy<>
A combination of proto::make<>
and proto::call<>
that is useful
when the nature of the transform depends on the expression, state
and/or data parameters. proto::lazy<R(A0,A1...An)>
first evaluates proto::make<R()>
to compute a callable type R2
.
Then, it evaluates proto::call<R2(A0,A1...An)>
.
In addition to the above primitive transforms, all of Proto's grammar elements are also primitive transforms. Their behaviors are described below.
proto::_
Return the current expression unmodified.
proto::or_<>
For the specified set of alternate sub-grammars, find the one that matches the given expression and apply its associated transform.
proto::and_<>
For the given set of sub-grammars, apply all the associated transforms and return the result of the last.
proto::not_<>
Return the current expression unmodified.
proto::if_<>
Given three transforms, evaluate the first and treat the result as a compile-time Boolean value. If it is true, evaluate the second transform. Otherwise, evaluate the third.
proto::switch_<>
As with proto::or_<>
, find the sub-grammar
that matches the given expression and apply its associated transform.
proto::terminal<>
Return the current terminal expression unmodified.
proto::plus<>
, proto::nary_expr<>
,
et. al.
A Proto grammar that matches a non-terminal such as proto::plus<
, when used as a primitive transform,
creates a new plus node where the left child is transformed according
to G0
, G1
>
and the right child
with G0
.
G1
Note the primitive transform associated with grammar elements such as
proto::plus<>
described above.
They possess a so-called pass-through transform.
The pass-through transform accepts an expression of a certain tag type
(say, proto::tag::plus
) and creates a new expression
of the same tag type, where each child expression is transformed according
to the corresponding child grammar of the pass-through transform. So
for instance this grammar ...
proto::function< X, proto::vararg<Y> >
... matches function expressions where the first child matches the X
grammar and the rest match the Y
grammar. When used as a transform,
the above grammar will create a new function expression where the first
child is transformed according to X
and the rest are transformed according to Y
.
The following class templates in Proto can be used as grammars with pass-through transforms:
Table 1.11. Class Templates With Pass-Through Transforms
Templates with Pass-Through Transforms |
---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
We've seen templates such as proto::terminal<>
,
proto::plus<>
and proto::nary_expr<>
fill many roles. They are metafunction that generate expression types.
They are grammars that match expression types. And they are primitive
transforms. The following code samples show examples of each.
As Metafunctions ...
// proto::terminal<> and proto::plus<> are metafunctions // that generate expression types: typedef proto::terminal<int>::type int_; typedef proto::plus<int_, int_>::type plus_; int_ i = {42}, j = {24}; plus_ p = {i, j};
As Grammars ...
// proto::terminal<> and proto::plus<> are grammars that // match expression types struct Int : proto::terminal<int> {}; struct Plus : proto::plus<Int, Int> {}; BOOST_MPL_ASSERT(( proto::matches< int_, Int > )); BOOST_MPL_ASSERT(( proto::matches< plus_, Plus > ));
As Primitive Transforms ...
// A transform that removes all unary_plus nodes in an expression struct RemoveUnaryPlus : proto::or_< proto::when< proto::unary_plus<RemoveUnaryPlus> , RemoveUnaryPlus(proto::_child) > // Use proto::terminal<> and proto::nary_expr<> // both as grammars and as primitive transforms. , proto::terminal<_> , proto::nary_expr<_, proto::vararg<RemoveUnaryPlus> > > {}; int main() { proto::literal<int> i(0); proto::display_expr( +i - +(i - +i) ); proto::display_expr( RemoveUnaryPlus()( +i - +(i - +i) ) ); }
The above code displays the following, which shows that unary plus nodes have been stripped from the expression:
minus( unary_plus( terminal(0) ) , unary_plus( minus( terminal(0) , unary_plus( terminal(0) ) ) ) ) minus( terminal(0) , minus( terminal(0) , terminal(0) ) )