/****************************************************************************
**
*W  calls.h                     GAP source                   Martin Schönert
**
**
*Y  Copyright (C)  1996,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
*Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
*Y  Copyright (C) 2002 The GAP Group
**
**  This file  declares the functions of the  generic function call mechanism
**  package.
**
**  This package defines the *call mechanism* through which one GAP function,
**  named the *caller*, can temporarily transfer control to another function,
**  named the *callee*.
**
**  There are *compiled functions* and  *interpreted functions*.  Thus  there
**  are four possible pairings of caller and callee.
**
**  If the caller is compiled,  then the call comes directly from the caller.
**  If it  is interpreted, then   the call comes  from one  of the  functions
**  'EvalFunccall<i>args' that implement evaluation of function calls.
**
**  If the callee is compiled,  then the call goes  directly  to the  callee.
**  If   it is interpreted,   then the  call   goes to one  of  the  handlers
**  'DoExecFunc<i>args' that implement execution of function bodies.
**
**  The call mechanism makes it in any case unneccessary for the calling code
**  to  know  whether the callee  is  a compiled or  an interpreted function.
**  Likewise the called code need not know, actually cannot know, whether the
**  caller is a compiled or an interpreted function.
**
**  Also the call mechanism checks that the number of arguments passed by the
**  caller is the same as the number of arguments  expected by the callee, or
**  it  collects the arguments   in a list  if  the callee allows  a variable
**  number of arguments.
**
**  Finally the call mechanism profiles all functions if requested.
**
**  All this has very little overhead.  In the  case of one compiled function
**  calling  another compiled function, which expects fewer than 4 arguments,
**  with no profiling, the overhead is only a couple of instructions.
*/

#ifndef libGAP_GAP_CALLS_H
#define libGAP_GAP_CALLS_H


/****************************************************************************
**

*T  ObjFunc . . . . . . . . . . . . . . . . type of function returning object
**
**  'ObjFunc' is the type of a function returning an object.
*/
typedef libGAP_Obj (* libGAP_ObjFunc) (/*arguments*/);

typedef libGAP_Obj (* libGAP_ObjFunc_0ARGS) (libGAP_Obj self);
typedef libGAP_Obj (* libGAP_ObjFunc_1ARGS) (libGAP_Obj self, libGAP_Obj a1);
typedef libGAP_Obj (* libGAP_ObjFunc_2ARGS) (libGAP_Obj self, libGAP_Obj a1, libGAP_Obj a2);
typedef libGAP_Obj (* libGAP_ObjFunc_3ARGS) (libGAP_Obj self, libGAP_Obj a1, libGAP_Obj a2, libGAP_Obj a3);
typedef libGAP_Obj (* libGAP_ObjFunc_4ARGS) (libGAP_Obj self, libGAP_Obj a1, libGAP_Obj a2, libGAP_Obj a3, libGAP_Obj a4);
typedef libGAP_Obj (* libGAP_ObjFunc_5ARGS) (libGAP_Obj self, libGAP_Obj a1, libGAP_Obj a2, libGAP_Obj a3, libGAP_Obj a4, libGAP_Obj a5);
typedef libGAP_Obj (* libGAP_ObjFunc_6ARGS) (libGAP_Obj self, libGAP_Obj a1, libGAP_Obj a2, libGAP_Obj a3, libGAP_Obj a4, libGAP_Obj a5, libGAP_Obj a6);


