[/============================================================================== Copyright (C) 2001-2010 Joel de Guzman Copyright (C) 2001-2005 Dan Marsden Copyright (C) 2001-2010 Thomas Heller Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ===============================================================================/] [section:actions More on Actions] As you know from the [link phoenix.inside.actor Actors in Detail] section, Actions are what brings life to a Phoenix expression tree. When dealing with a Phoenix expression tree, it gets evaluated top-down. Example: _1 + 3 * _2 Can be visualized as an AST in the following way: [$images/simple_ast.png] In terms of actions this means: * `rule::plus` is matched * evaluate left: * `rule::placeholder` is matched * evaluate right: * `rule::multiplies` is matched * evaluate left: * `rule::value` is matched * evaluate right: * `rule::placeholder` is matched Every time a rule is matched, an action will be called. The action determines how the Phoenix AST will be traversed. [heading Writing an Action] As mentioned in [link phoenix.inside.actor Actors in Detail] actions are __proto_primitive_transforms__ for convenience Phoenix provides an abstraction to this: template struct call; This is similar to __proto_call__ but does more. It calls the `Fun` function object passed as template parameter with the `Context` and the children of the expression associated with the rule. Lets have an (simplified) example on how to write an evaluation action for `rule::plus`: struct plus_eval { typedef int result_type; template result_type operator()(Lhs const& lhs, Rhs const &rhs, Context & ctx) { return eval(lhs, ctx) + eval(rhs, ctx); } }; template <> struct default_actions::when : call {}; That's it. When evaluating a `plus` expression, the `plus_eval` callable gets called with the left hand side and right hand side expression and the associated Context. [*But there is more:] As Actions /can/ be full fletched __proto_transforms__, you can in fact use any proto expression you can imagine as the action. Phoenix predifines a set of callables and transform to deal with the Context information passed along and of course every Phoenix expression can be used as a Phoenix grammar or __proto_pass_through_transform__. [variablelist [ [`functional::context(Env, Actions)`] [A __proto_callable__ that creates a new context out of the `Env` and `Actions` parameter] ] [ [`functional::env(Context)`] [A __proto_callable__ that returns the environment out of the `Context` parameter] ] [ [`functional::actions(Context)`] [A __proto_callable__ that returns the actions out of the `Context` parameter] ] [ [`_context`] [A __proto_primitive_transform__ that returns the current context] ] [ [`_env`] [A __proto_primitive_transform__ that returns the current environment] ] [ [`_actions`] [A __proto_primitive_transform__ that returns the current actions] ] [ [`context(env, actions)`] [A regular function that creates a context] ] [ [`env(ctx)`] [A regular function that returns the environment from the given context] ] [ [`actions(ctx)`] [A regular function that returns the actions from the given context] ] ] Phoenix is equipped with a predefined set of expressions, rules and actions to make all the stuff work you learned in the __phoenix_starter_kit__ and __phoenix_modules__ sections. See the [link phoenix.inside.rules next section] for more details! [endsect]