#include "setup.h"
#if DEFGENERIC_CONSTRUCT
#if BLOAD || BLOAD_AND_BSAVE
#include "bload.h"
#endif
#if OBJECT_SYSTEM
#include "classcom.h"
#include "classfun.h"
#endif
#include "argacces.h"
#include "constrct.h"
#include "cstrccom.h"
#include "cstrcpsr.h"
#include "envrnmnt.h"
#include "genrccom.h"
#include "genrcexe.h"
#include "genrcfun.h"
#include "memalloc.h"
#include "modulutl.h"
#include "prccode.h"
#include "prntutil.h"
#include "router.h"
#include "sysdep.h"
#include "genrcfun.h"
#if DEBUGGING_FUNCTIONS
static void DisplayGenericCore(Environment *,Defgeneric *);
#endif
#if RUN_TIME
static void RuntimeDefgenericAction(Environment *,ConstructHeader *,void *);
#endif
#if ! RUN_TIME
bool ClearDefgenericsReady(
Environment *theEnv,
void *context)
{
return((DefgenericData(theEnv)->CurrentGeneric != NULL) ? false : true);
}
void *AllocateDefgenericModule(
Environment *theEnv)
{
return (void *) get_struct(theEnv,defgenericModule);
}
void FreeDefgenericModule(
Environment *theEnv,
void *theItem)
{
#if (! BLOAD_ONLY)
FreeConstructHeaderModule(theEnv,(struct defmoduleItemHeader *) theItem,DefgenericData(theEnv)->DefgenericConstruct);
#endif
rtn_struct(theEnv,defgenericModule,theItem);
}
#endif
#if RUN_TIME
static void RuntimeDefgenericAction(
Environment *theEnv,
ConstructHeader *theConstruct,
void *buffer)
{
#if MAC_XCD
#pragma unused(buffer)
#endif
Defgeneric *theDefgeneric = (Defgeneric *) theConstruct;
long gi;
theDefgeneric->header.env = theEnv;
for (gi = 0 ; gi < theDefgeneric->mcnt ; gi++)
{ theDefgeneric->methods[gi].header.env = theEnv; }
}
void DefgenericRunTimeInitialize(
Environment *theEnv)
{
DoForAllConstructs(theEnv,RuntimeDefgenericAction,DefgenericData(theEnv)->DefgenericModuleIndex,true,NULL);
}
#endif
#if (! BLOAD_ONLY) && (! RUN_TIME)
bool ClearDefmethods(
Environment *theEnv)
{
Defgeneric *gfunc;
bool success = true;
#if BLOAD || BLOAD_AND_BSAVE
if (Bloaded(theEnv) == true) return false;
#endif
gfunc = GetNextDefgeneric(theEnv,NULL);
while (gfunc != NULL)
{
if (RemoveAllExplicitMethods(theEnv,gfunc) == false)
success = false;
gfunc = GetNextDefgeneric(theEnv,gfunc);
}
return success;
}
bool RemoveAllExplicitMethods(
Environment *theEnv,
Defgeneric *gfunc)
{
unsigned short i, j;
unsigned short systemMethodCount = 0;
Defmethod *narr;
if (MethodsExecuting(gfunc) == false)
{
for (i = 0 ; i < gfunc->mcnt ; i++)
{
if (gfunc->methods[i].system)
systemMethodCount++;
else
DeleteMethodInfo(theEnv,gfunc,&gfunc->methods[i]);
}
if (systemMethodCount != 0)
{
narr = (Defmethod *) gm2(theEnv,(systemMethodCount * sizeof(Defmethod)));
i = 0;
j = 0;
while (i < gfunc->mcnt)
{
if (gfunc->methods[i].system)
GenCopyMemory(Defmethod,1,&narr[j++],&gfunc->methods[i]);
i++;
}
rm(theEnv,gfunc->methods,(sizeof(Defmethod) * gfunc->mcnt));
gfunc->mcnt = systemMethodCount;
gfunc->methods = narr;
}
else
{
if (gfunc->mcnt != 0)
rm(theEnv,gfunc->methods,(sizeof(Defmethod) * gfunc->mcnt));
gfunc->mcnt = 0;
gfunc->methods = NULL;
}
return true;
}
return false;
}
void RemoveDefgeneric(
Environment *theEnv,
Defgeneric *theDefgeneric)
{
long i;
for (i = 0 ; i < theDefgeneric->mcnt ; i++)
DeleteMethodInfo(theEnv,theDefgeneric,&theDefgeneric->methods[i]);
if (theDefgeneric->mcnt != 0)
{ rm(theEnv,theDefgeneric->methods,(sizeof(Defmethod) * theDefgeneric->mcnt)); }
ReleaseLexeme(theEnv,GetDefgenericNamePointer(theDefgeneric));
SetDefgenericPPForm(theEnv,theDefgeneric,NULL);
ClearUserDataList(theEnv,theDefgeneric->header.usrData);
rtn_struct(theEnv,defgeneric,theDefgeneric);
}
bool ClearDefgenerics(
Environment *theEnv)
{
Defgeneric *gfunc, *gtmp;
bool success = true;
#if BLOAD || BLOAD_AND_BSAVE
if (Bloaded(theEnv) == true) return false;
#endif
gfunc = GetNextDefgeneric(theEnv,NULL);
while (gfunc != NULL)
{
gtmp = gfunc;
gfunc = GetNextDefgeneric(theEnv,gfunc);
if (RemoveAllExplicitMethods(theEnv,gtmp) == false)
{
CantDeleteItemErrorMessage(theEnv,"generic function",DefgenericName(gtmp));
success = false;
}
else
{
RemoveConstructFromModule(theEnv,>mp->header);
RemoveDefgeneric(theEnv,gtmp);
}
}
return(success);
}
void MethodAlterError(
Environment *theEnv,
Defgeneric *gfunc)
{
PrintErrorID(theEnv,"GENRCFUN",1,false);
WriteString(theEnv,STDERR,"Defgeneric '");
WriteString(theEnv,STDERR,DefgenericName(gfunc));
WriteString(theEnv,STDERR,"' cannot be modified while one of its methods is executing.\n");
}
void DeleteMethodInfo(
Environment *theEnv,
Defgeneric *gfunc,
Defmethod *meth)
{
short j,k;
RESTRICTION *rptr;
SaveBusyCount(gfunc);
ExpressionDeinstall(theEnv,meth->actions);
ReturnPackedExpression(theEnv,meth->actions);
ClearUserDataList(theEnv,meth->header.usrData);
if (meth->header.ppForm != NULL)
rm(theEnv,(void *) meth->header.ppForm,(sizeof(char) * (strlen(meth->header.ppForm)+1)));
for (j = 0 ; j < meth->restrictionCount ; j++)
{
rptr = &meth->restrictions[j];
for (k = 0 ; k < rptr->tcnt ; k++)
#if OBJECT_SYSTEM
DecrementDefclassBusyCount(theEnv,(Defclass *) rptr->types[k]);
#else
ReleaseInteger(theEnv,(CLIPSInteger *) rptr->types[k]);
#endif
if (rptr->types != NULL)
rm(theEnv,rptr->types,(sizeof(void *) * rptr->tcnt));
ExpressionDeinstall(theEnv,rptr->query);
ReturnPackedExpression(theEnv,rptr->query);
}
if (meth->restrictions != NULL)
rm(theEnv,meth->restrictions,
(sizeof(RESTRICTION) * meth->restrictionCount));
RestoreBusyCount(gfunc);
}
void DestroyMethodInfo(
Environment *theEnv,
Defgeneric *gfunc,
Defmethod *meth)
{
int j;
RESTRICTION *rptr;
#if MAC_XCD
#pragma unused(gfunc)
#endif
ReturnPackedExpression(theEnv,meth->actions);
ClearUserDataList(theEnv,meth->header.usrData);
if (meth->header.ppForm != NULL)
rm(theEnv,(void *) meth->header.ppForm,(sizeof(char) * (strlen(meth->header.ppForm)+1)));
for (j = 0 ; j < meth->restrictionCount ; j++)
{
rptr = &meth->restrictions[j];
if (rptr->types != NULL)
rm(theEnv,rptr->types,(sizeof(void *) * rptr->tcnt));
ReturnPackedExpression(theEnv,rptr->query);
}
if (meth->restrictions != NULL)
rm(theEnv,meth->restrictions,
(sizeof(RESTRICTION) * meth->restrictionCount));
}
bool MethodsExecuting(
Defgeneric *gfunc)
{
long i;
for (i = 0 ; i < gfunc->mcnt ; i++)
if (gfunc->methods[i].busy > 0)
return true;
return false;
}
#endif
#if ! OBJECT_SYSTEM
bool SubsumeType(
long long t1,
long long t2)
{
if ((t2 == OBJECT_TYPE_CODE) || (t2 == PRIMITIVE_TYPE_CODE))
return true;
if ((t2 == NUMBER_TYPE_CODE) && ((t1 == INTEGER_TYPE) || (t1 == FLOAT_TYPE)))
return true;
if ((t2 == LEXEME_TYPE_CODE) && ((t1 == STRING_TYPE) || (t1 == SYMBOL_TYPE)))
return true;
if ((t2 == ADDRESS_TYPE_CODE) && ((t1 == EXTERNAL_ADDRESS_TYPE) ||
(t1 == FACT_ADDRESS_TYPE) || (t1 == INSTANCE_ADDRESS_TYPE)))
return true;
if ((t2 == LEXEME_TYPE_CODE) &&
((t1 == INSTANCE_NAME_TYPE) || (t1 == INSTANCE_ADDRESS_TYPE)))
return true;
return false;
}
#endif
unsigned short FindMethodByIndex(
Defgeneric *gfunc,
unsigned short theIndex)
{
unsigned short i;
for (i = 0 ; i < gfunc->mcnt ; i++)
{
if (gfunc->methods[i].index == theIndex)
{ return i; }
}
return METHOD_NOT_FOUND;
}
#if DEBUGGING_FUNCTIONS || PROFILING_FUNCTIONS
void PrintMethod(
Environment *theEnv,
Defmethod *meth,
StringBuilder *theSB)
{
#if MAC_XCD
#pragma unused(theEnv)
#endif
unsigned short j,k;
RESTRICTION *rptr;
char numbuf[15];
SBReset(theSB);
if (meth->system)
SBAppend(theSB,"SYS");
gensprintf(numbuf,"%-2hu ",meth->index);
SBAppend(theSB,numbuf);
for (j = 0 ; j < meth->restrictionCount ; j++)
{
rptr = &meth->restrictions[j];
if (((j + 1) == meth->restrictionCount) && (meth->maxRestrictions == RESTRICTIONS_UNBOUNDED))
{
if ((rptr->tcnt == 0) && (rptr->query == NULL))
{
SBAppend(theSB,"$?");
break;
}
SBAppend(theSB,"($? ");
}
else
SBAppend(theSB,"(");
for (k = 0 ; k < rptr->tcnt ; k++)
{
#if OBJECT_SYSTEM
SBAppend(theSB,DefclassName((Defclass *) rptr->types[k]));
#else
SBAppend(theSB,TypeName(theEnv,((CLIPSInteger *) rptr->types[k])->contents));
#endif
if ((k + 1) < rptr->tcnt)
SBAppend(theSB," ");
}
if (rptr->query != NULL)
{
if (rptr->tcnt != 0)
SBAppend(theSB," ");
SBAppend(theSB,"<qry>");
}
SBAppend(theSB,")");
if ((j + 1) != meth->restrictionCount)
SBAppend(theSB," ");
}
}
#endif
#if DEBUGGING_FUNCTIONS
void PreviewGeneric(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
Defgeneric *gfunc;
Defgeneric *previousGeneric;
bool oldce;
UDFValue theArg;
EvaluationData(theEnv)->EvaluationError = false;
if (! UDFFirstArgument(context,SYMBOL_BIT,&theArg)) return;
gfunc = LookupDefgenericByMdlOrScope(theEnv,theArg.lexemeValue->contents);
if (gfunc == NULL)
{
PrintErrorID(theEnv,"GENRCFUN",3,false);
WriteString(theEnv,STDERR,"Unable to find generic function '");
WriteString(theEnv,STDERR,theArg.lexemeValue->contents);
WriteString(theEnv,STDERR,"' in function preview-generic.\n");
return;
}
oldce = ExecutingConstruct(theEnv);
SetExecutingConstruct(theEnv,true);
previousGeneric = DefgenericData(theEnv)->CurrentGeneric;
DefgenericData(theEnv)->CurrentGeneric = gfunc;
EvaluationData(theEnv)->CurrentEvaluationDepth++;
PushProcParameters(theEnv,GetFirstArgument()->nextArg,
CountArguments(GetFirstArgument()->nextArg),
DefgenericName(gfunc),"generic function",
UnboundMethodErr);
if (EvaluationData(theEnv)->EvaluationError)
{
PopProcParameters(theEnv);
DefgenericData(theEnv)->CurrentGeneric = previousGeneric;
EvaluationData(theEnv)->CurrentEvaluationDepth--;
SetExecutingConstruct(theEnv,oldce);
return;
}
gfunc->busy++;
DisplayGenericCore(theEnv,gfunc);
gfunc->busy--;
PopProcParameters(theEnv);
DefgenericData(theEnv)->CurrentGeneric = previousGeneric;
EvaluationData(theEnv)->CurrentEvaluationDepth--;
SetExecutingConstruct(theEnv,oldce);
}
#endif
Defgeneric *CheckGenericExists(
Environment *theEnv,
const char *fname,
const char *gname)
{
Defgeneric *gfunc;
gfunc = LookupDefgenericByMdlOrScope(theEnv,gname);
if (gfunc == NULL)
{
PrintErrorID(theEnv,"GENRCFUN",3,false);
WriteString(theEnv,STDERR,"Unable to find generic function '");
WriteString(theEnv,STDERR,gname);
WriteString(theEnv,STDERR,"' in function '");
WriteString(theEnv,STDERR,fname);
WriteString(theEnv,STDERR,"'.\n");
SetEvaluationError(theEnv,true);
}
return(gfunc);
}
unsigned short CheckMethodExists(
Environment *theEnv,
const char *fname,
Defgeneric *gfunc,
unsigned short mi)
{
unsigned short fi;
fi = FindMethodByIndex(gfunc,mi);
if (fi == METHOD_NOT_FOUND)
{
PrintErrorID(theEnv,"GENRCFUN",2,false);
WriteString(theEnv,STDERR,"Unable to find method '");
WriteString(theEnv,STDERR,DefgenericName(gfunc));
WriteString(theEnv,STDERR,"' #");
PrintUnsignedInteger(theEnv,STDERR,mi);
WriteString(theEnv,STDERR," in function '");
WriteString(theEnv,STDERR,fname);
WriteString(theEnv,STDERR,"'.\n");
SetEvaluationError(theEnv,true);
}
return fi;
}
#if ! OBJECT_SYSTEM
const char *TypeName(
Environment *theEnv,
long long tcode)
{
switch (tcode)
{
case INTEGER_TYPE : return(INTEGER_TYPE_NAME);
case FLOAT_TYPE : return(FLOAT_TYPE_NAME);
case SYMBOL_TYPE : return(SYMBOL_TYPE_NAME);
case STRING_TYPE : return(STRING_TYPE_NAME);
case MULTIFIELD_TYPE : return(MULTIFIELD_TYPE_NAME);
case EXTERNAL_ADDRESS_TYPE : return(EXTERNAL_ADDRESS_TYPE_NAME);
case FACT_ADDRESS_TYPE : return(FACT_ADDRESS_TYPE_NAME);
case INSTANCE_ADDRESS_TYPE : return(INSTANCE_ADDRESS_TYPE_NAME);
case INSTANCE_NAME_TYPE : return(INSTANCE_NAME_TYPE_NAME);
case OBJECT_TYPE_CODE : return(OBJECT_TYPE_NAME);
case PRIMITIVE_TYPE_CODE : return(PRIMITIVE_TYPE_NAME);
case NUMBER_TYPE_CODE : return(NUMBER_TYPE_NAME);
case LEXEME_TYPE_CODE : return(LEXEME_TYPE_NAME);
case ADDRESS_TYPE_CODE : return(ADDRESS_TYPE_NAME);
case INSTANCE_TYPE_CODE : return(INSTANCE_TYPE_NAME);
default : PrintErrorID(theEnv,"INSCOM",1,false);
WriteString(theEnv,STDERR,"Undefined type in function 'type'.\n");
SetEvaluationError(theEnv,true);
return("<UNKNOWN-TYPE>");
}
}
#endif
void PrintGenericName(
Environment *theEnv,
const char *logName,
Defgeneric *gfunc)
{
if (gfunc->header.whichModule->theModule != GetCurrentModule(theEnv))
{
WriteString(theEnv,logName,DefgenericModule(gfunc));
WriteString(theEnv,logName,"::");
}
WriteString(theEnv,logName,gfunc->header.name->contents);
}
#if DEBUGGING_FUNCTIONS
static void DisplayGenericCore(
Environment *theEnv,
Defgeneric *gfunc)
{
long i;
bool rtn = false;
StringBuilder *theSB;
theSB = CreateStringBuilder(theEnv,256);
for (i = 0 ; i < gfunc->mcnt ; i++)
{
gfunc->methods[i].busy++;
if (IsMethodApplicable(theEnv,&gfunc->methods[i]))
{
rtn = true;
WriteString(theEnv,STDOUT,DefgenericName(gfunc));
WriteString(theEnv,STDOUT," #");
PrintMethod(theEnv,&gfunc->methods[i],theSB);
WriteString(theEnv,STDOUT,theSB->contents);
WriteString(theEnv,STDOUT,"\n");
}
gfunc->methods[i].busy--;
}
if (rtn == false)
{
WriteString(theEnv,STDOUT,"No applicable methods for ");
WriteString(theEnv,STDOUT,DefgenericName(gfunc));
WriteString(theEnv,STDOUT,".\n");
}
SBDispose(theSB);
}
#endif
#endif