#include "setup.h"
#if DEFFUNCTION_CONSTRUCT
#if (BLOAD || BLOAD_ONLY || BLOAD_AND_BSAVE)
#include "bload.h"
#include "dffnxbin.h"
#endif
#if CONSTRUCT_COMPILER && (! RUN_TIME)
#include "dffnxcmp.h"
#endif
#if (! BLOAD_ONLY) && (! RUN_TIME)
#include "constrct.h"
#include "cstrcpsr.h"
#include "dffnxpsr.h"
#include "modulpsr.h"
#endif
#include "envrnmnt.h"
#if (! RUN_TIME)
#include "extnfunc.h"
#endif
#include "dffnxexe.h"
#if DEBUGGING_FUNCTIONS
#include "watch.h"
#endif
#include "argacces.h"
#include "cstrccom.h"
#include "memalloc.h"
#include "modulutl.h"
#include "multifld.h"
#include "prntutil.h"
#include "router.h"
#include "dffnxfun.h"
static void PrintDeffunctionCall(Environment *,const char *,Deffunction *);
static bool EvaluateDeffunctionCall(Environment *,Deffunction *,UDFValue *);
static void DecrementDeffunctionBusyCount(Environment *,Deffunction *);
static void IncrementDeffunctionBusyCount(Environment *,Deffunction *);
static void DeallocateDeffunctionData(Environment *);
#if ! RUN_TIME
static void DestroyDeffunctionAction(Environment *,ConstructHeader *,void *);
static void *AllocateModule(Environment *);
static void ReturnModule(Environment *,void *);
static bool ClearDeffunctionsReady(Environment *,void *);
#else
static void RuntimeDeffunctionAction(Environment *,ConstructHeader *,void *);
#endif
#if (! BLOAD_ONLY) && (! RUN_TIME)
static bool RemoveAllDeffunctions(Environment *);
static void DeffunctionDeleteError(Environment *,const char *);
static void SaveDeffunctionHeaders(Environment *,Defmodule *,const char *,void *);
static void SaveDeffunctionHeader(Environment *,ConstructHeader *,void *);
static void SaveDeffunctions(Environment *,Defmodule *,const char *,void *);
#endif
#if DEBUGGING_FUNCTIONS
static bool DeffunctionWatchAccess(Environment *,int,bool,Expression *);
static bool DeffunctionWatchPrint(Environment *,const char *,int,Expression *);
#endif
void SetupDeffunctions(
Environment *theEnv)
{
EntityRecord deffunctionEntityRecord =
{ "PCALL", PCALL,0,0,1,
(EntityPrintFunction *) PrintDeffunctionCall,
(EntityPrintFunction *) PrintDeffunctionCall,
NULL,
(EntityEvaluationFunction *) EvaluateDeffunctionCall,
NULL,
(EntityBusyCountFunction *) DecrementDeffunctionBusyCount,
(EntityBusyCountFunction *) IncrementDeffunctionBusyCount,
NULL,NULL,NULL,NULL,NULL };
AllocateEnvironmentData(theEnv,DEFFUNCTION_DATA,sizeof(struct deffunctionData),DeallocateDeffunctionData);
memcpy(&DeffunctionData(theEnv)->DeffunctionEntityRecord,&deffunctionEntityRecord,sizeof(struct entityRecord));
InstallPrimitive(theEnv,&DeffunctionData(theEnv)->DeffunctionEntityRecord,PCALL);
DeffunctionData(theEnv)->DeffunctionModuleIndex =
RegisterModuleItem(theEnv,"deffunction",
#if (! RUN_TIME)
AllocateModule,
ReturnModule,
#else
NULL,NULL,
#endif
#if BLOAD_AND_BSAVE || BLOAD || BLOAD_ONLY
BloadDeffunctionModuleReference,
#else
NULL,
#endif
#if CONSTRUCT_COMPILER && (! RUN_TIME)
DeffunctionCModuleReference,
#else
NULL,
#endif
(FindConstructFunction *) FindDeffunctionInModule);
DeffunctionData(theEnv)->DeffunctionConstruct = AddConstruct(theEnv,"deffunction","deffunctions",
#if (! BLOAD_ONLY) && (! RUN_TIME)
ParseDeffunction,
#else
NULL,
#endif
(FindConstructFunction *) FindDeffunction,
GetConstructNamePointer,GetConstructPPForm,
GetConstructModuleItem,
(GetNextConstructFunction *) GetNextDeffunction,
SetNextConstruct,
(IsConstructDeletableFunction *) DeffunctionIsDeletable,
(DeleteConstructFunction *) Undeffunction,
#if (! BLOAD_ONLY) && (! RUN_TIME)
(FreeConstructFunction *) RemoveDeffunction
#else
NULL
#endif
);
#if ! RUN_TIME
AddClearReadyFunction(theEnv,"deffunction",ClearDeffunctionsReady,0,NULL);
#if ! BLOAD_ONLY
#if DEFMODULE_CONSTRUCT
AddPortConstructItem(theEnv,"deffunction",SYMBOL_TOKEN);
#endif
AddSaveFunction(theEnv,"deffunction-headers",SaveDeffunctionHeaders,1000,NULL);
AddSaveFunction(theEnv,"deffunctions",SaveDeffunctions,0,NULL);
AddUDF(theEnv,"undeffunction","v",1,1,"y",UndeffunctionCommand,"UndeffunctionCommand",NULL);
#endif
#if DEBUGGING_FUNCTIONS
AddUDF(theEnv,"list-deffunctions","v",0,1,"y",ListDeffunctionsCommand,"ListDeffunctionsCommand",NULL);
AddUDF(theEnv,"ppdeffunction","vs",1,2,";y;ldsyn",PPDeffunctionCommand,"PPDeffunctionCommand",NULL);
#endif
AddUDF(theEnv,"get-deffunction-list","m",0,1,"y",GetDeffunctionListFunction,"GetDeffunctionListFunction",NULL);
AddUDF(theEnv,"deffunction-module","y",1,1,"y",GetDeffunctionModuleCommand,"GetDeffunctionModuleCommand",NULL);
#if BLOAD_AND_BSAVE || BLOAD || BLOAD_ONLY
SetupDeffunctionsBload(theEnv);
#endif
#if CONSTRUCT_COMPILER
SetupDeffunctionCompiler(theEnv);
#endif
#endif
#if DEBUGGING_FUNCTIONS
AddWatchItem(theEnv,"deffunctions",0,&DeffunctionData(theEnv)->WatchDeffunctions,32,
DeffunctionWatchAccess,DeffunctionWatchPrint);
#endif
}
static void DeallocateDeffunctionData(
Environment *theEnv)
{
#if ! RUN_TIME
DeffunctionModuleData *theModuleItem;
Defmodule *theModule;
#if BLOAD || BLOAD_AND_BSAVE
if (Bloaded(theEnv)) return;
#endif
DoForAllConstructs(theEnv,
DestroyDeffunctionAction,
DeffunctionData(theEnv)->DeffunctionModuleIndex,false,NULL);
for (theModule = GetNextDefmodule(theEnv,NULL);
theModule != NULL;
theModule = GetNextDefmodule(theEnv,theModule))
{
theModuleItem = (struct deffunctionModuleData *)
GetModuleItem(theEnv,theModule,
DeffunctionData(theEnv)->DeffunctionModuleIndex);
rtn_struct(theEnv,deffunctionModuleData,theModuleItem);
}
#else
#if MAC_XCD
#pragma unused(theEnv)
#endif
#endif
}
#if ! RUN_TIME
static void DestroyDeffunctionAction(
Environment *theEnv,
ConstructHeader *theConstruct,
void *buffer)
{
#if MAC_XCD
#pragma unused(buffer)
#endif
#if (! BLOAD_ONLY) && (! RUN_TIME)
Deffunction *theDeffunction = (Deffunction *) theConstruct;
if (theDeffunction == NULL) return;
ReturnPackedExpression(theEnv,theDeffunction->code);
DestroyConstructHeader(theEnv,&theDeffunction->header);
rtn_struct(theEnv,deffunction,theDeffunction);
#else
#if MAC_XCD
#pragma unused(theConstruct,theEnv)
#endif
#endif
}
#endif
Deffunction *FindDeffunction(
Environment *theEnv,
const char *dfnxModuleAndName)
{
return (Deffunction *) FindNamedConstructInModuleOrImports(theEnv,dfnxModuleAndName,DeffunctionData(theEnv)->DeffunctionConstruct);
}
Deffunction *FindDeffunctionInModule(
Environment *theEnv,
const char *dfnxModuleAndName)
{
return (Deffunction *) FindNamedConstructInModule(theEnv,dfnxModuleAndName,DeffunctionData(theEnv)->DeffunctionConstruct);
}
Deffunction *LookupDeffunctionByMdlOrScope(
Environment *theEnv,
const char *deffunctionName)
{
return((Deffunction *) LookupConstruct(theEnv,DeffunctionData(theEnv)->DeffunctionConstruct,deffunctionName,true));
}
Deffunction *LookupDeffunctionInScope(
Environment *theEnv,
const char *deffunctionName)
{
return (Deffunction *) LookupConstruct(theEnv,DeffunctionData(theEnv)->DeffunctionConstruct,deffunctionName,false);
}
bool Undeffunction(
Deffunction *theDeffunction,
Environment *allEnv)
{
#if BLOAD_ONLY || RUN_TIME
return false;
#else
Environment *theEnv;
bool success;
GCBlock gcb;
if (theDeffunction == NULL)
{ theEnv = allEnv; }
else
{ theEnv = theDeffunction->header.env; }
#if BLOAD || BLOAD_AND_BSAVE
if (Bloaded(theEnv) == true)
return false;
#endif
GCBlockStart(theEnv,&gcb);
if (theDeffunction == NULL)
{
success = RemoveAllDeffunctions(theEnv);
GCBlockEnd(theEnv,&gcb);
return success;
}
if (DeffunctionIsDeletable(theDeffunction) == false)
{
GCBlockEnd(theEnv,&gcb);
return false;
}
RemoveConstructFromModule(theEnv,&theDeffunction->header);
RemoveDeffunction(theEnv,theDeffunction);
GCBlockEnd(theEnv,&gcb);
return true;
#endif
}
Deffunction *GetNextDeffunction(
Environment *theEnv,
Deffunction *theDeffunction)
{
return (Deffunction *)
GetNextConstructItem(theEnv,&theDeffunction->header,
DeffunctionData(theEnv)->DeffunctionModuleIndex);
}
bool DeffunctionIsDeletable(
Deffunction *theDeffunction)
{
Environment *theEnv = theDeffunction->header.env;
if (! ConstructsDeletable(theEnv))
{ return false; }
return(((theDeffunction->busy == 0) && (theDeffunction->executing == 0)) ? true : false);
}
#if (! BLOAD_ONLY) && (! RUN_TIME)
void RemoveDeffunction(
Environment *theEnv,
Deffunction *theDeffunction)
{
if (theDeffunction == NULL)
return;
ReleaseLexeme(theEnv,GetDeffunctionNamePointer(theEnv,theDeffunction));
ExpressionDeinstall(theEnv,theDeffunction->code);
ReturnPackedExpression(theEnv,theDeffunction->code);
SetDeffunctionPPForm(theEnv,theDeffunction,NULL);
ClearUserDataList(theEnv,theDeffunction->header.usrData);
rtn_struct(theEnv,deffunction,theDeffunction);
}
#endif
void UndeffunctionCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
UndefconstructCommand(context,"undeffunction",DeffunctionData(theEnv)->DeffunctionConstruct);
}
void GetDeffunctionModuleCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
returnValue->value = GetConstructModuleCommand(context,"deffunction-module",DeffunctionData(theEnv)->DeffunctionConstruct);
}
#if DEBUGGING_FUNCTIONS
void PPDeffunctionCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
PPConstructCommand(context,"ppdeffunction",DeffunctionData(theEnv)->DeffunctionConstruct,returnValue);
}
void ListDeffunctionsCommand(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
ListConstructCommand(context,DeffunctionData(theEnv)->DeffunctionConstruct);
}
void ListDeffunctions(
Environment *theEnv,
const char *logicalName,
Defmodule *theModule)
{
ListConstruct(theEnv,DeffunctionData(theEnv)->DeffunctionConstruct,logicalName,theModule);
}
#endif
void GetDeffunctionListFunction(
Environment *theEnv,
UDFContext *context,
UDFValue *returnValue)
{
GetConstructListFunction(context,returnValue,DeffunctionData(theEnv)->DeffunctionConstruct);
}
void GetDeffunctionList(
Environment *theEnv,
CLIPSValue *returnValue,
Defmodule *theModule)
{
UDFValue result;
GetConstructList(theEnv,&result,DeffunctionData(theEnv)->DeffunctionConstruct,theModule);
NormalizeMultifield(theEnv,&result);
returnValue->value = result.value;
}
bool CheckDeffunctionCall(
Environment *theEnv,
Deffunction *theDeffunction,
int args)
{
if (theDeffunction == NULL)
return false;
if (args < theDeffunction->minNumberOfParameters)
{
if (theDeffunction->maxNumberOfParameters == PARAMETERS_UNBOUNDED)
ExpectedCountError(theEnv,DeffunctionName(theDeffunction),
AT_LEAST,theDeffunction->minNumberOfParameters);
else
ExpectedCountError(theEnv,DeffunctionName(theDeffunction),
EXACTLY,theDeffunction->minNumberOfParameters);
return false;
}
else if ((args > theDeffunction->minNumberOfParameters) &&
(theDeffunction->maxNumberOfParameters != PARAMETERS_UNBOUNDED))
{
ExpectedCountError(theEnv,DeffunctionName(theDeffunction),
EXACTLY,theDeffunction->minNumberOfParameters);
return false;
}
return true;
}
static void PrintDeffunctionCall(
Environment *theEnv,
const char *logName,
Deffunction *theDeffunction)
{
#if DEVELOPER
WriteString(theEnv,logName,"(");
WriteString(theEnv,logName,DeffunctionName(theDeffunction));
if (GetFirstArgument() != NULL)
{
WriteString(theEnv,logName," ");
PrintExpression(theEnv,logName,GetFirstArgument());
}
WriteString(theEnv,logName,")");
#else
#if MAC_XCD
#pragma unused(theEnv)
#pragma unused(logName)
#pragma unused(theDeffunction)
#endif
#endif
}
static bool EvaluateDeffunctionCall(
Environment *theEnv,
Deffunction *theDeffunction,
UDFValue *returnValue)
{
CallDeffunction(theEnv,theDeffunction,GetFirstArgument(),returnValue);
if (returnValue->value == FalseSymbol(theEnv))
{ return false; }
return true;
}
static void DecrementDeffunctionBusyCount(
Environment *theEnv,
Deffunction *theDeffunction)
{
if (! ConstructData(theEnv)->ClearInProgress)
theDeffunction->busy--;
}
static void IncrementDeffunctionBusyCount(
Environment *theEnv,
Deffunction *theDeffunction)
{
#if MAC_XCD
#pragma unused(theEnv)
#endif
#if (! RUN_TIME) && (! BLOAD_ONLY)
if (! ConstructData(theEnv)->ParsingConstruct)
{ ConstructData(theEnv)->DanglingConstructs++; }
#endif
theDeffunction->busy++;
}
#if ! RUN_TIME
static void *AllocateModule(
Environment *theEnv)
{
return (void *) get_struct(theEnv,deffunctionModuleData);
}
static void ReturnModule(
Environment *theEnv,
void *theItem)
{
#if (! BLOAD_ONLY)
FreeConstructHeaderModule(theEnv,(struct defmoduleItemHeader *) theItem,DeffunctionData(theEnv)->DeffunctionConstruct);
#endif
rtn_struct(theEnv,deffunctionModuleData,theItem);
}
static bool ClearDeffunctionsReady(
Environment *theEnv,
void *context)
{
return((DeffunctionData(theEnv)->ExecutingDeffunction != NULL) ? false : true);
}
#endif
#if RUN_TIME
static void RuntimeDeffunctionAction(
Environment *theEnv,
ConstructHeader *theConstruct,
void *buffer)
{
#if MAC_XCD
#pragma unused(buffer)
#endif
Deffunction *theDeffunction = (Deffunction *) theConstruct;
theDeffunction->header.env = theEnv;
}
void DeffunctionRunTimeInitialize(
Environment *theEnv)
{
DoForAllConstructs(theEnv,RuntimeDeffunctionAction,DeffunctionData(theEnv)->DeffunctionModuleIndex,true,NULL);
}
#endif
#if (! BLOAD_ONLY) && (! RUN_TIME)
static bool RemoveAllDeffunctions(
Environment *theEnv)
{
Deffunction *dptr, *dtmp;
unsigned oldbusy;
bool success = true;
#if BLOAD || BLOAD_AND_BSAVE
if (Bloaded(theEnv) == true)
return false;
#endif
dptr = GetNextDeffunction(theEnv,NULL);
while (dptr != NULL)
{
if (dptr->executing > 0)
{
DeffunctionDeleteError(theEnv,DeffunctionName(dptr));
success = false;
}
else
{
oldbusy = dptr->busy;
ExpressionDeinstall(theEnv,dptr->code);
dptr->busy = oldbusy;
ReturnPackedExpression(theEnv,dptr->code);
dptr->code = NULL;
}
dptr = GetNextDeffunction(theEnv,dptr);
}
dptr = GetNextDeffunction(theEnv,NULL);
while (dptr != NULL)
{
dtmp = dptr;
dptr = GetNextDeffunction(theEnv,dptr);
if (dtmp->executing == 0)
{
if (dtmp->busy > 0)
{
PrintWarningID(theEnv,"DFFNXFUN",1,false);
WriteString(theEnv,STDWRN,"Deffunction '");
WriteString(theEnv,STDWRN,DeffunctionName(dtmp));
WriteString(theEnv,STDWRN,"' only partially deleted due to usage by other constructs.\n");
SetDeffunctionPPForm(theEnv,dtmp,NULL);
success = false;
}
else
{
RemoveConstructFromModule(theEnv,&dtmp->header);
RemoveDeffunction(theEnv,dtmp);
}
}
}
return(success);
}
static void DeffunctionDeleteError(
Environment *theEnv,
const char *dfnxName)
{
CantDeleteItemErrorMessage(theEnv,"deffunction",dfnxName);
}
static void SaveDeffunctionHeaders(
Environment *theEnv,
Defmodule *theModule,
const char *logicalName,
void *context)
{
DoForAllConstructsInModule(theEnv,theModule,
SaveDeffunctionHeader,
DeffunctionData(theEnv)->DeffunctionModuleIndex,
false,(void *) logicalName);
}
static void SaveDeffunctionHeader(
Environment *theEnv,
ConstructHeader *theDeffunction,
void *userBuffer)
{
Deffunction *dfnxPtr = (Deffunction *) theDeffunction;
const char *logicalName = (const char *) userBuffer;
unsigned short i;
if (DeffunctionPPForm(dfnxPtr) != NULL)
{
WriteString(theEnv,logicalName,"(deffunction ");
WriteString(theEnv,logicalName,DeffunctionModule(dfnxPtr));
WriteString(theEnv,logicalName,"::");
WriteString(theEnv,logicalName,DeffunctionName(dfnxPtr));
WriteString(theEnv,logicalName," (");
for (i = 0 ; i < dfnxPtr->minNumberOfParameters ; i++)
{
WriteString(theEnv,logicalName,"?p");
PrintUnsignedInteger(theEnv,logicalName,i);
if ((i + 1) != dfnxPtr->minNumberOfParameters)
WriteString(theEnv,logicalName," ");
}
if (dfnxPtr->maxNumberOfParameters == PARAMETERS_UNBOUNDED)
{
if (dfnxPtr->minNumberOfParameters != 0)
WriteString(theEnv,logicalName," ");
WriteString(theEnv,logicalName,"$?wildargs))\n\n");
}
else
WriteString(theEnv,logicalName,"))\n\n");
}
}
static void SaveDeffunctions(
Environment *theEnv,
Defmodule *theModule,
const char *logicalName,
void *context)
{
SaveConstruct(theEnv,theModule,logicalName,DeffunctionData(theEnv)->DeffunctionConstruct);
}
#endif
#if DEBUGGING_FUNCTIONS
static bool DeffunctionWatchAccess(
Environment *theEnv,
int code,
bool newState,
Expression *argExprs)
{
#if MAC_XCD
#pragma unused(code)
#endif
return(ConstructSetWatchAccess(theEnv,DeffunctionData(theEnv)->DeffunctionConstruct,newState,argExprs,
(ConstructGetWatchFunction *) DeffunctionGetWatch,
(ConstructSetWatchFunction *) DeffunctionSetWatch));
}
static bool DeffunctionWatchPrint(
Environment *theEnv,
const char *logName,
int code,
Expression *argExprs)
{
#if MAC_XCD
#pragma unused(code)
#endif
return(ConstructPrintWatchAccess(theEnv,DeffunctionData(theEnv)->DeffunctionConstruct,logName,argExprs,
(ConstructGetWatchFunction *) DeffunctionGetWatch,
(ConstructSetWatchFunction *) DeffunctionSetWatch));
}
void DeffunctionSetWatch(
Deffunction *theDeffunction,
bool newState)
{
theDeffunction->trace = newState;
}
bool DeffunctionGetWatch(
Deffunction *theDeffunction)
{
return theDeffunction->trace;
}
#endif
const char *DeffunctionModule(
Deffunction *theDeffunction)
{
return GetConstructModuleName(&theDeffunction->header);
}
const char *DeffunctionName(
Deffunction *theDeffunction)
{
return GetConstructNameString(&theDeffunction->header);
}
const char *DeffunctionPPForm(
Deffunction *theDeffunction)
{
return GetConstructPPForm(&theDeffunction->header);
}
CLIPSLexeme *GetDeffunctionNamePointer(
Environment *theEnv,
Deffunction *theDeffunction)
{
return GetConstructNamePointer(&theDeffunction->header);
}
void SetDeffunctionPPForm(
Environment *theEnv,
Deffunction *theDeffunction,
const char *thePPForm)
{
SetConstructPPForm(theEnv,&theDeffunction->header,thePPForm);
}
#endif