summaryrefslogtreecommitdiffstats
path: root/generic/tclOO.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2008-07-18 17:23:56 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2008-07-18 17:23:56 (GMT)
commit7c31170f9b9f73628665a5656daddd8002c771f7 (patch)
tree51d468120cb21c5f86ab5cacff83f3fe4c6ee77a /generic/tclOO.c
parenta0226c67f814c3d4a641687615bf4171ea749088 (diff)
downloadtcl-7c31170f9b9f73628665a5656daddd8002c771f7.zip
tcl-7c31170f9b9f73628665a5656daddd8002c771f7.tar.gz
tcl-7c31170f9b9f73628665a5656daddd8002c771f7.tar.bz2
NRE-enable the TclOO constructor system.
Diffstat (limited to 'generic/tclOO.c')
-rw-r--r--generic/tclOO.c151
1 files changed, 140 insertions, 11 deletions
diff --git a/generic/tclOO.c b/generic/tclOO.c
index dbf85ea..7280172 100644
--- a/generic/tclOO.c
+++ b/generic/tclOO.c
@@ -8,7 +8,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclOO.c,v 1.11 2008/07/18 13:46:46 msofer Exp $
+ * RCS: @(#) $Id: tclOO.c,v 1.12 2008/07/18 17:23:56 dkf Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -70,6 +70,8 @@ static int CloneClassMethod(Tcl_Interp *interp, Class *clsPtr,
Method **newMPtrPtr);
static int CloneObjectMethod(Tcl_Interp *interp, Object *oPtr,
Method *mPtr, Tcl_Obj *namePtr);
+static int FinalizeAlloc(ClientData data[],
+ Tcl_Interp *interp, int result);
static int FinalizeNext(ClientData data[],
Tcl_Interp *interp, int result);
static int FinalizeObjectCall(ClientData data[],
@@ -1271,6 +1273,118 @@ Tcl_NewObjectInstance(
return (Tcl_Object) oPtr;
}
+
+int
+TclNRNewObjectInstance(
+ Tcl_Interp *interp, /* Interpreter context. */
+ Tcl_Class cls, /* Class to create an instance of. */
+ const char *nameStr, /* Name of object to create, or NULL to ask
+ * the code to pick its own unique name. */
+ const char *nsNameStr, /* Name of namespace to create inside object,
+ * or NULL to ask the code to pick its own
+ * unique name. */
+ int objc, /* Number of arguments. Negative value means
+ * do not call constructor. */
+ Tcl_Obj *const *objv, /* Argument list. */
+ int skip, /* Number of arguments to _not_ pass to the
+ * constructor. */
+ Tcl_Object *objectPtr) /* Place to write the object reference upon
+ * successful allocation. */
+{
+ register Class *classPtr = (Class *) cls;
+ Foundation *fPtr = GetFoundation(interp);
+ CallContext *contextPtr;
+ Tcl_InterpState state;
+ Object *oPtr;
+
+ /*
+ * Check if we're going to create an object over an existing command;
+ * that's not allowed.
+ */
+
+ if (nameStr && Tcl_FindCommand(interp, nameStr, NULL, 0)) {
+ Tcl_AppendResult(interp, "can't create object \"", nameStr,
+ "\": command already exists with that name", NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Create the object.
+ */
+
+ oPtr = AllocObject(interp, nameStr, nsNameStr);
+ oPtr->selfCls = classPtr;
+ TclOOAddToInstances(oPtr, classPtr);
+
+ /*
+ * Check to see if we're really creating a class. If so, allocate the
+ * class structure as well.
+ */
+
+ if (TclOOIsReachable(fPtr->classCls, classPtr)) {
+ /*
+ * Is a class, so attach a class structure. Note that the AllocClass
+ * function splices the structure into the object, so we don't have
+ * to. Once that's done, we need to repatch the object to have the
+ * right class since AllocClass interferes with that.
+ */
+
+ AllocClass(interp, oPtr);
+ oPtr->selfCls = classPtr;
+ TclOOAddToSubclasses(oPtr->classPtr, fPtr->objectCls);
+ }
+
+ /*
+ * Run constructors, except when objc < 0 (a special flag case used for
+ * object cloning only). If there aren't any constructors, we do nothing.
+ */
+
+ if (objc < 0) {
+ *objectPtr = (Tcl_Object) oPtr;
+ return TCL_OK;
+ }
+ contextPtr = TclOOGetCallContext(oPtr,NULL,CONSTRUCTOR);
+ if (contextPtr == NULL) {
+ *objectPtr = (Tcl_Object) oPtr;
+ return TCL_OK;
+ }
+
+ AddRef(oPtr);
+ state = Tcl_SaveInterpState(interp, TCL_OK);
+ contextPtr->callPtr->flags |= CONSTRUCTOR;
+ contextPtr->skip = skip;
+
+ /*
+ * Fire off the constructors non-recursively.
+ */
+
+ Tcl_NRAddCallback(interp, FinalizeAlloc, contextPtr, oPtr, state,
+ objectPtr);
+ return TclOOInvokeContext(contextPtr, interp, objc, objv);
+}
+
+static int
+FinalizeAlloc(
+ ClientData data[],
+ Tcl_Interp *interp,
+ int result)
+{
+ CallContext *contextPtr = data[0];
+ Object *oPtr = data[1];
+ Tcl_InterpState state = data[2];
+ Tcl_Object *objectPtr = data[3];
+
+ TclOODeleteContext(contextPtr);
+ DelRef(oPtr);
+ if (result != TCL_OK) {
+ Tcl_DiscardInterpState(state);
+ Tcl_DeleteCommandFromToken(interp, oPtr->command);
+ return TCL_ERROR;
+ }
+ Tcl_RestoreInterpState(interp, state);
+ *objectPtr = (Tcl_Object) oPtr;
+ return TCL_OK;
+}
/*
* ----------------------------------------------------------------------
@@ -1776,12 +1890,12 @@ Tcl_ObjectSetMetadata(
/*
* ----------------------------------------------------------------------
*
- * PublicObjectCmd, PrivateObjectCmd, TclOOInvokeObject, TclOOObjectCmdCore --
+ * PublicObjectCmd, PrivateObjectCmd, TclOOInvokeObject --
*
* Main entry point for object invokations. The Public* and Private*
- * wrapper functions are just thin wrappers round the main
- * TclOOObjectCmdCore function that does call chain creation, management
- * and invokation.
+ * wrapper functions (implementations of both object instance commands
+ * and [my]) are just thin wrappers round the main TclOOObjectCmdCore
+ * function. Note that the core is function is NRE-aware.
*
* ----------------------------------------------------------------------
*/
@@ -1857,6 +1971,18 @@ TclOOInvokeObject(
(Class *) startCls);
}
}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * TclOOObjectCmdCore, FinalizeObjectCall --
+ *
+ * Main function for object invokations. Does call chain creation,
+ * management and invokation. The function FinalizeObjectCall exists to
+ * clean up after the non-recursive processing of TclOOObjectCmdCore.
+ *
+ * ----------------------------------------------------------------------
+ */
int
TclOOObjectCmdCore(
@@ -1922,13 +2048,15 @@ TclOOObjectCmdCore(
*/
if (startCls != NULL) {
- while (contextPtr->index < contextPtr->callPtr->numChain) {
+ for (; contextPtr->index < contextPtr->callPtr->numChain;
+ contextPtr->index++) {
register struct MInvoke *miPtr =
&contextPtr->callPtr->chain[contextPtr->index];
- if (miPtr->isFilter || miPtr->mPtr->declaringClassPtr!=startCls) {
- contextPtr->index++;
- } else {
+ if (miPtr->isFilter) {
+ continue;
+ }
+ if (miPtr->mPtr->declaringClassPtr == startCls) {
break;
}
}
@@ -1972,12 +2100,13 @@ FinalizeObjectCall(
/*
* ----------------------------------------------------------------------
*
- * Tcl_ObjectContextInvokeNext, TclNRObjectContextInvokeNext --
+ * Tcl_ObjectContextInvokeNext, TclNRObjectContextInvokeNext, FinalizeNext --
*
* Invokes the next stage of the call chain described in an object
* context. This is the core of the implementation of the [next] command.
* Does not do management of the call-frame stack. Available in public
- * (standard API) and private (NRE-aware) forms.
+ * (standard API) and private (NRE-aware) forms. FinalizeNext is a
+ * private function used to clean up in the NRE case.
*
* ----------------------------------------------------------------------
*/