/*=============================================================================
    Phoenix V1.2.1
    Copyright (c) 2001-2002 Joel de Guzman

    Use, modification and distribution is subject to 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)
==============================================================================*/
#ifndef PHOENIX_STATEMENTS_HPP
#define PHOENIX_STATEMENTS_HPP

///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/phoenix/composite.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace phoenix {

///////////////////////////////////////////////////////////////////////////////
//
//  sequential_composite
//
//      Two or more actors separated by the comma generates a
//      sequential_composite which is a composite actor. Example:
//
//          actor,
//          actor,
//          actor
//
//      The actors are evaluated sequentially. The result type of this
//      is void. Note that the last actor should not have a trailing
//      comma.
//
///////////////////////////////////////////////////////////////////////////////
template <typename A0, typename A1>
struct sequential_composite {

    typedef sequential_composite<A0, A1> self_t;

    template <typename TupleT>
    struct result { typedef void type; };

    sequential_composite(A0 const& _0, A1 const& _1)
    :   a0(_0), a1(_1) {}

    template <typename TupleT>
    void
    eval(TupleT const& args) const
    {
        a0.eval(args);
        a1.eval(args);
    }

    A0 a0; A1 a1; //  actors
};

//////////////////////////////////
template <typename BaseT0, typename BaseT1>
inline actor<sequential_composite<actor<BaseT0>, actor<BaseT1> > >
operator,(actor<BaseT0> const& _0, actor<BaseT1> const& _1)
{
    return sequential_composite<actor<BaseT0>, actor<BaseT1> >(_0, _1);
}

///////////////////////////////////////////////////////////////////////////////
//
//  if_then_else_composite
//
//      This composite has two (2) forms:
//
//          if_(condition)
//          [
//              statement
//          ]
//
//      and
//
//          if_(condition)
//          [
//              true_statement
//          ]
//          .else_
//          [
//              false_statement
//          ]
//
//      where condition is an actor that evaluates to bool. If condition
//      is true, the true_statement (again an actor) is executed
//      otherwise, the false_statement (another actor) is executed. The
//      result type of this is void. Note the trailing underscore after
//      if_ and the the leading dot and the trailing underscore before
//      and after .else_.
//
///////////////////////////////////////////////////////////////////////////////
template <typename CondT, typename ThenT, typename ElseT>
struct if_then_else_composite {

    typedef if_then_else_composite<CondT, ThenT, ElseT> self_t;

    template <typename TupleT>
    struct result {

        typedef void type;
    };

    if_then_else_composite(
        CondT const& cond_,
        ThenT const& then_,
        ElseT const& else__)
    :   cond(cond_), then(then_), else_(else__) {}

    template <typename TupleT>
    void eval(TupleT const& args) const
    {
        if (cond.eval(args))
            then.eval(args);
        else
            else_.eval(args);
    }

    CondT cond; ThenT then; ElseT else_; //  actors
};

//////////////////////////////////
template <typename CondT, typename ThenT>
struct else_gen {

    else_gen(CondT const& cond_, ThenT const& then_)
    :   cond(cond_), then(then_) {}

    template <typename ElseT>
    actor<if_then_else_composite<CondT, ThenT,
        typename as_actor<ElseT>::type> >
    operator[](ElseT const& else_)
    {
        typedef if_then_else_composite<CondT, ThenT,
            typename as_actor<ElseT>::type>
        result;

        return result(cond, then, as_actor<ElseT>::convert(else_));
    }

    CondT cond; ThenT then;
};

//////////////////////////////////
template <typename CondT, typename ThenT>
struct if_then_composite {

    typedef if_then_composite<CondT, ThenT> self_t;

    template <typename TupleT>
    struct result { typedef void type; };

    if_then_composite(CondT const& cond_, ThenT const& then_)
    :   cond(cond_), then(then_), else_(cond, then) {}

    template <typename TupleT>
    void eval(TupleT const& args) const
    {
        if (cond.eval(args))
            then.eval(args);
    }

    CondT cond; ThenT then; //  actors
    else_gen<CondT, ThenT> else_;
};

//////////////////////////////////
template <typename CondT>
struct if_gen {

    if_gen(CondT const& cond_)
    :   cond(cond_) {}

    template <typename ThenT>
    actor<if_then_composite<
        typename as_actor<CondT>::type,
        typename as_actor<ThenT>::type> >
    operator[](ThenT const& then) const
    {
        typedef if_then_composite<
            typename as_actor<CondT>::type,
            typename as_actor<ThenT>::type>
        result;

        return result(
            as_actor<CondT>::convert(cond),
            as_actor<ThenT>::convert(then));
    }

    CondT cond;
};

//////////////////////////////////
template <typename CondT>
inline if_gen<CondT>
if_(CondT const& cond)
{
    return if_gen<CondT>(cond);
}

///////////////////////////////////////////////////////////////////////////////
//
//  while_composite
//
//      This composite has the form:
//
//          while_(condition)
//          [
//              statement
//          ]
//
//      While the condition (an actor) evaluates to true, statement
//      (another actor) is executed. The result type of this is void.
//      Note the trailing underscore after while_.
//
///////////////////////////////////////////////////////////////////////////////
template <typename CondT, typename DoT>
struct while_composite {

    typedef while_composite<CondT, DoT> self_t;