/****************************************************************************
**
*F  HDLR_FUNC(<func>,<i>) . . . . . . . . . <i>-th call handler of a function
*F  NAME_FUNC(<func>) . . . . . . . . . . . . . . . . . .  name of a function
*F  NARG_FUNC(<func>) . . . . . . . . . . . number of arguments of a function
*F  NAMS_FUNC(<func>) . . . . . . . .  names of local variables of a function
*F  NAMI_FUNC(<func>) . . . . . . name of <i>-th local variable of a function
*F  PROF_FUNC(<func>) . . . . . . . . profiling information bag of a function
*F  NLOC_FUNC(<func>) . . . . . . . . . . . .  number of locals of a function
*F  BODY_FUNC(<func>) . . . . . . . . . . . . . . . . . .  body of a function
*F  ENVI_FUNC(<func>) . . . . . . . . . . . . . . . environment of a function
*F  FEXS_FUNC(<func>) . . . . . . . . . . . .  func. expr. list of a function
*V  SIZE_FUNC . . . . . . . . . . . . . . . . . size of the bag of a function
**
**  These macros  make it possible  to access  the  various components  of  a
**  function.
**
**  'HDLR_FUNC(<func>,<i>)' is the <i>-th handler of the function <func>.
**
**  'NAME_FUNC(<func>)' is the name of the function.
**
**  'NARG_FUNC(<func>)' is the number of arguments (-1  if  <func>  accepts a
**  variable number of arguments).
**
**  'NAMS_FUNC(<func>)'  is the list of the names of the local variables,
**
**  'NAMI_FUNC(<func>,<i>)' is the name of the <i>-th local variable.
**
**  'PROF_FUNC(<func>)' is the profiling information bag.
**
**  'NLOC_FUNC(<func>)' is the number of local variables of  the  interpreted
**  function <func>.
**
**  'BODY_FUNC(<func>)' is the body.
**
**  'ENVI_FUNC(<func>)'  is the  environment  (i.e., the local  variables bag
**  that was current when <func> was created).
**
**  'FEXS_FUNC(<func>)'  is the function expressions list (i.e., the list of
**  the function expressions of the functions defined inside of <func>).
**
*/
#define libGAP_HDLR_FUNC(func,i)       (* (libGAP_ObjFunc*) (libGAP_ADDR_OBJ(func) + 0 +(i)) )
#define libGAP_NAME_FUNC(func)         (*            (libGAP_ADDR_OBJ(func) + 8     ) )
#define libGAP_NARG_FUNC(func)         (* (libGAP_Int*)     (libGAP_ADDR_OBJ(func) + 9     ) )
#define libGAP_NAMS_FUNC(func)         (*            (libGAP_ADDR_OBJ(func) +10     ) )
#define libGAP_NAMI_FUNC(func,i)       ((libGAP_Char *)libGAP_CHARS_STRING(libGAP_ELM_LIST(libGAP_NAMS_FUNC(func),i)))
#define libGAP_PROF_FUNC(func)         (*            (libGAP_ADDR_OBJ(func) +11     ) )
#define libGAP_NLOC_FUNC(func)         (* (libGAP_UInt*)    (libGAP_ADDR_OBJ(func) +12     ) )
#define libGAP_BODY_FUNC(func)         (*            (libGAP_ADDR_OBJ(func) +13     ) )
#define libGAP_ENVI_FUNC(func)         (*            (libGAP_ADDR_OBJ(func) +14     ) )
#define libGAP_FEXS_FUNC(func)         (*            (libGAP_ADDR_OBJ(func) +15     ) )
#define libGAP_SIZE_FUNC               (16*sizeof(libGAP_Bag))

#define libGAP_HDLR_0ARGS(func)        ((libGAP_ObjFunc_0ARGS)libGAP_HDLR_FUNC(func,0))
#define libGAP_HDLR_1ARGS(func)        ((libGAP_ObjFunc_1ARGS)libGAP_HDLR_FUNC(func,1))
#define libGAP_HDLR_2ARGS(func)        ((libGAP_ObjFunc_2ARGS)libGAP_HDLR_FUNC(func,2))
#define libGAP_HDLR_3ARGS(func)        ((libGAP_ObjFunc_3ARGS)libGAP_HDLR_FUNC(func,3))
#define libGAP_HDLR_4ARGS(func)        ((libGAP_ObjFunc_4ARGS)libGAP_HDLR_FUNC(func,4))
#define libGAP_HDLR_5ARGS(func)        ((libGAP_ObjFunc_5ARGS)libGAP_HDLR_FUNC(func,5))
#define libGAP_HDLR_6ARGS(func)        ((libGAP_ObjFunc_6ARGS)libGAP_HDLR_FUNC(func,6))
#define libGAP_HDLR_XARGS(func)        ((libGAP_ObjFunc_1ARGS)libGAP_HDLR_FUNC(func,7))

extern libGAP_Obj libGAP_NargError(libGAP_Obj func, libGAP_Int actual);

/****************************************************************************
**
*F  IS_FUNC( <obj> )  . . . . . . . . . . . . . check if object is a function
*/
#define libGAP_IS_FUNC(obj)    (libGAP_TNUM_OBJ(obj) == libGAP_T_FUNCTION)


