/*
    This file is part of GNU APL, a free implementation of the
    ISO/IEC Standard 13751, "Programming Language APL, Extended"

    Copyright (C) 2008-2013  Dr. Jürgen Sauermann

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __SCALAR_FUNCTION_HH_DEFINED__
#define __SCALAR_FUNCTION_HH_DEFINED__

#include <semaphore.h>

#include "PrimitiveFunction.hh"
#include "Value.icc"
#include "Id.hh"

typedef ErrorCode (Cell::*prim_f1)(Cell *) const;
typedef ErrorCode (Cell::*prim_f2)(Cell *, const Cell *) const;

//-----------------------------------------------------------------------------
/** Base class for scalar functions (functions whose monadic and/or dyadic
    version are scalar.
 */
class ScalarFunction : public PrimitiveFunction
{
public:
   /// Construct a ScalarFunction with \b Id \b id in
   ScalarFunction(TokenTag tag) : PrimitiveFunction(tag) {}

   /// Evaluate a scalar function monadically.
   Token eval_scalar_B(Value_P B, prim_f1 fun);

   /// Evaluate a scalar function dyadically.
   Token eval_scalar_AB(Value_P A, Value_P B, prim_f2 fun);

   /// Evaluate a scalar function dyadically with axis.
   Token eval_scalar_AXB(Value_P A, Value_P X, Value_P B, prim_f2 fun);

   /// Overloaded Function::eval_fill_AB()
   virtual Token eval_fill_AB(Value_P A, Value_P B);

   /// Overloaded Function::eval_fill_B()
   virtual Token eval_fill_B(Value_P B);

   /// Overloaded Function::has_result()
   virtual bool has_result() const   { return true; }

protected:
   /// Apply a function to a nested sub array.
   void expand_pointers(Cell * cell_Z, const Cell * cell_A,
                        const Cell * cell_B, prim_f2 fun);

   /// A helper function for eval_scalar_AXB().
   Token eval_scalar_AXB(Value_P A, bool * axis_present,
                         Value_P B, prim_f2 fun, bool reversed);

   /// Evaluate \b the identity function.
   Token eval_scalar_identity_fun(Value_P B, Axis axis, Value_P FI0);

   /// a helper struct for a non-recursive implementation of
   /// monaadic scalar functions with nested values.
   struct Worklist_item1
      {
        ShapeItem len_Z;   ///< the number of result cells
        Cell * cZ;         ///< result
        const Cell * cB;   ///< right argument

        /// return B[z]
        const Cell & B_at(ShapeItem z) const   { return cB[z]; }

        /// return Z[z]
        Cell & Z_at(ShapeItem z) const   { return cZ[z]; }
      };

   /// a helper struct for a non-recursive implementation of
   /// dyadic scalar functions with nested values.
   struct Worklist_item2
      {
        ShapeItem len_Z;   ///< the number of result cells
        Cell * cZ;         ///< result
        const Cell * cA;   ///< left argument
        int inc_A;         ///< 0 (for scalar A) or 1
        const Cell * cB;   ///< right argument
        int inc_B;         ///< 0 (for scalar B) or 1

        /// return A[z]
        const Cell & A_at(ShapeItem z) const   { return cA[z * inc_A]; }

        /// return B[z]
        const Cell & B_at(ShapeItem z) const   { return cB[z * inc_B]; }

        /// return Z[z]
        Cell & Z_at(ShapeItem z) const         { return cZ[z]; }
      };

   /// a list of worklist_1_item or worklist_2_item
   template<typename itype>
   struct Worklist
      {
        Worklist()
           {
             sem_init(&todo_sema,      /* shared */ 0, /* value */ 1);
             sem_init(&new_value_sema, /* shared */ 0, /* value */ 1);
           }
        vector<itype> todo;            ///< computations to be done
        sem_t         todo_sema;       ///< protection for todo
        sem_t         new_value_sema;  ///< protection for Value() constructors
      };

};
//-----------------------------------------------------------------------------
/** Scalar functions binomial and factorial.
 */
class Bif_F12_BINOM : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_BINOM() : ScalarFunction(TOK_F12_BINOM) {}

   static Bif_F12_BINOM     fun;       ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_factorial); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_binomial); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_binomial); }
};
//-----------------------------------------------------------------------------
/** Scalar function less than.
 */
