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

  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)
==============================================================================*/
#ifndef PHOENIX_PRIMITIVES_HPP
#define PHOENIX_PRIMITIVES_HPP

///////////////////////////////////////////////////////////////////////////////
#include <boost/spirit/home/classic/phoenix/actor.hpp>

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

///////////////////////////////////////////////////////////////////////////////
//
//  argument class
//
//      Lazy arguments
//
//      An actor base class that extracts and returns the Nth argument
//      from the argument list passed in the 'args' tuple in the eval
//      member function (see actor.hpp). There are some predefined
//      argument constants that can be used as actors (arg1..argN).
//
//      The argument actor is a place-holder for the actual arguments
//      passed by the client. For example, wherever arg1 is seen placed
//      in a lazy function (see functions.hpp) or lazy operator (see
//      operators.hpp), this will be replaced by the actual first
//      argument in the actual function evaluation. Argument actors are
//      essentially lazy arguments. A lazy argument is a full actor in
//      its own right and can be evaluated through the actor's operator().
//
//      Example:
//
//          char        c = 'A';
//          int         i = 123;
//          const char* s = "Hello World";
//
//          cout << arg1(c) << ' ';
//          cout << arg1(i, s) << ' ';
//          cout << arg2(i, s) << ' ';
//
//       will print out "A 123 Hello World"
//
///////////////////////////////////////////////////////////////////////////////
template <int N>
struct argument {

    template <typename TupleT>
    struct result { typedef typename tuple_element<N, TupleT>::type type; };

    template <typename TupleT>
    typename tuple_element<N, TupleT>::type
    eval(TupleT const& args) const
    {
        return args[tuple_index<N>()];
    }
};

//////////////////////////////////
actor<argument<0> > const arg1 = argument<0>();
actor<argument<1> > const arg2 = argument<1>();
actor<argument<2> > const arg3 = argument<2>();

#if PHOENIX_LIMIT > 3
actor<argument<3> > const arg4 = argument<3>();
actor<argument<4> > const arg5 = argument<4>();
actor<argument<5> > const arg6 = argument<5>();

#if PHOENIX_LIMIT > 6
actor<argument<6> > const arg7 = argument<6>();
actor<argument<7> > const arg8 = argument<7>();
actor<argument<8> > const arg9 = argument<8>();

#if PHOENIX_LIMIT > 9
actor<argument<9> > const arg10 = argument<9>();
actor<argument<10> > const arg11 = argument<10>();
actor<argument<11> > const arg12 = argument<11>();

#if PHOENIX_LIMIT > 12
actor<argument<12> > const arg13 = argument<12>();
actor<argument<13> > const arg14 = argument<13>();
actor<argument<14> > const arg15 = argument<14>();

#endif
#endif
#endif
#endif
///////////////////////////////////////////////////////////////////////////////
//
//  value class
//
//      Lazy values
//
//      A bound actual parameter is kept in a value class for deferred
//      access later when needed. A value object is immutable. Value
//      objects are typically created through the val(x) free function
//      which returns a value<T> with T deduced from the type of x. x is
//      held in the value<T> object by value.
//
//      Lazy values are actors. As such, lazy values can be evaluated
//      through the actor's operator(). Such invocation gives the value's
//      identity. Example:
//
//          cout << val(3)() << val("Hello World")();
//
//      prints out "3 Hello World"
//
///////////////////////////////////////////////////////////////////////////////
template <typename T>
struct value {

    typedef typename boost::remove_reference<T>::type plain_t;

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

    value(plain_t val_)
    :   val(val_) {}

    template <typename TupleT>
    plain_t const
    eval(TupleT const& /*args*/) const
    {
        return val;
    }

    plain_t val;
};

//////////////////////////////////
template <typename T>
inline actor<value<T> > const
val(T v)
{
    return value<T>(v);
}

//////////////////////////////////
template <typename BaseT>
void
val(actor<BaseT> const& v);     //  This is undefined and not allowed.

///////////////////////////////////////////////////////////////////////////
//
//  Arbitrary types T are typically converted to a actor<value<T> >
//  (see as_actor<T> in actor.hpp). A specialization is also provided
//  for arrays. T[N] arrays are converted to actor<value<T const*> >.
//
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct as_actor {

    typedef actor<value<T> > type;
    static type convert(T const& x)
    { return value<T>(x); }
};

//////////////////////////////////
template <typename T, int N>
struct as_actor<T[N]> {

    typedef actor<value<T const*> > type;
    static type convert(T const x[N])
    { return value<T const*>(x); }
};

///////////////////////////////////////////////////////////////////////////////
//
//  variable class
//
//      Lazy variables
//
//      A bound actual parameter may also be held by non-const reference
//      in a variable class for deferred access later when needed. A
//      variable object is mutable, i.e. its referenced variable can be
//      modified. Variable objects are typically created through the
//      var(x) free function which returns a variable<T> with T deduced
//      from the type of x. x is held in the value<T> object by
//      reference.
//
//      Lazy variables are actors. As such, lazy variables can be
//      evaluated through the actor's operator(). Such invocation gives
//      the variables's identity. Example:
//
//          int i = 3;
//          char const* s = "Hello World";
//          cout << var(i)() << var(s)();
//
//      prints out "3 Hello World"
//
//      Another free function const_(x) may also be used. const_(x) creates
//      a variable<T const&> object using a constant reference.
//
///////////////////////////////////////////////////////////////////////////////
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(push)
#pragma warning(disable:4512) //assignment operator could not be generated
#endif

template <typename T>
struct variable {

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

    variable(T& var_)
    :   var(var_) {}

    template <typename TupleT>
    T&
    eval(TupleT const& /*args*/) const
    {
        return var;
    }

    T& var;
};

#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif

//////////////////////////////////
template <typename T>
inline actor<variable<T> > const
var(T& v)
{
    return variable<T>(v);
}

//////////////////////////////////
template <typename T>
inline actor<variable<T const> > const
const_(T const& v)
{
    return variable<T const>(v);
}

//////////////////////////////////
template <typename BaseT>
void
var(actor<BaseT> const& v);     //  This is undefined and not allowed.

//////////////////////////////////
template <typename BaseT>
void
const_(actor<BaseT> const& v);  //  This is undefined and not allowed.

///////////////////////////////////////////////////////////////////////////////
}   //  namespace phoenix

#endif