    template <typename TupleT>
    struct result { typedef void type; };

    while_composite(CondT const& cond_, DoT const& do__)
    :   cond(cond_), do_(do__) {}

    template <typename TupleT>
    void eval(TupleT const& args) const
    {
        while (cond.eval(args))
            do_.eval(args);
    }

    CondT cond;
    DoT do_;
};

//////////////////////////////////
template <typename CondT>
struct while_gen {

    while_gen(CondT const& cond_)
    :   cond(cond_) {}

    template <typename DoT>
    actor<while_composite<
        typename as_actor<CondT>::type,
        typename as_actor<DoT>::type> >
    operator[](DoT const& do_) const
    {
        typedef while_composite<
            typename as_actor<CondT>::type,
            typename as_actor<DoT>::type>
        result;

        return result(
            as_actor<CondT>::convert(cond),
            as_actor<DoT>::convert(do_));
    }

    CondT cond;
};

//////////////////////////////////
template <typename CondT>
inline while_gen<CondT>
while_(CondT const& cond)
{
    return while_gen<CondT>(cond);
}

///////////////////////////////////////////////////////////////////////////////
//
//  do_composite
//
//      This composite has the form:
//
//          do_
//          [
//              statement
//          ]
//          .while_(condition)
//
//      While the condition (an actor) evaluates to true, statement
//      (another actor) is executed. The statement is executed at least
//      once. The result type of this is void. Note the trailing
//      underscore after do_ and the the leading dot and the trailing
//      underscore before and after .while_.
//
///////////////////////////////////////////////////////////////////////////////
template <typename DoT, typename CondT>
struct do_composite {

    typedef do_composite<DoT, CondT> self_t;

    template <typename TupleT>
    struct result { typedef void type; };

    do_composite(DoT const& do__, CondT const& cond_)
    :   do_(do__), cond(cond_) {}

    template <typename TupleT>
    void eval(TupleT const& args) const
    {
        do
            do_.eval(args);
        while (cond.eval(args));
    }

    DoT do_;
    CondT cond;
};

////////////////////////////////////
template <typename DoT>
struct do_gen2 {

    do_gen2(DoT const& do__)
    :   do_(do__) {}

    template <typename CondT>
    actor<do_composite<
        typename as_actor<DoT>::type,
        typename as_actor<CondT>::type> >
    while_(CondT const& cond) const
    {
        typedef do_composite<
            typename as_actor<DoT>::type,
            typename as_actor<CondT>::type>
        result;

        return result(
            as_actor<DoT>::convert(do_),
            as_actor<CondT>::convert(cond));
    }

    DoT do_;
};

////////////////////////////////////
struct do_gen {

    template <typename DoT>
    do_gen2<DoT>
    operator[](DoT const& do_) const
    {
        return do_gen2<DoT>(do_);
    }
};

do_gen const do_ = do_gen();

///////////////////////////////////////////////////////////////////////////////
//
//  for_composite
//
//      This statement has the form:
//
//          for_(init, condition, step)
//          [
//              statement
//          ]
//
//      Where init, condition, step and statement are all actors. init
//      is executed once before entering the for-loop. The for-loop
//      exits once condition evaluates to false. At each loop iteration,
//      step and statement is called. The result of this statement is
//      void. Note the trailing underscore after for_.
//
///////////////////////////////////////////////////////////////////////////////
template <typename InitT, typename CondT, typename StepT, typename DoT>
struct for_composite {

    typedef composite<InitT, CondT, StepT, DoT> self_t;

    template <typename TupleT>
    struct result { typedef void type; };

    for_composite(
        InitT const& init_,
        CondT const& cond_,
        StepT const& step_,
        DoT const& do__)
    :   init(init_), cond(cond_), step(step_), do_(do__) {}

    template <typename TupleT>
    void
    eval(TupleT const& args) const
    {
        for (init.eval(args); cond.eval(args); step.eval(args))
            do_.eval(args);
    }

    InitT init; CondT cond; StepT step; DoT do_; //  actors
};

//////////////////////////////////
template <typename InitT, typename CondT, typename StepT>
struct for_gen {

    for_gen(
        InitT const& init_,
        CondT const& cond_,
        StepT const& step_)
    :   init(init_), cond(cond_), step(step_) {}

    template <typename DoT>
    actor<for_composite<
        typename as_actor<InitT>::type,
        typename as_actor<CondT>::type,
        typename as_actor<StepT>::type,
        typename as_actor<DoT>::type> >
    operator[](DoT const& do_) const
    {
        typedef for_composite<
            typename as_actor<InitT>::type,
            typename as_actor<CondT>::type,
            typename as_actor<StepT>::type,
            typename as_actor<DoT>::type>
        result;

        return result(
            as_actor<InitT>::convert(init),
            as_actor<CondT>::convert(cond),
            as_actor<StepT>::convert(step),
            as_actor<DoT>::convert(do_));
    }

    InitT init; CondT cond; StepT step;
};

//////////////////////////////////
template <typename InitT, typename CondT, typename StepT>
inline for_gen<InitT, CondT, StepT>
for_(InitT const& init, CondT const& cond, StepT const& step)
{
    return for_gen<InitT, CondT, StepT>(init, cond, step);
}

}   //  namespace phoenix

#endif