/****************************************************************************
**

*F  CALL_0ARGS(<func>)  . . . . . . . . . call a function with 0    arguments
*F  CALL_1ARGS(<func>,<arg1>) . . . . . . call a function with 1    arguments
*F  CALL_2ARGS(<func>,<arg1>...)  . . . . call a function with 2    arguments
*F  CALL_3ARGS(<func>,<arg1>...)  . . . . call a function with 3    arguments
*F  CALL_4ARGS(<func>,<arg1>...)  . . . . call a function with 4    arguments
*F  CALL_5ARGS(<func>,<arg1>...)  . . . . call a function with 5    arguments
*F  CALL_6ARGS(<func>,<arg1>...)  . . . . call a function with 6    arguments
*F  CALL_XARGS(<func>,<args>) . . . . . . call a function with more arguments
**
**  'CALL_<i>ARGS' passes control  to  the function  <func>, which must  be a
**  function object  ('T_FUNCTION').  It returns the  return value of <func>.
**  'CALL_0ARGS' is for calls passing   no arguments, 'CALL_1ARGS' for  calls
**  passing one argument, and so on.   'CALL_XARGS' is for calls passing more
**  than 5 arguments, where the arguments must be collected  in a plain list,
**  and this plain list must then be passed.
**
**  'CALL_<i>ARGS' can be used independently  of whether the called  function
**  is a compiled   or interpreted function.    It checks that the number  of
**  passed arguments is the same  as the number of  arguments expected by the
**  callee,  or it collects the  arguments in a list  if  the callee allows a
**  variable number of arguments.
*/
#define libGAP_CALL_0ARGS(f)                     libGAP_HDLR_0ARGS(f)(f)
#define libGAP_CALL_1ARGS(f,a1)                  libGAP_HDLR_1ARGS(f)(f,a1)
#define libGAP_CALL_2ARGS(f,a1,a2)               libGAP_HDLR_2ARGS(f)(f,a1,a2)
#define libGAP_CALL_3ARGS(f,a1,a2,a3)            libGAP_HDLR_3ARGS(f)(f,a1,a2,a3)
#define libGAP_CALL_4ARGS(f,a1,a2,a3,a4)         libGAP_HDLR_4ARGS(f)(f,a1,a2,a3,a4)
#define libGAP_CALL_5ARGS(f,a1,a2,a3,a4,a5)      libGAP_HDLR_5ARGS(f)(f,a1,a2,a3,a4,a5)
#define libGAP_CALL_6ARGS(f,a1,a2,a3,a4,a5,a6)   libGAP_HDLR_6ARGS(f)(f,a1,a2,a3,a4,a5,a6)
#define libGAP_CALL_XARGS(f,as)                  libGAP_HDLR_XARGS(f)(f,as)


/****************************************************************************
**

*F  CALL_0ARGS_PROF( <func>, <arg1> ) . . . . .  call a prof func with 0 args
*F  CALL_1ARGS_PROF( <func>, <arg1>, ... )  . .  call a prof func with 1 args
*F  CALL_2ARGS_PROF( <func>, <arg1>, ... )  . .  call a prof func with 2 args
*F  CALL_3ARGS_PROF( <func>, <arg1>, ... )  . .  call a prof func with 3 args
*F  CALL_4ARGS_PROF( <func>, <arg1>, ... )  . .  call a prof func with 4 args
*F  CALL_5ARGS_PROF( <func>, <arg1>, ... )  . .  call a prof func with 5 args
*F  CALL_6ARGS_PROF( <func>, <arg1>, ... )  . .  call a prof func with 6 args
*F  CALL_XARGS_PROF( <func>, <arg1>, ... )  . .  call a prof func with X args
**
**  'CALL_<i>ARGS_PROF' is used   in the profile  handler 'DoProf<i>args'  to
**  call  the  real  handler  stored  in the   profiling  information of  the
**  function.
*/
#define libGAP_CALL_0ARGS_PROF(f) \
        libGAP_HDLR_0ARGS(libGAP_PROF_FUNC(f))(f)

#define libGAP_CALL_1ARGS_PROF(f,a1) \
        libGAP_HDLR_1ARGS(libGAP_PROF_FUNC(f))(f,a1)

#define libGAP_CALL_2ARGS_PROF(f,a1,a2) \
        libGAP_HDLR_2ARGS(libGAP_PROF_FUNC(f))(f,a1,a2)

#define libGAP_CALL_3ARGS_PROF(f,a1,a2,a3) \
        libGAP_HDLR_3ARGS(libGAP_PROF_FUNC(f))(f,a1,a2,a3)

#define libGAP_CALL_4ARGS_PROF(f,a1,a2,a3,a4) \
        libGAP_HDLR_4ARGS(libGAP_PROF_FUNC(f))(f,a1,a2,a3,a4)

#define libGAP_CALL_5ARGS_PROF(f,a1,a2,a3,a4,a5) \
        libGAP_HDLR_5ARGS(libGAP_PROF_FUNC(f))(f,a1,a2,a3,a4,a5)

#define libGAP_CALL_6ARGS_PROF(f,a1,a2,a3,a4,a5,a6) \
        libGAP_HDLR_6ARGS(libGAP_PROF_FUNC(f))(f,a1,a2,a3,a4,a5,a6)

