Phoenix Expressions

| Home | Libraries | People | FAQ | More

### Phoenix Expressions

A Phoenix Expression is a model of the Proto Expression Concept. These expressions are wrapped inside an Actor template. The `actor` provides the function call operator which evaluates the expressions. The `actor` is the domain specific wrapper around Phoenix expressions.

By design, Phoenix Expressions do not carry any information on how they will be evaluated later on. They are the data structure on which the `Actions` will work.

The library provides a convenience template to define expressions:

    template <template <typename> Actor, typename Tag, typename A0, ..., typename A1>
    struct expr_ext
        : proto::transform<expr_ext<Actor, Tag, A0, ..., A1> >
    {
        typedef unspecified base_expr;
        typedef Actor<base_expr> type;

        typedef unspecified proto_grammar;

        static type make(A0 a0, ..., A1 a1);
    };

    template <typename Tag, typename A0, ..., typename A1>
    struct expr : expr_ext<actor, Tag, A0, ..., A1> {};

Notation

`A0...AN`

  Child node types

`a0...aN`

  Child node objects

`G0...GN`

  Boost.Proto grammar types

Expression Semantics

Expression | Semantics
--- | ---
`expr<Tag, A0...AN>::type` | The type of Expression having tag `Tag` and `A0...AN` children
`expr<Tag, G0...GN>` | A Boost.Proto grammar and Proto Pass Through Transform
`expr<Tag, A0...AN>::make(a0...aN)` | Returns a Phoenix Expression

| Note
You might have noticed the template template argument `Actor` used in `expr_ext`. This can be a user supplied custom Actor adding other member functions or objects than the default `actor` template. See Extending Actors for more details.

##### meta_grammar

Defining expressions is only part of the game to make it a valid Phoenix Expression. In order to use the expressions in the Phoenix domain, we need to "register" them to our grammar.

The `meta_grammar` is a struct for exactly that purpose. It is an openly extendable Boost.Proto Grammar:

    struct meta_grammar
        : proto::switch_<meta_grammar>
    {
        template <typename Tag, typename Dummy>
        struct case_
            : proto::not_<proto::_>
        {};
    };

As you can see, by default the `meta_grammar` matches nothing. With every Module you include this grammar gets extended by various expressions.

##### Example

Define an expression:

    template <typename Lhs, typename Rhs>
    struct plus
        : expr<proto::tag::plus, Lhs, Rhs>
    {};

And add it to the grammar:

    template <>
    struct meta_grammar::case_<proto::tag::plus>
        : enable_rule<
            plus<
                meta_grammar
              , meta_grammar
            >
        >
    {};

Define a generator function to make the life of our potential users easier:

    template <typename Lhs, typename Rhs>
    typename plus<Lhs, Rhs>::type
    plus(Lhs const & lhs, Rhs const & rhs)
    {
        return expression::plus<Lhs, Rhs>::make(lhs, rhs);
    }

Look if it really works:

    plus(6, 5)();

returns 11!

    proto::display_expr(plus(5, 6));

prints:

    plus(
        terminal(6)
      , terminal(5)
    )

See define_expression.cpp for the full example.

| Note
The example shown here only works because `default_actions` knows how to handle an expression having the `proto::tag::plus` and two children. This is because `default_actions` uses the `proto::_default<meta_grammar>` transform to evaluate operators and functions. Learn more about actions here.