summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiguel Sofer <miguel.sofer@gmail.com>2009-12-05 21:30:05 (GMT)
committerMiguel Sofer <miguel.sofer@gmail.com>2009-12-05 21:30:05 (GMT)
commit90bd6886192a7f8aba161a9c45eb000b9e59e69c (patch)
tree364580df13345c4b42788e63d9c681325eb910a9
parent2aa99d284d6f4194676a3e2f5aac6ad2197a7714 (diff)
downloadtcl-90bd6886192a7f8aba161a9c45eb000b9e59e69c.zip
tcl-90bd6886192a7f8aba161a9c45eb000b9e59e69c.tar.gz
tcl-90bd6886192a7f8aba161a9c45eb000b9e59e69c.tar.bz2
* generic/tclBasic.c: Fixed things so that you can tailcall
* generic/tclNamesp.c: properly out of a coroutine. * tests/tailcall.test: * generic/tclInterp.c: Fixed tailcalls for same-interp aliases (no test)
-rw-r--r--ChangeLog9
-rw-r--r--generic/tclBasic.c3
-rw-r--r--generic/tclInterp.c4
-rw-r--r--generic/tclNamesp.c25
-rw-r--r--tests/tailcall.test19
5 files changed, 55 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 24089ba..c8acf07 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-12-05 Miguel Sofer <msofer@users.sf.net>
+
+ * generic/tclBasic.c: Fixed things so that you can tailcall
+ * generic/tclNamesp.c: properly out of a coroutine.
+ * tests/tailcall.test:
+
+ * generic/tclInterp.c: Fixed tailcalls for same-interp aliases (no
+ test)
+
2009-12-03 Donal K. Fellows <dkf@users.sf.net>
* library/safe.tcl (::safe::AliasEncoding): Make the safe encoding
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index b0cc7f6..ce330b1 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -16,7 +16,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclBasic.c,v 1.410 2009/11/18 21:59:50 nijtmans Exp $
+ * RCS: @(#) $Id: tclBasic.c,v 1.411 2009/12/05 21:30:05 msofer Exp $
*/
#include "tclInt.h"
@@ -8783,6 +8783,7 @@ TclNRCoroutineObjCmd(
corPtr->auxNumLevels = iPtr->numLevels;
TclNRAddCallback(interp, NRCoroutineExitCallback, corPtr, NULL,NULL,NULL);
+ iPtr->evalFlags |= TCL_EVAL_REDIRECT;
return TclNRRunCallbacks(interp,
TclNREvalObjEx(interp, cmdObjPtr, 0, NULL, 0), rootPtr, 0);
}
diff --git a/generic/tclInterp.c b/generic/tclInterp.c
index 3c841d9..edf31ff 100644
--- a/generic/tclInterp.c
+++ b/generic/tclInterp.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclInterp.c,v 1.106 2009/10/06 16:55:59 dgp Exp $
+ * RCS: @(#) $Id: tclInterp.c,v 1.107 2009/12/05 21:30:05 msofer Exp $
*/
#include "tclInt.h"
@@ -1805,7 +1805,7 @@ AliasNRCmd(
*/
if (isRootEnsemble) {
- TclNRAddCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL);
+ TclNRDeferCallback(interp, TclClearRootEnsemble, NULL, NULL, NULL, NULL);
}
iPtr->evalFlags |= TCL_EVAL_REDIRECT;
return Tcl_NREvalObj(interp, listPtr, flags);
diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c
index 5d08bcb..99f3f1a 100644
--- a/generic/tclNamesp.c
+++ b/generic/tclNamesp.c
@@ -23,7 +23,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclNamesp.c,v 1.195 2009/11/16 18:00:11 dgp Exp $
+ * RCS: @(#) $Id: tclNamesp.c,v 1.196 2009/12/05 21:30:05 msofer Exp $
*/
#include "tclInt.h"
@@ -517,13 +517,27 @@ Tcl_PopCallFrame(
*/
TEOV_callback *tailcallPtr, *runPtr;
+ ExecEnv *eePtr = NULL;
+
+ restart:
for (runPtr = TOP_CB(interp); runPtr; runPtr = runPtr->nextPtr) {
if (((runPtr->procPtr) == NRCommand) && !runPtr->data[1]) {
break;
}
}
if (!runPtr) {
+ /*
+ * If we are tailcalling out of a coroutine, the splicing spot is
+ * in the caller's execEnv: go find it!
+ */
+
+ CoroutineData *corPtr = iPtr->execEnvPtr->corPtr;
+ if (corPtr) {
+ eePtr = iPtr->execEnvPtr;
+ iPtr->execEnvPtr = corPtr->callerEEPtr;
+ goto restart;
+ }
Tcl_Panic("Tailcall cannot find the right splicing spot: should not happen!");
}
@@ -531,6 +545,15 @@ Tcl_PopCallFrame(
tailcallPtr->nextPtr = runPtr->nextPtr;
runPtr->nextPtr = tailcallPtr;
+
+ if (eePtr) {
+ /*
+ * Restore the right execEnv if it was swapped for tailcalling out
+ * of a coroutine.
+ */
+
+ iPtr->execEnvPtr = eePtr;
+ }
}
}
diff --git a/tests/tailcall.test b/tests/tailcall.test
index 335492a..5918bfe 100644
--- a/tests/tailcall.test
+++ b/tests/tailcall.test
@@ -9,7 +9,7 @@
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
-# RCS: @(#) $Id: tailcall.test,v 1.9 2009/06/25 19:24:16 dgp Exp $
+# RCS: @(#) $Id: tailcall.test,v 1.10 2009/12/05 21:30:06 msofer Exp $
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest
@@ -560,6 +560,23 @@ test tailcall-12.3b {[Bug 2695587]} -setup {
rename a {}
} -result {1 {Tailcall called from within a catch environment}}
+test tailcall-13.1 {tailcall and coroutine} -setup {
+ set lambda {i {
+ if {$i == 0} {
+ depthDiff
+ }
+ if {[incr i] > 10} {
+ return [depthDiff]
+ }
+ tailcall coroutine foo ::apply $::lambda $i
+ }}
+} -body {
+ coroutine moo ::apply $::lambda 0
+} -cleanup {
+ unset lambda
+} -result {0 0 0 0 0 0}
+
+
if {[testConstraint testnrelevels]} {
namespace forget testnre::*