Index: TODO =================================================================== diff -u -r1bc14766b62efc778ac40c26b1bbabac116a9f80 -r11911b4cef79513ac212b56be4270d1fb7a78ad6 --- TODO (.../TODO) (revision 1bc14766b62efc778ac40c26b1bbabac116a9f80) +++ TODO (.../TODO) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) @@ -1630,12 +1630,17 @@ - extended regression test - factored out ParamGetType() to obtain from a paramPtr a type string -- +- parametersyntax: + * changed "... -x arg ..." into ".... -x value ..." + * changed multiple values notation from "list" to "..." +- nsf::current: new option "methodpath", returns the full name of an ensemble + method starting from the ensemble root. +- documented functions in nfsStack.c +- removed obsolete CallStackGetFrame(), replaced by CallStackGetTopFrame() + TODO: - - - cleanup of xotcl-aol - method-modifiers/attribute-method.002: incorrect result for 'set _ {}' Index: generic/gentclAPI.decls =================================================================== diff -u -rb69a9b8de677b30774419057953a91c96df00e56 -r11911b4cef79513ac212b56be4270d1fb7a78ad6 --- generic/gentclAPI.decls (.../gentclAPI.decls) (revision b69a9b8de677b30774419057953a91c96df00e56) +++ generic/gentclAPI.decls (.../gentclAPI.decls) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) @@ -139,7 +139,7 @@ {-argName "value" -required 0 -type tclobj} } nsfCmd current NsfCurrentCmd { - {-argName "currentoption" -required 0 -type "proc|method|object|class|activelevel|args|activemixin|calledproc|calledmethod|calledclass|callingproc|callingmethod|callingclass|callinglevel|callingobject|filterreg|isnextcall|next"} + {-argName "currentoption" -required 0 -type "proc|method|methodpath|object|class|activelevel|args|activemixin|calledproc|calledmethod|calledclass|callingproc|callingmethod|callingclass|callinglevel|callingobject|filterreg|isnextcall|next"} } nsfCmd setvar NsfSetVarCmd { Index: generic/nsf.c =================================================================== diff -u -r1bc14766b62efc778ac40c26b1bbabac116a9f80 -r11911b4cef79513ac212b56be4270d1fb7a78ad6 --- generic/nsf.c (.../nsf.c) (revision 1bc14766b62efc778ac40c26b1bbabac116a9f80) +++ generic/nsf.c (.../nsf.c) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) @@ -238,7 +238,6 @@ NSF_INLINE static void CscInit(NsfCallStackContent *cscPtr, NsfObject *object, NsfClass *cl, Tcl_Command cmd, int frameType, int flags, char *msg); NSF_INLINE static void CscFinish(Tcl_Interp *interp, NsfCallStackContent *cscPtr, char *string); -static NsfCallStackContent *CallStackGetFrame(Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr); NSF_INLINE static void CallStackDoDestroy(Tcl_Interp *interp, NsfObject *object); /* prototypes for parameter and argument management */ @@ -2077,7 +2076,7 @@ static Tcl_Var CompiledColonVarFetch(Tcl_Interp *interp, Tcl_ResolvedVarInfo *vinfoPtr) { nsfResolvedVarInfo *resVarInfo = (nsfResolvedVarInfo *)vinfoPtr; - NsfCallStackContent *cscPtr = CallStackGetFrame(interp, NULL); + NsfCallStackContent *cscPtr = CallStackGetTopFrame(interp, NULL); NsfObject *object = cscPtr ? cscPtr->self : NULL; TclVarHashTable *varTablePtr; Tcl_Var var = resVarInfo->var; @@ -13067,7 +13066,7 @@ #if 0 /* TODO attempt to make "my" NRE-enabled, failed so far (crash in mixinInheritanceTest) */ int flags; - NsfCallStackContent *cscPtr = CallStackGetFrame(interp, NULL); + NsfCallStackContent *cscPtr = CallStackGetTopFrame(interp, NULL); if (!cscPtr || self != cscPtr->self) { flags = NSF_CSC_IMMEDIATE; } else { @@ -13658,13 +13657,14 @@ /* nsfCmd current NsfCurrentCmd { - {-argName "currentoption" -required 0 -type "proc|method|object|class|activelevel|args|activemixin|calledproc|calledmethod|calledclass|callingproc|callingmethod|callingclass|callinglevel|callingobject|filterreg|isnextcall|next"} + {-argName "currentoption" -required 0 -type "proc|method|methodpath|object|class|activelevel|args|activemixin|calledproc|calledmethod|calledclass|callingproc|callingmethod|callingclass|callinglevel|callingobject|filterreg|isnextcall|next"} } */ static int NsfCurrentCmd(Tcl_Interp *interp, int selfoption) { NsfObject *object = GetSelfObj(interp); NsfCallStackContent *cscPtr; + Tcl_CallFrame *framePtr; int result = TCL_OK; /*fprintf(stderr, "getSelfObj returns %p\n", object); TclShowStack(interp);*/ @@ -13694,6 +13694,12 @@ } break; + case CurrentoptionMethodpathIdx: + cscPtr = CallStackGetTopFrame(interp, &framePtr); + Tcl_SetObjResult(interp, + CallStackMethodPath(interp, framePtr, Tcl_NewListObj(0, NULL))); + break; + case CurrentoptionClassIdx: /* class subcommand */ cscPtr = CallStackGetTopFrame(interp, NULL); Tcl_SetObjResult(interp, cscPtr->cl ? cscPtr->cl->object.cmdName : NsfGlobalObjs[NSF_EMPTY]); @@ -13706,15 +13712,14 @@ case CurrentoptionArgsIdx: { int nobjc; Tcl_Obj **nobjv; - Tcl_CallFrame *topFramePtr; - cscPtr = CallStackGetTopFrame(interp, &topFramePtr); + cscPtr = CallStackGetTopFrame(interp, &framePtr); if (cscPtr->objv) { nobjc = cscPtr->objc; nobjv = (Tcl_Obj **)cscPtr->objv; } else { - nobjc = Tcl_CallFrame_objc(topFramePtr); - nobjv = (Tcl_Obj **)Tcl_CallFrame_objv(topFramePtr); + nobjc = Tcl_CallFrame_objc(framePtr); + nobjv = (Tcl_Obj **)Tcl_CallFrame_objv(framePtr); } Tcl_SetObjResult(interp, Tcl_NewListObj(nobjc-1, nobjv+1)); break; @@ -13782,9 +13787,9 @@ break; case CurrentoptionIsnextcallIdx: { - Tcl_CallFrame *framePtr; cscPtr = CallStackGetTopFrame(interp, &framePtr); - framePtr = CallStackNextFrameOfType(Tcl_CallFrame_callerPtr(framePtr), FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD); + framePtr = CallStackNextFrameOfType(Tcl_CallFrame_callerPtr(framePtr), + FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD); cscPtr = framePtr ? Tcl_CallFrame_clientData(framePtr) : NULL; Tcl_SetBooleanObj(Tcl_GetObjResult(interp), Index: generic/nsfStack.c =================================================================== diff -u -r595314aa4926c6455aa34fa4a10ca782e0e978df -r11911b4cef79513ac212b56be4270d1fb7a78ad6 --- generic/nsfStack.c (.../nsfStack.c) (revision 595314aa4926c6455aa34fa4a10ca782e0e978df) +++ generic/nsfStack.c (.../nsfStack.c) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) @@ -1,4 +1,18 @@ - +/* + *---------------------------------------------------------------------- + * TclShowStack -- + * + * Print the contents of the callstack to stderr. This function is + * for debugging purposes only. + * + * Results: + * None. + * + * Side effects: + * Output on stderr. + * + *---------------------------------------------------------------------- + */ void TclShowStack(Tcl_Interp *interp) { Tcl_CallFrame *framePtr; @@ -50,25 +64,37 @@ * a object->nsPtr can be created (e.g. during a read trace) */ +/* + *---------------------------------------------------------------------- + * Nsf_PushFrameObj, Nsf_PopFrameObj -- + * + * Push or pop a frame with a callstack content as a OBJECT + * frame. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + static void Nsf_PushFrameObj(Tcl_Interp *interp, NsfObject *object, Tcl_CallFrame *framePtr) { /*fprintf(stderr,"PUSH OBJECT_FRAME (Nsf_PushFrameObj) frame %p\n",framePtr);*/ if (object->nsPtr) { - /*fprintf(stderr,"Nsf_PushFrame frame %p with object->nsPtr %p\n", framePtr, object->nsPtr);*/ Tcl_PushCallFrame(interp, framePtr, object->nsPtr, 0|FRAME_IS_NSF_OBJECT); } else { - /*fprintf(stderr,"Nsf_PushFrame frame %p (with fakeProc)\n",framePtr);*/ + /* The object has no nsPtr, so we diguise as a proc, using fakeProc */ Tcl_PushCallFrame(interp, framePtr, Tcl_CallFrame_nsPtr(Tcl_Interp_varFramePtr(interp)), 1|FRAME_IS_NSF_OBJECT); Tcl_CallFrame_procPtr(framePtr) = &RUNTIME_STATE(interp)->fakeProc; if (object->varTablePtr == NULL) { object->varTablePtr = VarHashTableCreate(); - /*fprintf(stderr, "+++ create varTablePtr %p in PushFrameObj obj %p framePtr %p\n", - object->varTablePtr, object, framePtr);*/ } Tcl_CallFrame_varTablePtr(framePtr) = object->varTablePtr; - /*fprintf(stderr,"+++ setting varTablePtr %p in varFrame %p\n",object->varTablePtr,framePtr);*/ } Tcl_CallFrame_clientData(framePtr) = (ClientData)object; } @@ -80,7 +106,24 @@ Tcl_PopCallFrame(interp); } -static void Nsf_PushFrameCsc(Tcl_Interp *interp, NsfCallStackContent *cscPtr, Tcl_CallFrame *framePtr) { +/* + *---------------------------------------------------------------------- + * Nsf_PushFrameCsc, Nsf_PopFrameCsc -- + * + * Push or pop a frame with a callstack content as a CMETHOD + * frame. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +Nsf_PushFrameCsc(Tcl_Interp *interp, NsfCallStackContent *cscPtr, Tcl_CallFrame *framePtr) { CallFrame *varFramePtr = Tcl_Interp_varFramePtr(interp); /*fprintf(stderr,"PUSH CMETHOD_FRAME (Nsf_PushFrameCsc) frame %p cscPtr %p methodName %s\n", framePtr, cscPtr, Tcl_GetCommandName(interp,cscPtr->cmdPtr));*/ @@ -91,7 +134,8 @@ Tcl_CallFrame_procPtr(framePtr) = &RUNTIME_STATE(interp)->fakeProc; } -static void Nsf_PopFrameCsc(Tcl_Interp *interp, Tcl_CallFrame *framePtr) { +static void +Nsf_PopFrameCsc(Tcl_Interp *interp, Tcl_CallFrame *framePtr) { /*fprintf(stderr,"POP CMETHOD_FRAME (Nsf_PopFrameCsc) frame %p, varTablePtr = %p\n", framePtr, Tcl_CallFrame_varTablePtr(framePtr));*/ Tcl_PopCallFrame(interp); @@ -101,6 +145,21 @@ * stack query operations */ +/* + *---------------------------------------------------------------------- + * CallStackGetActiveProcFrame -- + * + * Return the Tcl call frame of the last scripted method. + * + * Results: + * Tcl_CallFrame + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + static Tcl_CallFrame * CallStackGetActiveProcFrame(Tcl_CallFrame *framePtr) { for (; framePtr; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { @@ -118,6 +177,22 @@ return framePtr; } +/* + *---------------------------------------------------------------------- + * CallStackNextFrameOfType -- + * + * Return the next frame with a specified type from the call stack. + * The type is specified by a bit mask passed as flags. + * + * Results: + * Tcl_CallFrame + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + static Tcl_CallFrame * CallStackNextFrameOfType(Tcl_CallFrame *framePtr, int flags) { for (; framePtr; framePtr = Tcl_CallFrame_callerPtr(framePtr)) { @@ -127,6 +202,21 @@ return framePtr; } +/* + *---------------------------------------------------------------------- + * GetSelfObj -- + * + * Return the currently active object from a method or object frame. + * + * Results: + * NsfObject * or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + #define SKIP_LEVELS 1 //#define SKIP_LAMBDA 1 @@ -171,8 +261,23 @@ return NULL; } +/* + *---------------------------------------------------------------------- + * CallStackGetTopFrame -- + * + * Return the topmost invocation of a (scripted or nonleaf) method + * + * Results: + * Call stack content or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + static NsfCallStackContent* -CallStackGetFrame(Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) { +CallStackGetTopFrame(Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) { register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); for (; varFramePtr; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { @@ -186,12 +291,21 @@ return NULL; } -NSF_INLINE static NsfCallStackContent* -CallStackGetTopFrame(Tcl_Interp *interp, Tcl_CallFrame **framePtrPtr) { - return CallStackGetFrame(interp, framePtrPtr); -} - -/* find last invocation of a scripted method */ +/* + *---------------------------------------------------------------------- + * NsfCallStackFindActiveFrame -- + * + * Find last invocation of a (scripted or nonleaf) method with a + * specified offset. + * + * Results: + * Call stack content or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ static NsfCallStackContent * NsfCallStackFindLastInvocation(Tcl_Interp *interp, int offset, Tcl_CallFrame **framePtrPtr) { register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); @@ -218,6 +332,21 @@ return NULL; } +/* + *---------------------------------------------------------------------- + * NsfCallStackFindActiveFrame -- + * + * Search for the first active frame on the callstack. + * + * Results: + * Call stack content or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + static NsfCallStackContent * NsfCallStackFindActiveFrame(Tcl_Interp *interp, int offset, Tcl_CallFrame **framePtrPtr) { register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); @@ -241,6 +370,24 @@ return NULL; } +/* + *---------------------------------------------------------------------- + * CallStackUseActiveFrames -- + * + * Activate the varFrame of the first active non-object frame and + * save the previously active frames in the call frame context. + * These stored frames are typically reactivated by + * CallStackRestoreSavedFrames(). + * + * Results: + * None. + * + * Side effects: + * The varFramePtr of the interp is potentially updated + * + *---------------------------------------------------------------------- + */ + static void CallStackUseActiveFrames(Tcl_Interp *interp, callFrameContext *ctx) { Tcl_CallFrame @@ -265,6 +412,23 @@ } } +/* + *---------------------------------------------------------------------- + * CallStackRestoreSavedFrames -- + * + * Restore the previously saved frames from the speficied call + * frame context. These frames are typically saved by + * CallStackUseActiveFrames(). + * + * Results: + * None. + * + * Side effects: + * The varFramePtr of the interp is potentially updated + * + *---------------------------------------------------------------------- + */ + static void CallStackRestoreSavedFrames(Tcl_Interp *interp, callFrameContext *ctx) { if (ctx->framesSaved) { @@ -274,6 +438,20 @@ } } +/* + *---------------------------------------------------------------------- + * CallStackFindActiveFilter -- + * + * Return the callstack content of the currently active filter + * + * Results: + * Callstack content or NULL, if no filter is active + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ static NsfCallStackContent * CallStackFindActiveFilter(Tcl_Interp *interp) { register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); @@ -330,8 +508,76 @@ } /* - * check, if there is an active filters on "obj" using cmd + *---------------------------------------------------------------------- + * CallStackMethodPath -- + * + * Return the method path of the current ensemble. + * + * Results: + * Tcl_Obj containing the method path + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- */ +static Tcl_Obj* +CallStackMethodPath(Tcl_Interp *interp, Tcl_CallFrame *framePtr, Tcl_Obj *methodPathObj) { + int elements; + Tcl_Obj *resultObj; + + assert(framePtr); + /* + * Append all ensemble names to the specified list obj + */ + for (framePtr = Tcl_CallFrame_callerPtr(framePtr), elements = 1; + Tcl_CallFrame_isProcCallFrame(framePtr) & (FRAME_IS_NSF_CMETHOD|FRAME_IS_NSF_METHOD); + framePtr = Tcl_CallFrame_callerPtr(framePtr), elements ++) { + NsfCallStackContent *cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(framePtr); + assert(cscPtr); + Tcl_ListObjAppendElement(interp, methodPathObj, + Tcl_NewStringObj(Tcl_GetCommandName(interp, cscPtr->cmdPtr), -1)); + if ((cscPtr->flags & NSF_CSC_TYPE_ENSEMBLE) == 0) break; + } + /* + * The resulting list has reveresed order. If there are multiple + * arguments, reverse the list to obtain the right order. + */ + + if (elements > 1) { + int oc, i; + Tcl_Obj **ov; + + Tcl_ListObjGetElements(interp, methodPathObj, &oc, &ov); + resultObj = Tcl_NewListObj(0, NULL); + + for (i = elements-1; i >= 0; i--) { + Tcl_ListObjAppendElement(interp, resultObj, ov[i]); + } + DECR_REF_COUNT(methodPathObj); + + } else { + resultObj = methodPathObj; + } + + return resultObj; +} + +/* + *---------------------------------------------------------------------- + * CallStackMethodPath -- + * + * Check, if there is an active filter on "obj" using the specified + * cmd. + * + * Results: + * 0 or 1 + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ NSF_INLINE static int FilterActiveOnObj(Tcl_Interp *interp, NsfObject *object, Tcl_Command cmd) { register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); @@ -348,6 +594,22 @@ return 0; } +/* + *---------------------------------------------------------------------- + * CallStackReplaceVarTableReferences -- + * + * Replace all references to the old var table (arg 1) by + * references to a new var table (arg 2) on the callstack. + * This function is e.g. used by require namespace. + * + * Results: + * None. + * + * Side effects: + * Updated stack. + * + *---------------------------------------------------------------------- + */ static void CallStackReplaceVarTableReferences(Tcl_Interp *interp, TclVarHashTable *oldVarTablePtr, TclVarHashTable *newVarTablePtr) { Tcl_CallFrame *framePtr; @@ -365,6 +627,21 @@ } } +/* + *---------------------------------------------------------------------- + * CallStackClearCmdReferences -- + * + * Clear all references to the specified cmd in the callstack + * contents. + * + * Results: + * None. + * + * Side effects: + * Updated stack. + * + *---------------------------------------------------------------------- + */ static void CallStackClearCmdReferences(Tcl_Interp *interp, Tcl_Command cmd) { register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); @@ -379,30 +656,23 @@ } } - -#if 0 -/* just used by NsfONextMethod() */ -static NsfCallStackContent* -CallStackGetObjectFrame(Tcl_Interp *interp, NsfObject *object) { - register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); - - for (; varFramePtr; varFramePtr = Tcl_CallFrame_callerPtr(varFramePtr)) { - if (Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) { - NsfCallStackContent *cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); - if (cscPtr->self == object) { - return cscPtr; - } - } - } - return NULL; -} -#endif - /* - * Pop any callstack entry that is still alive (e.g. - * if "exit" is called and we were jumping out of the - * callframe + *---------------------------------------------------------------------- + * CallStackPopAll -- + * + * Unwind the stack and pop all callstack entries that are still + * alive (e.g. if "exit" is called and we were jumping out of the + * callframe). + * + * Results: + * None. + * + * Side effects: + * Updated stack. + * + *---------------------------------------------------------------------- */ + static void CallStackPopAll(Tcl_Interp *interp) { TclShowStack(interp); @@ -484,7 +754,6 @@ * *---------------------------------------------------------------------- */ - NSF_INLINE static void CscInit(/*@notnull@*/ NsfCallStackContent *cscPtr, NsfObject *object, NsfClass *cl, Tcl_Command cmd, int frameType, int flags, char *msg) { Index: generic/tclAPI.h =================================================================== diff -u -rb69a9b8de677b30774419057953a91c96df00e56 -r11911b4cef79513ac212b56be4270d1fb7a78ad6 --- generic/tclAPI.h (.../tclAPI.h) (revision b69a9b8de677b30774419057953a91c96df00e56) +++ generic/tclAPI.h (.../tclAPI.h) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) @@ -68,13 +68,13 @@ static int ConvertToCurrentoption(Tcl_Interp *interp, Tcl_Obj *objPtr, NsfParam CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { int index, result; - static CONST char *opts[] = {"proc", "method", "object", "class", "activelevel", "args", "activemixin", "calledproc", "calledmethod", "calledclass", "callingproc", "callingmethod", "callingclass", "callinglevel", "callingobject", "filterreg", "isnextcall", "next", NULL}; + static CONST char *opts[] = {"proc", "method", "methodpath", "object", "class", "activelevel", "args", "activemixin", "calledproc", "calledmethod", "calledclass", "callingproc", "callingmethod", "callingclass", "callinglevel", "callingobject", "filterreg", "isnextcall", "next", NULL}; result = Tcl_GetIndexFromObj(interp, objPtr, opts, "currentoption", 0, &index); *clientData = (ClientData) INT2PTR(index + 1); *outObjPtr = objPtr; return result; } -enum CurrentoptionIdx {CurrentoptionNULL, CurrentoptionProcIdx, CurrentoptionMethodIdx, CurrentoptionObjectIdx, CurrentoptionClassIdx, CurrentoptionActivelevelIdx, CurrentoptionArgsIdx, CurrentoptionActivemixinIdx, CurrentoptionCalledprocIdx, CurrentoptionCalledmethodIdx, CurrentoptionCalledclassIdx, CurrentoptionCallingprocIdx, CurrentoptionCallingmethodIdx, CurrentoptionCallingclassIdx, CurrentoptionCallinglevelIdx, CurrentoptionCallingobjectIdx, CurrentoptionFilterregIdx, CurrentoptionIsnextcallIdx, CurrentoptionNextIdx}; +enum CurrentoptionIdx {CurrentoptionNULL, CurrentoptionProcIdx, CurrentoptionMethodIdx, CurrentoptionMethodpathIdx, CurrentoptionObjectIdx, CurrentoptionClassIdx, CurrentoptionActivelevelIdx, CurrentoptionArgsIdx, CurrentoptionActivemixinIdx, CurrentoptionCalledprocIdx, CurrentoptionCalledmethodIdx, CurrentoptionCalledclassIdx, CurrentoptionCallingprocIdx, CurrentoptionCallingmethodIdx, CurrentoptionCallingclassIdx, CurrentoptionCallinglevelIdx, CurrentoptionCallingobjectIdx, CurrentoptionFilterregIdx, CurrentoptionIsnextcallIdx, CurrentoptionNextIdx}; static int ConvertToMethodproperty(Tcl_Interp *interp, Tcl_Obj *objPtr, NsfParam CONST *pPtr, ClientData *clientData, Tcl_Obj **outObjPtr) { Index: library/nx/nx.tcl =================================================================== diff -u -r448c0563adb3705d6686bdb37dc316f37b325474 -r11911b4cef79513ac212b56be4270d1fb7a78ad6 --- library/nx/nx.tcl (.../nx.tcl) (revision 448c0563adb3705d6686bdb37dc316f37b325474) +++ library/nx/nx.tcl (.../nx.tcl) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) @@ -447,16 +447,14 @@ # The methods "unknown" and "defaultmethod" are called internally # :method unknown {obj m args} { - set self [::nsf::current object] - #puts stderr "+++ UNKNOWN $self obj $obj '$m' $args" - array set "" [$self ::nsf::classes::nx::EnsembleObject::methodPath] - - if {[catch {set valid [lsort [$obj ::nsf::methods::object::info::lookupmethods -expand "$(path) *"]]} errorMsg]} { + set path [current methodpath] + #puts stderr "+++ UNKNOWN $self obj $obj '$m' $args // path '[current methodpath]'" + if {[catch {set valid [$obj ::nsf::methods::object::info::lookupmethods -expand "$path *"]} errorMsg]} { set valid "" - puts stderr "+++ UNKNOWN has error $errorMsg" + puts stderr "+++ UNKNOWN raises error $errorMsg" } - set ref "\"[lindex $args 0]\" of $obj $(path)" - error "Unable to dispatch sub-method $ref; valid are:\n[join $valid {, }]" + set ref "\"[lindex $args 0]\" of $obj $path" + error "Unable to dispatch sub-method $ref; valid are:\n[join [lsort $valid] {, }]" } :method defaultmethod {} {