Index: TODO =================================================================== diff -u -rb9e39fb7a7a01c2b07a112700d42060eadde4d8d -r5c464365425434543edd13f1674e1dd2d7f17a71 --- TODO (.../TODO) (revision b9e39fb7a7a01c2b07a112700d42060eadde4d8d) +++ TODO (.../TODO) (revision 5c464365425434543edd13f1674e1dd2d7f17a71) @@ -2676,22 +2676,6 @@ TODO: -- Harmonising no-self-object error messages: Currently, we have at - least two (or even three) different variants of an intentionally - single message: - * No current object - * Cannot resolve 'self', probably called outside the context of a Next Scripting Object - * (in NsfDispatchClientDataError(), a confusingly similar wording is - used: "not dispatched on valid object"). -- Refactoring the inline occurrences of NsfPrintError() into a custom - function, e.g., NsfSelfObjectError()? -- Looking, for instance, at NsfProcAliasMethod(). I might be missing - the obvious, but does it make sense to differentiate between - GetSelfObj(interp) == NULL and tcd->object == NULL?! What is the - difference between NsfDispatchClientDataError() and a prospective - NsfSelfObjectError(), anyways?! ClientData representing the - definition (provider) object, and self the receiver object? - - the last two results of "info heritage" in info-method.test are not what we want (e.g. ::M3 ::B ::M3 ::nx::Object); would not be surprised if the same problem occursn somewhere else Index: generic/nsf.c =================================================================== diff -u -r6110e3a41d85384b97604012281b73e51781290e -r5c464365425434543edd13f1674e1dd2d7f17a71 --- generic/nsf.c (.../nsf.c) (revision 6110e3a41d85384b97604012281b73e51781290e) +++ generic/nsf.c (.../nsf.c) (revision 5c464365425434543edd13f1674e1dd2d7f17a71) @@ -8413,7 +8413,9 @@ * {1} Class ::State * {2} Class ::State -parameter x */ - NsfLog(interp, NSF_LOG_NOTICE, "Don't invoke object %s this way. Register object via alias...", methodName); + NsfLog(interp, NSF_LOG_NOTICE, + "Don't invoke object %s this way. Register object via alias...", + methodName); cmd = NULL; } else if (IsClassNsName(methodName)) { @@ -12494,6 +12496,8 @@ NsfObject *object = tcd->object; CallFrame frame, *framePtr = &frame; + tcd->object = NULL; + if (tcd->verbose) { Tcl_Obj *cmd = Tcl_NewListObj(objc, objv); fprintf(stderr, "forwarder calls '%s'\n", ObjStr(cmd)); @@ -12702,34 +12706,31 @@ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { AliasCmdClientData *tcd = (AliasCmdClientData *)clientData; - NsfObject *self = GetSelfObj(interp); CONST char *methodName = ObjStr(objv[0]); + NsfObject *self; - if (!self) { - return NsfPrintError(interp, "Cannot resolve 'self', " - "probably called outside the context of a Next Scripting Object"); - } + assert(tcd); + self = tcd->object; - if (!tcd->object) { - return NsfDispatchClientDataError(interp, tcd->object, "object", + if (!self) { + return NsfDispatchClientDataError(interp, self, "object", Tcl_GetCommandName(interp, tcd->aliasCmd)); } + tcd->object = NULL; - assert(tcd->object == self); + assert(self == GetSelfObj(interp)); if (Tcl_Command_cmdEpoch(tcd->aliasedCmd)) { - NsfObject *defObject = tcd->class ? &(tcd->class->object) : tcd->object; + NsfObject *defObject = tcd->class ? &(tcd->class->object) : self; Tcl_Obj **listElements, *entryObj, *targetObj; int nrElements, withPer_object; Tcl_Command cmd; - //int withFrame; /* * Get the targetObject. Currently, we can get it just via the * alias array. */ withPer_object = tcd->class ? 0 : 1; - //withFrame = (tcd->objProc == NsfObjscopedMethod); entryObj = AliasGet(interp, defObject->cmdName, methodName, withPer_object, 1); if (entryObj == NULL) { return TCL_ERROR; @@ -12739,10 +12740,10 @@ Tcl_ListObjGetElements(interp, entryObj, &nrElements, &listElements); targetObj = listElements[nrElements-1]; - //result = NsfAliasCmd(interp, defObject, withPer_object, methodName, withFrame, targetObj); + NsfLog(interp, NSF_LOG_NOTICE, + "trying to dispatch an epoched cmd %p as %s -- cmdName %s\n", + tcd->aliasedCmd, methodName, ObjStr(targetObj)); - fprintf(stderr, "trying to dispatch an epoched cmd %p as %s -- cmdName %s\n", - tcd->aliasedCmd, methodName, ObjStr(targetObj)); /* * Replace cmd and its objProc and clientData with a newly fetched * version. @@ -12781,6 +12782,7 @@ int result; /*fprintf(stderr, "objscopedMethod obj=%p %s, ptr=%p\n", object, ObjectName(object), tcd->objProc);*/ + tcd->object = NULL; Nsf_PushFrameObj(interp, object, framePtr); result = Tcl_NRCallObjProc(interp, tcd->objProc, tcd->clientData, objc, objv); @@ -14942,7 +14944,7 @@ tcd = NEW(AliasCmdClientData); tcd->cmdName = object->cmdName; tcd->interp = interp; /* just for deleting the associated variable */ - tcd->object = object; + tcd->object = NULL; tcd->class = cl ? (NsfClass *) object : NULL; tcd->objProc = objProc; tcd->aliasedCmd = cmd; @@ -15427,8 +15429,7 @@ NsfColonCmd(Tcl_Interp *interp, int nobjc, Tcl_Obj *CONST nobjv[]) { NsfObject *self = GetSelfObj(interp); if (!self) { - return NsfPrintError(interp, "Cannot resolve 'self', " - "probably called outside the context of a Next Scripting Object"); + NsfNoCurrentObjectError(interp, ObjStr(nobjv[0])); } /* fprintf(stderr, "Colon dispatch %s.%s\n", ObjectName(self),ObjStr(nobjv[0]));*/ return ObjectDispatch(self, interp, nobjc, nobjv, NSF_CM_NO_SHIFT); @@ -15527,6 +15528,7 @@ NULL : (NsfClass *)object; tcd->object = object; + if (cl == NULL) { result = NsfAddObjectMethod(interp, (Nsf_Object *)object, methodName, (Tcl_ObjCmdProc*)NsfForwardMethod, @@ -15884,8 +15886,7 @@ int result; if (!self) { - return NsfPrintError(interp, "Cannot resolve 'self', " - "probably called outside the context of a Next Scripting Object"); + NsfNoCurrentObjectError(interp, ObjStr(nobjv[0])); } if (withLocal) { @@ -16565,19 +16566,17 @@ Tcl_CallFrame *framePtr; int result = TCL_OK; - /*fprintf(stderr, "getSelfObj returns %p\n", object); NsfShowStack(interp);*/ - if (selfoption == 0 || selfoption == CurrentoptionObjectIdx) { if (object) { Tcl_SetObjResult(interp, object->cmdName); return TCL_OK; } else { - return NsfPrintError(interp, "No current object"); + return NsfNoCurrentObjectError(interp, NULL); } } if (!object && selfoption != CurrentoptionCallinglevelIdx) { - return NsfPrintError(interp, "No current object"); + return NsfNoCurrentObjectError(interp, NULL); } switch (selfoption) { @@ -16713,7 +16712,7 @@ Tcl_SetObjResult(interp, object->cmdName); return TCL_OK; } else { - return NsfPrintError(interp, "No current object"); + return NsfNoCurrentObjectError(interp, NULL); } } Index: generic/nsfError.c =================================================================== diff -u -r211c77c1a94a47be185a8bfb12c89512937b1901 -r5c464365425434543edd13f1674e1dd2d7f17a71 --- generic/nsfError.c (.../nsfError.c) (revision 211c77c1a94a47be185a8bfb12c89512937b1901) +++ generic/nsfError.c (.../nsfError.c) (revision 5c464365425434543edd13f1674e1dd2d7f17a71) @@ -31,7 +31,7 @@ *---------------------------------------------------------------------- */ -void +extern void NsfDStringPrintf(Tcl_DString *dsPtr, CONST char *fmt, va_list apSrc) { int result, avail = dsPtr->spaceAvl, offset = dsPtr->length; @@ -69,7 +69,7 @@ * *---------------------------------------------------------------------- */ -void +extern void NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *CONST objv[]) { int i; @@ -94,8 +94,7 @@ * *---------------------------------------------------------------------- */ - -int +extern int NsfPrintError(Tcl_Interp *interp, CONST char *fmt, ...) { va_list ap; Tcl_DString ds; @@ -112,7 +111,23 @@ return TCL_ERROR; } -int +/* + *---------------------------------------------------------------------- + * + * NsfErrInProc -- + * + * Produce a general error message when an error occurs in a scripted nsf + * method. + * + * Results: + * TCL_ERROR + * + * Side effects: + * Sets the result message. + * + *---------------------------------------------------------------------- + */ +extern int NsfErrInProc(Tcl_Interp *interp, Tcl_Obj *objName, Tcl_Obj *clName, CONST char *procName) { Tcl_DString errMsg; @@ -137,7 +152,23 @@ return TCL_ERROR; } -int +/* + *---------------------------------------------------------------------- + * + * NsfObjWrongArgs -- + * + * Produce a general error message when a nsf method is called with an + * invalid argument list (wrong number of arguments). + * + * Results: + * TCL_ERROR + * + * Side effects: + * Sets the result message. + * + *---------------------------------------------------------------------- + */ +extern int NsfObjWrongArgs(Tcl_Interp *interp, CONST char *msg, Tcl_Obj *cmdName, Tcl_Obj *methodName, char *arglist) { int need_space = 0; @@ -176,7 +207,7 @@ * *---------------------------------------------------------------------- */ -int +extern int NsfArgumentError(Tcl_Interp *interp, CONST char *errorMsg, Nsf_Param CONST *paramPtr, Tcl_Obj *cmdNameObj, Tcl_Obj *methodObj) { Tcl_Obj *argStringObj = NsfParamDefsSyntax(paramPtr); @@ -202,14 +233,51 @@ * *---------------------------------------------------------------------- */ -int +extern int NsfDispatchClientDataError(Tcl_Interp *interp, ClientData clientData, CONST char *what, CONST char *methodName) { return NsfPrintError(interp, "Method %s not dispatched on valid %s%s", methodName, what, clientData ? "" : " ; don't call aliased methods via namespace paths!"); } +/* + *---------------------------------------------------------------------- + * + * NsfNoDispatchObjectError -- + * + * Produce a error message when method was not dispatched on an object + * + * Results: + * TCL_ERROR + * + * Side effects: + * Sets the result message. + * + *---------------------------------------------------------------------- + */ extern int +NsfNoCurrentObjectError(Tcl_Interp *interp, CONST char *what) { + return NsfPrintError(interp, "No current object; %s called outside the context of a Next Scripting method", + what ? what : "command"); +} + +/* + *---------------------------------------------------------------------- + * + * NsfObjErrType -- + * + * Produce a general error message when a nsf method is called with an + * invalid value for some argument. + * + * Results: + * TCL_ERROR + * + * Side effects: + * Sets the result message. + * + *---------------------------------------------------------------------- + */ +extern int NsfObjErrType(Tcl_Interp *interp, CONST char *context, Tcl_Obj *value, Index: tests/methods.test =================================================================== diff -u -ra5e4ab3a3f85b51e855adb3fe981833c2534ee8b -r5c464365425434543edd13f1674e1dd2d7f17a71 --- tests/methods.test (.../methods.test) (revision a5e4ab3a3f85b51e855adb3fe981833c2534ee8b) +++ tests/methods.test (.../methods.test) (revision 5c464365425434543edd13f1674e1dd2d7f17a71) @@ -412,6 +412,7 @@ # the other methods don't require them as strong :forward b ::o2 bar :method foo {} {return [self]} + :alias x ::o::foo } nx::Object create o2 { :public method bar {} {return [self]} @@ -420,5 +421,11 @@ # dispatch methods without current object ? ::o::a "Method ::o::a not dispatched on valid object" ? ::o::b "::o2" - ? ::o::foo "No current object" + ? ::o::foo "No current object; command called outside the context of a Next Scripting method" + ? ::o::x "Method x not dispatched on valid object ; don't call aliased methods via namespace paths!" + # make a regular call, provide tcd->object with a value + ? {::o x} "::o" + # check, if missing object is still detected + ? ::o::x "Method x not dispatched on valid object ; don't call aliased methods via namespace paths!" + ? self "No current object; command called outside the context of a Next Scripting method" } \ No newline at end of file