#define libGAP_CALL_XARGS_PROF(f,as) \
        libGAP_HDLR_XARGS(libGAP_PROF_FUNC(f))(f,as)


/****************************************************************************
**

*F  COUNT_PROF( <prof> )  . . . . . . . . number of invocations of a function
*F  TIME_WITH_PROF( <prof> )  . . . . . . time with    children in a function
*F  TIME_WOUT_PROF( <prof> )  . . . . . . time without children in a function
*F  STOR_WITH_PROF( <prof> )  . . . .  storage with    children in a function
*F  STOR_WOUT_PROF( <prof> )  . . . .  storage without children in a function
*V  LEN_PROF  . . . . . . . . . . .  length of a profiling bag for a function
**
**  With each  function we associate two  time measurements.  First the *time
**  spent by this  function without its  children*, i.e., the amount  of time
**  during which this  function was active.   Second the *time  spent by this
**  function with its  children*, i.e., the amount  of time during which this
**  function was either active or suspended.
**
**  Likewise with each  function  we associate the two  storage measurements,
**  the storage spent by  this function without its  children and the storage
**  spent by this function with its children.
**
**  These  macros  make it possible to  access   the various components  of a
**  profiling information bag <prof> for a function <func>.
**
**  'COUNT_PROF(<prof>)' is the  number  of  calls  to the  function  <func>.
**  'TIME_WITH_PROF(<prof>) is  the time spent  while the function <func> was
**  either  active or suspended.   'TIME_WOUT_PROF(<prof>)' is the time spent
**  while the function <func>   was active.  'STOR_WITH_PROF(<prof>)'  is the
**  amount of  storage  allocated while  the  function  <func>  was active or
**  suspended.  'STOR_WOUT_PROF(<prof>)' is  the amount  of storage allocated
**  while the  function <func> was   active.  'LEN_PROF' is   the length of a
**  profiling information bag.
*/
#define libGAP_COUNT_PROF(prof)            (libGAP_INT_INTOBJ(libGAP_ELM_PLIST(prof,1)))
#define libGAP_TIME_WITH_PROF(prof)        (libGAP_INT_INTOBJ(libGAP_ELM_PLIST(prof,2)))
#define libGAP_TIME_WOUT_PROF(prof)        (libGAP_INT_INTOBJ(libGAP_ELM_PLIST(prof,3)))
#define libGAP_STOR_WITH_PROF(prof)        (libGAP_INT_INTOBJ(libGAP_ELM_PLIST(prof,4)))
#define libGAP_STOR_WOUT_PROF(prof)        (libGAP_INT_INTOBJ(libGAP_ELM_PLIST(prof,5)))

#define libGAP_SET_COUNT_PROF(prof,n)      libGAP_SET_ELM_PLIST(prof,1,libGAP_INTOBJ_INT(n))
#define libGAP_SET_TIME_WITH_PROF(prof,n)  libGAP_SET_ELM_PLIST(prof,2,libGAP_INTOBJ_INT(n))
#define libGAP_SET_TIME_WOUT_PROF(prof,n)  libGAP_SET_ELM_PLIST(prof,3,libGAP_INTOBJ_INT(n))
#define libGAP_SET_STOR_WITH_PROF(prof,n)  libGAP_SET_ELM_PLIST(prof,4,libGAP_INTOBJ_INT(n))
#define libGAP_SET_STOR_WOUT_PROF(prof,n)  libGAP_SET_ELM_PLIST(prof,5,libGAP_INTOBJ_INT(n))

#define libGAP_LEN_PROF                    5


/****************************************************************************
**

*F  FuncFILENAME_FUNC(Obj self, Obj func) . . . . . . .  filename of function
*F  FuncSTARTLINE_FUNC(Obj self, Obj func)  . . . . .  start line of function
*F  FuncENDLINE_FUNC(Obj self, Obj func)  . . . . . . .  end line of function
**
**  These functions, usually exported to GAP, get information about GAP
**  functions */
libGAP_Obj libGAP_FuncFILENAME_FUNC(libGAP_Obj self, libGAP_Obj func);
libGAP_Obj libGAP_FuncSTARTLINE_FUNC(libGAP_Obj self, libGAP_Obj func);
libGAP_Obj libGAP_FuncENDLINE_FUNC(libGAP_Obj self, libGAP_Obj func);

/****************************************************************************
**

*F * * * * * * * * * * * * *  create a new function * * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  InitHandlerFunc( <handler>, <cookie> ) . . . . . . . . register a handler
**
**  Every handler should  be registered (once) before  it is installed in any
**  function bag. This is needed so that it can be  identified when loading a
**  saved workspace.  <cookie> should be a  unique  C string, identifying the
**  handler
*/

