Tcl Source Code

Check-in [cf96e3ae67]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:updated, improved tailcall comments
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | mig-tailcall-cleanup
Files: files | file ages | folders
SHA1: cf96e3ae6781e46c6170c34cb7f0b35ff68dceac
User & Date: msofer 2015-03-23 02:11:30
Context
2015-03-23
13:43
more comments Closed-Leaf check-in: 8ef09a1e8a user: msofer tags: mig-tailcall-cleanup
02:11
updated, improved tailcall comments check-in: cf96e3ae67 user: msofer tags: mig-tailcall-cleanup
01:01
branch for ordering and grouping the tailcall related code, and especially clean up the comments check-in: 319c4b5555 user: msofer tags: mig-tailcall-cleanup
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclBasic.c.

4138
4139
4140
4141
4142
4143
4144
4145
4146

4147
4148
4149
4150
4151
4152
4153
....
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
....
8166
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
8191
8192
8193
8194
8195
8196
8197
8198
8199
8200
....
8278
8279
8280
8281
8282
8283
8284
8285
8286
8287
8288
8289
8290
8291
8292
8293
				 * here, otherwise the pointer to the
				 * requested Command struct to be invoked. */
{
    Interp *iPtr = (Interp *) interp;

    /*
     * data[1] stores a marker for use by tailcalls; it will be set to 1 by
     * command redirectors (imports, alias, ensembles) so that tailcalls
     * finishes the source command and not just the target.

     */

    if (iPtr->deferredCallbacks) {
        iPtr->deferredCallbacks = NULL;
    } else {
	TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);
    }
................................................................................
    int result)
{
    Interp *iPtr = (Interp *) interp;

    iPtr->numLevels--;

     /*
      * If there is a tailcall, schedule it
      */
 
    if (data[1] && (data[1] != INT2PTR(1))) {
        TclNRAddCallback(interp, TclNRTailcallEval, data[1], NULL, NULL, NULL);
    }

    /* OPT ??
................................................................................
    int flags)
{
    return TclNREvalObjv(interp, objc, objv, flags|TCL_EVAL_NOERR,
	    (Command *) cmd);
}
 
/*****************************************************************************
 * Stuff for tailcalls
 *****************************************************************************
 *
 * Just to show that IT CAN BE DONE! The precise semantics are not simple,
 * require more thought. Possibly need a new Tcl return code to do it right?
 * Questions include:
 *   (1) How is the objc/objv tailcall to be run? My current thinking is that
 *	 it should essentially be
 *	     [tailcall a b c] <=> [uplevel 1 [list a b c]]
 *	 with two caveats
 *	     (a) the current frame is dropped first, after running all pending
 *		 cleanup tasks and saving its namespace
 *	     (b) 'a' is looked up in the returning frame's namespace, but the
 *		 command is run in the context to which we are returning
 *	 Current implementation does this if [tailcall] is called from within
 *	 a proc, errors otherwise.
 *   (2) Should a tailcall bypass [catch] in the returning frame? Current
 *	 implementation does not (or does it? Changed, test!) - it causes an
 *	 error.
 *
 * FIXME NRE!
 */

void
TclMarkTailcall(
    Tcl_Interp *interp)
{
    Interp *iPtr = (Interp *) interp;
................................................................................
        Tcl_DecrRefCount(iPtr->varFramePtr->tailcallPtr);
        iPtr->varFramePtr->tailcallPtr = NULL;
    }

    /*
     * Create the callback to actually evaluate the tailcalled
     * command, then set it in the varFrame so that PopCallFrame can use it
     * at the proper time. Being lazy: exploit the TclNRAddCallBack macro to
     * build the callback.
     */

    if (objc > 1) {
        Tcl_Obj *listPtr, *nsObjPtr;
        Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
        Tcl_Namespace *ns1Ptr;







|
|
>







 







|







 







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<
<







 







|
<







4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
....
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
....
8167
8168
8169
8170
8171
8172
8173
8174
8175
8176
8177
8178
8179
8180
8181
8182
8183
8184
8185
8186
8187
8188
8189
8190
8191



8192
8193
8194
8195
8196
8197
8198
....
8276
8277
8278
8279
8280
8281
8282
8283

8284
8285
8286
8287
8288
8289
8290
				 * here, otherwise the pointer to the
				 * requested Command struct to be invoked. */
{
    Interp *iPtr = (Interp *) interp;

    /*
     * data[1] stores a marker for use by tailcalls; it will be set to 1 by
     * command redirectors (imports, alias, ensembles) so that tailcall skips
     * this callback (that marks the end of the target command) and goes back
     * to the end of the source command. 
     */

    if (iPtr->deferredCallbacks) {
        iPtr->deferredCallbacks = NULL;
    } else {
	TclNRAddCallback(interp, NRCommand, NULL, NULL, NULL, NULL);
    }
................................................................................
    int result)
{
    Interp *iPtr = (Interp *) interp;

    iPtr->numLevels--;

     /*
      * If there is a tailcall, schedule it next
      */
 
    if (data[1] && (data[1] != INT2PTR(1))) {
        TclNRAddCallback(interp, TclNRTailcallEval, data[1], NULL, NULL, NULL);
    }

    /* OPT ??
................................................................................
    int flags)
{
    return TclNREvalObjv(interp, objc, objv, flags|TCL_EVAL_NOERR,
	    (Command *) cmd);
}
 
/*****************************************************************************
 * Tailcall related code
 *****************************************************************************
 *
 * The steps of the tailcall dance are as follows:
 *
 *   1. when [tailcall] is invoked, it stores the corresponding callback in
 *      the current CallFrame and returns TCL_RETURN
 *   2. when the CallFrame is popped, it calls TclSetTailcall to store the
 *      callback in the proper NRCommand callback - the spot where the command
 *      that pushed the CallFrame is completely cleaned up
 *   3. The NRCommand schedules the tailcall callback to run immediately after
 *      NRCommand returns
 *
 *   One delicate point is to properly define the NRCommand where the tailcall
 *   will execute. There are functions whose purpose is to help define the
 *   precise spot: TclMarkTailcall ("this is the spot") and TclSkipTailcall
 *   ("skip the next command: we are redirecting to it, tailcalls should run
 *   after WE return"), TclPushTailcallPoint (special for OO).



 */

void
TclMarkTailcall(
    Tcl_Interp *interp)
{
    Interp *iPtr = (Interp *) interp;
................................................................................
        Tcl_DecrRefCount(iPtr->varFramePtr->tailcallPtr);
        iPtr->varFramePtr->tailcallPtr = NULL;
    }

    /*
     * Create the callback to actually evaluate the tailcalled
     * command, then set it in the varFrame so that PopCallFrame can use it
     * at the proper time.

     */

    if (objc > 1) {
        Tcl_Obj *listPtr, *nsObjPtr;
        Tcl_Namespace *nsPtr = (Tcl_Namespace *) iPtr->varFramePtr->nsPtr;
        Tcl_Namespace *ns1Ptr;