aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2015-06-03 08:13:08 +1000
committerSteve Bennett <steveb@workware.net.au>2015-06-03 10:53:24 +1000
commitb927888eaee48eba3ce78c1887120cc219275775 (patch)
tree1127666f0b5ee450c6065f5b15321a0dc15e4fc7
parentadcb761134c80285073a2c4728ab545dec101ff2 (diff)
downloadjimtcl-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.c50
-rw-r--r--jim.h1
2 files changed, 20 insertions, 31 deletions
diff --git a/jim.c b/jim.c
index dc92c47..e2a3d50 100644
--- a/jim.c
+++ b/jim.c
@@ -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;
}
diff --git a/jim.h b/jim.h
index ece4b74..fa8f5b4 100644
--- a/jim.h
+++ b/jim.h
@@ -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;