diff options
author | dgp <dgp@users.sourceforge.net> | 2018-11-13 16:29:17 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2018-11-13 16:29:17 (GMT) |
commit | 336de438e2cbe2e1933ac3a79292610831f260c1 (patch) | |
tree | 0d4a4ae70ee12b38c33bdb7fbe33b72d54843215 /generic/tclOODefineCmds.c | |
parent | 2e1715a99c9ab19730ce1a79c2d375ab279b80dc (diff) | |
download | tcl-336de438e2cbe2e1933ac3a79292610831f260c1.zip tcl-336de438e2cbe2e1933ac3a79292610831f260c1.tar.gz tcl-336de438e2cbe2e1933ac3a79292610831f260c1.tar.bz2 |
Implement TIP 524
Diffstat (limited to 'generic/tclOODefineCmds.c')
-rw-r--r-- | generic/tclOODefineCmds.c | 148 |
1 files changed, 131 insertions, 17 deletions
diff --git a/generic/tclOODefineCmds.c b/generic/tclOODefineCmds.c index a0f0080..965badf 100644 --- a/generic/tclOODefineCmds.c +++ b/generic/tclOODefineCmds.c @@ -63,6 +63,8 @@ static inline int MagicDefinitionInvoke(Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static inline Class * GetClassInOuterContext(Tcl_Interp *interp, Tcl_Obj *className, const char *errMsg); +static inline Tcl_Namespace *GetNamespaceInOuterContext(Tcl_Interp *interp, + Tcl_Obj *namespaceName); static inline int InitDefineContext(Tcl_Interp *interp, Tcl_Namespace *namespacePtr, Object *oPtr, int objc, Tcl_Obj *const objv[]); @@ -828,8 +830,7 @@ InitDefineContext( if (namespacePtr == NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj( - "cannot process definitions; support namespace deleted", - -1)); + "no definition namespace available", -1)); Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); return TCL_ERROR; } @@ -888,12 +889,12 @@ TclOOGetDefineCmdContext( /* * ---------------------------------------------------------------------- * - * GetClassInOuterContext -- + * GetClassInOuterContext, GetNamespaceInOuterContext -- * - * Wrapper round Tcl_GetObjectFromObj to perform the lookup in the - * context that called oo::define (or equivalent). Note that this may - * have to go up multiple levels to get the level that we started doing - * definitions at. + * Wrappers round Tcl_GetObjectFromObj and TclGetNamespaceFromObj to + * perform the lookup in the context that called oo::define (or + * equivalent). Note that this may have to go up multiple levels to get + * the level that we started doing definitions at. * * ---------------------------------------------------------------------- */ @@ -928,6 +929,31 @@ GetClassInOuterContext( } return oPtr->classPtr; } + +static inline Tcl_Namespace * +GetNamespaceInOuterContext( + Tcl_Interp *interp, + Tcl_Obj *namespaceName) +{ + Interp *iPtr = (Interp *) interp; + Tcl_Namespace *nsPtr; + int result; + CallFrame *savedFramePtr = iPtr->varFramePtr; + + while (iPtr->varFramePtr->isProcCallFrame == FRAME_IS_OO_DEFINE + || iPtr->varFramePtr->isProcCallFrame == PRIVATE_FRAME) { + if (iPtr->varFramePtr->callerVarPtr == NULL) { + Tcl_Panic("getting outer context when already in global context"); + } + iPtr->varFramePtr = iPtr->varFramePtr->callerVarPtr; + } + result = TclGetNamespaceFromObj(interp, namespaceName, &nsPtr); + iPtr->varFramePtr = savedFramePtr; + if (result != TCL_OK) { + return NULL; + } + return nsPtr; +} /* * ---------------------------------------------------------------------- @@ -1053,7 +1079,7 @@ TclOODefineObjCmd( int objc, Tcl_Obj *const *objv) { - Foundation *fPtr = TclOOGetFoundation(interp); + Tcl_Namespace *nsPtr; Object *oPtr; int result; @@ -1068,7 +1094,7 @@ TclOODefineObjCmd( } if (oPtr->classPtr == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "%s does not refer to a class",TclGetString(objv[1]))); + "%s does not refer to a class", TclGetString(objv[1]))); Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CLASS", TclGetString(objv[1]), NULL); return TCL_ERROR; @@ -1079,7 +1105,8 @@ TclOODefineObjCmd( * command(s). */ - if (InitDefineContext(interp, fPtr->defineNs, oPtr, objc,objv) != TCL_OK){ + nsPtr = TclOOGetDefineContextNamespace(interp, oPtr, 1); + if (InitDefineContext(interp, nsPtr, oPtr, objc, objv) != TCL_OK) { return TCL_ERROR; } @@ -1095,7 +1122,7 @@ TclOODefineObjCmd( } TclDecrRefCount(objNameObj); } else { - result = MagicDefinitionInvoke(interp, fPtr->defineNs, 2, objc, objv); + result = MagicDefinitionInvoke(interp, nsPtr, 2, objc, objv); } TclOODecrRefCount(oPtr); @@ -1128,7 +1155,7 @@ TclOOObjDefObjCmd( int objc, Tcl_Obj *const *objv) { - Foundation *fPtr = TclOOGetFoundation(interp); + Tcl_Namespace *nsPtr; Object *oPtr; int result; @@ -1147,7 +1174,8 @@ TclOOObjDefObjCmd( * command(s). */ - if (InitDefineContext(interp, fPtr->objdefNs, oPtr, objc,objv) != TCL_OK){ + nsPtr = TclOOGetDefineContextNamespace(interp, oPtr, 0); + if (InitDefineContext(interp, nsPtr, oPtr, objc, objv) != TCL_OK) { return TCL_ERROR; } @@ -1163,7 +1191,7 @@ TclOOObjDefObjCmd( } TclDecrRefCount(objNameObj); } else { - result = MagicDefinitionInvoke(interp, fPtr->objdefNs, 2, objc, objv); + result = MagicDefinitionInvoke(interp, nsPtr, 2, objc, objv); } TclOODecrRefCount(oPtr); @@ -1196,7 +1224,7 @@ TclOODefineSelfObjCmd( int objc, Tcl_Obj *const *objv) { - Foundation *fPtr = TclOOGetFoundation(interp); + Tcl_Namespace *nsPtr; Object *oPtr; int result, private; @@ -1217,7 +1245,8 @@ TclOODefineSelfObjCmd( * command(s). */ - if (InitDefineContext(interp, fPtr->objdefNs, oPtr, objc,objv) != TCL_OK){ + nsPtr = TclOOGetDefineContextNamespace(interp, oPtr, 0); + if (InitDefineContext(interp, nsPtr, oPtr, objc, objv) != TCL_OK) { return TCL_ERROR; } if (private) { @@ -1236,7 +1265,7 @@ TclOODefineSelfObjCmd( } TclDecrRefCount(objNameObj); } else { - result = MagicDefinitionInvoke(interp, fPtr->objdefNs, 1, objc, objv); + result = MagicDefinitionInvoke(interp, nsPtr, 1, objc, objv); } TclOODecrRefCount(oPtr); @@ -1536,6 +1565,91 @@ TclOODefineConstructorObjCmd( /* * ---------------------------------------------------------------------- * + * TclOODefineDefnNsObjCmd -- + * + * Implementation of the "definitionnamespace" subcommand of the + * "oo::define" command. + * + * ---------------------------------------------------------------------- + */ + +int +TclOODefineDefnNsObjCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const *objv) +{ + static const char *kindList[] = { + "-class", + "-instance", + NULL + }; + int kind = 0; + Object *oPtr; + Tcl_Namespace *nsPtr; + Tcl_Obj *nsNamePtr, **storagePtr; + + oPtr = (Object *) TclOOGetDefineCmdContext(interp); + if (oPtr == NULL) { + return TCL_ERROR; + } + if (!oPtr->classPtr) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "attempt to misuse API", -1)); + Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); + return TCL_ERROR; + } + if (oPtr->flags & (ROOT_OBJECT | ROOT_CLASS)) { + Tcl_SetObjResult(interp, Tcl_NewStringObj( + "may not modify the definition namespace of the root classes", + -1)); + Tcl_SetErrorCode(interp, "TCL", "OO", "MONKEY_BUSINESS", NULL); + return TCL_ERROR; + } + + /* + * Parse the arguments and work out what the user wants to do. + */ + + if (objc != 2 && objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "?kind? namespace"); + return TCL_ERROR; + } + if (objc == 3 && Tcl_GetIndexFromObj(interp, objv[1], kindList, "kind", 0, + &kind) != TCL_OK) { + return TCL_ERROR; + } + if (!Tcl_GetString(objv[objc - 1])[0]) { + nsNamePtr = NULL; + } else { + nsPtr = GetNamespaceInOuterContext(interp, objv[objc - 1]); + if (nsPtr == NULL) { + return TCL_ERROR; + } + nsNamePtr = Tcl_NewStringObj(nsPtr->fullName, -1); + Tcl_IncrRefCount(nsNamePtr); + } + + /* + * Update the correct field of the class definition. + */ + + if (kind) { + storagePtr = &oPtr->classPtr->objDefinitionNs; + } else { + storagePtr = &oPtr->classPtr->clsDefinitionNs; + } + if (*storagePtr != NULL) { + Tcl_DecrRefCount(*storagePtr); + } + *storagePtr = nsNamePtr; + return TCL_OK; +} + +/* + * ---------------------------------------------------------------------- + * * TclOODefineDeleteMethodObjCmd -- * * Implementation of the "deletemethod" subcommand of the "oo::define" |