/****************************************************************************
**
** This file is part of GAP, a system for computational discrete algebra.
**
** Copyright of GAP belongs to its developers, whose names are too numerous
** to list here. Please refer to the COPYRIGHT file for details.
**
** SPDX-License-Identifier: GPL-2.0-or-later
**
** This file contains the functions for the function call mechanism package.
**
** For a description of what the function call mechanism is about see the
** declaration part of this package.
**
** Each function is represented by a function bag (of type 'T_FUNCTION'),
** which has the following format.
**
** +-------+-------+- - - -+-------+
** |handler|handler| |handler| (for all functions)
** | 0 | 1 | | 7 |
** +-------+-------+- - - -+-------+
**
** +-------+-------+-------+-------+
** | name | number| args &| prof- | (for all functions)
** | func. | args | locals| iling |
** +-------+-------+-------+-------+
**
** +-------+-------+-------+-------+
** | number| body | envir-| funcs.| (only for interpreted functions)
** | locals| func. | onment| exprs.|
** +-------+-------+-------+-------+
**
** ...what the handlers are..
** ...what the other components are...
*/
#include "calls.h"
#include "bool.h"
#include "code.h"
#include "error.h"
#ifdef USE_GASMAN
#include "gasman_intern.h"
#endif
#include "gaptime.h"
#include "gvars.h"
#include "integer.h"
#include "io.h"
#include "lists.h"
#include "modules.h"
#include "opers.h"
#include "plist.h"
#include "saveload.h"
#include "stats.h"
#include "stringobj.h"
#include "sysstr.h"
#include "vars.h"
#ifdef HPCGAP
#include "hpc/thread.h"
#endif
void SET_NAME_FUNC(Obj func, Obj name)
{
GAP_ASSERT(name == 0 || IS_STRING_REP(name));
FUNC(func)->name = name;
}
Obj NAMI_FUNC(Obj func,
Int i)
{
return ELM_LIST(NAMS_FUNC(func),i);
}
/****************************************************************************
**
*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 COUNT_PROF(prof) (INT_INTOBJ(ELM_PLIST(prof,1)))
#define TIME_WITH_PROF(prof) (INT_INTOBJ(ELM_PLIST(prof,2)))
#define TIME_WOUT_PROF(prof) (INT_INTOBJ(ELM_PLIST(prof,3)))
#define STOR_WITH_PROF(prof) (UInt8_ObjInt(ELM_PLIST(prof,4)))
#define STOR_WOUT_PROF(prof) (UInt8_ObjInt(ELM_PLIST(prof,5)))
#define SET_COUNT_PROF(prof,n) SET_ELM_PLIST(prof,1,INTOBJ_INT(n))
#define SET_TIME_WITH_PROF(prof,n) SET_ELM_PLIST(prof,2,INTOBJ_INT(n))
#define SET_TIME_WOUT_PROF(prof,n) SET_ELM_PLIST(prof,3,INTOBJ_INT(n))
static inline void SET_STOR_WITH_PROF(Obj prof, UInt8 n)
{
SET_ELM_PLIST(prof,4,ObjInt_Int8(n));
CHANGED_BAG(prof);
}
static inline void SET_STOR_WOUT_PROF(Obj prof, UInt8 n)
{
SET_ELM_PLIST(prof,5,ObjInt_Int8(n));
CHANGED_BAG(prof);
}
#define LEN_PROF 5
/****************************************************************************
**
*F * * * * wrapper for functions with variable number of arguments * * * * *
*/
/****************************************************************************
**
*F DoWrap0args( <self> ) . . . . . . . . . . . wrap up 0 arguments in a list
**
** 'DoWrap<i>args' accepts the <i> arguments <arg1>, <arg2>, and so on,
** wraps them up in a list, and then calls <self> again via 'CALL_XARGS',
** passing this list. 'DoWrap<i>args' are the handlers for callees that
** accept a variable number of arguments. Note that there is no
** 'DoWrapXargs' handler, since in this case the function call mechanism
** already requires that the passed arguments are collected in a list.
*/
static Obj DoWrap0args(Obj self)
{
Obj result;
// value of function call, result
Obj args;
// arguments list
// make the arguments list
args = NEW_PLIST( T_PLIST, 0 );
// call the variable number of arguments function
result = CALL_XARGS( self, args );
return result;
}
/****************************************************************************
**
*F DoWrap1args( <self>, <arg1> ) . . . . . . . wrap up 1 argument in a list
*/
static Obj DoWrap1args(Obj self, Obj arg1)
{
Obj result;
// value of function call, result
Obj args;
// arguments list
// make the arguments list
args = NEW_PLIST( T_PLIST, 1 );
SET_LEN_PLIST( args, 1 );
SET_ELM_PLIST( args, 1, arg1 );
// call the variable number of arguments function
result = CALL_XARGS( self, args );
return result;
}
/****************************************************************************
**
*F DoWrap2args( <self>, <arg1>, ... ) . . . . wrap up 2 arguments in a list
*/
static Obj DoWrap2args(Obj self, Obj arg1, Obj arg2)
{
Obj result;
// value of function call, result
Obj args;
// arguments list
// make the arguments list
args = NEW_PLIST( T_PLIST, 2 );
SET_LEN_PLIST( args, 2 );
SET_ELM_PLIST( args, 1, arg1 );
SET_ELM_PLIST( args, 2, arg2 );
// call the variable number of arguments function
result = CALL_XARGS( self, args );
return result;
}
/****************************************************************************
**
*F DoWrap3args( <self>, <arg1>, ... ) . . . . wrap up 3 arguments in a list
*/
static Obj DoWrap3args(Obj self, Obj arg1, Obj arg2, Obj arg3)
{
Obj result;
// value of function call, result
Obj args;
// arguments list
// make the arguments list
args = NEW_PLIST( T_PLIST, 3 );
SET_LEN_PLIST( args, 3 );
SET_ELM_PLIST( args, 1, arg1 );
SET_ELM_PLIST( args, 2, arg2 );
SET_ELM_PLIST( args, 3, arg3 );
// call the variable number of arguments function
result = CALL_XARGS( self, args );
return result;
}
/****************************************************************************
**
*F DoWrap4args( <self>, <arg1>, ... ) . . . . wrap up 4 arguments in a list
*/
static Obj DoWrap4args(Obj self, Obj arg1, Obj arg2, Obj arg3, Obj arg4)
{
Obj result;
// value of function call, result
Obj args;
// arguments list
// make the arguments list
args = NEW_PLIST( T_PLIST, 4 );
SET_LEN_PLIST( args, 4 );
SET_ELM_PLIST( args, 1, arg1 );
SET_ELM_PLIST( args, 2, arg2 );
SET_ELM_PLIST( args, 3, arg3 );
SET_ELM_PLIST( args, 4, arg4 );
// call the variable number of arguments function
result = CALL_XARGS( self, args );
return result;
}
/****************************************************************************
**
*F DoWrap5args( <self>, <arg1>, ... ) . . . . wrap up 5 arguments in a list
*/
static Obj
DoWrap5args(Obj self, Obj arg1, Obj arg2, Obj arg3, Obj arg4, Obj arg5)
{
Obj result;
// value of function call, result
Obj args;
// arguments list
// make the arguments list
args = NEW_PLIST( T_PLIST, 5 );
SET_LEN_PLIST( args, 5 );
SET_ELM_PLIST( args, 1, arg1 );
SET_ELM_PLIST( args, 2, arg2 );
SET_ELM_PLIST( args, 3, arg3 );
SET_ELM_PLIST( args, 4, arg4 );
SET_ELM_PLIST( args, 5, arg5 );
// call the variable number of arguments function
result = CALL_XARGS( self, args );
return result;
}
/****************************************************************************
**
*F DoWrap6args( <self>, <arg1>, ... ) . . . . wrap up 6 arguments in a list
*/
static Obj DoWrap6args(
Obj self, Obj arg1, Obj arg2, Obj arg3, Obj arg4, Obj arg5, Obj arg6)
{
Obj result;
// value of function call, result
Obj args;
// arguments list
// make the arguments list
args = NEW_PLIST( T_PLIST, 6 );
SET_LEN_PLIST( args, 6 );
SET_ELM_PLIST( args, 1, arg1 );
SET_ELM_PLIST( args, 2, arg2 );
SET_ELM_PLIST( args, 3, arg3 );
SET_ELM_PLIST( args, 4, arg4 );
SET_ELM_PLIST( args, 5, arg5 );
SET_ELM_PLIST( args, 6, arg6 );
// call the variable number of arguments function
result = CALL_XARGS( self, args );
return result;
}
/****************************************************************************
**
*F * * wrapper for functions with do not support the number of arguments * *
*/
/****************************************************************************
**
*F DoFail0args( <self> ) . . . . . . fail a function call with 0 arguments
**
** 'DoFail<i>args' accepts the <i> arguments <arg1>, <arg2>, and so on, and
** signals an error, because the function for which they are installed
** expects another number of arguments. 'DoFail<i>args' are the handlers in
** the other slots of a function.
*/
// Pull this out to avoid repetition, since it gets a little more complex in
// the presence of partially variadic functions
NORETURN
static void NargError(Obj func,
Int actual)
{
Int narg = NARG_FUNC(func);
if (narg >= 0) {
assert(narg != actual);
ErrorMayQuitNrArgs(narg, actual);
}
else {
assert(-narg-1 > actual);
ErrorMayQuitNrAtLeastArgs(-narg - 1, actual);
}
}
static Obj DoFail0args(Obj self)
{
NargError(self, 0);
}
/****************************************************************************
**
*F DoFail1args( <self>,<arg1> ) . . . fail a function call with 1 argument
*/
static Obj DoFail1args(Obj self, Obj arg1)
{
NargError(self, 1);
}
/****************************************************************************
**
*F DoFail2args( <self>, <arg1>, ... ) fail a function call with 2 arguments
*/
static Obj DoFail2args(Obj self, Obj arg1, Obj arg2)
{
NargError(self, 2);
}
/****************************************************************************
**
*F DoFail3args( <self>, <arg1>, ... ) fail a function call with 3 arguments
*/
static Obj DoFail3args(Obj self, Obj arg1, Obj arg2, Obj arg3)
{
NargError(self, 3);
}
/****************************************************************************
**
*F DoFail4args( <self>, <arg1>, ... ) fail a function call with 4 arguments
*/
static Obj DoFail4args(Obj self, Obj arg1, Obj arg2, Obj arg3, Obj arg4)
{
NargError(self, 4);
}
/****************************************************************************
**
*F DoFail5args( <self>, <arg1>, ... ) fail a function call with 5 arguments
*/
static Obj
DoFail5args(Obj self, Obj arg1, Obj arg2, Obj arg3, Obj arg4, Obj arg5)
{
NargError(self, 5);
}
/****************************************************************************
**
*F DoFail6args( <self>, <arg1>, ... ) fail a function call with 6 arguments
*/
static Obj DoFail6args(
Obj self, Obj arg1, Obj arg2, Obj arg3, Obj arg4, Obj arg5, Obj arg6)
{
NargError(self, 6);
}
/****************************************************************************
**
*F DoFailXargs( <self>, <args> ) . . fail a function call with X arguments
*/
static Obj DoFailXargs(Obj self, Obj args)
{
NargError(self, LEN_LIST(args));
}
/****************************************************************************
**
*F * * * * * * * * * * * * * wrapper for profiling * * * * * * * * * * * * *
*/
/****************************************************************************
**
*V TimeDone . . . . . . amount of time spent for completed function calls
**
** 'TimeDone' is the amount of time spent for all function calls that have
** already been completed.
*/
static UInt TimeDone;
/****************************************************************************
**
*V StorDone . . . . . amount of storage spent for completed function calls
**
** 'StorDone' is the amount of storage spent for all function call that have
** already been completed.
*/
static UInt8 StorDone;
/****************************************************************************
**
*F DoProf0args( <self> ) . . . . . . . . profile a function with 0 arguments
**
** 'DoProf<i>args' accepts the <i> arguments <arg1>, <arg2>, and so on, and
** calls the function through the secondary handler. It also updates the
** profiling information in the profiling information bag of the called
** function. 'DoProf<i>args' are the primary handlers for all functions
** when profiling is requested.
*/
static ALWAYS_INLINE Obj DoProfNNNargs (
Obj self,
Int n,
Obj arg1,
Obj arg2,
Obj arg3,
Obj arg4,
Obj arg5,
Obj arg6 )
{
Obj result;
// value of function call, result
Obj prof;
// profiling bag
UInt timeElse;
// time spent elsewhere
UInt timeCurr;
// time spent in current funcs.
UInt8 storElse;
// storage spent elsewhere
UInt8 storCurr;
// storage spent in current funcs.
// get the profiling bag
prof = PROF_FUNC( PROF_FUNC( self ) );
// time and storage spent so far while this function what not active
timeElse = SyTime() - TIME_WITH_PROF(prof);
storElse = SizeAllBags - STOR_WITH_PROF(prof);
// time and storage spent so far by all currently suspended functions
timeCurr = SyTime() - TimeDone;
storCurr = SizeAllBags - StorDone;
// call the real function
switch (n) {
case 0: result = CALL_0ARGS_PROF( self );
break;
case 1: result = CALL_1ARGS_PROF( self, arg1 );
break;
case 2: result = CALL_2ARGS_PROF( self, arg1, arg2 );
break;
case 3: result = CALL_3ARGS_PROF( self, arg1, arg2, arg3 );
break;
case 4: result = CALL_4ARGS_PROF( self, arg1, arg2, arg3, arg4 );
break;
case 5: result = CALL_5ARGS_PROF( self, arg1, arg2, arg3, arg4, arg5 );
break;
case 6: result = CALL_6ARGS_PROF( self, arg1, arg2, arg3, arg4, arg5, arg6 );
break;
case -1: result = CALL_XARGS_PROF( self, arg1 );
break;
default: result = 0; GAP_ASSERT(0);
}
// number of invocation of this function
SET_COUNT_PROF( prof, COUNT_PROF(prof) + 1 );
// time and storage spent in this function and its children
SET_TIME_WITH_PROF( prof, SyTime() - timeElse );
SET_STOR_WITH_PROF( prof, SizeAllBags - storElse );
// time and storage spent by this invocation of this function
timeCurr = SyTime() - TimeDone - timeCurr;
SET_TIME_WOUT_PROF( prof, TIME_WOUT_PROF(prof) + timeCurr );
TimeDone += timeCurr;
storCurr = SizeAllBags - StorDone - storCurr;
SET_STOR_WOUT_PROF( prof, STOR_WOUT_PROF(prof) + storCurr );
StorDone += storCurr;
return result;
}
static Obj DoProf0args (
Obj self )
{
return DoProfNNNargs(self, 0, 0, 0, 0, 0, 0, 0);
}
/****************************************************************************
**
*F DoProf1args( <self>, <arg1>) . . . . profile a function with 1 argument
*/
static Obj DoProf1args (
Obj self,
Obj arg1 )
{
return DoProfNNNargs(self, 1, arg1, 0, 0, 0, 0, 0);
}
/****************************************************************************
**
*F DoProf2args( <self>, <arg1>, ... ) . profile a function with 2 arguments
*/
static Obj DoProf2args (
Obj self,
Obj arg1,
Obj arg2 )
{
return DoProfNNNargs(self, 2, arg1, arg2, 0, 0, 0, 0);
}
/****************************************************************************
**
*F DoProf3args( <self>, <arg1>, ... ) . profile a function with 3 arguments
*/
static Obj DoProf3args (
Obj self,
Obj arg1,
Obj arg2,
Obj arg3 )
{
return DoProfNNNargs(self, 3, arg1, arg2, arg3, 0, 0, 0);
}
/****************************************************************************
**
*F DoProf4args( <self>, <arg1>, ... ) . profile a function with 4 arguments
*/
static Obj DoProf4args (
Obj self,
Obj arg1,
Obj arg2,
Obj arg3,
Obj arg4 )
{
return DoProfNNNargs(self, 4, arg1, arg2, arg3, arg4, 0, 0);
}
/****************************************************************************
**
*F DoProf5args( <self>, <arg1>, ... ) . profile a function with 5 arguments
*/
static Obj DoProf5args (
Obj self,
Obj arg1,
Obj arg2,
Obj arg3,
Obj arg4,
Obj arg5 )
{
return DoProfNNNargs(self, 5, arg1, arg2, arg3, arg4, arg5, 0);
}
/****************************************************************************
**
*F DoProf6args( <self>, <arg1>, ... ) . profile a function with 6 arguments
*/
static Obj DoProf6args (
Obj self,
Obj arg1,
Obj arg2,
Obj arg3,
Obj arg4,
Obj arg5,
Obj arg6 )
{
return DoProfNNNargs(self, 6, arg1, arg2, arg3, arg4, arg5, arg6);
}
/****************************************************************************
**
*F DoProfXargs( <self>, <args> ) . . . . profile a function with X arguments
*/
static Obj DoProfXargs (
Obj self,
Obj args )
{
return DoProfNNNargs(self, -1, args, 0, 0, 0, 0, 0);
}
/****************************************************************************
**
*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
*/
#ifndef MAX_HANDLERS
#define MAX_HANDLERS 20000
#endif
typedef struct {
ObjFunc hdlr;
const Char * cookie;
}
TypeHandlerInfo;
static UInt HandlerSortingStatus = 0;
static TypeHandlerInfo HandlerFuncs[MAX_HANDLERS];
static UInt NHandlerFuncs = 0;
void InitHandlerFunc (
ObjFunc hdlr,
const Char * cookie )
{
if ( NHandlerFuncs >= MAX_HANDLERS ) {
Panic(
"No room left for function handler");
}
for (UInt i = 0; i < NHandlerFuncs; i++)
if (streq(HandlerFuncs[i].cookie, cookie))
Pr(
"Duplicate cookie %s\n", (
Int)cookie, 0);
HandlerFuncs[NHandlerFuncs].hdlr = hdlr;
HandlerFuncs[NHandlerFuncs].cookie = cookie;
HandlerSortingStatus = 0;
// no longer sorted by handler or cookie
NHandlerFuncs++;
}
/****************************************************************************
**
*f CheckHandlersBag( <bag> ) . . . . . . check that handlers are initialised
*/
#ifdef USE_GASMAN
static void CheckHandlersBag(
Bag bag )
{
UInt i;
UInt j;
ObjFunc hdlr;
if ( TNUM_BAG(bag) == T_FUNCTION ) {
for ( j = 0; j < 8; j++ ) {
hdlr = HDLR_FUNC(bag,j);
// zero handlers are used in a few odd places
if ( hdlr != 0 ) {
for ( i = 0; i < NHandlerFuncs; i++ ) {
if ( hdlr == HandlerFuncs[i].hdlr )
break;
}
if ( i == NHandlerFuncs ) {
Pr(
"Unregistered Handler %d args ", j, 0);
PrintObj(NAME_FUNC(bag));
Pr(
"\n", 0, 0);
}
}
}
}
}
void CheckAllHandlers(
void)
{
CallbackForAllBags(CheckHandlersBag);
}
static int IsLessHandlerInfo (
TypeHandlerInfo * h1,
TypeHandlerInfo * h2,
UInt byWhat )
{
switch (byWhat) {
case 1:
// cast to please Irix CC and HPUX CC
return (UInt)(h1->hdlr) < (UInt)(h2->hdlr);
case 2:
return strcmp(h1->cookie, h2->cookie) < 0;
default:
ErrorQuit(
"Invalid sort mode %u", (
Int)byWhat, 0);
}
}
void SortHandlers( UInt byWhat )
{
TypeHandlerInfo tmp;
UInt len, h, i, k;
if (HandlerSortingStatus == byWhat)
return;
len = NHandlerFuncs;
h = 1;
while ( 9*h + 4 < len )
{ h = 3*h + 1; }
while ( 0 < h ) {
for ( i = h; i < len; i++ ) {
tmp = HandlerFuncs[i];
k = i;
while ( h <= k && IsLessHandlerInfo(&tmp, HandlerFuncs+(k-h), byWhat))
{
HandlerFuncs[k] = HandlerFuncs[k-h];
k -= h;
}
HandlerFuncs[k] = tmp;
}
h = h / 3;
}
HandlerSortingStatus = byWhat;
}
const Char * CookieOfHandler (
ObjFunc hdlr )
{
UInt i, top, bottom, middle;
if ( HandlerSortingStatus != 1 ) {
for ( i = 0; i < NHandlerFuncs; i++ ) {
if ( hdlr == HandlerFuncs[i].hdlr )
return HandlerFuncs[i].cookie;
}
return (
Char *)0;
}
else {
top = NHandlerFuncs;
bottom = 0;
while ( top >= bottom ) {
middle = (top + bottom)/2;
if ( (UInt)(hdlr) < (UInt)(HandlerFuncs[middle].hdlr) )
top = middle-1;
else if ( (UInt)(hdlr) > (UInt)(HandlerFuncs[middle].hdlr) )
bottom = middle+1;
else
return HandlerFuncs[middle].cookie;
}
return (
Char *)0;
}
}
ObjFunc HandlerOfCookie(
const Char * cookie )
{
Int i,top,bottom,middle;
Int res;
if (HandlerSortingStatus != 2)
{
for (i = 0; i < NHandlerFuncs; i++)
{
if (streq(cookie, HandlerFuncs[i].cookie))
return HandlerFuncs[i].hdlr;
}
return (ObjFunc)0;
}
else
{
top = NHandlerFuncs;
bottom = 0;
while (top >= bottom) {
middle = (top + bottom)/2;
res = strcmp(cookie,HandlerFuncs[middle].cookie);
if (res < 0)
top = middle-1;
else if (res > 0)
bottom = middle+1;
else
return HandlerFuncs[middle].hdlr;
}
return (ObjFunc)0;
}
}
#endif
/****************************************************************************
**
*F NewFunction( <name>, <narg>, <nams>, <hdlr> ) . . . . make a new function
**
** '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 containing 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.
*/
Obj NewFunction (
Obj name,
Int narg,
Obj nams,
ObjFunc hdlr )
{
return NewFunctionT( T_FUNCTION,
sizeof(FuncBag), name, narg, nams, hdlr );
}
/****************************************************************************
**
*F NewFunctionC( <name>, <narg>, <nams>, <hdlr> ) . . . make a new function
**
** 'NewFunctionC' does the same as 'NewFunction', but expects <name> and
** <nams> as C strings.
*/
Obj NewFunctionC (
const Char * name,
Int narg,
const Char * nams,
ObjFunc hdlr )
{
return NewFunction(MakeImmString(name), narg, ArgStringToList(nams), hdlr);
}
/****************************************************************************
**
*F NewFunctionT( <type>, <size>, <name>, <narg>, <nams>, <hdlr> )
**
** 'NewFunctionT' does the same as 'NewFunction', but allows to specify the
** <type> and <size> of the newly created bag.
*/
Obj NewFunctionT (
UInt type,
UInt size,
Obj name,
Int narg,
Obj nams,
ObjFunc hdlr )
{
Obj func;
// function, result
Obj prof;
// profiling bag
// make the function object
func = NewBag( type, size );
// create a function with a fixed number of arguments
if ( narg >= 0 ) {
SET_HDLR_FUNC(func, 0, DoFail0args);
SET_HDLR_FUNC(func, 1, DoFail1args);
SET_HDLR_FUNC(func, 2, DoFail2args);
SET_HDLR_FUNC(func, 3, DoFail3args);
SET_HDLR_FUNC(func, 4, DoFail4args);
SET_HDLR_FUNC(func, 5, DoFail5args);
SET_HDLR_FUNC(func, 6, DoFail6args);
SET_HDLR_FUNC(func, 7, DoFailXargs);
SET_HDLR_FUNC(func, (narg <= 6 ? narg : 7), hdlr );
}
// create a function with a variable number of arguments
else {
SET_HDLR_FUNC(func, 0, (narg >= -1) ? DoWrap0args : DoFail0args);
SET_HDLR_FUNC(func, 1, (narg >= -2) ? DoWrap1args : DoFail1args);
SET_HDLR_FUNC(func, 2, (narg >= -3) ? DoWrap2args : DoFail2args);
SET_HDLR_FUNC(func, 3, (narg >= -4) ? DoWrap3args : DoFail3args);
SET_HDLR_FUNC(func, 4, (narg >= -5) ? DoWrap4args : DoFail4args);
SET_HDLR_FUNC(func, 5, (narg >= -6) ? DoWrap5args : DoFail5args);
SET_HDLR_FUNC(func, 6, (narg >= -7) ? DoWrap6args : DoFail6args);
SET_HDLR_FUNC(func, 7, hdlr);
}
// enter the arguments and the names
SET_NAME_FUNC(func, name ? ImmutableString(name) : 0);
SET_NARG_FUNC(func, narg);
SET_NAMS_FUNC(func, nams);
SET_NLOC_FUNC(func, 0);
#ifdef HPCGAP
if (nams) MakeBagPublic(nams);
#endif
CHANGED_BAG(func);
// enter the profiling bag
prof = NEW_PLIST( T_PLIST, LEN_PROF );
SET_LEN_PLIST( prof, LEN_PROF );
SET_COUNT_PROF( prof, 0 );
SET_TIME_WITH_PROF( prof, 0 );
SET_TIME_WOUT_PROF( prof, 0 );
SET_STOR_WITH_PROF( prof, 0 );
SET_STOR_WOUT_PROF( prof, 0 );
SET_PROF_FUNC(func, prof);
CHANGED_BAG(func);
// return the function bag
return func;
}
/****************************************************************************
**
*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>.
*/
Obj ArgStringToList(
const Char *nams_c) {
Obj tmp;
// argument name as an object
Obj nams_o;
// nams as an object
UInt len;
// length
UInt i, k, l;
// loop variables
// convert the arguments list to an object
len = 0;
for ( k = 0; nams_c[k] !=
'\0'; k++ ) {
if ( (0 == k || nams_c[k-1] ==
' ' || nams_c[k-1] ==
',')
&& ( nams_c[k ] !=
' ' && nams_c[k ] !=
',') ) {
len++;
}
}
nams_o = NEW_PLIST( T_PLIST, len );
SET_LEN_PLIST( nams_o, len );
k = 0;
for ( i = 1; i <= len; i++ ) {
while ( nams_c[k] ==
' ' || nams_c[k] ==
',' ) {
k++;
}
l = k;
while ( nams_c[l] !=
' ' && nams_c[l] !=
',' && nams_c[l] !=
'\0' ) {
l++;
}
tmp = MakeImmStringWithLen(nams_c + k, l - k);
SET_ELM_PLIST( nams_o, i, tmp );
CHANGED_BAG( nams_o );
k = l;
}
return nams_o;
}
/****************************************************************************
**
*F * * * * * * * * * * * * * type and print function * * * * * * * * * * * *
*/
/****************************************************************************
**
*F TypeFunction( <func> ) . . . . . . . . . . . . . . . type of a function
**
** 'TypeFunction' returns the type of the function <func>.
**
** 'TypeFunction' is the function in 'TypeObjFuncs' for functions.
*/
static Obj TYPE_FUNCTION;
static Obj TYPE_OPERATION;
static Obj TYPE_FUNCTION_WITH_NAME;
static Obj TYPE_OPERATION_WITH_NAME;
static Obj TypeFunction(Obj func)
{
if (NAME_FUNC(func) == 0)
return (IS_OPERATION(func) ? TYPE_OPERATION : TYPE_FUNCTION);
else
return (IS_OPERATION(func) ? TYPE_OPERATION_WITH_NAME : TYPE_FUNCTION_WITH_NAME);
}
/****************************************************************************
**
*F PrintFunction( <func> ) . . . . . . . . . . . . . . . print a function
**
*/
static Obj PrintOperation;
static void PrintFunction(Obj func)
{
Int narg;
// number of arguments
Int nloc;
// number of locals
UInt i;
// loop variable
BOOL isvarg;
// does function have varargs?
isvarg =
FALSE;
if ( IS_OPERATION(func) ) {
CALL_1ARGS( PrintOperation, func );
return;
}
#ifdef HPCGAP
// print 'function (' or 'atomic function ('
if (LCKS_FUNC(func)) {
Pr(
"%5>atomic function%< ( %>", 0, 0);
}
else
Pr(
"%5>function%< ( %>", 0, 0);
#else
// print 'function ('
Pr(
"%5>function%< ( %>", 0, 0);
#endif
// print the arguments
narg = NARG_FUNC(func);
if (narg < 0) {
isvarg =
TRUE;
narg = -narg;
}
for ( i = 1; i <= narg; i++ ) {
#ifdef HPCGAP
if (LCKS_FUNC(func)) {
const Char * locks = CONST_CSTR_STRING(LCKS_FUNC(func));
switch(locks[i-1]) {
case LOCK_QUAL_READONLY:
Pr(
"%>readonly %<", 0, 0);
break;
case LOCK_QUAL_READWRITE:
Pr(
"%>readwrite %<", 0, 0);
break;
}
}
#endif
if ( NAMS_FUNC(func) != 0 )
Pr(
"%I", (
Int)NAMI_FUNC(func, (
Int)i), 0);
else
Pr(
"<>", (
Int)i, 0);
if(isvarg && i == narg) {
Pr(
"...", 0, 0);
}
if (i != narg)
Pr(
"%<, %>", 0, 0);
}
Pr(
" %<)\n", 0, 0);
// print the body
if (IsKernelFunction(func)) {
PrintKernelFunction(func);
}
else {
// print the locals
nloc = NLOC_FUNC(func);
if ( nloc >= 1 ) {
Pr(
"%>local ", 0, 0);
for ( i = 1; i <= nloc; i++ ) {
if ( NAMS_FUNC(func) != 0 )
Pr(
"%I", (
Int)NAMI_FUNC(func, (
Int)(narg + i)), 0);
else
Pr(
"<>", (
Int)i, 0);
if (i != nloc)
Pr(
"%<, %>", 0, 0);
}
Pr(
"%<;\n", 0, 0);
}
// print the code
Obj oldLVars;
oldLVars = SWITCH_TO_NEW_LVARS(func, narg, NLOC_FUNC(func));
PrintStat( OFFSET_FIRST_STAT );
SWITCH_TO_OLD_LVARS( oldLVars );
}
Pr(
"%4<\n", 0, 0);
// print 'end'
Pr(
"end", 0, 0);
}
void PrintKernelFunction(Obj func)
{
GAP_ASSERT(IsKernelFunction(func));
Obj body = BODY_FUNC(func);
Obj filename = body ? GET_FILENAME_BODY(body) : 0;
if (filename) {
if ( GET_LOCATION_BODY(body) ) {
Pr(
"<> from %g:%g",
(
Int)filename,
(
Int)GET_LOCATION_BODY(body));
}
else if ( GET_STARTLINE_BODY(body) ) {
Pr(
"<> from %g:%d",
(
Int)filename,
GET_STARTLINE_BODY(body));
}
}
else {
Pr(
"<>", 0, 0);
}
}
/****************************************************************************
**
*F FiltIS_FUNCTION( <self>, <func> ) . . . . . . . . . . . test for function
**
** 'FiltIS_FUNCTION' implements the internal function 'IsFunction'.
**
** 'IsFunction( <func> )'
**
** 'IsFunction' returns 'true' if <func> is a function and 'false'
** otherwise.
*/
static Obj IsFunctionFilt;
static Obj FiltIS_FUNCTION(Obj self, Obj obj)
{
if ( TNUM_OBJ(obj) == T_FUNCTION ) {
return True;
}
else if ( TNUM_OBJ(obj) < FIRST_EXTERNAL_TNUM ) {
return False;
}
else {
return DoFilter( self, obj );
}
}
/****************************************************************************
**
*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]... )'.
*/
Obj CallFuncListOper;
static Obj CallFuncListWrapOper;
Obj CallFuncList ( Obj func, Obj list )
{
Obj result;
// result
Obj list2;
// list of arguments
Obj arg;
// one argument
UInt i;
// loop variable
if (TNUM_OBJ(func) == T_FUNCTION) {
// call the function
if ( LEN_LIST(list) == 0 ) {
result = CALL_0ARGS( func );
}
else if ( LEN_LIST(list) == 1 ) {
result = CALL_1ARGS( func, ELMV_LIST(list,1) );
}
else if ( LEN_LIST(list) == 2 ) {
result = CALL_2ARGS( func, ELMV_LIST(list,1), ELMV_LIST(list,2) );
}
else if ( LEN_LIST(list) == 3 ) {
result = CALL_3ARGS( func, ELMV_LIST(list,1), ELMV_LIST(list,2),
ELMV_LIST(list,3) );
}
else if ( LEN_LIST(list) == 4 ) {
result = CALL_4ARGS( func, ELMV_LIST(list,1), ELMV_LIST(list,2),
ELMV_LIST(list,3), ELMV_LIST(list,4) );
}
else if ( LEN_LIST(list) == 5 ) {
result = CALL_5ARGS( func, ELMV_LIST(list,1), ELMV_LIST(list,2),
ELMV_LIST(list,3), ELMV_LIST(list,4),
ELMV_LIST(list,5) );
}
else if ( LEN_LIST(list) == 6 ) {
result = CALL_6ARGS( func, ELMV_LIST(list,1), ELMV_LIST(list,2),
ELMV_LIST(list,3), ELMV_LIST(list,4),
ELMV_LIST(list,5), ELMV_LIST(list,6) );
}
else {
list2 = NEW_PLIST( T_PLIST, LEN_LIST(list) );
SET_LEN_PLIST( list2, LEN_LIST(list) );
for ( i = 1; i <= LEN_LIST(list); i++ ) {
arg = ELMV_LIST( list, (
Int)i );
SET_ELM_PLIST( list2, i, arg );
}
result = CALL_XARGS( func, list2 );
}
}
else {
result = DoOperation2Args(CallFuncListOper, func, list);
}
return result;
}
static Obj FuncCALL_FUNC_LIST(Obj self, Obj func, Obj list)
{
RequireSmallList(SELF_NAME, list);
return CallFuncList(func, list);
}
static Obj FuncCALL_FUNC_LIST_WRAP(Obj self, Obj func, Obj list)
{
RequireSmallList(SELF_NAME, list);
Obj retval = CallFuncList(func, list);
return (retval == 0) ? NewImmutableEmptyPlist()
: NewPlistFromArgs(retval);
}
/****************************************************************************
**
*F * * * * * * * * * * * * * * * utility functions * * * * * * * * * * * * *
*/
/****************************************************************************
**
*F AttrNAME_FUNC( <self>, <func> ) . . . . . . . . . . . name of a function
*/
static Obj NameFuncAttr;
static Obj SET_NAME_FUNC_Oper;
static Obj AttrNAME_FUNC(Obj self, Obj func)
{
Obj name;
if ( TNUM_OBJ(func) == T_FUNCTION ) {
name = NAME_FUNC(func);
if ( name == 0 ) {
name = MakeImmString(
"unknown");
SET_NAME_FUNC(func, name);
CHANGED_BAG(func);
}
return name;
}
else {
return DoAttribute( self, func );
}
}
static Obj FuncSET_NAME_FUNC(Obj self, Obj func, Obj name)
{
RequireStringRep(SELF_NAME, name);
if (TNUM_OBJ(func) == T_FUNCTION ) {
SET_NAME_FUNC(func, ImmutableString(name));
CHANGED_BAG(func);
}
else
DoOperation2Args(SET_NAME_FUNC_Oper, func, name);
return (Obj) 0;
}
/****************************************************************************
**
*F FuncNARG_FUNC( <self>, <func> ) . . . . number of arguments of a function
*/
static Obj NARG_FUNC_Oper;
static Obj FuncNARG_FUNC(Obj self, Obj func)
{
if ( TNUM_OBJ(func) == T_FUNCTION ) {
return INTOBJ_INT( NARG_FUNC(func) );
}
else {
return DoOperation1Args( self, func );
}
}
/****************************************************************************
**
*F FuncNAMS_FUNC( <self>, <func> ) . . . . names of local vars of a function
*/
static Obj NAMS_FUNC_Oper;
static Obj FuncNAMS_FUNC(Obj self, Obj func)
{
Obj nams;
if ( TNUM_OBJ(func) == T_FUNCTION ) {
nams = NAMS_FUNC(func);
return (nams != (Obj)0) ? nams : Fail;
}
else {
return DoOperation1Args( self, func );
}
}
/****************************************************************************
**
*F FuncLOCKS_FUNC( <self>, <func> ) . . . . locking status of a possibly
** atomic function
*/
static Obj LOCKS_FUNC_Oper;
static Obj FuncLOCKS_FUNC(Obj self, Obj func)
{
#ifdef HPCGAP
Obj locks;
if (TNUM_OBJ(func) == T_FUNCTION) {
locks = LCKS_FUNC(func);
if (locks == (Obj)0)
return Fail;
else
return locks;
}
else {
return DoOperation1Args(self, func);
}
#else
return Fail;
#endif
}
/****************************************************************************
**
*F FuncPROF_FUNC( <self>, <func> ) . . . . . . profiling info of a function
*/
static Obj PROF_FUNC_Oper;
static Obj FuncPROF_FUNC(Obj self, Obj func)
{
Obj prof;
if ( TNUM_OBJ(func) == T_FUNCTION ) {
prof = PROF_FUNC(func);
if ( TNUM_OBJ(prof) == T_FUNCTION ) {
return PROF_FUNC(prof);
}
else {
return prof;
}
}
else {
return DoOperation1Args( self, func );
}
}
/****************************************************************************
**
*F FuncCLEAR_PROFILE_FUNC( <self>, <func> ) . . . . . . . . . clear profile
*/
static Obj FuncCLEAR_PROFILE_FUNC(Obj self, Obj func)
{
Obj prof;
RequireFunction(SELF_NAME, func);
// clear profile info
prof = PROF_FUNC(func);
if ( prof == 0 ) {
ErrorQuit(
" has corrupted profile info", 0, 0);
}
if ( TNUM_OBJ(prof) == T_FUNCTION ) {
prof = PROF_FUNC(prof);
}
if ( prof == 0 ) {
ErrorQuit(
" has corrupted profile info", 0, 0);
}
SET_COUNT_PROF( prof, 0 );
SET_TIME_WITH_PROF( prof, 0 );
SET_TIME_WOUT_PROF( prof, 0 );
SET_STOR_WITH_PROF( prof, 0 );
SET_STOR_WOUT_PROF( prof, 0 );
return (Obj)0;
}
/****************************************************************************
**
*F FuncPROFILE_FUNC( <self>, <func> ) . . . . . . . . . . . . start profile
*/
static Obj FuncPROFILE_FUNC(Obj self, Obj func)
{
Obj prof;
Obj copy;
RequireFunction(SELF_NAME, func);
// uninstall trace handler
ChangeDoOperations( func, 0 );
// install profiling
prof = PROF_FUNC(func);
// install new handlers
if ( TNUM_OBJ(prof) != T_FUNCTION ) {
copy = NewBag( TNUM_OBJ(func), SIZE_OBJ(func) );
SET_HDLR_FUNC(copy,0, HDLR_FUNC(func,0));
SET_HDLR_FUNC(copy,1, HDLR_FUNC(func,1));
SET_HDLR_FUNC(copy,2, HDLR_FUNC(func,2));
SET_HDLR_FUNC(copy,3, HDLR_FUNC(func,3));
SET_HDLR_FUNC(copy,4, HDLR_FUNC(func,4));
SET_HDLR_FUNC(copy,5, HDLR_FUNC(func,5));
SET_HDLR_FUNC(copy,6, HDLR_FUNC(func,6));
SET_HDLR_FUNC(copy,7, HDLR_FUNC(func,7));
SET_NAME_FUNC(copy, NAME_FUNC(func));
SET_NARG_FUNC(copy, NARG_FUNC(func));
SET_NAMS_FUNC(copy, NAMS_FUNC(func));
SET_PROF_FUNC(copy, PROF_FUNC(func));
SET_NLOC_FUNC(copy, NLOC_FUNC(func));
SET_HDLR_FUNC(func,0, DoProf0args);
SET_HDLR_FUNC(func,1, DoProf1args);
SET_HDLR_FUNC(func,2, DoProf2args);
SET_HDLR_FUNC(func,3, DoProf3args);
SET_HDLR_FUNC(func,4, DoProf4args);
SET_HDLR_FUNC(func,5, DoProf5args);
SET_HDLR_FUNC(func,6, DoProf6args);
SET_HDLR_FUNC(func,7, DoProfXargs);
SET_PROF_FUNC(func, copy);
CHANGED_BAG(func);
}
return (Obj)0;
}
/****************************************************************************
**
*F FuncIS_PROFILED_FUNC( <self>, <func> ) . . check if function is profiled
*/
static Obj FuncIS_PROFILED_FUNC(Obj self, Obj func)
{
RequireFunction(SELF_NAME, func);
return ( TNUM_OBJ(PROF_FUNC(func)) != T_FUNCTION ) ?
False :
True;
}
static Obj FuncFILENAME_FUNC(Obj self, Obj func)
{
RequireFunction(SELF_NAME, func);
if (BODY_FUNC(func)) {
Obj fn = GET_FILENAME_BODY(BODY_FUNC(func));
if (fn)
return fn;
}
return Fail;
}
static Obj FuncSTARTLINE_FUNC(Obj self, Obj func)
{
RequireFunction(SELF_NAME, func);
if (BODY_FUNC(func)) {
UInt sl = GET_STARTLINE_BODY(BODY_FUNC(func));
if (sl)
return INTOBJ_INT(sl);
}
return Fail;
}
static Obj FuncENDLINE_FUNC(Obj self, Obj func)
{
RequireFunction(SELF_NAME, func);
if (BODY_FUNC(func)) {
UInt el = GET_ENDLINE_BODY(BODY_FUNC(func));
if (el)
return INTOBJ_INT(el);
}
return Fail;
}
static Obj FuncLOCATION_FUNC(Obj self, Obj func)
{
RequireFunction(SELF_NAME, func);
if (BODY_FUNC(func)) {
Obj sl = GET_LOCATION_BODY(BODY_FUNC(func));
if (sl)
return sl;
}
return Fail;
}
/****************************************************************************
**
*F FuncUNPROFILE_FUNC( <self>, <func> ) . . . . . . . . . . . stop profile
*/
static Obj FuncUNPROFILE_FUNC(Obj self, Obj func)
{
Obj prof;
RequireFunction(SELF_NAME, func);
// uninstall trace handler
ChangeDoOperations( func, 0 );
// profiling is active, restore handlers
prof = PROF_FUNC(func);
if ( TNUM_OBJ(prof) == T_FUNCTION ) {
for (
Int i = 0; i <= 7; i++)
SET_HDLR_FUNC(func, i, HDLR_FUNC(prof, i));
SET_PROF_FUNC(func, PROF_FUNC(prof));
CHANGED_BAG(func);
}
return (Obj)0;
}
/****************************************************************************
*
*F FuncIsKernelFunction( <self>, <func> )
**
** 'FuncIsKernelFunction' returns Fail if <func> is not a function, True if
** <func> is a kernel function, and False otherwise.
*/
static Obj FuncIsKernelFunction(Obj self, Obj func)
{
if (!IS_FUNC(func))
return Fail;
return IsKernelFunction(func) ?
True :
False;
}
BOOL IsKernelFunction(Obj func)
{
GAP_ASSERT(IS_FUNC(func));
return (BODY_FUNC(func) == 0) ||
(SIZE_OBJ(BODY_FUNC(func)) ==
sizeof(BodyHeader));
}
// Returns a measure of the size of a GAP function
static Obj FuncFUNC_BODY_SIZE(Obj self, Obj func)
{
RequireFunction(SELF_NAME, func);
Obj body = BODY_FUNC(func);
if (body == 0)
return INTOBJ_INT(0);
return ObjInt_UInt(SIZE_BAG(body));
}
#ifdef GAP_ENABLE_SAVELOAD
static void SaveHandler(ObjFunc hdlr)
{
const Char * cookie;
if (hdlr == (ObjFunc)0)
SaveCStr(
"");
else {
cookie = CookieOfHandler(hdlr);
if (!cookie) {
Pr(
"No cookie for Handler -- workspace will be corrupt\n", 0, 0);
SaveCStr(
"");
}
else
SaveCStr(cookie);
}
}
static ObjFunc LoadHandler(
void )
{
Char buf[256];
LoadCStr(buf, 256);
if (buf[0] ==
'\0')
return (ObjFunc) 0;
else
return HandlerOfCookie(buf);
}
/****************************************************************************
**
*F SaveFunction( <func> ) . . . . . . . . . . . . . . . . . save a function
**
*/
static void SaveFunction(Obj func)
{
const FuncBag * header = CONST_FUNC(func);
for (UInt i = 0; i < ARRAY_SIZE(header->handlers); i++)
SaveHandler(header->handlers[i]);
SaveSubObj(header->name);
SaveSubObj(header->nargs);
SaveSubObj(header->namesOfArgsAndLocals);
SaveSubObj(header->prof);
SaveSubObj(header->nloc);
SaveSubObj(header->body);
SaveSubObj(header->envi);
if (IS_OPERATION(func))
SaveOperationExtras( func );
}
/****************************************************************************
**
*F LoadFunction( <func> ) . . . . . . . . . . . . . . . . . load a function
**
*/
static void LoadFunction(Obj func)
{
FuncBag * header = FUNC(func);
for (UInt i = 0; i < ARRAY_SIZE(header->handlers); i++)
header->handlers[i] = LoadHandler();
header->name = LoadSubObj();
header->nargs = LoadSubObj();
header->namesOfArgsAndLocals = LoadSubObj();
header->prof = LoadSubObj();
header->nloc = LoadSubObj();
header->body = LoadSubObj();
header->envi = LoadSubObj();
if (IS_OPERATION(func))
LoadOperationExtras( func );
}
#endif
/****************************************************************************
**
*F MarkFunctionSubBags( <bag> ) . . . . . . . marking function for functions
**
** 'MarkFunctionSubBags' is the marking function for bags of type 'T_FUNCTION'.
*/
static void MarkFunctionSubBags(Obj func,
void * ref)
{
// the first eight slots are pointers to C functions, so we need
// to skip those for marking
UInt size = SIZE_BAG(func) /
sizeof(Obj) - 8;
const Bag * data = CONST_PTR_BAG(func) + 8;
MarkArrayOfBags(data, size, ref);
}
/****************************************************************************
**
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/
/****************************************************************************
**
*V BagNames . . . . . . . . . . . . . . . . . . . . . . . list of bag names
*/
static StructBagNames BagNames[] = {
{ T_FUNCTION,
"function" },
{ -1,
"" }
};
/****************************************************************************
**
*V GVarFilts . . . . . . . . . . . . . . . . . . . list of filters to export
*/
static StructGVarFilt GVarFilts [] = {
GVAR_FILT(IS_FUNCTION,
"obj", &IsFunctionFilt),
{ 0, 0, 0, 0, 0 }
};
/****************************************************************************
**
*V GVarAttrs . . . . . . . . . . . . . . . . . list of attributes to export
*/
static StructGVarAttr GVarAttrs [] = {
GVAR_ATTR(NAME_FUNC,
"func", &NameFuncAttr),
{ 0, 0, 0, 0, 0 }
};
/****************************************************************************
**
*V GVarOpers . . . . . . . . . . . . . . . . . list of operations to export
*/
static StructGVarOper GVarOpers [] = {
GVAR_OPER_2ARGS(CALL_FUNC_LIST, func, list, &CallFuncListOper),
GVAR_OPER_2ARGS(CALL_FUNC_LIST_WRAP, func, list, &CallFuncListWrapOper),
GVAR_OPER_2ARGS(SET_NAME_FUNC, func, name, &SET_NAME_FUNC_Oper),
GVAR_OPER_1ARGS(NARG_FUNC, func, &NARG_FUNC_Oper),
GVAR_OPER_1ARGS(NAMS_FUNC, func, &NAMS_FUNC_Oper),
GVAR_OPER_1ARGS(LOCKS_FUNC, func, &LOCKS_FUNC_Oper),
GVAR_OPER_1ARGS(PROF_FUNC, func, &PROF_FUNC_Oper),
{ 0, 0, 0, 0, 0, 0 }
};
/****************************************************************************
**
*V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
*/
static StructGVarFunc GVarFuncs[] = {
GVAR_FUNC_1ARGS(CLEAR_PROFILE_FUNC, func),
GVAR_FUNC_1ARGS(IS_PROFILED_FUNC, func),
GVAR_FUNC_1ARGS(PROFILE_FUNC, func),
GVAR_FUNC_1ARGS(UNPROFILE_FUNC, func),
GVAR_FUNC_1ARGS(IsKernelFunction, func),
GVAR_FUNC_1ARGS(FILENAME_FUNC, func),
GVAR_FUNC_1ARGS(LOCATION_FUNC, func),
GVAR_FUNC_1ARGS(STARTLINE_FUNC, func),
GVAR_FUNC_1ARGS(ENDLINE_FUNC, func),
GVAR_FUNC_1ARGS(FUNC_BODY_SIZE, func),
{ 0, 0, 0, 0, 0 }
};
/****************************************************************************
**
*F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
*/
static Int InitKernel (
StructInitInfo * module )
{
// set the bag type names (for error messages and debugging)
InitBagNamesFromTable( BagNames );
// install the marking functions
InitMarkFuncBags(T_FUNCTION, MarkFunctionSubBags);
#ifdef HPCGAP
// Allocate functions in the public region
MakeBagTypePublic(T_FUNCTION);
#endif
// install the type functions
ImportGVarFromLibrary(
"TYPE_FUNCTION", &TYPE_FUNCTION );
ImportGVarFromLibrary(
"TYPE_OPERATION", &TYPE_OPERATION );
ImportGVarFromLibrary(
"TYPE_FUNCTION_WITH_NAME", &TYPE_FUNCTION_WITH_NAME );
ImportGVarFromLibrary(
"TYPE_OPERATION_WITH_NAME", &TYPE_OPERATION_WITH_NAME );
TypeObjFuncs[ T_FUNCTION ] = TypeFunction;
// init filters and functions
InitHdlrFiltsFromTable( GVarFilts );
InitHdlrAttrsFromTable( GVarAttrs );
InitHdlrOpersFromTable( GVarOpers );
InitHdlrFuncsFromTable( GVarFuncs );
#ifdef USE_GASMAN
// and the saving function
SaveObjFuncs[ T_FUNCTION ] = SaveFunction;
LoadObjFuncs[ T_FUNCTION ] = LoadFunction;
#endif
// install the printer
InitFopyGVar(
"PRINT_OPERATION", &PrintOperation );
PrintObjFuncs[ T_FUNCTION ] = PrintFunction;
// initialise all 'Do<Something><N>args' handlers, give the most
// common ones short cookies to save space in the saved workspace
InitHandlerFunc( DoFail0args,
"f0" );
InitHandlerFunc( DoFail1args,
"f1" );
InitHandlerFunc( DoFail2args,
"f2" );
InitHandlerFunc( DoFail3args,
"f3" );
InitHandlerFunc( DoFail4args,
"f4" );
InitHandlerFunc( DoFail5args,
"f5" );
InitHandlerFunc( DoFail6args,
"f6" );
InitHandlerFunc( DoFailXargs,
"f7" );
InitHandlerFunc( DoWrap0args,
"w0" );
InitHandlerFunc( DoWrap1args,
"w1" );
InitHandlerFunc( DoWrap2args,
"w2" );
InitHandlerFunc( DoWrap3args,
"w3" );
InitHandlerFunc( DoWrap4args,
"w4" );
InitHandlerFunc( DoWrap5args,
"w5" );
InitHandlerFunc( DoWrap6args,
"w6" );
InitHandlerFunc( DoProf0args,
"p0" );
InitHandlerFunc( DoProf1args,
"p1" );
InitHandlerFunc( DoProf2args,
"p2" );
InitHandlerFunc( DoProf3args,
"p3" );
InitHandlerFunc( DoProf4args,
"p4" );
InitHandlerFunc( DoProf5args,
"p5" );
InitHandlerFunc( DoProf6args,
"p6" );
InitHandlerFunc( DoProfXargs,
"pX" );
return 0;
}
/****************************************************************************
**
*F InitLibrary( <module> ) . . . . . . . initialise library data structures
*/
static Int InitLibrary(StructInitInfo * module)
{
// init filters and functions
InitGVarFiltsFromTable( GVarFilts );
InitGVarAttrsFromTable( GVarAttrs );
InitGVarOpersFromTable( GVarOpers );
InitGVarFuncsFromTable( GVarFuncs );
return 0;
}
/****************************************************************************
**
*F InitInfoCalls() . . . . . . . . . . . . . . . . . table of init functions
*/
static StructInitInfo module = {
// init struct using C99 designated initializers; for a full list of
// fields, please refer to the definition of StructInitInfo
.type = MODULE_BUILTIN,
.name =
"calls",
.initKernel = InitKernel,
.initLibrary = InitLibrary,
};
StructInitInfo * InitInfoCalls (
void )
{
return &module;
}