Index: generic/nsf.c =================================================================== diff -u -r86caad4d5db5f26fcf0d5b2fe009eefef554282c -rb97fe27792607e6e3d6b89d3e012760e641a90df --- generic/nsf.c (.../nsf.c) (revision 86caad4d5db5f26fcf0d5b2fe009eefef554282c) +++ generic/nsf.c (.../nsf.c) (revision b97fe27792607e6e3d6b89d3e012760e641a90df) @@ -32336,24 +32336,27 @@ } */ static int -NsfOUplevelMethod(Tcl_Interp *interp, NsfObject *UNUSED(object), int objc, Tcl_Obj *const objv[]) { - int i, result; - Tcl_CallFrame *framePtr, *savedVarFramePtr; +NsfOUplevelMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *const objv[]) { + int result; + CallFrame *requestedFramePtr; + Tcl_CallFrame *framePtr = NULL, *savedVarFramePtr; nonnull_assert(interp != NULL); nonnull_assert(objv != NULL); - /* - * Find the level to use for executing the command. - */ - if (objc > 2) { - CallFrame *cf; - const char *frameInfo = ObjStr(objv[1]); + if (objc < 2) { + wrongArgs: + return NsfPrintError(interp, + "wrong # args: should be \"%s %s ?level? command ?arg ...?\"", + ObjectName(object), + NsfMethodName(objv[0])); + } - result = TclGetFrame(interp, frameInfo, &cf); - if (unlikely(result == -1)) { - return TCL_ERROR; + result = TclObjGetFrame(interp, objv[1], &requestedFramePtr); + if (unlikely(result == -1)) { + return TCL_ERROR; } +<<<<<<< HEAD framePtr = (Tcl_CallFrame *)cf; i = result+1; } else { @@ -32363,25 +32366,31 @@ objc -= i; objv += i; +======= + objc -= result + 1; + if (objc == 0) { + goto wrongArgs; + } + objv += result + 1; +>>>>>>> * nsf.c, methods.test (NsfOUplevelMethod): Fix argument handling - if (framePtr == NULL) { - Tcl_CallFrame *callingFramePtr = NULL; - NsfCallStackFindCallingContext(interp, 1, &framePtr, &callingFramePtr); - // fprintf(stderr, "UPLEVEL framePtr %p\n", framePtr); - // NsfCallStackFindLastInvocation(interp, 1, &framePtr); - if (framePtr == NULL) { - framePtr = callingFramePtr; + if (result == 0) { + /* 0 is returned from TclObjGetFrame when no (or, an invalid) level specifier was provided */ + Tcl_CallFrame *callingFramePtr = NULL; + NsfCallStackFindCallingContext(interp, 1, &framePtr, &callingFramePtr); if (framePtr == NULL) { - framePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp)->callerVarPtr; - if (framePtr == NULL) { - framePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); - } + /* no proc frame was found, default to parent frame */ + framePtr = callingFramePtr; } + } else { + /* use the requested frame corresponding to the (valid) level specifier */ + framePtr = (Tcl_CallFrame *)requestedFramePtr; } - } - savedVarFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); - Tcl_Interp_varFramePtr(interp) = (CallFrame *)framePtr; + assert(framePtr != NULL); + + savedVarFramePtr = (Tcl_CallFrame *)Tcl_Interp_varFramePtr(interp); + Tcl_Interp_varFramePtr(interp) = (CallFrame *)framePtr; /* * Execute the residual arguments as a command. Index: tests/methods.test =================================================================== diff -u -r6671e05d628c0ecec739c584d997c11da73dbd19 -rb97fe27792607e6e3d6b89d3e012760e641a90df --- tests/methods.test (.../methods.test) (revision 6671e05d628c0ecec739c584d997c11da73dbd19) +++ tests/methods.test (.../methods.test) (revision b97fe27792607e6e3d6b89d3e012760e641a90df) @@ -1732,7 +1732,7 @@ }} "intercept #2" namespace delete ::ns1 - ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept #1" + ? {uplevel #0 {apply {{} {objekt foo}}}} "intercept #1" ? {uplevel #0 { apply {{} { namespace eval ::ns1 { namespace eval ns2 { @@ -1845,7 +1845,67 @@ } +nx::test case uplevel-method-signature { + nx::Object create objekt + objekt public object method foo {} { + concat \ + [:uplevel return -level 0 "#\[info level\]"] \ + [uplevel [current callinglevel] return -level 0 "#\[info level\]"] + } + + ? {uplevel #0 { apply {{} { + namespace eval ::ns1 { + namespace eval ns2 { + objekt foo + } + } + }}}} "#1 #1" + + objekt public object method foo {} { + :uplevel + } + + ? {uplevel #0 {objekt foo}} {wrong # args: should be "::objekt uplevel ?level? command ?arg ...?"} + + objekt public object method foo {} { + :uplevel 1 + } + + ? {uplevel #0 {objekt foo}} {wrong # args: should be "::objekt uplevel ?level? command ?arg ...?"} + + objekt public object method foo {} { + :uplevel #1 + } + + ? {uplevel #0 {objekt foo}} {wrong # args: should be "::objekt uplevel ?level? command ?arg ...?"} + + objekt public object method foo {} { + :uplevel 1 {return -level 0 #[info level]} + } + + ? {uplevel #0 {objekt foo}} "#0" + + objekt public object method foo {} { + :uplevel 1 return -level 0 "#\[info level\]" + } + + ? {uplevel #0 {objekt foo}} "#0" + + objekt public object method foo {} { + :uplevel #0 {return -level 0 #[info level]} + } + + ? {uplevel #0 {objekt foo}} "#0" + + objekt public object method foo {} { + :uplevel #0 return -level 0 "#\[info level\]" + } + + ? {uplevel #0 {objekt foo}} "#0" +} + + # Local variables: # mode: tcl # tcl-indent-level: 2