extern void libGAP_InitHandlerRegistration( void );

extern void libGAP_InitHandlerFunc (
     libGAP_ObjFunc            hdlr,
     const libGAP_Char *       cookie );

extern const libGAP_Char * libGAP_CookieOfHandler(
     libGAP_ObjFunc            hdlr );

extern libGAP_ObjFunc libGAP_HandlerOfCookie (
     const libGAP_Char *       cookie );

extern void libGAP_SortHandlers( libGAP_UInt byWhat );

/****************************************************************************
**
*F  NewFunction( <name>, <narg>, <nams>, <hdlr> )  . . .  make a new function
*F  NewFunctionC( <name>, <narg>, <nams>, <hdlr> ) . . .  make a new function
*F  NewFunctionT( <type>, <size>, <name>, <narg>, <nams>, <hdlr> )
*F  NewFunctionCT( <type>, <size>, <name>, <narg>, <nams>, <hdlr> )
**
**  'NewFunction' creates and returns a new function.  <name> must be  a  GAP
**  string containing the name of the function.  <narg> must be the number of
**  arguments, where -1 means a variable number of arguments.  <nams> must be
**  a GAP list containg the names  of  the  arguments.  <hdlr>  must  be  the
**  C function (accepting <self> and  the  <narg>  arguments)  that  will  be
**  called to execute the function.
**
**  'NewFunctionC' does the same as 'NewFunction',  but  expects  <name>  and
**  <nams> as C strings.
**
**  'NewFunctionT' does the same as 'NewFunction', but allows to specify  the
**  <type> and <size> of the newly created bag.
**
**  'NewFunctionCT' does the same as 'NewFunction', but  expects  <name>  and
**  <nams> as C strings, and allows to specify the <type> and <size>  of  the
**  newly created bag.
*/
extern libGAP_Obj libGAP_NewFunction (
            libGAP_Obj                 name,
            libGAP_Int                 narg,
            libGAP_Obj                 nams,
            libGAP_ObjFunc             hdlr );
    
extern libGAP_Obj libGAP_NewFunctionC (
            const libGAP_Char *        name,
            libGAP_Int                 narg,
            const libGAP_Char *        nams,
            libGAP_ObjFunc             hdlr );
    
extern libGAP_Obj libGAP_NewFunctionT (
            libGAP_UInt                type,
            libGAP_UInt                size,
            libGAP_Obj                 name,
            libGAP_Int                 narg,
            libGAP_Obj                 nams,
            libGAP_ObjFunc             hdlr );
    
extern libGAP_Obj libGAP_NewFunctionCT (
            libGAP_UInt                type,
            libGAP_UInt                size,
            const libGAP_Char *        name,
            libGAP_Int                 narg,
            const libGAP_Char *        nams,
            libGAP_ObjFunc             hdlr );
    

/****************************************************************************
**
*F  ArgStringToList( <nams_c> )
**
** 'ArgStringToList' takes a C string <nams_c> containing a list of comma
** separated argument names, and turns it into a plist of strings, ready
** to be passed to 'NewFunction' as <nams>.
*/
extern libGAP_Obj libGAP_ArgStringToList(const libGAP_Char *nams_c);


/****************************************************************************
**

*F * * * * * * * * * * * * * type and print function  * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  PrintFunction( <func> )   . . . . . . . . . . . . . . .  print a function
**
**  'PrintFunction' prints  the   function  <func> in  abbreviated  form   if
**  'PrintObjFull' is false.
*/
extern void libGAP_PrintFunction (
    libGAP_Obj                 func );


/****************************************************************************
**
*F  FuncCALL_FUNC_LIST( <self>, <func>, <list> )  . . . . . . call a function
**
**  'FuncCALL_FUNC_LIST' implements the internal function 'CallFuncList'.
**
**  'CallFuncList( <func>, <list> )'
**
**  'CallFuncList' calls the  function <func> with the arguments list <list>,
**  i.e., it is equivalent to '<func>( <list>[1], <list>[2]... )'.
*/

extern libGAP_Obj libGAP_CallFuncList(
			libGAP_Obj func,
			libGAP_Obj list);

extern libGAP_Obj libGAP_CallFuncListOper;

/****************************************************************************
**

*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  InitInfoCalls() . . . . . . . . . . . . . . . . . table of init functions
*/
libGAP_StructInitInfo * libGAP_InitInfoCalls ( void );


#endif // GAP_CALLS_H

/****************************************************************************
**

*E  calls.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
*/
