Index: generic/nsf.c =================================================================== diff -u -r4f234291ad9583aafb5a8c9476d4c3f56838fab3 -r86caad4d5db5f26fcf0d5b2fe009eefef554282c --- generic/nsf.c (.../nsf.c) (revision 4f234291ad9583aafb5a8c9476d4c3f56838fab3) +++ generic/nsf.c (.../nsf.c) (revision 86caad4d5db5f26fcf0d5b2fe009eefef554282c) @@ -20693,9 +20693,15 @@ nonnull_assert(interp != NULL); switch (level) { - case CALLING_LEVEL: - NsfCallStackFindLastInvocation(interp, 1, &framePtr); + case CALLING_LEVEL: { + Tcl_CallFrame *callingFramePtr = NULL; + NsfCallStackFindCallingContext(interp, 1, &framePtr, &callingFramePtr); + if (framePtr == NULL) { + framePtr = callingFramePtr; + } + // NsfCallStackFindLastInvocation(interp, 1, &framePtr); break; + } case ACTIVE_LEVEL: NsfCallStackFindActiveFrame(interp, 1, &framePtr); break; @@ -32359,11 +32365,17 @@ objv += i; if (framePtr == NULL) { - NsfCallStackFindLastInvocation(interp, 1, &framePtr); + Tcl_CallFrame *callingFramePtr = NULL; + NsfCallStackFindCallingContext(interp, 1, &framePtr, &callingFramePtr); + // fprintf(stderr, "UPLEVEL framePtr %p\n", framePtr); + // NsfCallStackFindLastInvocation(interp, 1, &framePtr); if (framePtr == NULL) { - framePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp)->callerVarPtr; + framePtr = callingFramePtr; if (framePtr == NULL) { - framePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); + framePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp)->callerVarPtr; + if (framePtr == NULL) { + framePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); + } } } } Index: generic/nsfInt.h =================================================================== diff -u -r459516f92aed8b1287b3824d7dd39f58859dea4d -r86caad4d5db5f26fcf0d5b2fe009eefef554282c --- generic/nsfInt.h (.../nsfInt.h) (revision 459516f92aed8b1287b3824d7dd39f58859dea4d) +++ generic/nsfInt.h (.../nsfInt.h) (revision 86caad4d5db5f26fcf0d5b2fe009eefef554282c) @@ -1396,4 +1396,7 @@ #define NsfMax(a,b) ((a) > (b) ? a : b) #define NsfMin(a,b) ((a) < (b) ? a : b) +#define NsfCallStackFindLastInvocation(interp, offset, framePtrPtr) \ + NsfCallStackFindCallingContext((interp), (offset), (framePtrPtr), NULL) + #endif /* _nsf_int_h_ */ Index: generic/nsfStack.c =================================================================== diff -u -rb489939c82f4fd30a0c6dc404f272d29085e087e -r86caad4d5db5f26fcf0d5b2fe009eefef554282c --- generic/nsfStack.c (.../nsfStack.c) (revision b489939c82f4fd30a0c6dc404f272d29085e087e) +++ generic/nsfStack.c (.../nsfStack.c) (revision 86caad4d5db5f26fcf0d5b2fe009eefef554282c) @@ -77,12 +77,20 @@ NSF_INLINE static NsfCallStackContent* CallStackGetTopFrame0(const Tcl_Interp *interp) nonnull(1) pure; -static NsfCallStackContent* NsfCallStackFindLastInvocation( +/* static NsfCallStackContent* NsfCallStackFindLastInvocation( const Tcl_Interp *interp, int offset, Tcl_CallFrame **framePtrPtr + ) nonnull(1);*/ + +static NsfCallStackContent* NsfCallStackFindCallingContext( + const Tcl_Interp *interp, + int offset, + Tcl_CallFrame **callingProcFramePtrPtr, + Tcl_CallFrame **callingFramePtrPtr ) nonnull(1); + static NsfCallStackContent* NsfCallStackFindActiveFrame( const Tcl_Interp *interp, int offset, @@ -613,8 +621,92 @@ /* *---------------------------------------------------------------------- + * NsfCallStackFindCallingContext -- * NsfCallStackFindLastInvocation -- * + * Find the calling context (frame) with a specified offset. Find the + * frame corresponding to the calling proc or (scripted or non-leaf) + * method. + * + * Results: + * Call stack content (for NSF methods) or NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static NsfCallStackContent * +NsfCallStackFindCallingContext(const Tcl_Interp *interp, + int offset, + Tcl_CallFrame **callingProcFramePtrPtr, + Tcl_CallFrame **callingFramePtrPtr) { + register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); + int lvl = Tcl_CallFrame_level(varFramePtr); + + nonnull_assert(interp != NULL); + + // NsfShowStack((Tcl_Interp *)interp); + + for (; likely(varFramePtr != NULL); varFramePtr = Tcl_CallFrame_callerVarPtr(varFramePtr)) { + + if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & + (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { + NsfCallStackContent *cscPtr = (NsfCallStackContent *)Tcl_CallFrame_clientData(varFramePtr); + + /* + * An NSF method frame. + */ + if ((cscPtr->flags & (NSF_CSC_CALL_IS_NEXT|NSF_CSC_CALL_IS_ENSEMBLE)) + || (cscPtr->frameType & NSF_CSC_TYPE_INACTIVE)) { + continue; + } + + if (offset != 0) { + offset--; + } else if (Tcl_CallFrame_level(varFramePtr) < lvl) { + if (callingProcFramePtrPtr != NULL) { + *callingProcFramePtrPtr = varFramePtr; + } + return cscPtr; + } + } else if (Tcl_CallFrame_isProcCallFrame(varFramePtr)) { + + /* + * A Tcl proc frame. + */ + if (offset != 0) { + offset--; + } else if (Tcl_CallFrame_level(varFramePtr) < lvl) { + if (callingProcFramePtrPtr != NULL) { + *callingProcFramePtrPtr = varFramePtr; + } + return NULL; + } + } else { + /* some other frame */ + if (offset != 0) { + offset--; + } else if (callingFramePtrPtr != NULL && + *callingFramePtrPtr == NULL && + Tcl_CallFrame_level(varFramePtr) < lvl) { + /* fprintf(stderr, "firstFramePtr %p lvl %d\n", + varFramePtr, Tcl_CallFrame_level(varFramePtr));*/ + *callingFramePtrPtr = varFramePtr; + } + } + } + + if (callingProcFramePtrPtr != NULL) { + *callingProcFramePtrPtr = NULL; + } + return NULL; +} + +/* + *---------------------------------------------------------------------- + * NsfCallStackFindLastInvocation -- + * * Find last invocation of a (scripted or non-leaf) method with a * specified offset. * @@ -626,13 +718,18 @@ * *---------------------------------------------------------------------- */ -static NsfCallStackContent * + +#if 0 + static NsfCallStackContent * NsfCallStackFindLastInvocation(const Tcl_Interp *interp, int offset, Tcl_CallFrame **framePtrPtr) { register Tcl_CallFrame *varFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); int lvl = Tcl_CallFrame_level(varFramePtr); + Tcl_CallFrame *firstFramePtr = NULL; nonnull_assert(interp != NULL); + NsfShowStack((Tcl_Interp *)interp); + for (; likely(varFramePtr != NULL); varFramePtr = Tcl_CallFrame_callerVarPtr(varFramePtr)) { if (((unsigned int)Tcl_CallFrame_isProcCallFrame(varFramePtr) & (FRAME_IS_NSF_METHOD|FRAME_IS_NSF_CMETHOD)) != 0u) { @@ -667,6 +764,17 @@ } return NULL; } + } else { + /* some other frame */ + fprintf(stderr, "RUN\n"); + if (offset != 0) { + offset--; + } else if (firstFramePtr == NULL && + Tcl_CallFrame_level(varFramePtr) < lvl) { + fprintf(stderr, "firstFramePtr %p lvl %d\n", + varFramePtr, Tcl_CallFrame_level(varFramePtr)); + firstFramePtr = varFramePtr; + } } } @@ -675,6 +783,7 @@ } return NULL; } +#endif /* *---------------------------------------------------------------------- Index: tests/methods.test =================================================================== diff -u -ra65f2c7d3f02c9da0f878f59fa4dd5fb6008bade -r86caad4d5db5f26fcf0d5b2fe009eefef554282c --- tests/methods.test (.../methods.test) (revision a65f2c7d3f02c9da0f878f59fa4dd5fb6008bade) +++ tests/methods.test (.../methods.test) (revision 86caad4d5db5f26fcf0d5b2fe009eefef554282c) @@ -1607,6 +1607,96 @@ AbstractFile filters delete filterCall +nx::test case callinglevels { + + nx::Object create objekt + objekt public object method foo {} { + current callinglevel + } + + ? {uplevel #0 {objekt foo}} "#0" + ? {uplevel #0 { + namespace eval ::ns1 { + namespace eval ns2 { + objekt foo + } + } + }} "#2" + namespace delete ::ns1 + + ? {uplevel #0 {apply {{} {objekt foo}}}} "#1" + ? {uplevel #0 { apply {{} { + namespace eval ::ns1 { + namespace eval ns2 { + objekt foo + } + } + }}}} "#1" + namespace delete ::ns1 + + objekt public object method intercept args { + list [current method] {*}[next] + } + objekt object filters add intercept + + ? {uplevel #0 {objekt foo}} "intercept #0" + ? {uplevel #0 { + namespace eval ::ns1 { + namespace eval ns2 { + objekt foo + } + } + }} "intercept #2" + namespace delete ::ns1 + + ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept #1" + ? {uplevel #0 { apply {{} { + namespace eval ::ns1 { + namespace eval ns2 { + objekt foo + } + } + }}}} "intercept #1" + namespace delete ::ns1 + + objekt object mixins add [nx::Class new { + :public method foo {args} { + list [current method] {*}[next] + } + }] + + ? {uplevel #0 {objekt foo}} "intercept foo #0" + ? {uplevel #0 { + namespace eval ::ns1 { + namespace eval ns2 { + objekt foo + } + } + }} "intercept foo #2" + namespace delete ::ns1 + + ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept foo #1" + ? {uplevel #0 { apply {{} { + namespace eval ::ns1 { + namespace eval ns2 { + objekt foo + } + } + }}}} "intercept foo #1" + namespace delete ::ns1 + +} + +nx::test case uplevel { + nx::Object create objekt + objekt public object method foo {} { + :uplevel {return -level 0 #[info level]} + } + ? {uplevel #0 {objekt foo}} "#0" + +} + + # Local variables: # mode: tcl # tcl-indent-level: 2