Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext
Proto's Built-In Transforms

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<N> returns the 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<CT> 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.

proto::make<>

For a given object transform OT, proto::make<OT> 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.

proto::_default<>

Given a grammar G, proto::_default<G> 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.

proto::fold<>

Given three transforms ET, ST, and FT, proto::fold<ET, ST, FT> first evaluates ET to obtain a Fusion sequence and ST to obtain an initial state for the fold, and then evaluates FT for each element in the sequence to generate the next state from the previous.

proto::reverse_fold<>

Like proto::fold<>, except the elements in the Fusion sequence are iterated in reverse order.

proto::fold_tree<>

Like proto::fold<ET, ST, FT>, except that the result of the ET 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, 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)>.

All Grammars Are Primitive Transforms

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<G0, G1>, when used as a primitive transform, creates a new plus node where the left child is transformed according to G0 and the right child with G1.

The Pass-Through Transform

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

proto::unary_plus<>

proto::negate<>

proto::dereference<>

proto::complement<>

proto::address_of<>

proto::logical_not<>

proto::pre_inc<>

proto::pre_dec<>

proto::post_inc<>

proto::post_dec<>

proto::shift_left<>

proto::shift_right<>

proto::multiplies<>

proto::divides<>

proto::modulus<>

proto::plus<>

proto::minus<>

proto::less<>

proto::greater<>

proto::less_equal<>

proto::greater_equal<>

proto::equal_to<>

proto::not_equal_to<>

proto::logical_or<>

proto::logical_and<>

proto::bitwise_and<>

proto::bitwise_or<>

proto::bitwise_xor<>

proto::comma<>

proto::mem_ptr<>

proto::assign<>

proto::shift_left_assign<>

proto::shift_right_assign<>

proto::multiplies_assign<>

proto::divides_assign<>

proto::modulus_assign<>

proto::plus_assign<>

proto::minus_assign<>

proto::bitwise_and_assign<>

proto::bitwise_or_assign<>

proto::bitwise_xor_assign<>

proto::subscript<>

proto::if_else_<>

proto::function<>

proto::unary_expr<>

proto::binary_expr<>

proto::nary_expr<>


The Many Roles of Proto Operator Metafunctions

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

PrevUpHomeNext