summaryrefslogtreecommitdiffstats
path: root/generic/tclOOMethod.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclOOMethod.c')
-rw-r--r--generic/tclOOMethod.c1783
1 files changed, 0 insertions, 1783 deletions
diff --git a/generic/tclOOMethod.c b/generic/tclOOMethod.c
deleted file mode 100644
index 61215de..0000000
--- a/generic/tclOOMethod.c
+++ /dev/null
@@ -1,1783 +0,0 @@
-/*
- * tclOOMethod.c --
- *
- * This file contains code to create and manage methods.
- *
- * Copyright (c) 2005-2011 by Donal K. Fellows
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#include "tclInt.h"
-#include "tclOOInt.h"
-#include "tclCompile.h"
-
-/*
- * Structure used to help delay computing names of objects or classes for
- * [info frame] until needed, making invokation faster in the normal case.
- */
-
-struct PNI {
- Tcl_Interp *interp; /* Interpreter in which to compute the name of
- * a method. */
- Tcl_Method method; /* Method to compute the name of. */
-};
-
-/*
- * Structure used to contain all the information needed about a call frame
- * used in a procedure-like method.
- */
-
-typedef struct {
- CallFrame *framePtr; /* Reference to the call frame itself (it's
- * actually allocated on the Tcl stack). */
- ProcErrorProc *errProc; /* The error handler for the body. */
- Tcl_Obj *nameObj; /* The "name" of the command. */
- Command cmd; /* The command structure. Mostly bogus. */
- ExtraFrameInfo efi; /* Extra information used for [info frame]. */
- Command *oldCmdPtr; /* Saved cmdPtr so that we can be safe after a
- * recursive call returns. */
- struct PNI pni; /* Specialist information used in the efi
- * field for this type of call. */
-} PMFrameData;
-
-/*
- * Structure used to pass information about variable resolution to the
- * on-the-ground resolvers used when working with resolved compiled variables.
- */
-
-typedef struct {
- Tcl_ResolvedVarInfo info; /* "Type" information so that the compiled
- * variable can be linked to the namespace
- * variable at the right time. */
- Tcl_Obj *variableObj; /* The name of the variable. */
- Tcl_Var cachedObjectVar; /* TODO: When to flush this cache? Can class
- * variables be cached? */
-} OOResVarInfo;
-
-/*
- * Function declarations for things defined in this file.
- */
-
-static Tcl_Obj ** InitEnsembleRewrite(Tcl_Interp *interp, int objc,
- Tcl_Obj *const *objv, int toRewrite,
- int rewriteLength, Tcl_Obj *const *rewriteObjs,
- int *lengthPtr);
-static int InvokeProcedureMethod(ClientData clientData,
- Tcl_Interp *interp, Tcl_ObjectContext context,
- int objc, Tcl_Obj *const *objv);
-static int FinalizeForwardCall(ClientData data[], Tcl_Interp *interp,
- int result);
-static int FinalizePMCall(ClientData data[], Tcl_Interp *interp,
- int result);
-static int PushMethodCallFrame(Tcl_Interp *interp,
- CallContext *contextPtr, ProcedureMethod *pmPtr,
- int objc, Tcl_Obj *const *objv,
- PMFrameData *fdPtr);
-static void DeleteProcedureMethodRecord(ProcedureMethod *pmPtr);
-static void DeleteProcedureMethod(ClientData clientData);
-static int CloneProcedureMethod(Tcl_Interp *interp,
- ClientData clientData, ClientData *newClientData);
-static void MethodErrorHandler(Tcl_Interp *interp,
- Tcl_Obj *procNameObj);
-static void ConstructorErrorHandler(Tcl_Interp *interp,
- Tcl_Obj *procNameObj);
-static void DestructorErrorHandler(Tcl_Interp *interp,
- Tcl_Obj *procNameObj);
-static Tcl_Obj * RenderDeclarerName(ClientData clientData);
-static int InvokeForwardMethod(ClientData clientData,
- Tcl_Interp *interp, Tcl_ObjectContext context,
- int objc, Tcl_Obj *const *objv);
-static void DeleteForwardMethod(ClientData clientData);
-static int CloneForwardMethod(Tcl_Interp *interp,
- ClientData clientData, ClientData *newClientData);
-static int ProcedureMethodVarResolver(Tcl_Interp *interp,
- const char *varName, Tcl_Namespace *contextNs,
- int flags, Tcl_Var *varPtr);
-static int ProcedureMethodCompiledVarResolver(Tcl_Interp *interp,
- const char *varName, int length,
- Tcl_Namespace *contextNs,
- Tcl_ResolvedVarInfo **rPtrPtr);
-
-/*
- * The types of methods defined by the core OO system.
- */
-
-static const Tcl_MethodType procMethodType = {
- TCL_OO_METHOD_VERSION_CURRENT, "method",
- InvokeProcedureMethod, DeleteProcedureMethod, CloneProcedureMethod
-};
-static const Tcl_MethodType fwdMethodType = {
- TCL_OO_METHOD_VERSION_CURRENT, "forward",
- InvokeForwardMethod, DeleteForwardMethod, CloneForwardMethod
-};
-
-/*
- * Helper macros (derived from things private to tclVar.c)
- */
-
-#define TclVarTable(contextNs) \
- ((Tcl_HashTable *) (&((Namespace *) (contextNs))->varTable))
-#define TclVarHashGetValue(hPtr) \
- ((Tcl_Var) ((char *)hPtr - TclOffset(VarInHash, entry)))
-
-/*
- * ----------------------------------------------------------------------
- *
- * Tcl_NewInstanceMethod --
- *
- * Attach a method to an object instance.
- *
- * ----------------------------------------------------------------------
- */
-
-Tcl_Method
-Tcl_NewInstanceMethod(
- Tcl_Interp *interp, /* Unused? */
- Tcl_Object object, /* The object that has the method attached to
- * it. */
- Tcl_Obj *nameObj, /* The name of the method. May be NULL; if so,
- * up to caller to manage storage (e.g., when
- * it is a constructor or destructor). */
- int flags, /* Whether this is a public method. */
- const Tcl_MethodType *typePtr,
- /* The type of method this is, which defines
- * how to invoke, delete and clone the
- * method. */
- ClientData clientData) /* Some data associated with the particular
- * method to be created. */
-{
- register Object *oPtr = (Object *) object;
- register Method *mPtr;
- Tcl_HashEntry *hPtr;
- int isNew;
-
- if (nameObj == NULL) {
- mPtr = ckalloc(sizeof(Method));
- mPtr->namePtr = NULL;
- mPtr->refCount = 1;
- goto populate;
- }
- if (!oPtr->methodsPtr) {
- oPtr->methodsPtr = ckalloc(sizeof(Tcl_HashTable));
- Tcl_InitObjHashTable(oPtr->methodsPtr);
- oPtr->flags &= ~USE_CLASS_CACHE;
- }
- hPtr = Tcl_CreateHashEntry(oPtr->methodsPtr, (char *) nameObj, &isNew);
- if (isNew) {
- mPtr = ckalloc(sizeof(Method));
- mPtr->namePtr = nameObj;
- mPtr->refCount = 1;
- Tcl_IncrRefCount(nameObj);
- Tcl_SetHashValue(hPtr, mPtr);
- } else {
- mPtr = Tcl_GetHashValue(hPtr);
- if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) {
- mPtr->typePtr->deleteProc(mPtr->clientData);
- }
- }
-
- populate:
- mPtr->typePtr = typePtr;
- mPtr->clientData = clientData;
- mPtr->flags = 0;
- mPtr->declaringObjectPtr = oPtr;
- mPtr->declaringClassPtr = NULL;
- if (flags) {
- mPtr->flags |= flags & (PUBLIC_METHOD | PRIVATE_METHOD);
- }
- oPtr->epoch++;
- return (Tcl_Method) mPtr;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Tcl_NewMethod --
- *
- * Attach a method to a class.
- *
- * ----------------------------------------------------------------------
- */
-
-Tcl_Method
-Tcl_NewMethod(
- Tcl_Interp *interp, /* The interpreter containing the class. */
- Tcl_Class cls, /* The class to attach the method to. */
- Tcl_Obj *nameObj, /* The name of the object. May be NULL (e.g.,
- * for constructors or destructors); if so, up
- * to caller to manage storage. */
- int flags, /* Whether this is a public method. */
- const Tcl_MethodType *typePtr,
- /* The type of method this is, which defines
- * how to invoke, delete and clone the
- * method. */
- ClientData clientData) /* Some data associated with the particular
- * method to be created. */
-{
- register Class *clsPtr = (Class *) cls;
- register Method *mPtr;
- Tcl_HashEntry *hPtr;
- int isNew;
-
- if (nameObj == NULL) {
- mPtr = ckalloc(sizeof(Method));
- mPtr->namePtr = NULL;
- mPtr->refCount = 1;
- goto populate;
- }
- hPtr = Tcl_CreateHashEntry(&clsPtr->classMethods, (char *)nameObj,&isNew);
- if (isNew) {
- mPtr = ckalloc(sizeof(Method));
- mPtr->refCount = 1;
- mPtr->namePtr = nameObj;
- Tcl_IncrRefCount(nameObj);
- Tcl_SetHashValue(hPtr, mPtr);
- } else {
- mPtr = Tcl_GetHashValue(hPtr);
- if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) {
- mPtr->typePtr->deleteProc(mPtr->clientData);
- }
- }
-
- populate:
- clsPtr->thisPtr->fPtr->epoch++;
- mPtr->typePtr = typePtr;
- mPtr->clientData = clientData;
- mPtr->flags = 0;
- mPtr->declaringObjectPtr = NULL;
- mPtr->declaringClassPtr = clsPtr;
- if (flags) {
- mPtr->flags |= flags & (PUBLIC_METHOD | PRIVATE_METHOD);
- }
-
- return (Tcl_Method) mPtr;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOODelMethodRef --
- *
- * How to delete a method.
- *
- * ----------------------------------------------------------------------
- */
-
-void
-TclOODelMethodRef(
- Method *mPtr)
-{
- if ((mPtr != NULL) && (--mPtr->refCount <= 0)) {
- if (mPtr->typePtr != NULL && mPtr->typePtr->deleteProc != NULL) {
- mPtr->typePtr->deleteProc(mPtr->clientData);
- }
- if (mPtr->namePtr != NULL) {
- Tcl_DecrRefCount(mPtr->namePtr);
- }
-
- ckfree(mPtr);
- }
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOONewBasicMethod --
- *
- * Helper that makes it cleaner to create very simple methods during
- * basic system initialization. Not suitable for general use.
- *
- * ----------------------------------------------------------------------
- */
-
-void
-TclOONewBasicMethod(
- Tcl_Interp *interp,
- Class *clsPtr, /* Class to attach the method to. */
- const DeclaredClassMethod *dcm)
- /* Name of the method, whether it is public,
- * and the function to implement it. */
-{
- Tcl_Obj *namePtr = Tcl_NewStringObj(dcm->name, -1);
-
- Tcl_IncrRefCount(namePtr);
- Tcl_NewMethod(interp, (Tcl_Class) clsPtr, namePtr,
- (dcm->isPublic ? PUBLIC_METHOD : 0), &dcm->definition, NULL);
- Tcl_DecrRefCount(namePtr);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOONewProcInstanceMethod --
- *
- * Create a new procedure-like method for an object.
- *
- * ----------------------------------------------------------------------
- */
-
-Method *
-TclOONewProcInstanceMethod(
- Tcl_Interp *interp, /* The interpreter containing the object. */
- Object *oPtr, /* The object to modify. */
- int flags, /* Whether this is a public method. */
- Tcl_Obj *nameObj, /* The name of the method, which must not be
- * NULL. */
- Tcl_Obj *argsObj, /* The formal argument list for the method,
- * which must not be NULL. */
- Tcl_Obj *bodyObj, /* The body of the method, which must not be
- * NULL. */
- ProcedureMethod **pmPtrPtr) /* Place to write pointer to procedure method
- * structure to allow for deeper tuning of the
- * structure's contents. NULL if caller is not
- * interested. */
-{
- int argsLen;
- register ProcedureMethod *pmPtr;
- Tcl_Method method;
-
- if (Tcl_ListObjLength(interp, argsObj, &argsLen) != TCL_OK) {
- return NULL;
- }
- pmPtr = ckalloc(sizeof(ProcedureMethod));
- memset(pmPtr, 0, sizeof(ProcedureMethod));
- pmPtr->version = TCLOO_PROCEDURE_METHOD_VERSION;
- pmPtr->flags = flags & USE_DECLARER_NS;
- pmPtr->refCount = 1;
-
- method = TclOOMakeProcInstanceMethod(interp, oPtr, flags, nameObj,
- argsObj, bodyObj, &procMethodType, pmPtr, &pmPtr->procPtr);
- if (method == NULL) {
- ckfree(pmPtr);
- } else if (pmPtrPtr != NULL) {
- *pmPtrPtr = pmPtr;
- }
- return (Method *) method;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOONewProcMethod --
- *
- * Create a new procedure-like method for a class.
- *
- * ----------------------------------------------------------------------
- */
-
-Method *
-TclOONewProcMethod(
- Tcl_Interp *interp, /* The interpreter containing the class. */
- Class *clsPtr, /* The class to modify. */
- int flags, /* Whether this is a public method. */
- Tcl_Obj *nameObj, /* The name of the method, which may be NULL;
- * if so, up to caller to manage storage
- * (e.g., because it is a constructor or
- * destructor). */
- Tcl_Obj *argsObj, /* The formal argument list for the method,
- * which may be NULL; if so, it is equivalent
- * to an empty list. */
- Tcl_Obj *bodyObj, /* The body of the method, which must not be
- * NULL. */
- ProcedureMethod **pmPtrPtr) /* Place to write pointer to procedure method
- * structure to allow for deeper tuning of the
- * structure's contents. NULL if caller is not
- * interested. */
-{
- int argsLen; /* -1 => delete argsObj before exit */
- register ProcedureMethod *pmPtr;
- const char *procName;
- Tcl_Method method;
-
- if (argsObj == NULL) {
- argsLen = -1;
- argsObj = Tcl_NewObj();
- Tcl_IncrRefCount(argsObj);
- procName = "<destructor>";
- } else if (Tcl_ListObjLength(interp, argsObj, &argsLen) != TCL_OK) {
- return NULL;
- } else {
- procName = (nameObj==NULL ? "<constructor>" : TclGetString(nameObj));
- }
-
- pmPtr = ckalloc(sizeof(ProcedureMethod));
- memset(pmPtr, 0, sizeof(ProcedureMethod));
- pmPtr->version = TCLOO_PROCEDURE_METHOD_VERSION;
- pmPtr->flags = flags & USE_DECLARER_NS;
- pmPtr->refCount = 1;
-
- method = TclOOMakeProcMethod(interp, clsPtr, flags, nameObj, procName,
- argsObj, bodyObj, &procMethodType, pmPtr, &pmPtr->procPtr);
-
- if (argsLen == -1) {
- Tcl_DecrRefCount(argsObj);
- }
- if (method == NULL) {
- ckfree(pmPtr);
- } else if (pmPtrPtr != NULL) {
- *pmPtrPtr = pmPtr;
- }
-
- return (Method *) method;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOOMakeProcInstanceMethod --
- *
- * The guts of the code to make a procedure-like method for an object.
- * Split apart so that it is easier for other extensions to reuse (in
- * particular, it frees them from having to pry so deeply into Tcl's
- * guts).
- *
- * ----------------------------------------------------------------------
- */
-
-Tcl_Method
-TclOOMakeProcInstanceMethod(
- Tcl_Interp *interp, /* The interpreter containing the object. */
- Object *oPtr, /* The object to modify. */
- int flags, /* Whether this is a public method. */
- Tcl_Obj *nameObj, /* The name of the method, which _must not_ be
- * NULL. */
- Tcl_Obj *argsObj, /* The formal argument list for the method,
- * which _must not_ be NULL. */
- Tcl_Obj *bodyObj, /* The body of the method, which _must not_ be
- * NULL. */
- const Tcl_MethodType *typePtr,
- /* The type of the method to create. */
- ClientData clientData, /* The per-method type-specific data. */
- Proc **procPtrPtr) /* A pointer to the variable in which to write
- * the procedure record reference. Presumably
- * inside the structure indicated by the
- * pointer in clientData. */
-{
- Interp *iPtr = (Interp *) interp;
- Proc *procPtr;
-
- if (TclCreateProc(interp, NULL, TclGetString(nameObj), argsObj, bodyObj,
- procPtrPtr) != TCL_OK) {
- return NULL;
- }
- procPtr = *procPtrPtr;
- procPtr->cmdPtr = NULL;
-
- if (iPtr->cmdFramePtr) {
- CmdFrame context = *iPtr->cmdFramePtr;
-
- if (context.type == TCL_LOCATION_BC) {
- /*
- * Retrieve source information from the bytecode, if possible. If
- * the information is retrieved successfully, context.type will be
- * TCL_LOCATION_SOURCE and the reference held by
- * context.data.eval.path will be counted.
- */
-
- TclGetSrcInfoForPc(&context);
- } else if (context.type == TCL_LOCATION_SOURCE) {
- /*
- * The copy into 'context' up above has created another reference
- * to 'context.data.eval.path'; account for it.
- */
-
- Tcl_IncrRefCount(context.data.eval.path);
- }
-
- if (context.type == TCL_LOCATION_SOURCE) {
- /*
- * We can account for source location within a proc only if the
- * proc body was not created by substitution.
- * (FIXME: check that this is sane and correct!)
- */
-
- if (context.line
- && (context.nline >= 4) && (context.line[3] >= 0)) {
- int isNew;
- CmdFrame *cfPtr = ckalloc(sizeof(CmdFrame));
- Tcl_HashEntry *hPtr;
-
- cfPtr->level = -1;
- cfPtr->type = context.type;
- cfPtr->line = ckalloc(sizeof(int));
- cfPtr->line[0] = context.line[3];
- cfPtr->nline = 1;
- cfPtr->framePtr = NULL;
- cfPtr->nextPtr = NULL;
-
- cfPtr->data.eval.path = context.data.eval.path;
- Tcl_IncrRefCount(cfPtr->data.eval.path);
-
- cfPtr->cmd = NULL;
- cfPtr->len = 0;
-
- hPtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr,
- (char *) procPtr, &isNew);
- Tcl_SetHashValue(hPtr, cfPtr);
- }
-
- /*
- * 'context' is going out of scope; account for the reference that
- * it's holding to the path name.
- */
-
- Tcl_DecrRefCount(context.data.eval.path);
- context.data.eval.path = NULL;
- }
- }
-
- return Tcl_NewInstanceMethod(interp, (Tcl_Object) oPtr, nameObj, flags,
- typePtr, clientData);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOOMakeProcMethod --
- *
- * The guts of the code to make a procedure-like method for a class.
- * Split apart so that it is easier for other extensions to reuse (in
- * particular, it frees them from having to pry so deeply into Tcl's
- * guts).
- *
- * ----------------------------------------------------------------------
- */
-
-Tcl_Method
-TclOOMakeProcMethod(
- Tcl_Interp *interp, /* The interpreter containing the class. */
- Class *clsPtr, /* The class to modify. */
- int flags, /* Whether this is a public method. */
- Tcl_Obj *nameObj, /* The name of the method, which may be NULL;
- * if so, up to caller to manage storage
- * (e.g., because it is a constructor or
- * destructor). */
- const char *namePtr, /* The name of the method as a string, which
- * _must not_ be NULL. */
- Tcl_Obj *argsObj, /* The formal argument list for the method,
- * which _must not_ be NULL. */
- Tcl_Obj *bodyObj, /* The body of the method, which _must not_ be
- * NULL. */
- const Tcl_MethodType *typePtr,
- /* The type of the method to create. */
- ClientData clientData, /* The per-method type-specific data. */
- Proc **procPtrPtr) /* A pointer to the variable in which to write
- * the procedure record reference. Presumably
- * inside the structure indicated by the
- * pointer in clientData. */
-{
- Interp *iPtr = (Interp *) interp;
- Proc *procPtr;
-
- if (TclCreateProc(interp, NULL, namePtr, argsObj, bodyObj,
- procPtrPtr) != TCL_OK) {
- return NULL;
- }
- procPtr = *procPtrPtr;
- procPtr->cmdPtr = NULL;
-
- if (iPtr->cmdFramePtr) {
- CmdFrame context = *iPtr->cmdFramePtr;
-
- if (context.type == TCL_LOCATION_BC) {
- /*
- * Retrieve source information from the bytecode, if possible. If
- * the information is retrieved successfully, context.type will be
- * TCL_LOCATION_SOURCE and the reference held by
- * context.data.eval.path will be counted.
- */
-
- TclGetSrcInfoForPc(&context);
- } else if (context.type == TCL_LOCATION_SOURCE) {
- /*
- * The copy into 'context' up above has created another reference
- * to 'context.data.eval.path'; account for it.
- */
-
- Tcl_IncrRefCount(context.data.eval.path);
- }
-
- if (context.type == TCL_LOCATION_SOURCE) {
- /*
- * We can account for source location within a proc only if the
- * proc body was not created by substitution.
- * (FIXME: check that this is sane and correct!)
- */
-
- if (context.line
- && (context.nline >= 4) && (context.line[3] >= 0)) {
- int isNew;
- CmdFrame *cfPtr = ckalloc(sizeof(CmdFrame));
- Tcl_HashEntry *hPtr;
-
- cfPtr->level = -1;
- cfPtr->type = context.type;
- cfPtr->line = ckalloc(sizeof(int));
- cfPtr->line[0] = context.line[3];
- cfPtr->nline = 1;
- cfPtr->framePtr = NULL;
- cfPtr->nextPtr = NULL;
-
- cfPtr->data.eval.path = context.data.eval.path;
- Tcl_IncrRefCount(cfPtr->data.eval.path);
-
- cfPtr->cmd = NULL;
- cfPtr->len = 0;
-
- hPtr = Tcl_CreateHashEntry(iPtr->linePBodyPtr,
- (char *) procPtr, &isNew);
- Tcl_SetHashValue(hPtr, cfPtr);
- }
-
- /*
- * 'context' is going out of scope; account for the reference that
- * it's holding to the path name.
- */
-
- Tcl_DecrRefCount(context.data.eval.path);
- context.data.eval.path = NULL;
- }
- }
-
- return Tcl_NewMethod(interp, (Tcl_Class) clsPtr, nameObj, flags, typePtr,
- clientData);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * InvokeProcedureMethod, PushMethodCallFrame --
- *
- * How to invoke a procedure-like method.
- *
- * ----------------------------------------------------------------------
- */
-
-static int
-InvokeProcedureMethod(
- ClientData clientData, /* Pointer to some per-method context. */
- Tcl_Interp *interp,
- Tcl_ObjectContext context, /* The method calling context. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const *objv) /* Arguments as actually seen. */
-{
- ProcedureMethod *pmPtr = clientData;
- int result;
- PMFrameData *fdPtr; /* Important data that has to have a lifetime
- * matched by this function (or rather, by the
- * call frame's lifetime). */
-
- /*
- * If the interpreter was deleted, we just skip to the next thing in the
- * chain.
- */
-
- if (Tcl_InterpDeleted(interp)) {
- return TclNRObjectContextInvokeNext(interp, context, objc, objv,
- Tcl_ObjectContextSkippedArgs(context));
- }
-
- /*
- * Allocate the special frame data.
- */
-
- fdPtr = TclStackAlloc(interp, sizeof(PMFrameData));
-
- /*
- * Create a call frame for this method.
- */
-
- result = PushMethodCallFrame(interp, (CallContext *) context, pmPtr,
- objc, objv, fdPtr);
- if (result != TCL_OK) {
- TclStackFree(interp, fdPtr);
- return result;
- }
- pmPtr->refCount++;
-
- /*
- * Give the pre-call callback a chance to do some setup and, possibly,
- * veto the call.
- */
-
- if (pmPtr->preCallProc != NULL) {
- int isFinished;
-
- result = pmPtr->preCallProc(pmPtr->clientData, interp, context,
- (Tcl_CallFrame *) fdPtr->framePtr, &isFinished);
- if (isFinished || result != TCL_OK) {
- /*
- * Restore the old cmdPtr so that a subsequent use of [info frame]
- * won't crash on us. [Bug 3001438]
- */
-
- pmPtr->procPtr->cmdPtr = fdPtr->oldCmdPtr;
-
- Tcl_PopCallFrame(interp);
- TclStackFree(interp, fdPtr->framePtr);
- if (--pmPtr->refCount < 1) {
- DeleteProcedureMethodRecord(pmPtr);
- }
- TclStackFree(interp, fdPtr);
- return result;
- }
- }
-
- /*
- * Now invoke the body of the method.
- */
-
- TclNRAddCallback(interp, FinalizePMCall, pmPtr, context, fdPtr, NULL);
- return TclNRInterpProcCore(interp, fdPtr->nameObj,
- Tcl_ObjectContextSkippedArgs(context), fdPtr->errProc);
-}
-
-static int
-FinalizePMCall(
- ClientData data[],
- Tcl_Interp *interp,
- int result)
-{
- ProcedureMethod *pmPtr = data[0];
- Tcl_ObjectContext context = data[1];
- PMFrameData *fdPtr = data[2];
-
- /*
- * Give the post-call callback a chance to do some cleanup. Note that at
- * this point the call frame itself is invalid; it's already been popped.
- */
-
- if (pmPtr->postCallProc) {
- result = pmPtr->postCallProc(pmPtr->clientData, interp, context,
- Tcl_GetObjectNamespace(Tcl_ObjectContextObject(context)),
- result);
- }
-
- /*
- * Restore the old cmdPtr so that a subsequent use of [info frame] won't
- * crash on us. [Bug 3001438]
- */
-
- pmPtr->procPtr->cmdPtr = fdPtr->oldCmdPtr;
-
- /*
- * Scrap the special frame data now that we're done with it. Note that we
- * are inlining DeleteProcedureMethod() here; this location is highly
- * sensitive when it comes to performance!
- */
-
- if (--pmPtr->refCount < 1) {
- DeleteProcedureMethodRecord(pmPtr);
- }
- TclStackFree(interp, fdPtr);
- return result;
-}
-
-static int
-PushMethodCallFrame(
- Tcl_Interp *interp, /* Current interpreter. */
- CallContext *contextPtr, /* Current method call context. */
- ProcedureMethod *pmPtr, /* Information about this procedure-like
- * method. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const *objv, /* Array of arguments. */
- PMFrameData *fdPtr) /* Place to store information about the call
- * frame. */
-{
- Namespace *nsPtr = (Namespace *) contextPtr->oPtr->namespacePtr;
- register int result;
- const char *namePtr;
- CallFrame **framePtrPtr = &fdPtr->framePtr;
-
- /*
- * Compute basic information on the basis of the type of method it is.
- */
-
- if (contextPtr->callPtr->flags & CONSTRUCTOR) {
- namePtr = "<constructor>";
- fdPtr->nameObj = contextPtr->oPtr->fPtr->constructorName;
- fdPtr->errProc = ConstructorErrorHandler;
- } else if (contextPtr->callPtr->flags & DESTRUCTOR) {
- namePtr = "<destructor>";
- fdPtr->nameObj = contextPtr->oPtr->fPtr->destructorName;
- fdPtr->errProc = DestructorErrorHandler;
- } else {
- fdPtr->nameObj = Tcl_MethodName(
- Tcl_ObjectContextMethod((Tcl_ObjectContext) contextPtr));
- namePtr = TclGetString(fdPtr->nameObj);
- fdPtr->errProc = MethodErrorHandler;
- }
- if (pmPtr->errProc != NULL) {
- fdPtr->errProc = pmPtr->errProc;
- }
-
- /*
- * Magic to enable things like [incr Tcl], which wants methods to run in
- * their class's namespace.
- */
-
- if (pmPtr->flags & USE_DECLARER_NS) {
- register Method *mPtr =
- contextPtr->callPtr->chain[contextPtr->index].mPtr;
-
- if (mPtr->declaringClassPtr != NULL) {
- nsPtr = (Namespace *)
- mPtr->declaringClassPtr->thisPtr->namespacePtr;
- } else {
- nsPtr = (Namespace *) mPtr->declaringObjectPtr->namespacePtr;
- }
- }
-
- /*
- * Save the old cmdPtr so that when this recursive call returns, we can
- * restore it. To do otherwise causes crashes in [info frame] after we
- * return from a recursive call. [Bug 3001438]
- */
-
- fdPtr->oldCmdPtr = pmPtr->procPtr->cmdPtr;
-
- /*
- * Compile the body. This operation may fail.
- */
-
- fdPtr->efi.length = 2;
- memset(&fdPtr->cmd, 0, sizeof(Command));
- fdPtr->cmd.nsPtr = nsPtr;
- fdPtr->cmd.clientData = &fdPtr->efi;
- pmPtr->procPtr->cmdPtr = &fdPtr->cmd;
-
- /*
- * [Bug 2037727] Always call TclProcCompileProc so that we check not only
- * that we have bytecode, but also that it remains valid. Note that we set
- * the namespace of the code here directly; this is a hack, but the
- * alternative is *so* slow...
- */
-
- if (pmPtr->procPtr->bodyPtr->typePtr == &tclByteCodeType) {
- ByteCode *codePtr =
- pmPtr->procPtr->bodyPtr->internalRep.twoPtrValue.ptr1;
-
- codePtr->nsPtr = nsPtr;
- }
- result = TclProcCompileProc(interp, pmPtr->procPtr,
- pmPtr->procPtr->bodyPtr, nsPtr, "body of method", namePtr);
- if (result != TCL_OK) {
- goto failureReturn;
- }
-
- /*
- * Make the stack frame and fill it out with information about this call.
- * This operation may fail.
- */
-
- result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
- (Tcl_Namespace *) nsPtr, FRAME_IS_PROC|FRAME_IS_METHOD);
- if (result != TCL_OK) {
- goto failureReturn;
- }
-
- fdPtr->framePtr->clientData = contextPtr;
- fdPtr->framePtr->objc = objc;
- fdPtr->framePtr->objv = objv;
- fdPtr->framePtr->procPtr = pmPtr->procPtr;
-
- /*
- * Finish filling out the extra frame info so that [info frame] works.
- */
-
- fdPtr->efi.fields[0].name = "method";
- fdPtr->efi.fields[0].proc = NULL;
- fdPtr->efi.fields[0].clientData = fdPtr->nameObj;
- if (pmPtr->gfivProc != NULL) {
- fdPtr->efi.fields[1].name = "";
- fdPtr->efi.fields[1].proc = pmPtr->gfivProc;
- fdPtr->efi.fields[1].clientData = pmPtr;
- } else {
- register Tcl_Method method =
- Tcl_ObjectContextMethod((Tcl_ObjectContext) contextPtr);
-
- if (Tcl_MethodDeclarerObject(method) != NULL) {
- fdPtr->efi.fields[1].name = "object";
- } else {
- fdPtr->efi.fields[1].name = "class";
- }
- fdPtr->efi.fields[1].proc = RenderDeclarerName;
- fdPtr->efi.fields[1].clientData = &fdPtr->pni;
- fdPtr->pni.interp = interp;
- fdPtr->pni.method = method;
- }
-
- return TCL_OK;
-
- /*
- * Restore the old cmdPtr so that a subsequent use of [info frame] won't
- * crash on us. [Bug 3001438]
- */
-
- failureReturn:
- pmPtr->procPtr->cmdPtr = fdPtr->oldCmdPtr;
- return result;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOOSetupVariableResolver, etc. --
- *
- * Variable resolution engine used to connect declared variables to local
- * variables used in methods. The compiled variable resolver is more
- * important, but both are needed as it is possible to have a variable
- * that is only referred to in ways that aren't compilable and we can't
- * force LVT presence. [TIP #320]
- *
- * ----------------------------------------------------------------------
- */
-
-void
-TclOOSetupVariableResolver(
- Tcl_Namespace *nsPtr)
-{
- Tcl_ResolverInfo info;
-
- Tcl_GetNamespaceResolvers(nsPtr, &info);
- if (info.compiledVarResProc == NULL) {
- Tcl_SetNamespaceResolvers(nsPtr, NULL, ProcedureMethodVarResolver,
- ProcedureMethodCompiledVarResolver);
- }
-}
-
-static int
-ProcedureMethodVarResolver(
- Tcl_Interp *interp,
- const char *varName,
- Tcl_Namespace *contextNs,
- int flags,
- Tcl_Var *varPtr)
-{
- int result;
- Tcl_ResolvedVarInfo *rPtr = NULL;
-
- result = ProcedureMethodCompiledVarResolver(interp, varName,
- strlen(varName), contextNs, &rPtr);
-
- if (result != TCL_OK) {
- return result;
- }
-
- *varPtr = rPtr->fetchProc(interp, rPtr);
-
- /*
- * Must not retain reference to resolved information. [Bug 3105999]
- */
-
- if (rPtr != NULL) {
- rPtr->deleteProc(rPtr);
- }
- return (*varPtr? TCL_OK : TCL_CONTINUE);
-}
-
-static Tcl_Var
-ProcedureMethodCompiledVarConnect(
- Tcl_Interp *interp,
- Tcl_ResolvedVarInfo *rPtr)
-{
- OOResVarInfo *infoPtr = (OOResVarInfo *) rPtr;
- Interp *iPtr = (Interp *) interp;
- CallFrame *framePtr = iPtr->varFramePtr;
- CallContext *contextPtr;
- Tcl_Obj *variableObj;
- Tcl_HashEntry *hPtr;
- int i, isNew, cacheIt, varLen, len;
- const char *match, *varName;
-
- /*
- * Check that the variable is being requested in a context that is also a
- * method call; if not (i.e. we're evaluating in the object's namespace or
- * in a procedure of that namespace) then we do nothing.
- */
-
- if (framePtr == NULL || !(framePtr->isProcCallFrame & FRAME_IS_METHOD)) {
- return NULL;
- }
- contextPtr = framePtr->clientData;
-
- /*
- * If we've done the work before (in a comparable context) then reuse that
- * rather than performing resolution ourselves.
- */
-
- if (infoPtr->cachedObjectVar) {
- return infoPtr->cachedObjectVar;
- }
-
- /*
- * Check if the variable is one we want to resolve at all (i.e. whether it
- * is in the list provided by the user). If not, we mustn't do anything
- * either.
- */
-
- varName = TclGetStringFromObj(infoPtr->variableObj, &varLen);
- if (contextPtr->callPtr->chain[contextPtr->index]
- .mPtr->declaringClassPtr != NULL) {
- FOREACH(variableObj, contextPtr->callPtr->chain[contextPtr->index]
- .mPtr->declaringClassPtr->variables) {
- match = TclGetStringFromObj(variableObj, &len);
- if ((len == varLen) && !memcmp(match, varName, len)) {
- cacheIt = 0;
- goto gotMatch;
- }
- }
- } else {
- FOREACH(variableObj, contextPtr->oPtr->variables) {
- match = TclGetStringFromObj(variableObj, &len);
- if ((len == varLen) && !memcmp(match, varName, len)) {
- cacheIt = 1;
- goto gotMatch;
- }
- }
- }
- return NULL;
-
- /*
- * It is a variable we want to resolve, so resolve it.
- */
-
- gotMatch:
- hPtr = Tcl_CreateHashEntry(TclVarTable(contextPtr->oPtr->namespacePtr),
- (char *) variableObj, &isNew);
- if (isNew) {
- TclSetVarNamespaceVar((Var *) TclVarHashGetValue(hPtr));
- }
- if (cacheIt) {
- infoPtr->cachedObjectVar = TclVarHashGetValue(hPtr);
-
- /*
- * We must keep a reference to the variable so everything will
- * continue to work correctly even if it is unset; being unset does
- * not end the life of the variable at this level. [Bug 3185009]
- */
-
- VarHashRefCount(infoPtr->cachedObjectVar)++;
- }
- return TclVarHashGetValue(hPtr);
-}
-
-static void
-ProcedureMethodCompiledVarDelete(
- Tcl_ResolvedVarInfo *rPtr)
-{
- OOResVarInfo *infoPtr = (OOResVarInfo *) rPtr;
-
- /*
- * Release the reference to the variable if we were holding it.
- */
-
- if (infoPtr->cachedObjectVar) {
- VarHashRefCount(infoPtr->cachedObjectVar)--;
- TclCleanupVar((Var *) infoPtr->cachedObjectVar, NULL);
- }
- Tcl_DecrRefCount(infoPtr->variableObj);
- ckfree(infoPtr);
-}
-
-static int
-ProcedureMethodCompiledVarResolver(
- Tcl_Interp *interp,
- const char *varName,
- int length,
- Tcl_Namespace *contextNs,
- Tcl_ResolvedVarInfo **rPtrPtr)
-{
- OOResVarInfo *infoPtr;
- Tcl_Obj *variableObj = Tcl_NewStringObj(varName, length);
-
- /*
- * Do not create resolvers for cases that contain namespace separators or
- * which look like array accesses. Both will lead us astray.
- */
-
- if (strstr(Tcl_GetString(variableObj), "::") != NULL ||
- Tcl_StringMatch(Tcl_GetString(variableObj), "*(*)")) {
- Tcl_DecrRefCount(variableObj);
- return TCL_CONTINUE;
- }
-
- infoPtr = ckalloc(sizeof(OOResVarInfo));
- infoPtr->info.fetchProc = ProcedureMethodCompiledVarConnect;
- infoPtr->info.deleteProc = ProcedureMethodCompiledVarDelete;
- infoPtr->cachedObjectVar = NULL;
- infoPtr->variableObj = variableObj;
- Tcl_IncrRefCount(variableObj);
- *rPtrPtr = &infoPtr->info;
- return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * RenderDeclarerName --
- *
- * Returns the name of the entity (object or class) which declared a
- * method. Used for producing information for [info frame] in such a way
- * that the expensive part of this (generating the object or class name
- * itself) isn't done until it is needed.
- *
- * ----------------------------------------------------------------------
- */
-
-static Tcl_Obj *
-RenderDeclarerName(
- ClientData clientData)
-{
- struct PNI *pni = clientData;
- Tcl_Object object = Tcl_MethodDeclarerObject(pni->method);
-
- if (object == NULL) {
- object = Tcl_GetClassAsObject(Tcl_MethodDeclarerClass(pni->method));
- }
- return TclOOObjectName(pni->interp, (Object *) object);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * MethodErrorHandler, ConstructorErrorHandler, DestructorErrorHandler --
- *
- * How to fill in the stack trace correctly upon error in various forms
- * of procedure-like methods. LIMIT is how long the inserted strings in
- * the error traces should get before being converted to have ellipses,
- * and ELLIPSIFY is a macro to do the conversion (with the help of a
- * %.*s%s format field). Note that ELLIPSIFY is only safe for use in
- * suitable formatting contexts.
- *
- * ----------------------------------------------------------------------
- */
-
-#define LIMIT 60
-#define ELLIPSIFY(str,len) \
- ((len) > LIMIT ? LIMIT : (len)), (str), ((len) > LIMIT ? "..." : "")
-
-static void
-MethodErrorHandler(
- Tcl_Interp *interp,
- Tcl_Obj *methodNameObj)
-{
- int nameLen, objectNameLen;
- CallContext *contextPtr = ((Interp *) interp)->varFramePtr->clientData;
- Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr;
- const char *objectName, *kindName, *methodName =
- Tcl_GetStringFromObj(mPtr->namePtr, &nameLen);
- Object *declarerPtr;
-
- if (mPtr->declaringObjectPtr != NULL) {
- declarerPtr = mPtr->declaringObjectPtr;
- kindName = "object";
- } else {
- if (mPtr->declaringClassPtr == NULL) {
- Tcl_Panic("method not declared in class or object");
- }
- declarerPtr = mPtr->declaringClassPtr->thisPtr;
- kindName = "class";
- }
-
- objectName = Tcl_GetStringFromObj(TclOOObjectName(interp, declarerPtr),
- &objectNameLen);
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
- "\n (%s \"%.*s%s\" method \"%.*s%s\" line %d)",
- kindName, ELLIPSIFY(objectName, objectNameLen),
- ELLIPSIFY(methodName, nameLen), Tcl_GetErrorLine(interp)));
-}
-
-static void
-ConstructorErrorHandler(
- Tcl_Interp *interp,
- Tcl_Obj *methodNameObj)
-{
- CallContext *contextPtr = ((Interp *) interp)->varFramePtr->clientData;
- Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr;
- Object *declarerPtr;
- const char *objectName, *kindName;
- int objectNameLen;
-
- if (mPtr->declaringObjectPtr != NULL) {
- declarerPtr = mPtr->declaringObjectPtr;
- kindName = "object";
- } else {
- if (mPtr->declaringClassPtr == NULL) {
- Tcl_Panic("method not declared in class or object");
- }
- declarerPtr = mPtr->declaringClassPtr->thisPtr;
- kindName = "class";
- }
-
- objectName = Tcl_GetStringFromObj(TclOOObjectName(interp, declarerPtr),
- &objectNameLen);
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
- "\n (%s \"%.*s%s\" constructor line %d)", kindName,
- ELLIPSIFY(objectName, objectNameLen), Tcl_GetErrorLine(interp)));
-}
-
-static void
-DestructorErrorHandler(
- Tcl_Interp *interp,
- Tcl_Obj *methodNameObj)
-{
- CallContext *contextPtr = ((Interp *) interp)->varFramePtr->clientData;
- Method *mPtr = contextPtr->callPtr->chain[contextPtr->index].mPtr;
- Object *declarerPtr;
- const char *objectName, *kindName;
- int objectNameLen;
-
- if (mPtr->declaringObjectPtr != NULL) {
- declarerPtr = mPtr->declaringObjectPtr;
- kindName = "object";
- } else {
- if (mPtr->declaringClassPtr == NULL) {
- Tcl_Panic("method not declared in class or object");
- }
- declarerPtr = mPtr->declaringClassPtr->thisPtr;
- kindName = "class";
- }
-
- objectName = Tcl_GetStringFromObj(TclOOObjectName(interp, declarerPtr),
- &objectNameLen);
- Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
- "\n (%s \"%.*s%s\" destructor line %d)", kindName,
- ELLIPSIFY(objectName, objectNameLen), Tcl_GetErrorLine(interp)));
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * DeleteProcedureMethod, CloneProcedureMethod --
- *
- * How to delete and clone procedure-like methods.
- *
- * ----------------------------------------------------------------------
- */
-
-static void
-DeleteProcedureMethodRecord(
- ProcedureMethod *pmPtr)
-{
- TclProcDeleteProc(pmPtr->procPtr);
- if (pmPtr->deleteClientdataProc) {
- pmPtr->deleteClientdataProc(pmPtr->clientData);
- }
- ckfree(pmPtr);
-}
-
-static void
-DeleteProcedureMethod(
- ClientData clientData)
-{
- register ProcedureMethod *pmPtr = clientData;
-
- if (--pmPtr->refCount < 1) {
- DeleteProcedureMethodRecord(pmPtr);
- }
-}
-
-static int
-CloneProcedureMethod(
- Tcl_Interp *interp,
- ClientData clientData,
- ClientData *newClientData)
-{
- ProcedureMethod *pmPtr = clientData;
- ProcedureMethod *pm2Ptr;
- Tcl_Obj *bodyObj, *argsObj;
- CompiledLocal *localPtr;
-
- /*
- * Copy the argument list.
- */
-
- argsObj = Tcl_NewObj();
- for (localPtr=pmPtr->procPtr->firstLocalPtr; localPtr!=NULL;
- localPtr=localPtr->nextPtr) {
- if (TclIsVarArgument(localPtr)) {
- Tcl_Obj *argObj = Tcl_NewObj();
-
- Tcl_ListObjAppendElement(NULL, argObj,
- Tcl_NewStringObj(localPtr->name, -1));
- if (localPtr->defValuePtr != NULL) {
- Tcl_ListObjAppendElement(NULL, argObj, localPtr->defValuePtr);
- }
- Tcl_ListObjAppendElement(NULL, argsObj, argObj);
- }
- }
-
- /*
- * Must strip the internal representation in order to ensure that any
- * bound references to instance variables are removed. [Bug 3609693]
- */
-
- bodyObj = Tcl_DuplicateObj(pmPtr->procPtr->bodyPtr);
- TclFreeIntRep(bodyObj);
-
- /*
- * Create the actual copy of the method record, manufacturing a new proc
- * record.
- */
-
- pm2Ptr = ckalloc(sizeof(ProcedureMethod));
- memcpy(pm2Ptr, pmPtr, sizeof(ProcedureMethod));
- pm2Ptr->refCount = 1;
- Tcl_IncrRefCount(argsObj);
- Tcl_IncrRefCount(bodyObj);
- if (TclCreateProc(interp, NULL, "", argsObj, bodyObj,
- &pm2Ptr->procPtr) != TCL_OK) {
- Tcl_DecrRefCount(argsObj);
- Tcl_DecrRefCount(bodyObj);
- ckfree(pm2Ptr);
- return TCL_ERROR;
- }
- Tcl_DecrRefCount(argsObj);
- Tcl_DecrRefCount(bodyObj);
-
- if (pmPtr->cloneClientdataProc) {
- pm2Ptr->clientData = pmPtr->cloneClientdataProc(pmPtr->clientData);
- }
- *newClientData = pm2Ptr;
- return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOONewForwardMethod --
- *
- * Create a forwarded method for an object.
- *
- * ----------------------------------------------------------------------
- */
-
-Method *
-TclOONewForwardInstanceMethod(
- Tcl_Interp *interp, /* Interpreter for error reporting. */
- Object *oPtr, /* The object to attach the method to. */
- int flags, /* Whether the method is public or not. */
- Tcl_Obj *nameObj, /* The name of the method. */
- Tcl_Obj *prefixObj) /* List of arguments that form the command
- * prefix to forward to. */
-{
- int prefixLen;
- register ForwardMethod *fmPtr;
- Tcl_Obj *cmdObj;
-
- if (Tcl_ListObjLength(interp, prefixObj, &prefixLen) != TCL_OK) {
- return NULL;
- }
- if (prefixLen < 1) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "method forward prefix must be non-empty", -1));
- Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_FORWARD", NULL);
- return NULL;
- }
-
- fmPtr = ckalloc(sizeof(ForwardMethod));
- fmPtr->prefixObj = prefixObj;
- Tcl_ListObjIndex(interp, prefixObj, 0, &cmdObj);
- Tcl_IncrRefCount(prefixObj);
- return (Method *) Tcl_NewInstanceMethod(interp, (Tcl_Object) oPtr,
- nameObj, flags, &fwdMethodType, fmPtr);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOONewForwardMethod --
- *
- * Create a new forwarded method for a class.
- *
- * ----------------------------------------------------------------------
- */
-
-Method *
-TclOONewForwardMethod(
- Tcl_Interp *interp, /* Interpreter for error reporting. */
- Class *clsPtr, /* The class to attach the method to. */
- int flags, /* Whether the method is public or not. */
- Tcl_Obj *nameObj, /* The name of the method. */
- Tcl_Obj *prefixObj) /* List of arguments that form the command
- * prefix to forward to. */
-{
- int prefixLen;
- register ForwardMethod *fmPtr;
- Tcl_Obj *cmdObj;
-
- if (Tcl_ListObjLength(interp, prefixObj, &prefixLen) != TCL_OK) {
- return NULL;
- }
- if (prefixLen < 1) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "method forward prefix must be non-empty", -1));
- Tcl_SetErrorCode(interp, "TCL", "OO", "BAD_FORWARD", NULL);
- return NULL;
- }
-
- fmPtr = ckalloc(sizeof(ForwardMethod));
- fmPtr->prefixObj = prefixObj;
- Tcl_ListObjIndex(interp, prefixObj, 0, &cmdObj);
- Tcl_IncrRefCount(prefixObj);
- return (Method *) Tcl_NewMethod(interp, (Tcl_Class) clsPtr, nameObj,
- flags, &fwdMethodType, fmPtr);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * InvokeForwardMethod --
- *
- * How to invoke a forwarded method. Works by doing some ensemble-like
- * command rearranging and then invokes some other Tcl command.
- *
- * ----------------------------------------------------------------------
- */
-
-static int
-InvokeForwardMethod(
- ClientData clientData, /* Pointer to some per-method context. */
- Tcl_Interp *interp,
- Tcl_ObjectContext context, /* The method calling context. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const *objv) /* Arguments as actually seen. */
-{
- CallContext *contextPtr = (CallContext *) context;
- ForwardMethod *fmPtr = clientData;
- Tcl_Obj **argObjs, **prefixObjs;
- int numPrefixes, len, skip = contextPtr->skip;
-
- /*
- * Build the real list of arguments to use. Note that we know that the
- * prefixObj field of the ForwardMethod structure holds a reference to a
- * non-empty list, so there's a whole class of failures ("not a list") we
- * can ignore here.
- */
-
- Tcl_ListObjGetElements(NULL, fmPtr->prefixObj, &numPrefixes, &prefixObjs);
- argObjs = InitEnsembleRewrite(interp, objc, objv, skip,
- numPrefixes, prefixObjs, &len);
- Tcl_NRAddCallback(interp, FinalizeForwardCall, argObjs, NULL, NULL, NULL);
- ((Interp *)interp)->lookupNsPtr
- = (Namespace *) contextPtr->oPtr->namespacePtr;
- return TclNREvalObjv(interp, len, argObjs, TCL_EVAL_NOERR, NULL);
-}
-
-static int
-FinalizeForwardCall(
- ClientData data[],
- Tcl_Interp *interp,
- int result)
-{
- Tcl_Obj **argObjs = data[0];
-
- TclStackFree(interp, argObjs);
- return result;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * DeleteForwardMethod, CloneForwardMethod --
- *
- * How to delete and clone forwarded methods.
- *
- * ----------------------------------------------------------------------
- */
-
-static void
-DeleteForwardMethod(
- ClientData clientData)
-{
- ForwardMethod *fmPtr = clientData;
-
- Tcl_DecrRefCount(fmPtr->prefixObj);
- ckfree(fmPtr);
-}
-
-static int
-CloneForwardMethod(
- Tcl_Interp *interp,
- ClientData clientData,
- ClientData *newClientData)
-{
- ForwardMethod *fmPtr = clientData;
- ForwardMethod *fm2Ptr = ckalloc(sizeof(ForwardMethod));
-
- fm2Ptr->prefixObj = fmPtr->prefixObj;
- Tcl_IncrRefCount(fm2Ptr->prefixObj);
- *newClientData = fm2Ptr;
- return TCL_OK;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * TclOOGetProcFromMethod, TclOOGetFwdFromMethod --
- *
- * Utility functions used for procedure-like and forwarding method
- * introspection.
- *
- * ----------------------------------------------------------------------
- */
-
-Proc *
-TclOOGetProcFromMethod(
- Method *mPtr)
-{
- if (mPtr->typePtr == &procMethodType) {
- ProcedureMethod *pmPtr = mPtr->clientData;
-
- return pmPtr->procPtr;
- }
- return NULL;
-}
-
-Tcl_Obj *
-TclOOGetMethodBody(
- Method *mPtr)
-{
- if (mPtr->typePtr == &procMethodType) {
- ProcedureMethod *pmPtr = mPtr->clientData;
-
- if (pmPtr->procPtr->bodyPtr->bytes == NULL) {
- (void) Tcl_GetString(pmPtr->procPtr->bodyPtr);
- }
- return pmPtr->procPtr->bodyPtr;
- }
- return NULL;
-}
-
-Tcl_Obj *
-TclOOGetFwdFromMethod(
- Method *mPtr)
-{
- if (mPtr->typePtr == &fwdMethodType) {
- ForwardMethod *fwPtr = mPtr->clientData;
-
- return fwPtr->prefixObj;
- }
- return NULL;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * InitEnsembleRewrite --
- *
- * Utility function that wraps up a lot of the complexity involved in
- * doing ensemble-like command forwarding. Here is a picture of memory
- * management plan:
- *
- * <-----------------objc---------------------->
- * objv: |=============|===============================|
- * <-toRewrite-> |
- * \
- * <-rewriteLength-> \
- * rewriteObjs: |=================| \
- * | |
- * V V
- * argObjs: |=================|===============================|
- * <------------------*lengthPtr------------------->
- *
- * ----------------------------------------------------------------------
- */
-
-static Tcl_Obj **
-InitEnsembleRewrite(
- Tcl_Interp *interp, /* Place to log the rewrite info. */
- int objc, /* Number of real arguments. */
- Tcl_Obj *const *objv, /* The real arguments. */
- int toRewrite, /* Number of real arguments to replace. */
- int rewriteLength, /* Number of arguments to insert instead. */
- Tcl_Obj *const *rewriteObjs,/* Arguments to insert instead. */
- int *lengthPtr) /* Where to write the resulting length of the
- * array of rewritten arguments. */
-{
- Interp *iPtr = (Interp *) interp;
- int isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
- Tcl_Obj **argObjs;
- unsigned len = rewriteLength + objc - toRewrite;
-
- argObjs = TclStackAlloc(interp, sizeof(Tcl_Obj *) * len);
- memcpy(argObjs, rewriteObjs, rewriteLength * sizeof(Tcl_Obj *));
- memcpy(argObjs + rewriteLength, objv + toRewrite,
- sizeof(Tcl_Obj *) * (objc - toRewrite));
-
- /*
- * Now plumb this into the core ensemble rewrite logging system so that
- * Tcl_WrongNumArgs() can rewrite its result appropriately. The rules for
- * how to store the rewrite rules get complex solely because of the case
- * where an ensemble rewrites itself out of the picture; when that
- * happens, the quality of the error message rewrite falls drastically
- * (and unavoidably).
- */
-
- if (isRootEnsemble) {
- iPtr->ensembleRewrite.sourceObjs = objv;
- iPtr->ensembleRewrite.numRemovedObjs = toRewrite;
- iPtr->ensembleRewrite.numInsertedObjs = rewriteLength;
- } else {
- int numIns = iPtr->ensembleRewrite.numInsertedObjs;
-
- if (numIns < toRewrite) {
- iPtr->ensembleRewrite.numRemovedObjs += toRewrite - numIns;
- iPtr->ensembleRewrite.numInsertedObjs += rewriteLength - 1;
- } else {
- iPtr->ensembleRewrite.numInsertedObjs +=
- rewriteLength - toRewrite;
- }
- }
-
- *lengthPtr = len;
- return argObjs;
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * assorted trivial 'getter' functions
- *
- * ----------------------------------------------------------------------
- */
-
-Tcl_Object
-Tcl_MethodDeclarerObject(
- Tcl_Method method)
-{
- return (Tcl_Object) ((Method *) method)->declaringObjectPtr;
-}
-
-Tcl_Class
-Tcl_MethodDeclarerClass(
- Tcl_Method method)
-{
- return (Tcl_Class) ((Method *) method)->declaringClassPtr;
-}
-
-Tcl_Obj *
-Tcl_MethodName(
- Tcl_Method method)
-{
- return ((Method *) method)->namePtr;
-}
-
-int
-Tcl_MethodIsType(
- Tcl_Method method,
- const Tcl_MethodType *typePtr,
- ClientData *clientDataPtr)
-{
- Method *mPtr = (Method *) method;
-
- if (mPtr->typePtr == typePtr) {
- if (clientDataPtr != NULL) {
- *clientDataPtr = mPtr->clientData;
- }
- return 1;
- }
- return 0;
-}
-
-int
-Tcl_MethodIsPublic(
- Tcl_Method method)
-{
- return (((Method *)method)->flags & PUBLIC_METHOD) ? 1 : 0;
-}
-
-/*
- * Extended method construction for itcl-ng.
- */
-
-Tcl_Method
-TclOONewProcInstanceMethodEx(
- Tcl_Interp *interp, /* The interpreter containing the object. */
- Tcl_Object oPtr, /* The object to modify. */
- TclOO_PreCallProc *preCallPtr,
- TclOO_PostCallProc *postCallPtr,
- ProcErrorProc *errProc,
- ClientData clientData,
- Tcl_Obj *nameObj, /* The name of the method, which must not be
- * NULL. */
- Tcl_Obj *argsObj, /* The formal argument list for the method,
- * which must not be NULL. */
- Tcl_Obj *bodyObj, /* The body of the method, which must not be
- * NULL. */
- int flags, /* Whether this is a public method. */
- void **internalTokenPtr) /* If non-NULL, points to a variable that gets
- * the reference to the ProcedureMethod
- * structure. */
-{
- ProcedureMethod *pmPtr;
- Tcl_Method method = (Tcl_Method) TclOONewProcInstanceMethod(interp,
- (Object *) oPtr, flags, nameObj, argsObj, bodyObj, &pmPtr);
-
- if (method == NULL) {
- return NULL;
- }
- pmPtr->flags = flags & USE_DECLARER_NS;
- pmPtr->preCallProc = preCallPtr;
- pmPtr->postCallProc = postCallPtr;
- pmPtr->errProc = errProc;
- pmPtr->clientData = clientData;
- if (internalTokenPtr != NULL) {
- *internalTokenPtr = pmPtr;
- }
- return method;
-}
-
-Tcl_Method
-TclOONewProcMethodEx(
- Tcl_Interp *interp, /* The interpreter containing the class. */
- Tcl_Class clsPtr, /* The class to modify. */
- TclOO_PreCallProc *preCallPtr,
- TclOO_PostCallProc *postCallPtr,
- ProcErrorProc *errProc,
- ClientData clientData,
- Tcl_Obj *nameObj, /* The name of the method, which may be NULL;
- * if so, up to caller to manage storage
- * (e.g., because it is a constructor or
- * destructor). */
- Tcl_Obj *argsObj, /* The formal argument list for the method,
- * which may be NULL; if so, it is equivalent
- * to an empty list. */
- Tcl_Obj *bodyObj, /* The body of the method, which must not be
- * NULL. */
- int flags, /* Whether this is a public method. */
- void **internalTokenPtr) /* If non-NULL, points to a variable that gets
- * the reference to the ProcedureMethod
- * structure. */
-{
- ProcedureMethod *pmPtr;
- Tcl_Method method = (Tcl_Method) TclOONewProcMethod(interp,
- (Class *) clsPtr, flags, nameObj, argsObj, bodyObj, &pmPtr);
-
- if (method == NULL) {
- return NULL;
- }
- pmPtr->flags = flags & USE_DECLARER_NS;
- pmPtr->preCallProc = preCallPtr;
- pmPtr->postCallProc = postCallPtr;
- pmPtr->errProc = errProc;
- pmPtr->clientData = clientData;
- if (internalTokenPtr != NULL) {
- *internalTokenPtr = pmPtr;
- }
- return method;
-}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */