diff options
author | Miguel Sofer <miguel.sofer@gmail.com> | 2009-12-07 16:33:01 (GMT) |
---|---|---|
committer | Miguel Sofer <miguel.sofer@gmail.com> | 2009-12-07 16:33:01 (GMT) |
commit | 7b7f63470a6ad3bc615a4120d09489ae02c9fa7d (patch) | |
tree | 3a2cefb694b5d02ed1e89b00ed6d427ef8877af3 /generic/tclBasic.c | |
parent | f02342c0abbf0a641833353f729836274db3b80a (diff) | |
download | tcl-7b7f63470a6ad3bc615a4120d09489ae02c9fa7d.zip tcl-7b7f63470a6ad3bc615a4120d09489ae02c9fa7d.tar.gz tcl-7b7f63470a6ad3bc615a4120d09489ae02c9fa7d.tar.bz2 |
* generic/tclBasic.c: add ::tcl::unsupported::yieldTo
* generic/tclInt.h: [Patch 2910056]
Diffstat (limited to 'generic/tclBasic.c')
-rw-r--r-- | generic/tclBasic.c | 71 |
1 files changed, 66 insertions, 5 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 33e0273..b201af9 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.414 2009/12/07 14:04:27 msofer Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.415 2009/12/07 16:33:01 msofer Exp $ */ #include "tclInt.h" @@ -799,6 +799,9 @@ Tcl_CreateInterp(void) Tcl_NRCreateCommand(interp, "tailcall", NULL, TclNRTailcallObjCmd, NULL, NULL); + Tcl_NRCreateCommand(interp, "::tcl::unsupported::yieldTo", NULL, + TclNRYieldToObjCmd, NULL, NULL); + #ifdef USE_DTRACE /* * Register the tcl::dtrace command. @@ -8415,15 +8418,24 @@ YieldCallback( int result) { CoroutineData *corPtr = data[0]; - Tcl_Obj *cmdPtr = data[1]; + Tcl_Obj *listPtr = data[1]; corPtr->stackLevel = NULL; /* mark suspended */ iPtr->execEnvPtr = corPtr->callerEEPtr; - if (cmdPtr) { - /* yieldTo: invoke the command, use tailcall tech */ + if (listPtr) { + /* yieldTo: invoke the command using tailcall tech */ + TEOV_callback *cbPtr; + ClientData nsPtr = data[2]; + + TclNRAddCallback(interp, NRTailcallEval, listPtr, nsPtr, + NULL, NULL); + cbPtr = TOP_CB(interp); + TOP_CB(interp) = cbPtr->nextPtr; + + TclSpliceTailcall(interp, cbPtr); } - return result; + return TCL_OK; } int @@ -8459,6 +8471,55 @@ TclNRYieldObjCmd( NULL, NULL, NULL); return TCL_OK; } + +int +TclNRYieldToObjCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + CoroutineData *corPtr = iPtr->execEnvPtr->corPtr; + int numLevels = iPtr->numLevels; + + Tcl_Obj *listPtr, *nsObjPtr; + Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr; + Tcl_Namespace *ns1Ptr; + + if (objc < 2) { + Tcl_WrongNumArgs(interp, 1, objv, "command ?arg ...?"); + return TCL_ERROR; + } + + if (!corPtr) { + Tcl_SetResult(interp, "yieldTo can only be called in a coroutine", + TCL_STATIC); + return TCL_ERROR; + } + + iPtr->numLevels = corPtr->auxNumLevels; + corPtr->auxNumLevels = numLevels - corPtr->auxNumLevels; + + /* + * This is essentially code from TclNRTailcallObjCmd + */ + + listPtr = Tcl_NewListObj(objc-1, objv+1); + Tcl_IncrRefCount(listPtr); + + nsObjPtr = Tcl_NewStringObj(nsPtr->fullName, -1); + if ((TCL_OK != TclGetNamespaceFromObj(interp, nsObjPtr, &ns1Ptr)) + || (nsPtr != ns1Ptr)) { + Tcl_Panic("yieldTo failed to find the proper namespace"); + } + Tcl_IncrRefCount(nsObjPtr); + + TclNRAddCallback(interp, YieldCallback, corPtr, listPtr, nsObjPtr, NULL); + TclNRAddCallback(interp, NRCallTEBC, INT2PTR(TCL_NR_YIELD_TYPE), + NULL, NULL, NULL); + return TCL_OK; +} + static int RewindCoroutine( |