Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/generic/tclProc.c @ 63

Last change on this file since 63 was 25, checked in by landauf, 17 years ago

added tcl to libs

File size: 79.9 KB
Line 
1/*
2 * tclProc.c --
3 *
4 *      This file contains routines that implement Tcl procedures, including
5 *      the "proc" and "uplevel" commands.
6 *
7 * Copyright (c) 1987-1993 The Regents of the University of California.
8 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
9 * Copyright (c) 2004-2006 Miguel Sofer
10 * Copyright (c) 2007 Daniel A. Steffen <das@users.sourceforge.net>
11 *
12 * See the file "license.terms" for information on usage and redistribution of
13 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 * RCS: @(#) $Id: tclProc.c,v 1.139 2007/12/13 15:23:20 dgp Exp $
16 */
17
18#include "tclInt.h"
19#include "tclCompile.h"
20
21/*
22 * Prototypes for static functions in this file
23 */
24
25static void             DupLambdaInternalRep(Tcl_Obj *objPtr,
26                            Tcl_Obj *copyPtr);
27static void             FreeLambdaInternalRep(Tcl_Obj *objPtr);
28static int              InitArgsAndLocals(Tcl_Interp *interp,
29                            Tcl_Obj *procNameObj, int skip);
30static void             InitResolvedLocals(Tcl_Interp *interp,
31                            ByteCode *codePtr, Var *defPtr,
32                            Namespace *nsPtr);
33static void             InitLocalCache(Proc *procPtr);
34static int              PushProcCallFrame(ClientData clientData,
35                            register Tcl_Interp *interp, int objc,
36                            Tcl_Obj *CONST objv[], int isLambda);
37static void             ProcBodyDup(Tcl_Obj *srcPtr, Tcl_Obj *dupPtr);
38static void             ProcBodyFree(Tcl_Obj *objPtr);
39static int              ProcWrongNumArgs(Tcl_Interp *interp, int skip);
40static void             MakeProcError(Tcl_Interp *interp,
41                            Tcl_Obj *procNameObj);
42static void             MakeLambdaError(Tcl_Interp *interp,
43                            Tcl_Obj *procNameObj);
44static int              SetLambdaFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr);
45static int              ProcCompileProc(Tcl_Interp *interp, Proc *procPtr,
46                            Tcl_Obj *bodyPtr, Namespace *nsPtr,
47                            CONST char *description, CONST char *procName,
48                            Proc **procPtrPtr);
49
50/*
51 * The ProcBodyObjType type
52 */
53
54Tcl_ObjType tclProcBodyType = {
55    "procbody",                 /* name for this type */
56    ProcBodyFree,               /* FreeInternalRep function */
57    ProcBodyDup,                /* DupInternalRep function */
58    NULL,                       /* UpdateString function; Tcl_GetString and
59                                 * Tcl_GetStringFromObj should panic
60                                 * instead. */
61    NULL                        /* SetFromAny function; Tcl_ConvertToType
62                                 * should panic instead. */
63};
64
65/*
66 * The [upvar]/[uplevel] level reference type. Uses the twoPtrValue field,
67 * encoding the type of level reference in ptr1 and the actual parsed out
68 * offset in ptr2.
69 *
70 * Uses the default behaviour throughout, and never disposes of the string
71 * rep; it's just a cache type.
72 */
73
74static Tcl_ObjType levelReferenceType = {
75    "levelReference",
76    NULL, NULL, NULL, NULL
77};
78
79/*
80 * The type of lambdas. Note that every lambda will *always* have a string
81 * representation.
82 *
83 * Internally, ptr1 is a pointer to a Proc instance that is not bound to a
84 * command name, and ptr2 is a pointer to the namespace that the Proc instance
85 * will execute within.
86 */
87
88static Tcl_ObjType lambdaType = {
89    "lambdaExpr",               /* name */
90    FreeLambdaInternalRep,      /* freeIntRepProc */
91    DupLambdaInternalRep,       /* dupIntRepProc */
92    NULL,                       /* updateStringProc */
93    SetLambdaFromAny            /* setFromAnyProc */
94};
95
96/*
97 *----------------------------------------------------------------------
98 *
99 * Tcl_ProcObjCmd --
100 *
101 *      This object-based function is invoked to process the "proc" Tcl
102 *      command. See the user documentation for details on what it does.
103 *
104 * Results:
105 *      A standard Tcl object result value.
106 *
107 * Side effects:
108 *      A new procedure gets created.
109 *
110 *----------------------------------------------------------------------
111 */
112
113        /* ARGSUSED */
114int
115Tcl_ProcObjCmd(
116    ClientData dummy,           /* Not used. */
117    Tcl_Interp *interp,         /* Current interpreter. */
118    int objc,                   /* Number of arguments. */
119    Tcl_Obj *CONST objv[])      /* Argument objects. */
120{
121    register Interp *iPtr = (Interp *) interp;
122    Proc *procPtr;
123    char *fullName;
124    CONST char *procName, *procArgs, *procBody;
125    Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
126    Tcl_Command cmd;
127    Tcl_DString ds;
128
129    if (objc != 4) {
130        Tcl_WrongNumArgs(interp, 1, objv, "name args body");
131        return TCL_ERROR;
132    }
133
134    /*
135     * Determine the namespace where the procedure should reside. Unless the
136     * command name includes namespace qualifiers, this will be the current
137     * namespace.
138     */
139
140    fullName = TclGetString(objv[1]);
141    TclGetNamespaceForQualName(interp, fullName, NULL, 0,
142            &nsPtr, &altNsPtr, &cxtNsPtr, &procName);
143
144    if (nsPtr == NULL) {
145        Tcl_AppendResult(interp, "can't create procedure \"", fullName,
146                "\": unknown namespace", NULL);
147        return TCL_ERROR;
148    }
149    if (procName == NULL) {
150        Tcl_AppendResult(interp, "can't create procedure \"", fullName,
151                "\": bad procedure name", NULL);
152        return TCL_ERROR;
153    }
154    if ((nsPtr != iPtr->globalNsPtr)
155            && (procName != NULL) && (procName[0] == ':')) {
156        Tcl_AppendResult(interp, "can't create procedure \"", procName,
157                "\" in non-global namespace with name starting with \":\"",
158                NULL);
159        return TCL_ERROR;
160    }
161
162    /*
163     * Create the data structure to represent the procedure.
164     */
165
166    if (TclCreateProc(interp, nsPtr, procName, objv[2], objv[3],
167            &procPtr) != TCL_OK) {
168        Tcl_AddErrorInfo(interp, "\n    (creating proc \"");
169        Tcl_AddErrorInfo(interp, procName);
170        Tcl_AddErrorInfo(interp, "\")");
171        return TCL_ERROR;
172    }
173
174    /*
175     * Now create a command for the procedure. This will initially be in the
176     * current namespace unless the procedure's name included namespace
177     * qualifiers. To create the new command in the right namespace, we
178     * generate a fully qualified name for it.
179     */
180
181    Tcl_DStringInit(&ds);
182    if (nsPtr != iPtr->globalNsPtr) {
183        Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
184        Tcl_DStringAppend(&ds, "::", 2);
185    }
186    Tcl_DStringAppend(&ds, procName, -1);
187
188    cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds),
189            TclObjInterpProc, (ClientData) procPtr, TclProcDeleteProc);
190
191    Tcl_DStringFree(&ds);
192
193    /*
194     * Now initialize the new procedure's cmdPtr field. This will be used
195     * later when the procedure is called to determine what namespace the
196     * procedure will run in. This will be different than the current
197     * namespace if the proc was renamed into a different namespace.
198     */
199
200    procPtr->cmdPtr = (Command *) cmd;
201
202    /*
203     * TIP #280: Remember the line the procedure body is starting on. In a
204     * bytecode context we ask the engine to provide us with the necessary
205     * information. This is for the initialization of the byte code compiler
206     * when the body is used for the first time.
207     *
208     * This code is nearly identical to the #280 code in SetLambdaFromAny, see
209     * this file. The differences are the different index of the body in the
210     * line array of the context, and the lamdba code requires some special
211     * processing. Find a way to factor the common elements into a single
212     * function.
213     */
214
215    if (iPtr->cmdFramePtr) {
216        CmdFrame *contextPtr;
217
218        contextPtr = (CmdFrame *) TclStackAlloc(interp, sizeof(CmdFrame));
219        *contextPtr = *iPtr->cmdFramePtr;
220
221        if (contextPtr->type == TCL_LOCATION_BC) {
222            /*
223             * Retrieve source information from the bytecode, if possible. If
224             * the information is retrieved successfully, context.type will be
225             * TCL_LOCATION_SOURCE and the reference held by
226             * context.data.eval.path will be counted.
227             */
228
229            TclGetSrcInfoForPc(contextPtr);
230        } else if (contextPtr->type == TCL_LOCATION_SOURCE) {
231            /*
232             * The copy into 'context' up above has created another reference
233             * to 'context.data.eval.path'; account for it.
234             */
235
236            Tcl_IncrRefCount(contextPtr->data.eval.path);
237        }
238
239        if (contextPtr->type == TCL_LOCATION_SOURCE) {
240            /*
241             * We can account for source location within a proc only if the
242             * proc body was not created by substitution.
243             */
244
245            if (contextPtr->line
246                    && (contextPtr->nline >= 4) && (contextPtr->line[3] >= 0)) {
247                int isNew;
248                CmdFrame *cfPtr = (CmdFrame *) ckalloc(sizeof(CmdFrame));
249
250                cfPtr->level = -1;
251                cfPtr->type = contextPtr->type;
252                cfPtr->line = (int *) ckalloc(sizeof(int));
253                cfPtr->line[0] = contextPtr->line[3];
254                cfPtr->nline = 1;
255                cfPtr->framePtr = NULL;
256                cfPtr->nextPtr = NULL;
257
258                cfPtr->data.eval.path = contextPtr->data.eval.path;
259                Tcl_IncrRefCount(cfPtr->data.eval.path);
260
261                cfPtr->cmd.str.cmd = NULL;
262                cfPtr->cmd.str.len = 0;
263
264                Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr,
265                        (char *) procPtr, &isNew), cfPtr);
266            }
267
268            /*
269             * 'contextPtr' is going out of scope; account for the reference that
270             * it's holding to the path name.
271             */
272
273            Tcl_DecrRefCount(contextPtr->data.eval.path);
274            contextPtr->data.eval.path = NULL;
275        }
276        TclStackFree(interp, contextPtr);
277    }
278
279    /*
280     * Optimize for no-op procs: if the body is not precompiled (like a TclPro
281     * procbody), and the argument list is just "args" and the body is empty,
282     * define a compileProc to compile a no-op.
283     *
284     * Notes:
285     *   - cannot be done for any argument list without having different
286     *     compiled/not-compiled behaviour in the "wrong argument #" case, or
287     *     making this code much more complicated. In any case, it doesn't
288     *     seem to make a lot of sense to verify the number of arguments we
289     *     are about to ignore ...
290     *   - could be enhanced to handle also non-empty bodies that contain only
291     *     comments; however, parsing the body will slow down the compilation
292     *     of all procs whose argument list is just _args_
293     */
294
295    if (objv[3]->typePtr == &tclProcBodyType) {
296        goto done;
297    }
298
299    procArgs = TclGetString(objv[2]);
300
301    while (*procArgs == ' ') {
302        procArgs++;
303    }
304
305    if ((procArgs[0] == 'a') && (strncmp(procArgs, "args", 4) == 0)) {
306        procArgs +=4;
307        while(*procArgs != '\0') {
308            if (*procArgs != ' ') {
309                goto done;
310            }
311            procArgs++;
312        }
313
314        /*
315         * The argument list is just "args"; check the body
316         */
317
318        procBody = TclGetString(objv[3]);
319        while (*procBody != '\0') {
320            if (!isspace(UCHAR(*procBody))) {
321                goto done;
322            }
323            procBody++;
324        }
325
326        /*
327         * The body is just spaces: link the compileProc
328         */
329
330        ((Command *) cmd)->compileProc = TclCompileNoOp;
331    }
332
333  done:
334    return TCL_OK;
335}
336
337/*
338 *----------------------------------------------------------------------
339 *
340 * TclCreateProc --
341 *
342 *      Creates the data associated with a Tcl procedure definition. This
343 *      function knows how to handle two types of body objects: strings and
344 *      procbody. Strings are the traditional (and common) value for bodies,
345 *      procbody are values created by extensions that have loaded a
346 *      previously compiled script.
347 *
348 * Results:
349 *      Returns TCL_OK on success, along with a pointer to a Tcl procedure
350 *      definition in procPtrPtr where the cmdPtr field is not initialised.
351 *      This definition should be freed by calling TclProcCleanupProc() when
352 *      it is no longer needed. Returns TCL_ERROR if anything goes wrong.
353 *
354 * Side effects:
355 *      If anything goes wrong, this function returns an error message in the
356 *      interpreter.
357 *
358 *----------------------------------------------------------------------
359 */
360
361int
362TclCreateProc(
363    Tcl_Interp *interp,         /* Interpreter containing proc. */
364    Namespace *nsPtr,           /* Namespace containing this proc. */
365    CONST char *procName,       /* Unqualified name of this proc. */
366    Tcl_Obj *argsPtr,           /* Description of arguments. */
367    Tcl_Obj *bodyPtr,           /* Command body. */
368    Proc **procPtrPtr)          /* Returns: pointer to proc data. */
369{
370    Interp *iPtr = (Interp *) interp;
371    CONST char **argArray = NULL;
372
373    register Proc *procPtr;
374    int i, length, result, numArgs;
375    CONST char *args, *bytes, *p;
376    register CompiledLocal *localPtr = NULL;
377    Tcl_Obj *defPtr;
378    int precompiled = 0;
379
380    if (bodyPtr->typePtr == &tclProcBodyType) {
381        /*
382         * Because the body is a TclProProcBody, the actual body is already
383         * compiled, and it is not shared with anyone else, so it's OK not to
384         * unshare it (as a matter of fact, it is bad to unshare it, because
385         * there may be no source code).
386         *
387         * We don't create and initialize a Proc structure for the procedure;
388         * rather, we use what is in the body object. We increment the ref
389         * count of the Proc struct since the command (soon to be created)
390         * will be holding a reference to it.
391         */
392
393        procPtr = bodyPtr->internalRep.otherValuePtr;
394        procPtr->iPtr = iPtr;
395        procPtr->refCount++;
396        precompiled = 1;
397    } else {
398        /*
399         * If the procedure's body object is shared because its string value
400         * is identical to, e.g., the body of another procedure, we must
401         * create a private copy for this procedure to use. Such sharing of
402         * procedure bodies is rare but can cause problems. A procedure body
403         * is compiled in a context that includes the number of "slots"
404         * allocated by the compiler for local variables. There is a local
405         * variable slot for each formal parameter (the
406         * "procPtr->numCompiledLocals = numArgs" assignment below). This
407         * means that the same code can not be shared by two procedures that
408         * have a different number of arguments, even if their bodies are
409         * identical. Note that we don't use Tcl_DuplicateObj since we would
410         * not want any bytecode internal representation.
411         */
412
413        if (Tcl_IsShared(bodyPtr)) {
414            bytes = TclGetStringFromObj(bodyPtr, &length);
415            bodyPtr = Tcl_NewStringObj(bytes, length);
416        }
417
418        /*
419         * Create and initialize a Proc structure for the procedure. We
420         * increment the ref count of the procedure's body object since there
421         * will be a reference to it in the Proc structure.
422         */
423
424        Tcl_IncrRefCount(bodyPtr);
425
426        procPtr = (Proc *) ckalloc(sizeof(Proc));
427        procPtr->iPtr = iPtr;
428        procPtr->refCount = 1;
429        procPtr->bodyPtr = bodyPtr;
430        procPtr->numArgs = 0;   /* Actual argument count is set below. */
431        procPtr->numCompiledLocals = 0;
432        procPtr->firstLocalPtr = NULL;
433        procPtr->lastLocalPtr = NULL;
434    }
435
436    /*
437     * Break up the argument list into argument specifiers, then process each
438     * argument specifier. If the body is precompiled, processing is limited
439     * to checking that the parsed argument is consistent with the one stored
440     * in the Proc.
441     *
442     * THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULS.
443     */
444
445    args = TclGetStringFromObj(argsPtr, &length);
446    result = Tcl_SplitList(interp, args, &numArgs, &argArray);
447    if (result != TCL_OK) {
448        goto procError;
449    }
450
451    if (precompiled) {
452        if (numArgs > procPtr->numArgs) {
453            Tcl_SetObjResult(interp, Tcl_ObjPrintf(
454                    "procedure \"%s\": arg list contains %d entries, "
455                    "precompiled header expects %d", procName, numArgs,
456                    procPtr->numArgs));
457            goto procError;
458        }
459        localPtr = procPtr->firstLocalPtr;
460    } else {
461        procPtr->numArgs = numArgs;
462        procPtr->numCompiledLocals = numArgs;
463    }
464
465    for (i = 0; i < numArgs; i++) {
466        int fieldCount, nameLength, valueLength;
467        CONST char **fieldValues;
468
469        /*
470         * Now divide the specifier up into name and default.
471         */
472
473        result = Tcl_SplitList(interp, argArray[i], &fieldCount,
474                &fieldValues);
475        if (result != TCL_OK) {
476            goto procError;
477        }
478        if (fieldCount > 2) {
479            ckfree((char *) fieldValues);
480            Tcl_AppendResult(interp,
481                    "too many fields in argument specifier \"",
482                    argArray[i], "\"", NULL);
483            goto procError;
484        }
485        if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
486            ckfree((char *) fieldValues);
487            Tcl_AppendResult(interp, "argument with no name", NULL);
488            goto procError;
489        }
490
491        nameLength = strlen(fieldValues[0]);
492        if (fieldCount == 2) {
493            valueLength = strlen(fieldValues[1]);
494        } else {
495            valueLength = 0;
496        }
497
498        /*
499         * Check that the formal parameter name is a scalar.
500         */
501
502        p = fieldValues[0];
503        while (*p != '\0') {
504            if (*p == '(') {
505                CONST char *q = p;
506                do {
507                    q++;
508                } while (*q != '\0');
509                q--;
510                if (*q == ')') {        /* We have an array element. */
511                    Tcl_AppendResult(interp, "formal parameter \"",
512                            fieldValues[0],
513                            "\" is an array element", NULL);
514                    ckfree((char *) fieldValues);
515                    goto procError;
516                }
517            } else if ((*p == ':') && (*(p+1) == ':')) {
518                Tcl_AppendResult(interp, "formal parameter \"",
519                        fieldValues[0],
520                        "\" is not a simple name", NULL);
521                ckfree((char *) fieldValues);
522                goto procError;
523            }
524            p++;
525        }
526
527        if (precompiled) {
528            /*
529             * Compare the parsed argument with the stored one. Note that the
530             * only flag value that makes sense at this point is VAR_ARGUMENT
531             * (its value was kept the same as pre VarReform to simplify
532             * tbcload's processing of older byetcodes).
533             *
534             * The only other flag vlaue that is important to retrieve from
535             * precompiled procs is VAR_TEMPORARY (also unchanged). It is
536             * needed later when retrieving the variable names.
537             */
538
539            if ((localPtr->nameLength != nameLength)
540                    || (strcmp(localPtr->name, fieldValues[0]))
541                    || (localPtr->frameIndex != i)
542                    || !(localPtr->flags & VAR_ARGUMENT)
543                    || (localPtr->defValuePtr == NULL && fieldCount == 2)
544                    || (localPtr->defValuePtr != NULL && fieldCount != 2)) {
545                Tcl_SetObjResult(interp, Tcl_ObjPrintf(
546                        "procedure \"%s\": formal parameter %d is "
547                        "inconsistent with precompiled body", procName, i));
548                ckfree((char *) fieldValues);
549                goto procError;
550            }
551
552            /*
553             * Compare the default value if any.
554             */
555
556            if (localPtr->defValuePtr != NULL) {
557                int tmpLength;
558                char *tmpPtr = TclGetStringFromObj(localPtr->defValuePtr,
559                        &tmpLength);
560
561                if ((valueLength != tmpLength) ||
562                        strncmp(fieldValues[1], tmpPtr, (size_t) tmpLength)) {
563                    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
564                            "procedure \"%s\": formal parameter \"%s\" has "
565                            "default value inconsistent with precompiled body",
566                            procName, fieldValues[0]));
567                    ckfree((char *) fieldValues);
568                    goto procError;
569                }
570            }
571            if ((i == numArgs - 1)
572                    && (localPtr->nameLength == 4)
573                    && (localPtr->name[0] == 'a')
574                    && (strcmp(localPtr->name, "args") == 0)) {
575                localPtr->flags |= VAR_IS_ARGS;
576            }
577
578            localPtr = localPtr->nextPtr;
579        } else {
580            /*
581             * Allocate an entry in the runtime procedure frame's array of
582             * local variables for the argument.
583             */
584
585            localPtr = (CompiledLocal *) ckalloc((unsigned)
586                    (sizeof(CompiledLocal) - sizeof(localPtr->name)
587                            + nameLength + 1));
588            if (procPtr->firstLocalPtr == NULL) {
589                procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
590            } else {
591                procPtr->lastLocalPtr->nextPtr = localPtr;
592                procPtr->lastLocalPtr = localPtr;
593            }
594            localPtr->nextPtr = NULL;
595            localPtr->nameLength = nameLength;
596            localPtr->frameIndex = i;
597            localPtr->flags = VAR_ARGUMENT;
598            localPtr->resolveInfo = NULL;
599
600            if (fieldCount == 2) {
601                localPtr->defValuePtr =
602                        Tcl_NewStringObj(fieldValues[1], valueLength);
603                Tcl_IncrRefCount(localPtr->defValuePtr);
604            } else {
605                localPtr->defValuePtr = NULL;
606            }
607            strcpy(localPtr->name, fieldValues[0]);
608            if ((i == numArgs - 1)
609                    && (localPtr->nameLength == 4)
610                    && (localPtr->name[0] == 'a')
611                    && (strcmp(localPtr->name, "args") == 0)) {
612                localPtr->flags |= VAR_IS_ARGS;
613            }
614        }
615
616        ckfree((char *) fieldValues);
617    }
618
619    *procPtrPtr = procPtr;
620    ckfree((char *) argArray);
621    return TCL_OK;
622
623  procError:
624    if (precompiled) {
625        procPtr->refCount--;
626    } else {
627        Tcl_DecrRefCount(bodyPtr);
628        while (procPtr->firstLocalPtr != NULL) {
629            localPtr = procPtr->firstLocalPtr;
630            procPtr->firstLocalPtr = localPtr->nextPtr;
631
632            defPtr = localPtr->defValuePtr;
633            if (defPtr != NULL) {
634                Tcl_DecrRefCount(defPtr);
635            }
636
637            ckfree((char *) localPtr);
638        }
639        ckfree((char *) procPtr);
640    }
641    if (argArray != NULL) {
642        ckfree((char *) argArray);
643    }
644    return TCL_ERROR;
645}
646
647/*
648 *----------------------------------------------------------------------
649 *
650 * TclGetFrame --
651 *
652 *      Given a description of a procedure frame, such as the first argument
653 *      to an "uplevel" or "upvar" command, locate the call frame for the
654 *      appropriate level of procedure.
655 *
656 * Results:
657 *      The return value is -1 if an error occurred in finding the frame (in
658 *      this case an error message is left in the interp's result). 1 is
659 *      returned if string was either a number or a number preceded by "#" and
660 *      it specified a valid frame. 0 is returned if string isn't one of the
661 *      two things above (in this case, the lookup acts as if string were
662 *      "1"). The variable pointed to by framePtrPtr is filled in with the
663 *      address of the desired frame (unless an error occurs, in which case it
664 *      isn't modified).
665 *
666 * Side effects:
667 *      None.
668 *
669 *----------------------------------------------------------------------
670 */
671
672int
673TclGetFrame(
674    Tcl_Interp *interp,         /* Interpreter in which to find frame. */
675    CONST char *name,           /* String describing frame. */
676    CallFrame **framePtrPtr)    /* Store pointer to frame here (or NULL if
677                                 * global frame indicated). */
678{
679    register Interp *iPtr = (Interp *) interp;
680    int curLevel, level, result;
681    CallFrame *framePtr;
682
683    /*
684     * Parse string to figure out which level number to go to.
685     */
686
687    result = 1;
688    curLevel = iPtr->varFramePtr->level;
689    if (*name== '#') {
690        if (Tcl_GetInt(interp, name+1, &level) != TCL_OK || level < 0) {
691            goto levelError;
692        }
693    } else if (isdigit(UCHAR(*name))) { /* INTL: digit */
694        if (Tcl_GetInt(interp, name, &level) != TCL_OK) {
695            goto levelError;
696        }
697        level = curLevel - level;
698    } else {
699        level = curLevel - 1;
700        result = 0;
701    }
702
703    /*
704     * Figure out which frame to use, and return it to the caller.
705     */
706
707    for (framePtr = iPtr->varFramePtr; framePtr != NULL;
708            framePtr = framePtr->callerVarPtr) {
709        if (framePtr->level == level) {
710            break;
711        }
712    }
713    if (framePtr == NULL) {
714        goto levelError;
715    }
716
717    *framePtrPtr = framePtr;
718    return result;
719
720  levelError:
721    Tcl_ResetResult(interp);
722    Tcl_AppendResult(interp, "bad level \"", name, "\"", NULL);
723    return -1;
724}
725
726/*
727 *----------------------------------------------------------------------
728 *
729 * TclObjGetFrame --
730 *
731 *      Given a description of a procedure frame, such as the first argument
732 *      to an "uplevel" or "upvar" command, locate the call frame for the
733 *      appropriate level of procedure.
734 *
735 * Results:
736 *      The return value is -1 if an error occurred in finding the frame (in
737 *      this case an error message is left in the interp's result). 1 is
738 *      returned if objPtr was either a number or a number preceded by "#" and
739 *      it specified a valid frame. 0 is returned if objPtr isn't one of the
740 *      two things above (in this case, the lookup acts as if objPtr were
741 *      "1"). The variable pointed to by framePtrPtr is filled in with the
742 *      address of the desired frame (unless an error occurs, in which case it
743 *      isn't modified).
744 *
745 * Side effects:
746 *      None.
747 *
748 *----------------------------------------------------------------------
749 */
750
751int
752TclObjGetFrame(
753    Tcl_Interp *interp,         /* Interpreter in which to find frame. */
754    Tcl_Obj *objPtr,            /* Object describing frame. */
755    CallFrame **framePtrPtr)    /* Store pointer to frame here (or NULL if
756                                 * global frame indicated). */
757{
758    register Interp *iPtr = (Interp *) interp;
759    int curLevel, level, result;
760    CallFrame *framePtr;
761    CONST char *name = TclGetString(objPtr);
762
763    /*
764     * Parse object to figure out which level number to go to.
765     */
766
767    result = 1;
768    curLevel = iPtr->varFramePtr->level;
769    if (objPtr->typePtr == &levelReferenceType) {
770        if (PTR2INT(objPtr->internalRep.twoPtrValue.ptr1)) {
771            level = curLevel - PTR2INT(objPtr->internalRep.twoPtrValue.ptr2);
772        } else {
773            level = PTR2INT(objPtr->internalRep.twoPtrValue.ptr2);
774        }
775        if (level < 0) {
776            goto levelError;
777        }
778        /* TODO: Consider skipping the typePtr checks */
779    } else if (objPtr->typePtr == &tclIntType
780#ifndef NO_WIDE_TYPE
781            || objPtr->typePtr == &tclWideIntType
782#endif
783            ) {
784        if (TclGetIntFromObj(NULL, objPtr, &level) != TCL_OK || level < 0) {
785            goto levelError;
786        }
787        level = curLevel - level;
788    } else if (*name == '#') {
789        if (Tcl_GetInt(interp, name+1, &level) != TCL_OK || level < 0) {
790            goto levelError;
791        }
792
793        /*
794         * Cache for future reference.
795         *
796         * TODO: Use the new ptrAndLongRep intrep
797         */
798
799        TclFreeIntRep(objPtr);
800        objPtr->typePtr = &levelReferenceType;
801        objPtr->internalRep.twoPtrValue.ptr1 = (void *) 0;
802        objPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(level);
803    } else if (isdigit(UCHAR(*name))) { /* INTL: digit */
804        if (Tcl_GetInt(interp, name, &level) != TCL_OK) {
805            return -1;
806        }
807
808        /*
809         * Cache for future reference.
810         *
811         * TODO: Use the new ptrAndLongRep intrep
812         */
813
814        TclFreeIntRep(objPtr);
815        objPtr->typePtr = &levelReferenceType;
816        objPtr->internalRep.twoPtrValue.ptr1 = (void *) 1;
817        objPtr->internalRep.twoPtrValue.ptr2 = INT2PTR(level);
818        level = curLevel - level;
819    } else {
820        /*
821         * Don't cache as the object *isn't* a level reference.
822         */
823
824        level = curLevel - 1;
825        result = 0;
826    }
827
828    /*
829     * Figure out which frame to use, and return it to the caller.
830     */
831
832    for (framePtr = iPtr->varFramePtr; framePtr != NULL;
833            framePtr = framePtr->callerVarPtr) {
834        if (framePtr->level == level) {
835            break;
836        }
837    }
838    if (framePtr == NULL) {
839        goto levelError;
840    }
841    *framePtrPtr = framePtr;
842    return result;
843
844  levelError:
845    Tcl_ResetResult(interp);
846    Tcl_AppendResult(interp, "bad level \"", name, "\"", NULL);
847    return -1;
848}
849
850/*
851 *----------------------------------------------------------------------
852 *
853 * Tcl_UplevelObjCmd --
854 *
855 *      This object function is invoked to process the "uplevel" Tcl command.
856 *      See the user documentation for details on what it does.
857 *
858 * Results:
859 *      A standard Tcl object result value.
860 *
861 * Side effects:
862 *      See the user documentation.
863 *
864 *----------------------------------------------------------------------
865 */
866
867        /* ARGSUSED */
868int
869Tcl_UplevelObjCmd(
870    ClientData dummy,           /* Not used. */
871    Tcl_Interp *interp,         /* Current interpreter. */
872    int objc,                   /* Number of arguments. */
873    Tcl_Obj *CONST objv[])      /* Argument objects. */
874{
875    register Interp *iPtr = (Interp *) interp;
876    int result;
877    CallFrame *savedVarFramePtr, *framePtr;
878
879    if (objc < 2) {
880    uplevelSyntax:
881        Tcl_WrongNumArgs(interp, 1, objv, "?level? command ?arg ...?");
882        return TCL_ERROR;
883    }
884
885    /*
886     * Find the level to use for executing the command.
887     */
888
889    result = TclObjGetFrame(interp, objv[1], &framePtr);
890    if (result == -1) {
891        return TCL_ERROR;
892    }
893    objc -= (result+1);
894    if (objc == 0) {
895        goto uplevelSyntax;
896    }
897    objv += (result+1);
898
899    /*
900     * Modify the interpreter state to execute in the given frame.
901     */
902
903    savedVarFramePtr = iPtr->varFramePtr;
904    iPtr->varFramePtr = framePtr;
905
906    /*
907     * Execute the residual arguments as a command.
908     */
909
910    if (objc == 1) {
911        result = Tcl_EvalObjEx(interp, objv[0], TCL_EVAL_DIRECT);
912    } else {
913        /*
914         * More than one argument: concatenate them together with spaces
915         * between, then evaluate the result. Tcl_EvalObjEx will delete the
916         * object when it decrements its refcount after eval'ing it.
917         */
918
919        Tcl_Obj *objPtr;
920
921        objPtr = Tcl_ConcatObj(objc, objv);
922        result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT);
923    }
924    if (result == TCL_ERROR) {
925        Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
926                "\n    (\"uplevel\" body line %d)", interp->errorLine));
927    }
928
929    /*
930     * Restore the variable frame, and return.
931     */
932
933    iPtr->varFramePtr = savedVarFramePtr;
934    return result;
935}
936
937/*
938 *----------------------------------------------------------------------
939 *
940 * TclFindProc --
941 *
942 *      Given the name of a procedure, return a pointer to the record
943 *      describing the procedure. The procedure will be looked up using the
944 *      usual rules: first in the current namespace and then in the global
945 *      namespace.
946 *
947 * Results:
948 *      NULL is returned if the name doesn't correspond to any procedure.
949 *      Otherwise, the return value is a pointer to the procedure's record. If
950 *      the name is found but refers to an imported command that points to a
951 *      "real" procedure defined in another namespace, a pointer to that
952 *      "real" procedure's structure is returned.
953 *
954 * Side effects:
955 *      None.
956 *
957 *----------------------------------------------------------------------
958 */
959
960Proc *
961TclFindProc(
962    Interp *iPtr,               /* Interpreter in which to look. */
963    CONST char *procName)       /* Name of desired procedure. */
964{
965    Tcl_Command cmd;
966    Tcl_Command origCmd;
967    Command *cmdPtr;
968
969    cmd = Tcl_FindCommand((Tcl_Interp *) iPtr, procName, NULL, /*flags*/ 0);
970    if (cmd == (Tcl_Command) NULL) {
971        return NULL;
972    }
973    cmdPtr = (Command *) cmd;
974
975    origCmd = TclGetOriginalCommand(cmd);
976    if (origCmd != NULL) {
977        cmdPtr = (Command *) origCmd;
978    }
979    if (cmdPtr->objProc != TclObjInterpProc) {
980        return NULL;
981    }
982    return (Proc *) cmdPtr->objClientData;
983}
984
985/*
986 *----------------------------------------------------------------------
987 *
988 * TclIsProc --
989 *
990 *      Tells whether a command is a Tcl procedure or not.
991 *
992 * Results:
993 *      If the given command is actually a Tcl procedure, the return value is
994 *      the address of the record describing the procedure. Otherwise the
995 *      return value is 0.
996 *
997 * Side effects:
998 *      None.
999 *
1000 *----------------------------------------------------------------------
1001 */
1002
1003Proc *
1004TclIsProc(
1005    Command *cmdPtr)            /* Command to test. */
1006{
1007    Tcl_Command origCmd;
1008
1009    origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);
1010    if (origCmd != NULL) {
1011        cmdPtr = (Command *) origCmd;
1012    }
1013    if (cmdPtr->objProc == TclObjInterpProc) {
1014        return (Proc *) cmdPtr->objClientData;
1015    }
1016    return (Proc *) 0;
1017}
1018
1019/*
1020 *----------------------------------------------------------------------
1021 *
1022 * InitArgsAndLocals --
1023 *
1024 *      This routine is invoked in order to initialize the arguments and other
1025 *      compiled locals table for a new call frame.
1026 *
1027 * Results:
1028 *      A standard Tcl result.
1029 *
1030 * Side effects:
1031 *      Allocates memory on the stack for the compiled local variables, the
1032 *      caller is responsible for freeing them. Initialises all variables. May
1033 *      invoke various name resolvers in order to determine which variables
1034 *      are being referenced at runtime.
1035 *
1036 *----------------------------------------------------------------------
1037 */
1038
1039static int
1040ProcWrongNumArgs(
1041    Tcl_Interp *interp, int skip)
1042{
1043    CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
1044    register Proc *procPtr = framePtr->procPtr;
1045    register Var *defPtr;
1046    int localCt = procPtr->numCompiledLocals, numArgs, i;
1047    Tcl_Obj **desiredObjs;
1048    const char *final = NULL;
1049   
1050    /*
1051     * Build up desired argument list for Tcl_WrongNumArgs
1052     */
1053
1054    numArgs = framePtr->procPtr->numArgs;
1055    desiredObjs = (Tcl_Obj **) TclStackAlloc(interp,
1056            (int) sizeof(Tcl_Obj *) * (numArgs+1));
1057
1058#ifdef AVOID_HACKS_FOR_ITCL
1059    desiredObjs[0] = framePtr->objv[skip-1];
1060#else
1061    desiredObjs[0] = ((framePtr->isProcCallFrame & FRAME_IS_LAMBDA)
1062            ? framePtr->objv[skip-1]
1063            : Tcl_NewListObj(skip, framePtr->objv));
1064#endif /* AVOID_HACKS_FOR_ITCL */
1065    Tcl_IncrRefCount(desiredObjs[0]);
1066
1067    defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt);
1068    for (i=1 ; i<=numArgs ; i++, defPtr++) {
1069        Tcl_Obj *argObj;
1070        Tcl_Obj *namePtr = localName(framePtr, i-1);
1071
1072        if (defPtr->value.objPtr != NULL) {
1073            TclNewObj(argObj);
1074            Tcl_AppendStringsToObj(argObj, "?", TclGetString(namePtr), "?", NULL);
1075        } else if (defPtr->flags & VAR_IS_ARGS) {
1076            numArgs--;
1077            final = "...";
1078            break;
1079        } else {
1080            argObj = namePtr;
1081            Tcl_IncrRefCount(namePtr);
1082        }
1083        desiredObjs[i] = argObj;
1084    }
1085
1086    Tcl_ResetResult(interp);
1087    Tcl_WrongNumArgs(interp, numArgs+1, desiredObjs, final);
1088
1089    for (i=0 ; i<=numArgs ; i++) {
1090        Tcl_DecrRefCount(desiredObjs[i]);
1091    }
1092    TclStackFree(interp, desiredObjs);
1093    return TCL_ERROR;
1094}
1095
1096/*
1097 *----------------------------------------------------------------------
1098 *
1099 * TclInitCompiledLocals --
1100 *
1101 *      This routine is invoked in order to initialize the compiled locals
1102 *      table for a new call frame.
1103 *
1104 *      DEPRECATED: functionality has been inlined elsewhere; this function
1105 *      remains to insure binary compatibility with Itcl.
1106 *
1107
1108 * Results:
1109 *      None.
1110 *
1111 * Side effects:
1112 *      May invoke various name resolvers in order to determine which
1113 *      variables are being referenced at runtime.
1114 *
1115 *----------------------------------------------------------------------
1116 */
1117void
1118TclInitCompiledLocals(
1119    Tcl_Interp *interp,         /* Current interpreter. */
1120    CallFrame *framePtr,        /* Call frame to initialize. */
1121    Namespace *nsPtr)           /* Pointer to current namespace. */
1122{
1123    Var *varPtr = framePtr->compiledLocals;
1124    Tcl_Obj *bodyPtr;
1125    ByteCode *codePtr;
1126
1127    bodyPtr = framePtr->procPtr->bodyPtr;
1128    if (bodyPtr->typePtr != &tclByteCodeType) {
1129        Tcl_Panic("body object for proc attached to frame is not a byte code type");
1130    }
1131    codePtr = bodyPtr->internalRep.otherValuePtr;
1132
1133    if (framePtr->numCompiledLocals) {
1134        if (!codePtr->localCachePtr) {
1135            InitLocalCache(framePtr->procPtr) ;
1136        }
1137        framePtr->localCachePtr = codePtr->localCachePtr;
1138        framePtr->localCachePtr->refCount++;
1139    }   
1140
1141    InitResolvedLocals(interp, codePtr, varPtr, nsPtr);
1142}
1143
1144/*
1145 *----------------------------------------------------------------------
1146 *
1147 * InitResolvedLocals --
1148 *
1149 *      This routine is invoked in order to initialize the compiled locals
1150 *      table for a new call frame.
1151 *
1152 * Results:
1153 *      None.
1154 *
1155 * Side effects:
1156 *      May invoke various name resolvers in order to determine which
1157 *      variables are being referenced at runtime.
1158 *
1159 *----------------------------------------------------------------------
1160 */
1161
1162static void
1163InitResolvedLocals(
1164    Tcl_Interp *interp,         /* Current interpreter. */
1165    ByteCode *codePtr,
1166    Var *varPtr,
1167    Namespace *nsPtr)           /* Pointer to current namespace. */
1168{
1169    Interp *iPtr = (Interp *) interp;
1170    int haveResolvers = (nsPtr->compiledVarResProc || iPtr->resolverPtr);
1171    CompiledLocal *firstLocalPtr, *localPtr;
1172    int varNum;
1173    Tcl_ResolvedVarInfo *resVarInfo;
1174
1175    /*
1176     * Find the localPtr corresponding to varPtr
1177     */
1178
1179    varNum = varPtr - iPtr->framePtr->compiledLocals;
1180    localPtr = iPtr->framePtr->procPtr->firstLocalPtr;
1181    while (varNum--) {
1182        localPtr = localPtr->nextPtr;
1183    }
1184
1185    if (!(haveResolvers && (codePtr->flags & TCL_BYTECODE_RESOLVE_VARS))) {
1186        /*
1187         * Initialize the array of local variables stored in the call frame.
1188         * Some variables may have special resolution rules. In that case, we
1189         * call their "resolver" procs to get our hands on the variable, and
1190         * we make the compiled local a link to the real variable.
1191         */
1192
1193    doInitResolvedLocals:
1194        for (; localPtr != NULL; varPtr++, localPtr = localPtr->nextPtr) {
1195            varPtr->flags = 0;
1196            varPtr->value.objPtr = NULL;
1197           
1198            /*
1199             * Now invoke the resolvers to determine the exact variables
1200             * that should be used.
1201             */
1202           
1203            resVarInfo = localPtr->resolveInfo;
1204            if (resVarInfo && resVarInfo->fetchProc) {
1205                Var *resolvedVarPtr = (Var *)
1206                    (*resVarInfo->fetchProc)(interp, resVarInfo);
1207                if (resolvedVarPtr) {
1208                    if (TclIsVarInHash(resolvedVarPtr)) {
1209                        VarHashRefCount(resolvedVarPtr)++;
1210                    }
1211                    varPtr->flags = VAR_LINK;
1212                    varPtr->value.linkPtr = resolvedVarPtr;
1213                }
1214            }
1215        }
1216        return;
1217    }
1218
1219    /*
1220     * This is the first run after a recompile, or else the resolver epoch
1221     * has changed: update the resolver cache.
1222     */
1223   
1224    firstLocalPtr = localPtr;
1225    for (; localPtr != NULL; localPtr = localPtr->nextPtr) {
1226        if (localPtr->resolveInfo) {
1227            if (localPtr->resolveInfo->deleteProc) {
1228                localPtr->resolveInfo->deleteProc(localPtr->resolveInfo);
1229            } else {
1230                ckfree((char *) localPtr->resolveInfo);
1231            }
1232            localPtr->resolveInfo = NULL;
1233        }
1234        localPtr->flags &= ~VAR_RESOLVED;
1235       
1236        if (haveResolvers &&
1237                !(localPtr->flags & (VAR_ARGUMENT|VAR_TEMPORARY))) {
1238            ResolverScheme *resPtr = iPtr->resolverPtr;
1239            Tcl_ResolvedVarInfo *vinfo;
1240            int result;
1241           
1242            if (nsPtr->compiledVarResProc) {
1243                result = (*nsPtr->compiledVarResProc)(nsPtr->interp,
1244                        localPtr->name, localPtr->nameLength,
1245                        (Tcl_Namespace *) nsPtr, &vinfo);
1246            } else {
1247                result = TCL_CONTINUE;
1248            }
1249
1250            while ((result == TCL_CONTINUE) && resPtr) {
1251                if (resPtr->compiledVarResProc) {
1252                    result = (*resPtr->compiledVarResProc)(nsPtr->interp,
1253                            localPtr->name, localPtr->nameLength,
1254                            (Tcl_Namespace *) nsPtr, &vinfo);
1255                }
1256                resPtr = resPtr->nextPtr;
1257            }
1258            if (result == TCL_OK) {
1259                localPtr->resolveInfo = vinfo;
1260                localPtr->flags |= VAR_RESOLVED;
1261            }
1262        }
1263    }
1264    localPtr = firstLocalPtr;
1265    codePtr->flags &= ~TCL_BYTECODE_RESOLVE_VARS;
1266    goto doInitResolvedLocals;
1267}
1268
1269void
1270TclFreeLocalCache(
1271    Tcl_Interp *interp,
1272    LocalCache *localCachePtr)
1273{
1274    int i;
1275    Tcl_Obj **namePtrPtr = &localCachePtr->varName0;
1276
1277    for (i = 0; i < localCachePtr->numVars; i++, namePtrPtr++) {
1278        Tcl_Obj *objPtr = *namePtrPtr;
1279        /*
1280         * Note that this can be called with interp==NULL, on interp
1281         * deletion. In that case, the literal table and objects go away
1282         * on their own.
1283         */
1284        if (objPtr) {
1285            if (interp) {
1286                TclReleaseLiteral(interp, objPtr);
1287            } else {
1288                Tcl_DecrRefCount(objPtr);
1289            }
1290        }
1291    }
1292    ckfree((char *) localCachePtr);
1293}
1294
1295static void
1296InitLocalCache(Proc *procPtr)
1297{
1298    Interp *iPtr = procPtr->iPtr;
1299    ByteCode *codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
1300    int localCt = procPtr->numCompiledLocals;
1301    int numArgs = procPtr->numArgs, i = 0;
1302
1303    Tcl_Obj **namePtr;
1304    Var *varPtr;
1305    LocalCache *localCachePtr;
1306    CompiledLocal *localPtr;
1307    int new;
1308
1309    /*
1310     * Cache the names and initial values of local variables; store the
1311     * cache in both the framePtr for this execution and in the codePtr
1312     * for future calls.
1313     */
1314
1315    localCachePtr = (LocalCache *) ckalloc(sizeof(LocalCache)
1316            + (localCt-1)*sizeof(Tcl_Obj *)
1317            + numArgs*sizeof(Var));
1318
1319    namePtr = &localCachePtr->varName0;
1320    varPtr = (Var *) (namePtr + localCt);
1321    localPtr = procPtr->firstLocalPtr;
1322    while (localPtr) {
1323        if (TclIsVarTemporary(localPtr)) {
1324            *namePtr = NULL;
1325        } else {
1326            *namePtr = TclCreateLiteral(iPtr, localPtr->name,
1327                    localPtr->nameLength, /* hash */ (unsigned int) -1,
1328                    &new, /* nsPtr */ NULL, 0, NULL);
1329            Tcl_IncrRefCount(*namePtr);
1330        }
1331
1332        if (i < numArgs) {
1333            varPtr->flags = (localPtr->flags & VAR_IS_ARGS);
1334            varPtr->value.objPtr = localPtr->defValuePtr;
1335            varPtr++;
1336            i++;
1337        }
1338        namePtr++;
1339        localPtr=localPtr->nextPtr;
1340    }
1341    codePtr->localCachePtr = localCachePtr;
1342    localCachePtr->refCount = 1;
1343    localCachePtr->numVars  = localCt;
1344}
1345
1346static int
1347InitArgsAndLocals(
1348    register Tcl_Interp *interp,/* Interpreter in which procedure was
1349                                 * invoked. */
1350    Tcl_Obj *procNameObj,       /* Procedure name for error reporting. */
1351    int skip)                   /* Number of initial arguments to be skipped,
1352                                 * i.e., words in the "command name". */
1353{
1354    CallFrame *framePtr = ((Interp *)interp)->varFramePtr;
1355    register Proc *procPtr = framePtr->procPtr;
1356    ByteCode *codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
1357    register Var *varPtr, *defPtr;
1358    int localCt = procPtr->numCompiledLocals, numArgs, argCt, i, imax;
1359    Tcl_Obj *const *argObjs;
1360       
1361    /*
1362     * Make sure that the local cache of variable names and initial values has
1363     * been initialised properly .
1364     */
1365
1366    if (localCt) {
1367        if (!codePtr->localCachePtr) {
1368            InitLocalCache(procPtr) ;
1369        }
1370        framePtr->localCachePtr = codePtr->localCachePtr;
1371        framePtr->localCachePtr->refCount++;
1372        defPtr = (Var *) (&framePtr->localCachePtr->varName0 + localCt);
1373    } else {
1374        defPtr = NULL;
1375    }
1376   
1377    /*
1378     * Create the "compiledLocals" array. Make sure it is large enough to hold
1379     * all the procedure's compiled local variables, including its formal
1380     * parameters.
1381     */
1382
1383    varPtr = (Var*) TclStackAlloc(interp, (int)(localCt*sizeof(Var)));
1384    framePtr->compiledLocals = varPtr;
1385    framePtr->numCompiledLocals = localCt;
1386
1387    /*
1388     * Match and assign the call's actual parameters to the procedure's formal
1389     * arguments. The formal arguments are described by the first numArgs
1390     * entries in both the Proc structure's local variable list and the call
1391     * frame's local variable array.
1392     */
1393
1394    numArgs = procPtr->numArgs;
1395    argCt = framePtr->objc - skip;      /* Set it to the number of args to the
1396                                         * procedure. */
1397    argObjs = framePtr->objv + skip;
1398    if (numArgs == 0) {
1399        if (argCt) {
1400            goto incorrectArgs;
1401        } else {
1402            goto correctArgs;
1403        }
1404    }
1405    imax = ((argCt < numArgs-1) ? argCt : numArgs-1);
1406    for (i = 0; i < imax; i++, varPtr++, defPtr++) {
1407        /*
1408         * "Normal" arguments; last formal is special, depends on it being
1409         * 'args'.
1410         */
1411
1412        Tcl_Obj *objPtr = argObjs[i];
1413
1414        varPtr->flags = 0;
1415        varPtr->value.objPtr = objPtr;
1416        Tcl_IncrRefCount(objPtr);       /* Local var is a reference. */
1417    }
1418    for (; i < numArgs-1; i++, varPtr++, defPtr++) {
1419        /*
1420         * This loop is entered if argCt < (numArgs-1). Set default values;
1421         * last formal is special.
1422         */
1423
1424        Tcl_Obj *objPtr = defPtr->value.objPtr;
1425
1426        if (objPtr) {
1427            varPtr->flags = 0;
1428            varPtr->value.objPtr = objPtr;
1429            Tcl_IncrRefCount(objPtr);   /* Local var reference. */
1430        } else {
1431            goto incorrectArgs;
1432        }
1433    }
1434
1435    /*
1436     * When we get here, the last formal argument remains to be defined:
1437     * defPtr and varPtr point to the last argument to be initialized.
1438     */
1439
1440
1441    varPtr->flags = 0;
1442    if (defPtr->flags & VAR_IS_ARGS) {
1443        Tcl_Obj *listPtr = Tcl_NewListObj(argCt-i, argObjs+i);
1444
1445        varPtr->value.objPtr = listPtr;
1446        Tcl_IncrRefCount(listPtr);      /* Local var is a reference. */
1447    } else if (argCt == numArgs) {
1448        Tcl_Obj *objPtr = argObjs[i];
1449
1450        varPtr->value.objPtr = objPtr;
1451        Tcl_IncrRefCount(objPtr);       /* Local var is a reference. */
1452    } else if ((argCt < numArgs) && (defPtr->value.objPtr != NULL)) {
1453        Tcl_Obj *objPtr = defPtr->value.objPtr;
1454
1455        varPtr->value.objPtr = objPtr;
1456        Tcl_IncrRefCount(objPtr);       /* Local var is a reference. */
1457    } else {
1458        goto incorrectArgs;
1459    }
1460    varPtr++;
1461
1462    /*
1463     * Initialise and resolve the remaining compiledLocals. In the absence of
1464     * resolvers, they are undefined local vars: (flags=0, value=NULL).
1465     */
1466
1467  correctArgs:
1468    if (numArgs < localCt) {
1469        if (!framePtr->nsPtr->compiledVarResProc && !((Interp *)interp)->resolverPtr) {
1470            memset(varPtr, 0, (localCt - numArgs)*sizeof(Var));
1471        } else {
1472            InitResolvedLocals(interp, codePtr, varPtr, framePtr->nsPtr);
1473        }
1474    }
1475
1476    return TCL_OK;
1477
1478
1479    incorrectArgs:
1480    /*
1481     * Initialise all compiled locals to avoid problems at DeleteLocalVars.
1482     */
1483
1484    memset(varPtr, 0, ((framePtr->compiledLocals + localCt)-varPtr)*sizeof(Var));
1485    return ProcWrongNumArgs(interp, skip);
1486}
1487
1488/*
1489 *----------------------------------------------------------------------
1490 *
1491 * PushProcCallFrame --
1492 *
1493 *      Compiles a proc body if necessary, then pushes a CallFrame suitable
1494 *      for executing it.
1495 *
1496 * Results:
1497 *      A standard Tcl object result value.
1498 *
1499 * Side effects:
1500 *      The proc's body may be recompiled. A CallFrame is pushed, it will have
1501 *      to be popped by the caller.
1502 *
1503 *----------------------------------------------------------------------
1504 */
1505
1506static int
1507PushProcCallFrame(
1508    ClientData clientData,      /* Record describing procedure to be
1509                                 * interpreted. */
1510    register Tcl_Interp *interp,/* Interpreter in which procedure was
1511                                 * invoked. */
1512    int objc,                   /* Count of number of arguments to this
1513                                 * procedure. */
1514    Tcl_Obj *CONST objv[],      /* Argument value objects. */
1515    int isLambda)               /* 1 if this is a call by ApplyObjCmd: it
1516                                 * needs special rules for error msg */
1517{
1518    Proc *procPtr = (Proc *) clientData;
1519    Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
1520    CallFrame *framePtr, **framePtrPtr;
1521    int result;
1522    ByteCode *codePtr;
1523
1524    /*
1525     * If necessary (i.e. if we haven't got a suitable compilation already
1526     * cached) compile the procedure's body. The compiler will allocate frame
1527     * slots for the procedure's non-argument local variables. Note that
1528     * compiling the body might increase procPtr->numCompiledLocals if new
1529     * local variables are found while compiling.
1530     */
1531
1532    if (procPtr->bodyPtr->typePtr == &tclByteCodeType) {
1533        Interp *iPtr = (Interp *) interp;
1534
1535        /*
1536         * When we've got bytecode, this is the check for validity. That is,
1537         * the bytecode must be for the right interpreter (no cross-leaks!),
1538         * the code must be from the current epoch (so subcommand compilation
1539         * is up-to-date), the namespace must match (so variable handling
1540         * is right) and the resolverEpoch must match (so that new shadowed
1541         * commands and/or resolver changes are considered).
1542         */
1543
1544        codePtr = procPtr->bodyPtr->internalRep.otherValuePtr;
1545        if (((Interp *) *codePtr->interpHandle != iPtr)
1546                || (codePtr->compileEpoch != iPtr->compileEpoch)
1547                || (codePtr->nsPtr != nsPtr)
1548                || (codePtr->nsEpoch != nsPtr->resolverEpoch)) {
1549            goto doCompilation;
1550        }
1551    } else {
1552    doCompilation:
1553        result = ProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr,
1554                (isLambda ? "body of lambda term" : "body of proc"),
1555                TclGetString(objv[isLambda]), &procPtr);
1556        if (result != TCL_OK) {
1557            return result;
1558        }
1559    }
1560
1561    /*
1562     * Set up and push a new call frame for the new procedure invocation.
1563     * This call frame will execute in the proc's namespace, which might be
1564     * different than the current namespace. The proc's namespace is that of
1565     * its command, which can change if the command is renamed from one
1566     * namespace to another.
1567     */
1568
1569    framePtrPtr = &framePtr;
1570    result = TclPushStackFrame(interp, (Tcl_CallFrame **) framePtrPtr,
1571            (Tcl_Namespace *) nsPtr,
1572            (isLambda? (FRAME_IS_PROC|FRAME_IS_LAMBDA) : FRAME_IS_PROC));
1573    if (result != TCL_OK) {
1574        return result;
1575    }
1576
1577    framePtr->objc = objc;
1578    framePtr->objv = objv;
1579    framePtr->procPtr = procPtr;
1580
1581    return TCL_OK;
1582}
1583
1584/*
1585 *----------------------------------------------------------------------
1586 *
1587 * TclObjInterpProc --
1588 *
1589 *      When a Tcl procedure gets invoked during bytecode evaluation, this
1590 *      object-based routine gets invoked to interpret the procedure.
1591 *
1592 * Results:
1593 *      A standard Tcl object result value.
1594 *
1595 * Side effects:
1596 *      Depends on the commands in the procedure.
1597 *
1598 *----------------------------------------------------------------------
1599 */
1600
1601int
1602TclObjInterpProc(
1603    ClientData clientData,      /* Record describing procedure to be
1604                                 * interpreted. */
1605    register Tcl_Interp *interp,/* Interpreter in which procedure was
1606                                 * invoked. */
1607    int objc,                   /* Count of number of arguments to this
1608                                 * procedure. */
1609    Tcl_Obj *CONST objv[])      /* Argument value objects. */
1610{
1611    int result;
1612
1613    result = PushProcCallFrame(clientData, interp, objc, objv, /*isLambda*/ 0);
1614    if (result == TCL_OK) {
1615        return TclObjInterpProcCore(interp, objv[0], 1, &MakeProcError);
1616    } else {
1617        return TCL_ERROR;
1618    }
1619}
1620
1621/*
1622 *----------------------------------------------------------------------
1623 *
1624 * TclObjInterpProcCore --
1625 *
1626 *      When a Tcl procedure, lambda term or anything else that works like a
1627 *      procedure gets invoked during bytecode evaluation, this object-based
1628 *      routine gets invoked to interpret the body.
1629 *
1630 * Results:
1631 *      A standard Tcl object result value.
1632 *
1633 * Side effects:
1634 *      Nearly anything; depends on the commands in the procedure body.
1635 *
1636 *----------------------------------------------------------------------
1637 */
1638
1639int
1640TclObjInterpProcCore(
1641    register Tcl_Interp *interp,/* Interpreter in which procedure was
1642                                 * invoked. */
1643    Tcl_Obj *procNameObj,       /* Procedure name for error reporting. */
1644    int skip,                   /* Number of initial arguments to be skipped,
1645                                 * i.e., words in the "command name". */
1646    ProcErrorProc errorProc)    /* How to convert results from the script into
1647                                 * results of the overall procedure. */
1648{
1649    Interp *iPtr = (Interp *) interp;
1650    register Proc *procPtr = iPtr->varFramePtr->procPtr;
1651    int result;
1652    CallFrame *freePtr;
1653
1654    result = InitArgsAndLocals(interp, procNameObj, skip);
1655    if (result != TCL_OK) {
1656        goto procDone;
1657    }
1658
1659#if defined(TCL_COMPILE_DEBUG)
1660    if (tclTraceExec >= 1) {
1661        register CallFrame *framePtr = iPtr->varFramePtr;
1662        register int i;
1663
1664        if (framePtr->isProcCallFrame & FRAME_IS_LAMBDA) {
1665            fprintf(stdout, "Calling lambda ");
1666        } else {
1667            fprintf(stdout, "Calling proc ");
1668        }
1669        for (i = 0; i < framePtr->objc; i++) {
1670            TclPrintObject(stdout, framePtr->objv[i], 15);
1671            fprintf(stdout, " ");
1672        }
1673        fprintf(stdout, "\n");
1674        fflush(stdout);
1675    }
1676#endif /*TCL_COMPILE_DEBUG*/
1677
1678    if (TCL_DTRACE_PROC_ARGS_ENABLED()) {
1679        char *a[10];
1680        int i = 0;
1681        int l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 1 : 0;
1682
1683        while (i < 10) {
1684            a[i] = (l < iPtr->varFramePtr->objc ? 
1685                    TclGetString(iPtr->varFramePtr->objv[l]) : NULL); i++; l++;
1686        }
1687        TCL_DTRACE_PROC_ARGS(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
1688                a[8], a[9]);
1689    }
1690    if (TCL_DTRACE_PROC_INFO_ENABLED() && iPtr->cmdFramePtr) {
1691        Tcl_Obj *info = TclInfoFrame(interp, iPtr->cmdFramePtr);
1692        char *a[4]; int i[2];
1693       
1694        TclDTraceInfo(info, a, i);
1695        TCL_DTRACE_PROC_INFO(a[0], a[1], a[2], a[3], i[0], i[1]);
1696        TclDecrRefCount(info);
1697    }
1698
1699    /*
1700     * Invoke the commands in the procedure's body.
1701     */
1702
1703    procPtr->refCount++;
1704    iPtr->numLevels++;
1705
1706    if (TclInterpReady(interp) == TCL_ERROR) {
1707        result = TCL_ERROR;
1708    } else {
1709        register ByteCode *codePtr =
1710                procPtr->bodyPtr->internalRep.otherValuePtr;
1711
1712        codePtr->refCount++;
1713        if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
1714            int l;
1715           
1716            l = iPtr->varFramePtr->isProcCallFrame & FRAME_IS_LAMBDA ? 2 : 1;
1717            TCL_DTRACE_PROC_ENTRY(TclGetString(procNameObj),
1718                    iPtr->varFramePtr->objc - l,
1719                    (Tcl_Obj **)(iPtr->varFramePtr->objv + l));
1720        }
1721        result = TclExecuteByteCode(interp, codePtr);
1722        if (TCL_DTRACE_PROC_RETURN_ENABLED()) {
1723            TCL_DTRACE_PROC_RETURN(TclGetString(procNameObj), result);
1724        }
1725        codePtr->refCount--;
1726        if (codePtr->refCount <= 0) {
1727            TclCleanupByteCode(codePtr);
1728        }
1729    }
1730
1731    iPtr->numLevels--;
1732    procPtr->refCount--;
1733    if (procPtr->refCount <= 0) {
1734        TclProcCleanupProc(procPtr);
1735    }
1736
1737    /*
1738     * Process the result code.
1739     */
1740
1741    switch (result) {
1742    case TCL_RETURN:
1743        /*
1744         * If it is a 'return', do the TIP#90 processing now.
1745         */
1746
1747        result = TclUpdateReturnInfo((Interp *) interp);
1748        break;
1749
1750    case TCL_CONTINUE:
1751    case TCL_BREAK:
1752        /*
1753         * It's an error to get to this point from a 'break' or 'continue', so
1754         * transform to an error now.
1755         */
1756
1757        Tcl_ResetResult(interp);
1758        Tcl_AppendResult(interp, "invoked \"",
1759                ((result == TCL_BREAK) ? "break" : "continue"),
1760                "\" outside of a loop", NULL);
1761        result = TCL_ERROR;
1762
1763        /*
1764         * Fall through to the TCL_ERROR handling code.
1765         */
1766
1767    case TCL_ERROR:
1768        /*
1769         * Now it _must_ be an error, so we need to log it as such. This means
1770         * filling out the error trace. Luckily, we just hand this off to the
1771         * function handed to us as an argument.
1772         */
1773
1774        (*errorProc)(interp, procNameObj);
1775
1776    default:
1777        /*
1778         * Process other results (OK and non-standard) by doing nothing
1779         * special, skipping directly to the code afterwards that cleans up
1780         * associated memory.
1781         *
1782         * Non-standard results are processed by passing them through quickly.
1783         * This means they all work as exceptions, unwinding the stack quickly
1784         * and neatly. Who knows how well they are handled by third-party code
1785         * though...
1786         */
1787
1788        (void) 0;               /* do nothing */
1789    }
1790
1791    if (TCL_DTRACE_PROC_RESULT_ENABLED()) {
1792        Tcl_Obj *r;
1793
1794        r = Tcl_GetObjResult(interp);
1795        TCL_DTRACE_PROC_RESULT(TclGetString(procNameObj), result,
1796                TclGetString(r), r);
1797    }
1798
1799  procDone:
1800    /*
1801     * Free the stack-allocated compiled locals and CallFrame. It is important
1802     * to pop the call frame without freeing it first: the compiledLocals
1803     * cannot be freed before the frame is popped, as the local variables must
1804     * be deleted. But the compiledLocals must be freed first, as they were
1805     * allocated later on the stack.
1806     */
1807
1808    freePtr = iPtr->framePtr;
1809    Tcl_PopCallFrame(interp);           /* Pop but do not free. */
1810    TclStackFree(interp, freePtr->compiledLocals);
1811                                        /* Free compiledLocals. */
1812    TclStackFree(interp, freePtr);      /* Free CallFrame. */
1813    return result;
1814}
1815
1816/*
1817 *----------------------------------------------------------------------
1818 *
1819 * TclProcCompileProc --
1820 *
1821 *      Called just before a procedure is executed to compile the body to byte
1822 *      codes. If the type of the body is not "byte code" or if the compile
1823 *      conditions have changed (namespace context, epoch counters, etc.) then
1824 *      the body is recompiled. Otherwise, this function does nothing.
1825 *
1826 * Results:
1827 *      None.
1828 *
1829 * Side effects:
1830 *      May change the internal representation of the body object to compiled
1831 *      code.
1832 *
1833 *----------------------------------------------------------------------
1834 */
1835
1836int
1837TclProcCompileProc(
1838    Tcl_Interp *interp,         /* Interpreter containing procedure. */
1839    Proc *procPtr,              /* Data associated with procedure. */
1840    Tcl_Obj *bodyPtr,           /* Body of proc. (Usually procPtr->bodyPtr,
1841                                 * but could be any code fragment compiled in
1842                                 * the context of this procedure.) */
1843    Namespace *nsPtr,           /* Namespace containing procedure. */
1844    CONST char *description,    /* string describing this body of code. */
1845    CONST char *procName)       /* Name of this procedure. */
1846{
1847    return ProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description,
1848            procName, NULL);
1849}
1850
1851static int
1852ProcCompileProc(
1853    Tcl_Interp *interp,         /* Interpreter containing procedure. */
1854    Proc *procPtr,              /* Data associated with procedure. */
1855    Tcl_Obj *bodyPtr,           /* Body of proc. (Usually procPtr->bodyPtr,
1856                                 * but could be any code fragment compiled in
1857                                 * the context of this procedure.) */
1858    Namespace *nsPtr,           /* Namespace containing procedure. */
1859    CONST char *description,    /* string describing this body of code. */
1860    CONST char *procName,       /* Name of this procedure. */
1861    Proc **procPtrPtr)          /* Points to storage where a replacement
1862                                 * (Proc *) value may be written. */
1863{
1864    Interp *iPtr = (Interp *) interp;
1865    int i;
1866    Tcl_CallFrame *framePtr;
1867    Proc *saveProcPtr;
1868    ByteCode *codePtr = bodyPtr->internalRep.otherValuePtr;
1869    CompiledLocal *localPtr;
1870
1871    /*
1872     * If necessary, compile the procedure's body. The compiler will allocate
1873     * frame slots for the procedure's non-argument local variables. If the
1874     * ByteCode already exists, make sure it hasn't been invalidated by
1875     * someone redefining a core command (this might make the compiled code
1876     * wrong). Also, if the code was compiled in/for a different interpreter,
1877     * we recompile it. Note that compiling the body might increase
1878     * procPtr->numCompiledLocals if new local variables are found while
1879     * compiling.
1880     *
1881     * Precompiled procedure bodies, however, are immutable and therefore they
1882     * are not recompiled, even if things have changed.
1883     */
1884
1885    if (bodyPtr->typePtr == &tclByteCodeType) {
1886        if (((Interp *) *codePtr->interpHandle == iPtr)
1887                && (codePtr->compileEpoch == iPtr->compileEpoch)
1888                && (codePtr->nsPtr == nsPtr)
1889                && (codePtr->nsEpoch == nsPtr->resolverEpoch)) {
1890            return TCL_OK;
1891        } else {
1892            if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
1893                if ((Interp *) *codePtr->interpHandle != iPtr) {
1894                    Tcl_AppendResult(interp,
1895                            "a precompiled script jumped interps", NULL);
1896                    return TCL_ERROR;
1897                }
1898                codePtr->compileEpoch = iPtr->compileEpoch;
1899                codePtr->nsPtr = nsPtr;
1900            } else {
1901                bodyPtr->typePtr->freeIntRepProc(bodyPtr);
1902                bodyPtr->typePtr = NULL;
1903            }
1904        }
1905    }
1906    if (bodyPtr->typePtr != &tclByteCodeType) {
1907        Tcl_HashEntry *hePtr;
1908
1909#ifdef TCL_COMPILE_DEBUG
1910        if (tclTraceCompile >= 1) {
1911            /*
1912             * Display a line summarizing the top level command we are about
1913             * to compile.
1914             */
1915
1916            Tcl_Obj *message;
1917
1918            TclNewLiteralStringObj(message, "Compiling ");
1919            Tcl_IncrRefCount(message);
1920            Tcl_AppendStringsToObj(message, description, " \"", NULL);
1921            Tcl_AppendLimitedToObj(message, procName, -1, 50, NULL);
1922            fprintf(stdout, "%s\"\n", TclGetString(message));
1923            Tcl_DecrRefCount(message);
1924        }
1925#endif
1926
1927        /*
1928         * Plug the current procPtr into the interpreter and coerce the code
1929         * body to byte codes. The interpreter needs to know which proc it's
1930         * compiling so that it can access its list of compiled locals.
1931         *
1932         * TRICKY NOTE: Be careful to push a call frame with the proper
1933         *   namespace context, so that the byte codes are compiled in the
1934         *   appropriate class context.
1935         */
1936
1937        saveProcPtr = iPtr->compiledProcPtr;
1938
1939        if (procPtrPtr != NULL && procPtr->refCount > 1) {
1940            Tcl_Command token;
1941            Tcl_CmdInfo info;
1942            Proc *newProc = (Proc *) ckalloc(sizeof(Proc));
1943
1944            newProc->iPtr = procPtr->iPtr;
1945            newProc->refCount = 1;
1946            newProc->cmdPtr = procPtr->cmdPtr;
1947            token = (Tcl_Command) newProc->cmdPtr;
1948            newProc->bodyPtr = Tcl_DuplicateObj(bodyPtr);
1949            bodyPtr = newProc->bodyPtr;
1950            Tcl_IncrRefCount(bodyPtr);
1951            newProc->numArgs = procPtr->numArgs;
1952
1953            newProc->numCompiledLocals = newProc->numArgs;
1954            newProc->firstLocalPtr = NULL;
1955            newProc->lastLocalPtr = NULL;
1956            localPtr = procPtr->firstLocalPtr;
1957            for (i=0; i<newProc->numArgs; i++, localPtr=localPtr->nextPtr) {
1958                CompiledLocal *copy = (CompiledLocal *) ckalloc((unsigned)
1959                        (sizeof(CompiledLocal) - sizeof(localPtr->name)
1960                        + localPtr->nameLength + 1));
1961
1962                if (newProc->firstLocalPtr == NULL) {
1963                    newProc->firstLocalPtr = newProc->lastLocalPtr = copy;
1964                } else {
1965                    newProc->lastLocalPtr->nextPtr = copy;
1966                    newProc->lastLocalPtr = copy;
1967                }
1968                copy->nextPtr = NULL;
1969                copy->nameLength = localPtr->nameLength;
1970                copy->frameIndex = localPtr->frameIndex;
1971                copy->flags = localPtr->flags;
1972                copy->defValuePtr = localPtr->defValuePtr;
1973                if (copy->defValuePtr) {
1974                    Tcl_IncrRefCount(copy->defValuePtr);
1975                }
1976                copy->resolveInfo = localPtr->resolveInfo;
1977                strcpy(copy->name, localPtr->name);
1978            }
1979
1980            /*
1981             * Reset the ClientData
1982             */
1983
1984            Tcl_GetCommandInfoFromToken(token, &info);
1985            if (info.objClientData == (ClientData) procPtr) {
1986                info.objClientData = (ClientData) newProc;
1987            }
1988            if (info.clientData == (ClientData) procPtr) {
1989                info.clientData = (ClientData) newProc;
1990            }
1991            if (info.deleteData == (ClientData) procPtr) {
1992                info.deleteData = (ClientData) newProc;
1993            }
1994            Tcl_SetCommandInfoFromToken(token, &info);
1995
1996            procPtr->refCount--;
1997            *procPtrPtr = procPtr = newProc;
1998        }
1999        iPtr->compiledProcPtr = procPtr;
2000
2001        (void) TclPushStackFrame(interp, &framePtr,
2002                (Tcl_Namespace *) nsPtr, /* isProcCallFrame */ 0);
2003
2004        /*
2005         * TIP #280: We get the invoking context from the cmdFrame which
2006         * was saved by 'Tcl_ProcObjCmd' (using linePBodyPtr).
2007         */
2008
2009        hePtr = Tcl_FindHashEntry(iPtr->linePBodyPtr, (char *) procPtr);
2010
2011        /*
2012         * Constructed saved frame has body as word 0. See Tcl_ProcObjCmd.
2013         */
2014
2015        iPtr->invokeWord = 0;
2016        iPtr->invokeCmdFramePtr =
2017                (hePtr ? (CmdFrame *) Tcl_GetHashValue(hePtr) : NULL);
2018        (void) tclByteCodeType.setFromAnyProc(interp, bodyPtr);
2019        iPtr->invokeCmdFramePtr = NULL;
2020        TclPopStackFrame(interp);
2021        iPtr->compiledProcPtr = saveProcPtr;
2022    } else if (codePtr->nsEpoch != nsPtr->resolverEpoch) {
2023        /*
2024         * The resolver epoch has changed, but we only need to invalidate the
2025         * resolver cache.
2026         */
2027
2028        codePtr->nsEpoch = nsPtr->resolverEpoch;
2029        codePtr->flags |= TCL_BYTECODE_RESOLVE_VARS;
2030    }
2031    return TCL_OK;
2032}
2033
2034/*
2035 *----------------------------------------------------------------------
2036 *
2037 * MakeProcError --
2038 *
2039 *      Function called by TclObjInterpProc to create the stack information
2040 *      upon an error from a procedure.
2041 *
2042 * Results:
2043 *      The interpreter's error info trace is set to a value that supplements
2044 *      the error code.
2045 *
2046 * Side effects:
2047 *      none.
2048 *
2049 *----------------------------------------------------------------------
2050 */
2051
2052static void
2053MakeProcError(
2054    Tcl_Interp *interp,         /* The interpreter in which the procedure was
2055                                 * called. */
2056    Tcl_Obj *procNameObj)       /* Name of the procedure. Used for error
2057                                 * messages and trace information. */
2058{
2059    int overflow, limit = 60, nameLen;
2060    const char *procName = Tcl_GetStringFromObj(procNameObj, &nameLen);
2061
2062    overflow = (nameLen > limit);
2063    Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
2064            "\n    (procedure \"%.*s%s\" line %d)",
2065            (overflow ? limit : nameLen), procName,
2066            (overflow ? "..." : ""), interp->errorLine));
2067}
2068
2069/*
2070 *----------------------------------------------------------------------
2071 *
2072 * TclProcDeleteProc --
2073 *
2074 *      This function is invoked just before a command procedure is removed
2075 *      from an interpreter. Its job is to release all the resources allocated
2076 *      to the procedure.
2077 *
2078 * Results:
2079 *      None.
2080 *
2081 * Side effects:
2082 *      Memory gets freed, unless the procedure is actively being executed.
2083 *      In this case the cleanup is delayed until the last call to the current
2084 *      procedure completes.
2085 *
2086 *----------------------------------------------------------------------
2087 */
2088
2089void
2090TclProcDeleteProc(
2091    ClientData clientData)      /* Procedure to be deleted. */
2092{
2093    Proc *procPtr = (Proc *) clientData;
2094
2095    procPtr->refCount--;
2096    if (procPtr->refCount <= 0) {
2097        TclProcCleanupProc(procPtr);
2098    }
2099}
2100
2101/*
2102 *----------------------------------------------------------------------
2103 *
2104 * TclProcCleanupProc --
2105 *
2106 *      This function does all the real work of freeing up a Proc structure.
2107 *      It's called only when the structure's reference count becomes zero.
2108 *
2109 * Results:
2110 *      None.
2111 *
2112 * Side effects:
2113 *      Memory gets freed.
2114 *
2115 *----------------------------------------------------------------------
2116 */
2117
2118void
2119TclProcCleanupProc(
2120    register Proc *procPtr)     /* Procedure to be deleted. */
2121{
2122    register CompiledLocal *localPtr;
2123    Tcl_Obj *bodyPtr = procPtr->bodyPtr;
2124    Tcl_Obj *defPtr;
2125    Tcl_ResolvedVarInfo *resVarInfo;
2126    Tcl_HashEntry *hePtr = NULL;
2127    CmdFrame *cfPtr = NULL;
2128    Interp *iPtr = procPtr->iPtr;
2129
2130    if (bodyPtr != NULL) {
2131        Tcl_DecrRefCount(bodyPtr);
2132    }
2133    for (localPtr = procPtr->firstLocalPtr; localPtr != NULL; ) {
2134        CompiledLocal *nextPtr = localPtr->nextPtr;
2135
2136        resVarInfo = localPtr->resolveInfo;
2137        if (resVarInfo) {
2138            if (resVarInfo->deleteProc) {
2139                (*resVarInfo->deleteProc)(resVarInfo);
2140            } else {
2141                ckfree((char *) resVarInfo);
2142            }
2143        }
2144
2145        if (localPtr->defValuePtr != NULL) {
2146            defPtr = localPtr->defValuePtr;
2147            Tcl_DecrRefCount(defPtr);
2148        }
2149        ckfree((char *) localPtr);
2150        localPtr = nextPtr;
2151    }
2152    ckfree((char *) procPtr);
2153
2154    /*
2155     * TIP #280: Release the location data associated with this Proc
2156     * structure, if any. The interpreter may not exist (For example for
2157     * procbody structurues created by tbcload.
2158     */
2159
2160    if (!iPtr) {
2161        return;
2162    }
2163
2164    hePtr = Tcl_FindHashEntry(iPtr->linePBodyPtr, (char *) procPtr);
2165    if (!hePtr) {
2166        return;
2167    }
2168
2169    cfPtr = (CmdFrame *) Tcl_GetHashValue(hePtr);
2170
2171    if (cfPtr->type == TCL_LOCATION_SOURCE) {
2172        Tcl_DecrRefCount(cfPtr->data.eval.path);
2173        cfPtr->data.eval.path = NULL;
2174    }
2175    ckfree((char *) cfPtr->line);
2176    cfPtr->line = NULL;
2177    ckfree((char *) cfPtr);
2178    Tcl_DeleteHashEntry(hePtr);
2179}
2180
2181/*
2182 *----------------------------------------------------------------------
2183 *
2184 * TclUpdateReturnInfo --
2185 *
2186 *      This function is called when procedures return, and at other points
2187 *      where the TCL_RETURN code is used. It examines the returnLevel and
2188 *      returnCode to determine the real return status.
2189 *
2190 * Results:
2191 *      The return value is the true completion code to use for the procedure
2192 *      or script, instead of TCL_RETURN.
2193 *
2194 * Side effects:
2195 *      None.
2196 *
2197 *----------------------------------------------------------------------
2198 */
2199
2200int
2201TclUpdateReturnInfo(
2202    Interp *iPtr)               /* Interpreter for which TCL_RETURN exception
2203                                 * is being processed. */
2204{
2205    int code = TCL_RETURN;
2206
2207    iPtr->returnLevel--;
2208    if (iPtr->returnLevel < 0) {
2209        Tcl_Panic("TclUpdateReturnInfo: negative return level");
2210    }
2211    if (iPtr->returnLevel == 0) {
2212        /*
2213         * Now we've reached the level to return the requested -code.
2214         */
2215
2216        code = iPtr->returnCode;
2217        if (code == TCL_ERROR) {
2218            iPtr->flags |= ERR_LEGACY_COPY;
2219        }
2220    }
2221    return code;
2222}
2223
2224/*
2225 *----------------------------------------------------------------------
2226 *
2227 * TclGetObjInterpProc --
2228 *
2229 *      Returns a pointer to the TclObjInterpProc function; this is different
2230 *      from the value obtained from the TclObjInterpProc reference on systems
2231 *      like Windows where import and export versions of a function exported
2232 *      by a DLL exist.
2233 *
2234 * Results:
2235 *      Returns the internal address of the TclObjInterpProc function.
2236 *
2237 * Side effects:
2238 *      None.
2239 *
2240 *----------------------------------------------------------------------
2241 */
2242
2243TclObjCmdProcType
2244TclGetObjInterpProc(void)
2245{
2246    return (TclObjCmdProcType) TclObjInterpProc;
2247}
2248
2249/*
2250 *----------------------------------------------------------------------
2251 *
2252 * TclNewProcBodyObj --
2253 *
2254 *      Creates a new object, of type "procbody", whose internal
2255 *      representation is the given Proc struct. The newly created object's
2256 *      reference count is 0.
2257 *
2258 * Results:
2259 *      Returns a pointer to a newly allocated Tcl_Obj, NULL on error.
2260 *
2261 * Side effects:
2262 *      The reference count in the ByteCode attached to the Proc is bumped up
2263 *      by one, since the internal rep stores a pointer to it.
2264 *
2265 *----------------------------------------------------------------------
2266 */
2267
2268Tcl_Obj *
2269TclNewProcBodyObj(
2270    Proc *procPtr)              /* the Proc struct to store as the internal
2271                                 * representation. */
2272{
2273    Tcl_Obj *objPtr;
2274
2275    if (!procPtr) {
2276        return NULL;
2277    }
2278
2279    TclNewObj(objPtr);
2280    if (objPtr) {
2281        objPtr->typePtr = &tclProcBodyType;
2282        objPtr->internalRep.otherValuePtr = procPtr;
2283
2284        procPtr->refCount++;
2285    }
2286
2287    return objPtr;
2288}
2289
2290/*
2291 *----------------------------------------------------------------------
2292 *
2293 * ProcBodyDup --
2294 *
2295 *      Tcl_ObjType's Dup function for the proc body object. Bumps the
2296 *      reference count on the Proc stored in the internal representation.
2297 *
2298 * Results:
2299 *      None.
2300 *
2301 * Side effects:
2302 *      Sets up the object in dupPtr to be a duplicate of the one in srcPtr.
2303 *
2304 *----------------------------------------------------------------------
2305 */
2306
2307static void
2308ProcBodyDup(
2309    Tcl_Obj *srcPtr,            /* Object to copy. */
2310    Tcl_Obj *dupPtr)            /* Target object for the duplication. */
2311{
2312    Proc *procPtr = srcPtr->internalRep.otherValuePtr;
2313
2314    dupPtr->typePtr = &tclProcBodyType;
2315    dupPtr->internalRep.otherValuePtr = procPtr;
2316    procPtr->refCount++;
2317}
2318
2319/*
2320 *----------------------------------------------------------------------
2321 *
2322 * ProcBodyFree --
2323 *
2324 *      Tcl_ObjType's Free function for the proc body object. The reference
2325 *      count on its Proc struct is decreased by 1; if the count reaches 0,
2326 *      the proc is freed.
2327 *
2328 * Results:
2329 *      None.
2330 *
2331 * Side effects:
2332 *      If the reference count on the Proc struct reaches 0, the struct is
2333 *      freed.
2334 *
2335 *----------------------------------------------------------------------
2336 */
2337
2338static void
2339ProcBodyFree(
2340    Tcl_Obj *objPtr)            /* The object to clean up. */
2341{
2342    Proc *procPtr = objPtr->internalRep.otherValuePtr;
2343
2344    procPtr->refCount--;
2345    if (procPtr->refCount <= 0) {
2346        TclProcCleanupProc(procPtr);
2347    }
2348}
2349
2350/*
2351 *----------------------------------------------------------------------
2352 *
2353 * DupLambdaInternalRep, FreeLambdaInternalRep, SetLambdaFromAny --
2354 *
2355 *      How to manage the internal representations of lambda term objects.
2356 *      Syntactically they look like a two- or three-element list, where the
2357 *      first element is the formal arguments, the second is the the body, and
2358 *      the (optional) third is the namespace to execute the lambda term
2359 *      within (the global namespace is assumed if it is absent).
2360 *
2361 *----------------------------------------------------------------------
2362 */
2363
2364static void
2365DupLambdaInternalRep(
2366    Tcl_Obj *srcPtr,            /* Object with internal rep to copy. */
2367    register Tcl_Obj *copyPtr)  /* Object with internal rep to set. */
2368{
2369    Proc *procPtr = srcPtr->internalRep.twoPtrValue.ptr1;
2370    Tcl_Obj *nsObjPtr = srcPtr->internalRep.twoPtrValue.ptr2;
2371
2372    copyPtr->internalRep.twoPtrValue.ptr1 = procPtr;
2373    copyPtr->internalRep.twoPtrValue.ptr2 = nsObjPtr;
2374
2375    procPtr->refCount++;
2376    Tcl_IncrRefCount(nsObjPtr);
2377    copyPtr->typePtr = &lambdaType;
2378}
2379
2380static void
2381FreeLambdaInternalRep(
2382    register Tcl_Obj *objPtr)   /* CmdName object with internal representation
2383                                 * to free. */
2384{
2385    Proc *procPtr = objPtr->internalRep.twoPtrValue.ptr1;
2386    Tcl_Obj *nsObjPtr = objPtr->internalRep.twoPtrValue.ptr2;
2387
2388    procPtr->refCount--;
2389    if (procPtr->refCount == 0) {
2390        TclProcCleanupProc(procPtr);
2391    }
2392    TclDecrRefCount(nsObjPtr);
2393}
2394
2395static int
2396SetLambdaFromAny(
2397    Tcl_Interp *interp,         /* Used for error reporting if not NULL. */
2398    register Tcl_Obj *objPtr)   /* The object to convert. */
2399{
2400    Interp *iPtr = (Interp *) interp;
2401    char *name;
2402    Tcl_Obj *argsPtr, *bodyPtr, *nsObjPtr, **objv, *errPtr;
2403    int objc, result;
2404    Proc *procPtr;
2405
2406    /*
2407     * Convert objPtr to list type first; if it cannot be converted, or if its
2408     * length is not 2, then it cannot be converted to lambdaType.
2409     */
2410
2411    result = TclListObjGetElements(interp, objPtr, &objc, &objv);
2412    if ((result != TCL_OK) || ((objc != 2) && (objc != 3))) {
2413        TclNewLiteralStringObj(errPtr, "can't interpret \"");
2414        Tcl_AppendObjToObj(errPtr, objPtr);
2415        Tcl_AppendToObj(errPtr, "\" as a lambda expression", -1);
2416        Tcl_SetObjResult(interp, errPtr);
2417        return TCL_ERROR;
2418    }
2419
2420    argsPtr = objv[0];
2421    bodyPtr = objv[1];
2422
2423    /*
2424     * Create and initialize the Proc struct. The cmdPtr field is set to NULL
2425     * to signal that this is an anonymous function.
2426     */
2427
2428    name = TclGetString(objPtr);
2429
2430    if (TclCreateProc(interp, /*ignored nsPtr*/ NULL, name, argsPtr, bodyPtr,
2431            &procPtr) != TCL_OK) {
2432        Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
2433                "\n    (parsing lambda expression \"%s\")", name));
2434        return TCL_ERROR;
2435    }
2436
2437    /*
2438     * CAREFUL: TclCreateProc returns refCount==1! [Bug 1578454]
2439     * procPtr->refCount = 1;
2440     */
2441
2442    procPtr->cmdPtr = NULL;
2443
2444    /*
2445     * TIP #280: Remember the line the apply body is starting on. In a Byte
2446     * code context we ask the engine to provide us with the necessary
2447     * information. This is for the initialization of the byte code compiler
2448     * when the body is used for the first time.
2449     *
2450     * NOTE: The body is the second word in the 'objPtr'. Its location,
2451     * accessible through 'context.line[1]' (see below) is therefore only the
2452     * first approximation of the actual line the body is on. We have to use
2453     * the string rep of the 'objPtr' to determine the exact line. This is
2454     * available already through 'name'. Use 'TclListLines', see 'switch'
2455     * (tclCmdMZ.c).
2456     *
2457     * This code is nearly identical to the #280 code in Tcl_ProcObjCmd, see
2458     * this file. The differences are the different index of the body in the
2459     * line array of the context, and the special processing mentioned in the
2460     * previous paragraph to track into the list. Find a way to factor the
2461     * common elements into a single function.
2462     */
2463
2464    if (iPtr->cmdFramePtr) {
2465        CmdFrame *contextPtr;
2466
2467        contextPtr = (CmdFrame *) TclStackAlloc(interp, sizeof(CmdFrame));
2468        *contextPtr = *iPtr->cmdFramePtr;
2469
2470        if (contextPtr->type == TCL_LOCATION_BC) {
2471            /*
2472             * Retrieve the source context from the bytecode. This call
2473             * accounts for the reference to the source file, if any, held in
2474             * 'context.data.eval.path'.
2475             */
2476
2477            TclGetSrcInfoForPc(contextPtr);
2478        } else if (contextPtr->type == TCL_LOCATION_SOURCE) {
2479            /*
2480             * We created a new reference to the source file path name when we
2481             * created 'context' above. Account for the reference.
2482             */
2483
2484            Tcl_IncrRefCount(contextPtr->data.eval.path);
2485
2486        }
2487
2488        if (contextPtr->type == TCL_LOCATION_SOURCE) {
2489            /*
2490             * We can record source location within a lambda only if the body
2491             * was not created by substitution.
2492             */
2493
2494            if (contextPtr->line
2495                    && (contextPtr->nline >= 2) && (contextPtr->line[1] >= 0)) {
2496                int isNew, buf[2];
2497                CmdFrame *cfPtr = (CmdFrame *) ckalloc(sizeof(CmdFrame));
2498
2499                /*
2500                 * Move from approximation (line of list cmd word) to actual
2501                 * location (line of 2nd list element).
2502                 */
2503
2504                TclListLines(name, contextPtr->line[1], 2, buf);
2505
2506                cfPtr->level = -1;
2507                cfPtr->type = contextPtr->type;
2508                cfPtr->line = (int *) ckalloc(sizeof(int));
2509                cfPtr->line[0] = buf[1];
2510                cfPtr->nline = 1;
2511                cfPtr->framePtr = NULL;
2512                cfPtr->nextPtr = NULL;
2513
2514                cfPtr->data.eval.path = contextPtr->data.eval.path;
2515                Tcl_IncrRefCount(cfPtr->data.eval.path);
2516
2517                cfPtr->cmd.str.cmd = NULL;
2518                cfPtr->cmd.str.len = 0;
2519
2520                Tcl_SetHashValue(Tcl_CreateHashEntry(iPtr->linePBodyPtr,
2521                        (char *) procPtr, &isNew), cfPtr);
2522            }
2523
2524            /*
2525             * 'contextPtr' is going out of scope. Release the reference that
2526             * it's holding to the source file path
2527             */
2528
2529            Tcl_DecrRefCount(contextPtr->data.eval.path);
2530        }
2531        TclStackFree(interp, contextPtr);
2532    }
2533
2534    /*
2535     * Set the namespace for this lambda: given by objv[2] understood as a
2536     * global reference, or else global per default.
2537     */
2538
2539    if (objc == 2) {
2540        TclNewLiteralStringObj(nsObjPtr, "::");
2541    } else {
2542        char *nsName = TclGetString(objv[2]);
2543
2544        if ((*nsName != ':') || (*(nsName+1) != ':')) {
2545            TclNewLiteralStringObj(nsObjPtr, "::");
2546            Tcl_AppendObjToObj(nsObjPtr, objv[2]);
2547        } else {
2548            nsObjPtr = objv[2];
2549        }
2550    }
2551
2552    Tcl_IncrRefCount(nsObjPtr);
2553
2554    /*
2555     * Free the list internalrep of objPtr - this will free argsPtr, but
2556     * bodyPtr retains a reference from the Proc structure. Then finish the
2557     * conversion to lambdaType.
2558     */
2559
2560    objPtr->typePtr->freeIntRepProc(objPtr);
2561
2562    objPtr->internalRep.twoPtrValue.ptr1 = procPtr;
2563    objPtr->internalRep.twoPtrValue.ptr2 = nsObjPtr;
2564    objPtr->typePtr = &lambdaType;
2565    return TCL_OK;
2566}
2567
2568/*
2569 *----------------------------------------------------------------------
2570 *
2571 * Tcl_ApplyObjCmd --
2572 *
2573 *      This object-based function is invoked to process the "apply" Tcl
2574 *      command. See the user documentation for details on what it does.
2575 *
2576 * Results:
2577 *      A standard Tcl object result value.
2578 *
2579 * Side effects:
2580 *      Depends on the content of the lambda term (i.e., objv[1]).
2581 *
2582 *----------------------------------------------------------------------
2583 */
2584
2585int
2586Tcl_ApplyObjCmd(
2587    ClientData dummy,           /* Not used. */
2588    Tcl_Interp *interp,         /* Current interpreter. */
2589    int objc,                   /* Number of arguments. */
2590    Tcl_Obj *CONST objv[])      /* Argument objects. */
2591{
2592    Interp *iPtr = (Interp *) interp;
2593    Proc *procPtr = NULL;
2594    Tcl_Obj *lambdaPtr, *nsObjPtr;
2595    int result, isRootEnsemble;
2596    Command cmd;
2597    Tcl_Namespace *nsPtr;
2598    ExtraFrameInfo efi;
2599
2600    if (objc < 2) {
2601        Tcl_WrongNumArgs(interp, 1, objv, "lambdaExpr ?arg1 arg2 ...?");
2602        return TCL_ERROR;
2603    }
2604
2605    /*
2606     * Set lambdaPtr, convert it to lambdaType in the current interp if
2607     * necessary.
2608     */
2609
2610    lambdaPtr = objv[1];
2611    if (lambdaPtr->typePtr == &lambdaType) {
2612        procPtr = lambdaPtr->internalRep.twoPtrValue.ptr1;
2613    }
2614
2615#define JOE_EXTENSION 0
2616#if JOE_EXTENSION
2617    else {
2618        /*
2619         * Joe English's suggestion to allow cmdNames to function as lambdas.
2620         * Also requires making tclCmdNameType non-static in tclObj.c
2621         */
2622
2623        Tcl_Obj *elemPtr;
2624        int numElem;
2625
2626        if ((lambdaPtr->typePtr == &tclCmdNameType) ||
2627                (TclListObjGetElements(interp, lambdaPtr, &numElem,
2628                &elemPtr) == TCL_OK && numElem == 1)) {
2629            return Tcl_EvalObjv(interp, objc-1, objv+1, 0);
2630        }
2631    }
2632#endif
2633
2634    if ((procPtr == NULL) || (procPtr->iPtr != iPtr)) {
2635        result = SetLambdaFromAny(interp, lambdaPtr);
2636        if (result != TCL_OK) {
2637            return result;
2638        }
2639        procPtr = lambdaPtr->internalRep.twoPtrValue.ptr1;
2640    }
2641
2642    memset(&cmd, 0, sizeof(Command));
2643    procPtr->cmdPtr = &cmd;
2644
2645    /*
2646     * TIP#280 (semi-)HACK!
2647     *
2648     * Using cmd.clientData to tell [info frame] how to render the
2649     * 'lambdaPtr'. The InfoFrameCmd will detect this case by testing cmd.hPtr
2650     * for NULL. This condition holds here because of the 'memset' above, and
2651     * nowhere else (in the core). Regular commands always have a valid
2652     * 'hPtr', and lambda's never.
2653     */
2654
2655    efi.length = 1;
2656    efi.fields[0].name = "lambda";
2657    efi.fields[0].proc = NULL;
2658    efi.fields[0].clientData = lambdaPtr;
2659    cmd.clientData = &efi;
2660
2661    /*
2662     * Find the namespace where this lambda should run, and push a call frame
2663     * for that namespace. Note that TclObjInterpProc() will pop it.
2664     */
2665
2666    nsObjPtr = lambdaPtr->internalRep.twoPtrValue.ptr2;
2667    result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
2668    if (result != TCL_OK) {
2669        return result;
2670    }
2671
2672    cmd.nsPtr = (Namespace *) nsPtr;
2673
2674    isRootEnsemble = (iPtr->ensembleRewrite.sourceObjs == NULL);
2675    if (isRootEnsemble) {
2676        iPtr->ensembleRewrite.sourceObjs = objv;
2677        iPtr->ensembleRewrite.numRemovedObjs = 1;
2678        iPtr->ensembleRewrite.numInsertedObjs = 0;
2679    } else {
2680        iPtr->ensembleRewrite.numInsertedObjs -= 1;
2681    }
2682
2683    result = PushProcCallFrame((ClientData) procPtr, interp, objc, objv, 1);
2684    if (result == TCL_OK) {
2685        result = TclObjInterpProcCore(interp, objv[1], 2, &MakeLambdaError);
2686    }
2687
2688    if (isRootEnsemble) {
2689        iPtr->ensembleRewrite.sourceObjs = NULL;
2690        iPtr->ensembleRewrite.numRemovedObjs = 0;
2691        iPtr->ensembleRewrite.numInsertedObjs = 0;
2692    }
2693
2694    return result;
2695}
2696
2697/*
2698 *----------------------------------------------------------------------
2699 *
2700 * MakeLambdaError --
2701 *
2702 *      Function called by TclObjInterpProc to create the stack information
2703 *      upon an error from a lambda term.
2704 *
2705 * Results:
2706 *      The interpreter's error info trace is set to a value that supplements
2707 *      the error code.
2708 *
2709 * Side effects:
2710 *      none.
2711 *
2712 *----------------------------------------------------------------------
2713 */
2714
2715static void
2716MakeLambdaError(
2717    Tcl_Interp *interp,         /* The interpreter in which the procedure was
2718                                 * called. */
2719    Tcl_Obj *procNameObj)       /* Name of the procedure. Used for error
2720                                 * messages and trace information. */
2721{
2722    int overflow, limit = 60, nameLen;
2723    const char *procName = Tcl_GetStringFromObj(procNameObj, &nameLen);
2724
2725    overflow = (nameLen > limit);
2726    Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
2727            "\n    (lambda term \"%.*s%s\" line %d)",
2728            (overflow ? limit : nameLen), procName,
2729            (overflow ? "..." : ""), interp->errorLine));
2730}
2731
2732
2733/*
2734 *----------------------------------------------------------------------
2735 *
2736 * Tcl_DisassembleObjCmd --
2737 *
2738 *      Implementation of the "::tcl::unsupported::disassemble" command. This
2739 *      command is not documented, but will disassemble procedures, lambda
2740 *      terms and general scripts. Note that will compile terms if necessary
2741 *      in order to disassemble them.
2742 *
2743 *----------------------------------------------------------------------
2744 */
2745
2746int
2747Tcl_DisassembleObjCmd(
2748    ClientData dummy,           /* Not used. */
2749    Tcl_Interp *interp,         /* Current interpreter. */
2750    int objc,                   /* Number of arguments. */
2751    Tcl_Obj *CONST objv[])      /* Argument objects. */
2752{
2753    static const char *types[] = {
2754        "lambda", "proc", "script", NULL
2755    };
2756    enum Types {
2757        DISAS_LAMBDA, DISAS_PROC, DISAS_SCRIPT
2758    };
2759    int idx, result;
2760
2761    if (objc != 3) {
2762        Tcl_WrongNumArgs(interp, 1, objv, "type procName|lambdaTerm|script");
2763        return TCL_ERROR;
2764    }
2765    if (Tcl_GetIndexFromObj(interp, objv[1], types, "type", 0, &idx)!=TCL_OK){
2766        return TCL_ERROR;
2767    }
2768
2769    switch ((enum Types) idx) {
2770    case DISAS_LAMBDA: {
2771        Proc *procPtr = NULL;
2772        Command cmd;
2773        Tcl_Obj *nsObjPtr;
2774        Tcl_Namespace *nsPtr;
2775
2776        /*
2777         * Compile (if uncompiled) and disassemble a lambda term.
2778         */
2779
2780        if (objv[2]->typePtr == &lambdaType) {
2781            procPtr = objv[2]->internalRep.twoPtrValue.ptr1;
2782        }
2783        if (procPtr == NULL || procPtr->iPtr != (Interp *) interp) {
2784            result = SetLambdaFromAny(interp, objv[2]);
2785            if (result != TCL_OK) {
2786                return result;
2787            }
2788            procPtr = objv[2]->internalRep.twoPtrValue.ptr1;
2789        }
2790
2791        memset(&cmd, 0, sizeof(Command));
2792        nsObjPtr = objv[2]->internalRep.twoPtrValue.ptr2;
2793        result = TclGetNamespaceFromObj(interp, nsObjPtr, &nsPtr);
2794        if (result != TCL_OK) {
2795            return result;
2796        }
2797        cmd.nsPtr = (Namespace *) nsPtr;
2798        procPtr->cmdPtr = &cmd;
2799        result = PushProcCallFrame(procPtr, interp, objc, objv, 1);
2800        if (result != TCL_OK) {
2801            return result;
2802        }
2803        TclPopStackFrame(interp);
2804        if (((ByteCode *) procPtr->bodyPtr->internalRep.otherValuePtr)->flags
2805                & TCL_BYTECODE_PRECOMPILED) {
2806            Tcl_AppendResult(interp, "may not disassemble prebuilt bytecode",
2807                    NULL);
2808            return TCL_ERROR;
2809        }
2810        Tcl_SetObjResult(interp, TclDisassembleByteCodeObj(procPtr->bodyPtr));
2811        break;
2812    }
2813    case DISAS_PROC: {
2814        Proc *procPtr = TclFindProc((Interp *) interp, TclGetString(objv[2]));
2815
2816        if (procPtr == NULL) {
2817            Tcl_AppendResult(interp, "\"", TclGetString(objv[2]),
2818                    "\" isn't a procedure", NULL);
2819            return TCL_ERROR;
2820        }
2821
2822        /*
2823         * Compile (if uncompiled) and disassemble a procedure.
2824         */
2825
2826        result = PushProcCallFrame(procPtr, interp, 2, objv+1, 1);
2827        if (result != TCL_OK) {
2828            return result;
2829        }
2830        TclPopStackFrame(interp);
2831        if (((ByteCode *) procPtr->bodyPtr->internalRep.otherValuePtr)->flags
2832                & TCL_BYTECODE_PRECOMPILED) {
2833            Tcl_AppendResult(interp, "may not disassemble prebuilt bytecode",
2834                    NULL);
2835            return TCL_ERROR;
2836        }
2837        Tcl_SetObjResult(interp, TclDisassembleByteCodeObj(procPtr->bodyPtr));
2838        break;
2839    }
2840    case DISAS_SCRIPT:
2841        /*
2842         * Compile and disassemble a script.
2843         */
2844
2845        if (objv[2]->typePtr != &tclByteCodeType) {
2846            if (TclSetByteCodeFromAny(interp, objv[2], NULL, NULL) != TCL_OK){
2847                return TCL_ERROR;
2848            }
2849        }
2850        Tcl_SetObjResult(interp, TclDisassembleByteCodeObj(objv[2]));
2851        break;
2852    }
2853    return TCL_OK;
2854}
2855
2856/*
2857 * Local Variables:
2858 * mode: c
2859 * c-basic-offset: 4
2860 * fill-column: 78
2861 * End:
2862 */
Note: See TracBrowser for help on using the repository browser.