class Bif_F2_LESS : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_LESS() : ScalarFunction(TOK_F2_LESS) {}

   static Bif_F2_LESS       fun;         ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_less_than); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(0, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_less_than); }
};
//-----------------------------------------------------------------------------
/** Scalar function equal.
 */
class Bif_F2_EQUAL : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_EQUAL() : ScalarFunction(TOK_F2_EQUAL) {}

   static Bif_F2_EQUAL      fun;        ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_equal); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_equal); }
};
//-----------------------------------------------------------------------------
/** Scalar function greater than.
 */
class Bif_F2_GREATER : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_GREATER() : ScalarFunction(TOK_F2_GREATER) {}

   static Bif_F2_GREATER    fun;      ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_greater_than); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(0, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_greater_than); }
};
//-----------------------------------------------------------------------------
/** Scalar function and.
 */
class Bif_F2_AND : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_AND() : ScalarFunction(TOK_F2_AND) {}

   static Bif_F2_AND        fun;          ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_and); }

   /// return the associative cell function of this function
   virtual assoc_f2 get_assoc() const { return &Cell::bif_and; }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_and); }
};
//-----------------------------------------------------------------------------
/** Scalar function or.
 */
class Bif_F2_OR : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_OR() : ScalarFunction(TOK_F2_OR) {}

   static Bif_F2_OR         fun;           ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_or); }

   /// return the associative cell function of this function
   virtual assoc_f2 get_assoc() const { return &Cell::bif_or; }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(0, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_or); }
};
//-----------------------------------------------------------------------------
/** Scalar function less or equal.
 */
class Bif_F2_LEQ : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_LEQ() : ScalarFunction(TOK_F2_LEQ) {}

   static Bif_F2_LEQ        fun;          ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_less_eq); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_less_eq); }
};
//-----------------------------------------------------------------------------
/** Scalar function equal.
 */
class Bif_F2_MEQ : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_MEQ() : ScalarFunction(TOK_F2_MEQ) {}

   static Bif_F2_MEQ        fun;          ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_greater_eq); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_greater_eq); }
};
//-----------------------------------------------------------------------------
/** Scalar function not equal
 */
class Bif_F2_UNEQ : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_UNEQ() : ScalarFunction(TOK_F2_UNEQ) {}

   static Bif_F2_UNEQ       fun;         ///< Built-in function.

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_not_equal); }

protected:
   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(0, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_not_equal); }
};
//-----------------------------------------------------------------------------
/** Scalar function find.
 */
class Bif_F2_FIND : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_FIND() : ScalarFunction(TOK_F2_FIND) {}

   static Bif_F2_FIND       fun;         ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B);

   /// Return true iff A is contained in B.
   static bool contained(const Shape & shape_A, const Cell * cA,
                         Value_P B, const Shape & idx_B, double qct);
};
//-----------------------------------------------------------------------------
/** Scalar function nor.
 */
class Bif_F2_NOR : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_NOR() : ScalarFunction(TOK_F2_NOR) {}

   static Bif_F2_NOR        fun;          ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_nor); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_nor); }
};
//-----------------------------------------------------------------------------
/** Scalar function nand.
 */
class Bif_F2_NAND : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F2_NAND() : ScalarFunction(TOK_F2_NAND) {}

   static Bif_F2_NAND       fun;         ///< Built-in function.

protected:
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_nand); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_nand); }
};
//-----------------------------------------------------------------------------
/** Scalar functions power and exponential.
 */
class Bif_F12_POWER : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_POWER() : ScalarFunction(TOK_F12_POWER) {}

   static Bif_F12_POWER     fun;       ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_exponential); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_power); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_power); }
};
//-----------------------------------------------------------------------------
/** Scalar functions add and conjugate.
 */
class Bif_F12_PLUS : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_PLUS() : ScalarFunction(TOK_F12_PLUS) {}

   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_conjugate); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_add); }

   /// return the associative cell function of this function
   virtual assoc_f2 get_assoc() const { return &Cell::bif_add; }

   static Bif_F12_PLUS      fun;        ///< Built-in function.

protected:
   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(0, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_add); }
};
//-----------------------------------------------------------------------------
/** Scalar functions subtrct and negative.
 */
class Bif_F12_MINUS : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_MINUS() : ScalarFunction(TOK_F12_MINUS) {}

   static Bif_F12_MINUS     fun;       ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_negative); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_subtract); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(0, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_subtract); }
};
//-----------------------------------------------------------------------------
/** Scalar function roll and non-scalar function dial.
 */
