diff options
author | Steve Bennett <steveb@workware.net.au> | 2015-06-03 08:13:08 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2015-06-03 10:53:24 +1000 |
commit | b927888eaee48eba3ce78c1887120cc219275775 (patch) | |
tree | 1127666f0b5ee450c6065f5b15321a0dc15e4fc7 | |
parent | adcb761134c80285073a2c4728ab545dec101ff2 (diff) | |
download | jimtcl-b927888eaee48eba3ce78c1887120cc219275775.zip jimtcl-b927888eaee48eba3ce78c1887120cc219275775.tar.gz jimtcl-b927888eaee48eba3ce78c1887120cc219275775.tar.bz2 |
chained tailcalls were not always being run
There is no need to protect against merging tailcalls across
uplevel since any tailcalls should already be fully resolved.
This fixes a problem with the following only running one loop:
foreach a {b c d} {
command-with-tailcall $a
}
In particular:
dict for {a b} {1 2 3 4} { puts $a,$b }
Reported-by: Jon Povey <jon.povey@emsolutions.com.au>
Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r-- | jim.c | 50 | ||||
-rw-r--r-- | jim.h | 1 |
2 files changed, 20 insertions, 31 deletions
@@ -4916,7 +4916,6 @@ static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *pare cf->next = NULL; cf->staticVars = NULL; cf->localCommands = NULL; - cf->tailcall = 0; cf->tailcallObj = NULL; cf->tailcallCmd = NULL; } @@ -10900,34 +10899,30 @@ badargset: interp->framePtr = interp->framePtr->parent; JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE); + /* Now chain any tailcalls in the parent frame */ if (interp->framePtr->tailcallObj) { - /* If a tailcall is already being executed, merge this tailcall with that one */ - if (interp->framePtr->tailcall++ == 0) { - /* No current tailcall in this frame, so invoke the tailcall command */ - do { - Jim_Obj *tailcallObj = interp->framePtr->tailcallObj; - - interp->framePtr->tailcallObj = NULL; - - if (retcode == JIM_EVAL) { - retcode = Jim_EvalObjList(interp, tailcallObj); - if (retcode == JIM_RETURN) { - /* If the result of the tailcall is 'return', push - * it up to the caller - */ - interp->returnLevel++; - } - } - Jim_DecrRefCount(interp, tailcallObj); - } while (interp->framePtr->tailcallObj); + do { + Jim_Obj *tailcallObj = interp->framePtr->tailcallObj; + + interp->framePtr->tailcallObj = NULL; - /* If the tailcall chain finished early, may need to manually discard the command */ - if (interp->framePtr->tailcallCmd) { - JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd); - interp->framePtr->tailcallCmd = NULL; + if (retcode == JIM_EVAL) { + retcode = Jim_EvalObjList(interp, tailcallObj); + if (retcode == JIM_RETURN) { + /* If the result of the tailcall is 'return', push + * it up to the caller + */ + interp->returnLevel++; + } } + Jim_DecrRefCount(interp, tailcallObj); + } while (interp->framePtr->tailcallObj); + + /* If the tailcall chain finished early, may need to manually discard the command */ + if (interp->framePtr->tailcallCmd) { + JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd); + interp->framePtr->tailcallCmd = NULL; } - interp->framePtr->tailcall--; } /* Handle the JIM_RETURN return code */ @@ -12936,7 +12931,6 @@ static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * if (argc >= 2) { int retcode; Jim_CallFrame *savedCallFrame, *targetCallFrame; - int savedTailcall; const char *str; /* Save the old callframe pointer */ @@ -12961,16 +12955,12 @@ static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const * } /* Eval the code in the target callframe. */ interp->framePtr = targetCallFrame; - /* Can't merge tailcalls across upcall */ - savedTailcall = interp->framePtr->tailcall; - interp->framePtr->tailcall = 0; if (argc == 2) { retcode = Jim_EvalObj(interp, argv[1]); } else { retcode = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); } - interp->framePtr->tailcall = savedTailcall; interp->framePtr = savedCallFrame; return retcode; } @@ -437,7 +437,6 @@ typedef struct Jim_CallFrame { Jim_Obj *fileNameObj; /* file and line of caller of this proc (if available) */ int line; Jim_Stack *localCommands; /* commands to be destroyed when the call frame is destroyed */ - int tailcall; /* non-zero if a tailcall is being evaluated at this level */ struct Jim_Obj *tailcallObj; /* Pending tailcall invocation */ struct Jim_Cmd *tailcallCmd; /* Resolved command for pending tailcall invocation */ } Jim_CallFrame; |