/*=============================================================================

    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_FUNCTIONS_HPP

#define PHOENIX_FUNCTIONS_HPP



///////////////////////////////////////////////////////////////////////////////

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

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



///////////////////////////////////////////////////////////////////////////////

namespace phoenix {



///////////////////////////////////////////////////////////////////////////////

//

//  function class

//

//      Lazy functions

//

//      This class provides a mechanism for lazily evaluating functions.

//      Syntactically, a lazy function looks like an ordinary C/C++

//      function. The function call looks the same. However, unlike

//      ordinary functions, the actual function execution is deferred.

//      (see actor.hpp, primitives.hpp and composite.hpp for an

//      overview). For example here are sample factorial function calls:

//

//          factorial(4)

//          factorial(arg1)

//          factorial(arg1 * 6)

//

//      These functions are automatically lazily bound unlike ordinary

//      function pointers or functor objects that need to be explicitly

//      bound through the bind function (see binders.hpp).

//

//      A lazy function works in conjunction with a user defined functor

//      (as usual with a member operator()). Only special forms of

//      functor objects are allowed. This is required to enable true

//      polymorphism (STL style monomorphic functors and function

//      pointers can still be used through the bind facility in

//      binders.hpp).

//

//      This special functor is expected to have a nested template class

//      result<A...TN> (where N is the number of arguments of its

//      member operator()). The nested template class result should have

//      a typedef 'type' that reflects the return type of its member

//      operator(). This is essentially a type computer that answers the

//      metaprogramming question "Given arguments of type A...TN, what

//      will be the operator()'s return type?".

//

//      There is a special case for functors that accept no arguments.

//      Such nullary functors are only required to define a typedef

//      result_type that reflects the return type of its operator().

//

//      Here's an example of a simple functor that computes the

//      factorial of a number:

//

//          struct factorial_impl {

//

//              template <typename Arg>

//              struct result { typedef Arg type; };

//

//              template <typename Arg>

//              Arg operator()(Arg n) const

//              { return (n <= 0) ? 1 : n * this->operator()(n-1); }

//          };

//

//      As can be seen, the functor can be polymorphic. Its arguments

//      and return type are not fixed to a particular type. The example

//      above for example, can handle any type as long as it can carry

//      out the required operations (i.e. <=, * and -).

//

//      We can now declare and instantiate a lazy 'factorial' function:

//

//          function<factorial_impl> factorial;

//

//      Invoking a lazy function 'factorial' does not immediately

//      execute the functor factorial_impl. Instead, a composite (see

//      composite.hpp) object is created and returned to the caller.

//      Example:

//

//          factorial(arg1)

//

//      does nothing more than return a composite. A second function

//      call will invoke the actual factorial function. Example:

//

//          int i = 4;

//          cout << factorial(arg1)(i);

//

//      will print out "24".

//

//      Take note that in certain cases (e.g. for functors with state),

//      an instance may be passed on to the constructor. Example:

//

//          function<factorial_impl> factorial(ftor);

//

//      where ftor is an instance of factorial_impl (this is not

//      necessary in this case since factorial is a simple stateless

//      functor). Take care though when using functors with state

//      because the functors are taken in by value. It is best to keep

//      the data manipulated by a functor outside the functor itself and

//      keep a reference to this data inside the functor. Also, it is

//      best to keep functors as small as possible.

//

///////////////////////////////////////////////////////////////////////////////

template <typename OperationT>

struct function {



    function() : op() {}

    function(OperationT const& op_) : op(op_) {}



    actor<composite<OperationT> >

    operator()() const;



    template <typename A>

    typename impl::make_composite<OperationT, A>::type

    operator()(A const& a) const;



    template <typename A, typename B>

    typename impl::make_composite<OperationT, A, B>::type

    operator()(A const& a, B const& b) const;



    template <typename A, typename B, typename C>

    typename impl::make_composite<OperationT, A, B, C>::type

    operator()(A const& a, B const& b, C const& c) const;



#if PHOENIX_LIMIT > 3



    template <typename A, typename B, typename C, typename D>

    typename impl::make_composite<OperationT, A, B, C, D>::type

    operator()(A const& a, B const& b, C const& c, D const& d) const;



    template <typename A, typename B, typename C, typename D, typename E>

    typename impl::make_composite<

        OperationT, A, B, C, D, E

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e

    ) const;



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f

    ) const;



#if PHOENIX_LIMIT > 6



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g

    ) const;



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h

    ) const;



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H, typename I

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H, I

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h, I const& i

    ) const;



#if PHOENIX_LIMIT > 9



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H, typename I, typename J

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H, I, J

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h, I const& i, J const& j

    ) const;



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H, typename I, typename J,

        typename K

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H, I, J, K

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h, I const& i, J const& j,

        K const& k

    ) const;



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H, typename I, typename J,

        typename K, typename L

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H, I, J, K, L

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h, I const& i, J const& j,

        K const& k, L const& l

    ) const;



#if PHOENIX_LIMIT > 12



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H, typename I, typename J,

        typename K, typename L, typename M

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h, I const& i, J const& j,

        K const& k, L const& l, M const& m

    ) const;



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H, typename I, typename J,

        typename K, typename L, typename M, typename N

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M, N

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h, I const& i, J const& j,

        K const& k, L const& l, M const& m, N const& n

    ) const;



    template <

        typename A, typename B, typename C, typename D, typename E,

        typename F, typename G, typename H, typename I, typename J,

        typename K, typename L, typename M, typename N, typename O

    >

    typename impl::make_composite<

        OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O

    >::type

    operator()(

        A const& a, B const& b, C const& c, D const& d, E const& e,

        F const& f, G const& g, H const& h, I const& i, J const& j,

        K const& k, L const& l, M const& m, N const& n, O const& o

    ) const;



#endif

#endif

#endif

#endif



    OperationT op;

};



///////////////////////////////////////////////////////////////////////////////

//

//  function class implementation

//

///////////////////////////////////////////////////////////////////////////////

template <typename OperationT>

inline actor<composite<OperationT> >

function<OperationT>::operator()() const

{

    return actor<composite<OperationT> >(op);

}



//////////////////////////////////

template <typename OperationT>

template <typename A>

inline typename impl::make_composite<OperationT, A>::type

function<OperationT>::operator()(A const& a) const

{

    typedef typename impl::make_composite<OperationT, A>::composite_type ret_t;

    return ret_t

    (

        op,

        as_actor<A>::convert(a)

    );

}



//////////////////////////////////

template <typename OperationT>

template <typename A, typename B>

inline typename impl::make_composite<OperationT, A, B>::type

function<OperationT>::operator()(A const& a, B const& b) const

{

    typedef 

        typename impl::make_composite<OperationT, A, B>::composite_type 

        ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b)

    );

}



//////////////////////////////////

template <typename OperationT>

template <typename A, typename B, typename C>

inline typename impl::make_composite<OperationT, A, B, C>::type

function<OperationT>::operator()(A const& a, B const& b, C const& c) const

{

    typedef 

        typename impl::make_composite<OperationT, A, B, C>::composite_type

        ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c)

    );

}



#if PHOENIX_LIMIT > 3

//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D

>

inline typename impl::make_composite<

    OperationT, A, B, C, D

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E

        >::composite_type ret_t;



    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F

        >::composite_type ret_t;



    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f)

    );

}



#if PHOENIX_LIMIT > 6



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G

        >::composite_type ret_t;



    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H, typename I

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H, I

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h, I const& i

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H, I

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h),

        as_actor<I>::convert(i)

    );

}



#if PHOENIX_LIMIT > 9



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H, typename I, typename J

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H, I, J

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h, I const& i, J const& j

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H, I, J

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h),

        as_actor<I>::convert(i),

        as_actor<J>::convert(j)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H, typename I, typename J,

    typename K

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H, I, J, K

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h, I const& i, J const& j,

    K const& k

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H, I, J, K

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h),

        as_actor<I>::convert(i),

        as_actor<J>::convert(j),

        as_actor<K>::convert(k)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H, typename I, typename J,

    typename K, typename L

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H, I, J, K, L

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h, I const& i, J const& j,

    K const& k, L const& l

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H, I, J, K, L

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h),

        as_actor<I>::convert(i),

        as_actor<J>::convert(j),

        as_actor<K>::convert(k),

        as_actor<L>::convert(l)

    );

}



#if PHOENIX_LIMIT > 12



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H, typename I, typename J,

    typename K, typename L, typename M

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h, I const& i, J const& j,

    K const& k, L const& l, M const& m

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h),

        as_actor<I>::convert(i),

        as_actor<J>::convert(j),

        as_actor<K>::convert(k),

        as_actor<L>::convert(l),

        as_actor<M>::convert(m)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H, typename I, typename J,

    typename K, typename L, typename M, typename N

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M, N

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h, I const& i, J const& j,

    K const& k, L const& l, M const& m, N const& n

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M, N

        >::composite_type ret_t;



    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h),

        as_actor<I>::convert(i),

        as_actor<J>::convert(j),

        as_actor<K>::convert(k),

        as_actor<L>::convert(l),

        as_actor<M>::convert(m),

        as_actor<N>::convert(n)

    );

}



//////////////////////////////////

template <typename OperationT>

template <

    typename A, typename B, typename C, typename D, typename E,

    typename F, typename G, typename H, typename I, typename J,

    typename K, typename L, typename M, typename N, typename O

>

inline typename impl::make_composite<

    OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O

>::type

function<OperationT>::operator()(

    A const& a, B const& b, C const& c, D const& d, E const& e,

    F const& f, G const& g, H const& h, I const& i, J const& j,

    K const& k, L const& l, M const& m, N const& n, O const& o

) const

{

    typedef typename impl::make_composite<

            OperationT, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O

        >::composite_type ret_t;

        

    return ret_t(

        op,

        as_actor<A>::convert(a),

        as_actor<B>::convert(b),

        as_actor<C>::convert(c),

        as_actor<D>::convert(d),

        as_actor<E>::convert(e),

        as_actor<F>::convert(f),

        as_actor<G>::convert(g),

        as_actor<H>::convert(h),

        as_actor<I>::convert(i),

        as_actor<J>::convert(j),

        as_actor<K>::convert(k),

        as_actor<L>::convert(l),

        as_actor<M>::convert(m),

        as_actor<N>::convert(n),

        as_actor<O>::convert(o)

    );

}



#endif

#endif

#endif

#endif



///////////////////////////////////////////////////////////////////////////////

}   //  namespace phoenix



#endif