class Bif_F12_ROLL : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_ROLL() : ScalarFunction(TOK_F12_ROLL) {}

   static Bif_F12_ROLL      fun;        ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B);

   /// dial A from B.
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B);

   /// recursively check that all ravel elements of B are integers ≥ 0 and
   /// return \b true iff not.
   static bool check_B(const Value & B, const APL_Float qct);
};
//-----------------------------------------------------------------------------
/** Scalar function not and non-scalar function without.
 */
class Bif_F12_WITHOUT : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_WITHOUT() : ScalarFunction(TOK_F12_WITHOUT) {}

   static Bif_F12_WITHOUT   fun;     ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_not); }

   /// Compute A without B.
   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B);
};
//-----------------------------------------------------------------------------
/** Scalar functions times and direction.
 */
class Bif_F12_TIMES : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_TIMES() : ScalarFunction(TOK_F12_TIMES) {}

   static Bif_F12_TIMES     fun;       ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_direction); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_multiply); }

   /// return the associative cell function of this function
   virtual assoc_f2 get_assoc() const { return &Cell::bif_multiply; }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_multiply); }
};
//-----------------------------------------------------------------------------
/** Scalar functions divide and reciprocal.
 */
class Bif_F12_DIVIDE : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_DIVIDE() : ScalarFunction(TOK_F12_DIVIDE) {}

   static Bif_F12_DIVIDE    fun;      ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_reciprocal); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_divide); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, IntScalar(1, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_divide); }
};
//-----------------------------------------------------------------------------
/** Scalar functions circle functions and pi times.
 */
class Bif_F12_CIRCLE : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_CIRCLE() : ScalarFunction(TOK_F12_CIRCLE) {}

   static Bif_F12_CIRCLE    fun;      ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_pi_times); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_circle_fun); }
};
//-----------------------------------------------------------------------------
/** Scalar functions minimum and round up.
 */
class Bif_F12_RND_UP : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_RND_UP() : ScalarFunction(TOK_F12_RND_UP) {}

   static Bif_F12_RND_UP    fun;      ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_ceiling); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_maximum); }

   /// return the associative cell function of this function
   virtual assoc_f2 get_assoc() const { return &Cell::bif_maximum; }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, FloatScalar(-BIG_FLOAT, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_maximum); }
};
//-----------------------------------------------------------------------------
/** Scalar functions maximum and round down.
 */
class Bif_F12_RND_DN : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_RND_DN() : ScalarFunction(TOK_F12_RND_DN) {}

   static Bif_F12_RND_DN    fun;      ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_floor); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_minimum); }

   /// return the associative cell function of this function
   virtual assoc_f2 get_assoc() const { return &Cell::bif_minimum; }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
      { return eval_scalar_identity_fun(B, axis, FloatScalar(BIG_FLOAT, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_minimum); }
};
//-----------------------------------------------------------------------------
/** Scalar functions residue and magnitude.
 */
class Bif_F12_STILE : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_STILE() : ScalarFunction(TOK_F12_STILE) {}

   static Bif_F12_STILE     fun;       ///< Built-in function.

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_residue); }

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_magnitude); }

   /// Overloaded Function::eval_identity_fun();
   virtual Token eval_identity_fun(Value_P B, Axis axis)
   { return eval_scalar_identity_fun(B, axis, IntScalar(0, LOC)); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_residue); }
};
//-----------------------------------------------------------------------------
/** Scalar functions logarithms.
 */
class Bif_F12_LOGA : public ScalarFunction
{
public:
   /// Constructor.
   Bif_F12_LOGA() : ScalarFunction(TOK_F12_LOGA) {}

   static Bif_F12_LOGA      fun;        ///< Built-in function.

protected:
   /// Overloaded Function::eval_B().
   virtual Token eval_B(Value_P B)
      { return eval_scalar_B(B, &Cell::bif_nat_log); }

   /// Overloaded Function::eval_AB().
   virtual Token eval_AB(Value_P A, Value_P B)
      { return eval_scalar_AB(A, B, &Cell::bif_logarithm); }

   /// Overloaded Function::eval_AXB().
   virtual Token eval_AXB(Value_P A, Value_P X, Value_P B)
      { return eval_scalar_AXB(A, X, B, &Cell::bif_logarithm); }
};
//-----------------------------------------------------------------------------

#endif // __SCALAR_FUNCTION_HH_DEFINED__
