[/
 / Copyright (c) 2008 Eric Niebler
 /
 / 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 Hello Calculator]

"Hello, world" is nice, but it doesn't get you very far. Let's use Proto to
build a Domain Specific Embedded Language for a lazily-evaluated calculator.
We'll see how to define the terminals in your mini-language, how Proto combines
the terminals into larger expressions, and how to define an evaluation context
so that your expressions can do useful work. When we're done, we'll have a
mini-language that will allow us to declare a lazily-evaluated arithmetic
expression, such as `(_2 - _1) / _2 * 100`, where `_1` and `_2` are
placeholders for values to be passed in when the expression is evaluated.

[heading Defining Terminals]

The first order of business is to define the placeholders `_1` and `_2`. For
that, we'll use the _terminal_ metafunction.

    // Define some placeholder types
    struct placeholder1 {};
    struct placeholder2 {};

    // Define the Proto-ified placeholder terminals
    proto::terminal< placeholder1 >::type const _1 = {{}};
    proto::terminal< placeholder2 >::type const _2 = {{}};

The initialization may look a little odd at first, but there is a good reason
for doing things this way. The objects `_1` and `_2` above do not require
run-time construction -- they are ['statically initialized], which means they
are essentially initialized at compile time. See the
[link boost_proto.appendices.rationale.static_initialization Static
Initialization] section in the [link boost_proto.appendices.rationale Rationale]
appendix for more information.

[heading Constructing Expression Trees]

Now that we have terminals, we can use Proto's operator overloads to combine
these terminals into larger expressions. So, for instance, we can immediately
create the expression `(_2 - _1) / _2 * 100`. This creates an expression tree
with a node for each operator. The type of the resulting object is large and
complex, but we are not terribly interested in it.

So far, the object is just a tree representing the expression. It has no
behavior. In particular, it is not yet a calculator. Below we'll see how
to make it a calculator by defining an evaluation context.

[heading Defining an Evaluation Context]

No doubt you want your expression templates to actually /do/ something. One
approach is to define an ['evaluation context]. The context is like a function
object that associates behaviors with the node types in your expression tree.
An example should make it clear.

    struct calculator_context
      : proto::callable_context< calculator_context const >
    {
        calculator_context(double d1, double d2)
          : d1_(d1), d2_(d2)
        {}

        // Define the result type of the calculator.
        // (This makes the the calculator_context "callable".)
        typedef double result_type;

        // Handle the placeholders:
        double operator()(proto::tag::terminal, placeholder1) const
        {
            return this->d1_;
        }

        double operator()(proto::tag::terminal, placeholder2) const
        {
            return this->d2_;
        }

        // Handle literals:
        double operator()(proto::tag::terminal, double d) const
        {
            return d;
        }

        // Handle addition:
        template< typename Left, typename Right >
        double operator()(proto::tag::plus, Left const &left, Right const &right) const
        {
            return proto::eval(left, *this) + proto::eval(right, *this);
        }

        // Handle subtraction:
        template< typename Left, typename Right >
        double operator()(proto::tag::minus, Left const &left, Right const &right) const
        {
            return proto::eval(left, *this) - proto::eval(right, *this);
        }

        // Handle multiplication:
        template< typename Left, typename Right >
        double operator()(proto::tag::multiplies, Left const &left, Right const &right) const
        {
            return proto::eval(left, *this) * proto::eval(right, *this);
        }

        // Handle division:
        template< typename Left, typename Right >
        double operator()(proto::tag::divides, Left const &left, Right const &right) const
        {
            return proto::eval(left, *this) / proto::eval(right, *this);
        }

    private:
        double d1_, d2_;
    };

Notice how the binary arithmetic operations are handled. First the left and
right operands are evaluated by invoking `proto::eval()`. After the left and
right children are evaluated, the results are combined using the appropriate
arithmetic operation.

Now that we have an evaluation context for our calculator, we can use it to
evaluate our arithmetic expressions, as below:

    // Define a calculator context, where _1 is 45 and _2 is 50
    calculator_context ctx( 45, 50 );

    // Create an arithmetic expression and immediately evaluate it
    double d = proto::eval( (_2 - _1) / _2 * 100, ctx );

    // This prints "10"
    std::cout << d << std::endl;

[heading Default Expression Evaluation]

You might notice that the `calculator_context` has a lot of boilerplate. It
is fairly common for addition nodes to be handled by evaluating the left and
right children and then adding the result, for instance. For this purpose,
Boost.Proto provides the _default_context_, which gives the operators their usual
meanings, and uses Boost.Typeof to deduce return types. In fact, the
_callable_context_ from which our `calculator_context` inherits uses
_default_context_ as a fall-back for any expression types you don't handle
explicitly. We can use that fact to simplify our `calculator_context`
considerably:

    struct calculator_context
      : proto::callable_context< calculator_context const >
    {
        calculator_context(double d1, double d2)
          : d1_(d1), d2_(d2)
        {}

        // Define the result type of the calculator.
        // (This makes the the calculator_context "callable".)
        typedef double result_type;

        // Handle the placeholders:
        double operator()(proto::tag::terminal, placeholder1) const
        {
            return this->d1_;
        }

        double operator()(proto::tag::terminal, placeholder2) const
        {
            return this->d2_;
        }

    private:
        double d1_, d2_;
    };

That's pretty simple!

[endsect]
