tclProc.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:57k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclProc.c --
  3.  *
  4.  * This file contains routines that implement Tcl procedures,
  5.  * including 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) 2007 Daniel A. Steffen <das@users.sourceforge.net>
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tclProc.c,v 1.44.2.7 2007/09/13 15:28:17 das Exp $
  15.  */
  16. #include "tclInt.h"
  17. #include "tclCompile.h"
  18. /*
  19.  * Prototypes for static functions in this file
  20.  */
  21. static void ProcBodyDup _ANSI_ARGS_((Tcl_Obj *srcPtr, Tcl_Obj *dupPtr));
  22. static void ProcBodyFree _ANSI_ARGS_((Tcl_Obj *objPtr));
  23. static int ProcBodySetFromAny _ANSI_ARGS_((Tcl_Interp *interp,
  24. Tcl_Obj *objPtr));
  25. static void ProcBodyUpdateString _ANSI_ARGS_((Tcl_Obj *objPtr));
  26. static int ProcCompileProc _ANSI_ARGS_((Tcl_Interp *interp,
  27.     Proc *procPtr, Tcl_Obj *bodyPtr, Namespace *nsPtr,
  28.     CONST char *description, CONST char *procName,
  29.     Proc **procPtrPtr));
  30. static  int ProcessProcResultCode _ANSI_ARGS_((Tcl_Interp *interp,
  31.     char *procName, int nameLen, int returnCode));
  32. static int TclCompileNoOp _ANSI_ARGS_((Tcl_Interp *interp,
  33.     Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
  34. /*
  35.  * The ProcBodyObjType type
  36.  */
  37. Tcl_ObjType tclProcBodyType = {
  38.     "procbody", /* name for this type */
  39.     ProcBodyFree, /* FreeInternalRep procedure */
  40.     ProcBodyDup, /* DupInternalRep procedure */
  41.     ProcBodyUpdateString, /* UpdateString procedure */
  42.     ProcBodySetFromAny /* SetFromAny procedure */
  43. };
  44. /*
  45.  *----------------------------------------------------------------------
  46.  *
  47.  * Tcl_ProcObjCmd --
  48.  *
  49.  * This object-based procedure is invoked to process the "proc" Tcl 
  50.  * command. See the user documentation for details on what it does.
  51.  *
  52.  * Results:
  53.  * A standard Tcl object result value.
  54.  *
  55.  * Side effects:
  56.  * A new procedure gets created.
  57.  *
  58.  *----------------------------------------------------------------------
  59.  */
  60. /* ARGSUSED */
  61. int
  62. Tcl_ProcObjCmd(dummy, interp, objc, objv)
  63.     ClientData dummy; /* Not used. */
  64.     Tcl_Interp *interp; /* Current interpreter. */
  65.     int objc; /* Number of arguments. */
  66.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  67. {
  68.     register Interp *iPtr = (Interp *) interp;
  69.     Proc *procPtr;
  70.     char *fullName;
  71.     CONST char *procName, *procArgs, *procBody;
  72.     Namespace *nsPtr, *altNsPtr, *cxtNsPtr;
  73.     Tcl_Command cmd;
  74.     Tcl_DString ds;
  75.     if (objc != 4) {
  76. Tcl_WrongNumArgs(interp, 1, objv, "name args body");
  77. return TCL_ERROR;
  78.     }
  79.     /*
  80.      * Determine the namespace where the procedure should reside. Unless
  81.      * the command name includes namespace qualifiers, this will be the
  82.      * current namespace.
  83.      */
  84.     
  85.     fullName = TclGetString(objv[1]);
  86.     TclGetNamespaceForQualName(interp, fullName, (Namespace *) NULL,
  87.     0, &nsPtr, &altNsPtr, &cxtNsPtr, &procName);
  88.     if (nsPtr == NULL) {
  89.         Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  90. "can't create procedure "", fullName,
  91. "": unknown namespace", (char *) NULL);
  92.         return TCL_ERROR;
  93.     }
  94.     if (procName == NULL) {
  95. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  96. "can't create procedure "", fullName,
  97. "": bad procedure name", (char *) NULL);
  98.         return TCL_ERROR;
  99.     }
  100.     if ((nsPtr != iPtr->globalNsPtr)
  101.     && (procName != NULL) && (procName[0] == ':')) {
  102. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  103. "can't create procedure "", procName,
  104. "" in non-global namespace with name starting with ":"",
  105.         (char *) NULL);
  106.         return TCL_ERROR;
  107.     }
  108.     /*
  109.      *  Create the data structure to represent the procedure.
  110.      */
  111.     if (TclCreateProc(interp, nsPtr, procName, objv[2], objv[3],
  112.         &procPtr) != TCL_OK) {
  113.         return TCL_ERROR;
  114.     }
  115.     /*
  116.      * Now create a command for the procedure. This will initially be in
  117.      * the current namespace unless the procedure's name included namespace
  118.      * qualifiers. To create the new command in the right namespace, we
  119.      * generate a fully qualified name for it.
  120.      */
  121.     Tcl_DStringInit(&ds);
  122.     if (nsPtr != iPtr->globalNsPtr) {
  123. Tcl_DStringAppend(&ds, nsPtr->fullName, -1);
  124. Tcl_DStringAppend(&ds, "::", 2);
  125.     }
  126.     Tcl_DStringAppend(&ds, procName, -1);
  127.     
  128.     Tcl_CreateCommand(interp, Tcl_DStringValue(&ds), TclProcInterpProc,
  129.     (ClientData) procPtr, TclProcDeleteProc);
  130.     cmd = Tcl_CreateObjCommand(interp, Tcl_DStringValue(&ds),
  131.     TclObjInterpProc, (ClientData) procPtr, TclProcDeleteProc);
  132.     Tcl_DStringFree(&ds);
  133.     /*
  134.      * Now initialize the new procedure's cmdPtr field. This will be used
  135.      * later when the procedure is called to determine what namespace the
  136.      * procedure will run in. This will be different than the current
  137.      * namespace if the proc was renamed into a different namespace.
  138.      */
  139.     
  140.     procPtr->cmdPtr = (Command *) cmd;
  141. #ifdef TCL_TIP280
  142.     /* TIP #280 Remember the line the procedure body is starting on. In a
  143.      * Byte code context we ask the engine to provide us with the necessary
  144.      * information. This is for the initialization of the byte code compiler
  145.      * when the body is used for the first time.
  146.      */
  147.     if (iPtr->cmdFramePtr) {
  148.         CmdFrame context = *iPtr->cmdFramePtr;
  149. if (context.type == TCL_LOCATION_BC) {
  150.     TclGetSrcInfoForPc (&context);
  151.     /* May get path in context */
  152. } else if (context.type == TCL_LOCATION_SOURCE) {
  153.     /* context now holds another reference */
  154.     Tcl_IncrRefCount (context.data.eval.path);
  155. }
  156. /* type == TCL_LOCATION_PREBC implies that 'line' is NULL here!  We
  157.  * cannot assume that 'line' is valid here, we have to check. If the
  158.  * outer context is an eval (bc, prebc, eval) we do not save any
  159.  * information. Counting relative to the beginning of the proc body is
  160.  * more sensible than counting relative to the outer eval block.
  161.  */
  162. if ((context.type == TCL_LOCATION_SOURCE) &&
  163.     context.line &&
  164.     (context.nline >= 4) &&
  165.     (context.line [3] >= 0)) {
  166.     int       new;
  167.     CmdFrame* cfPtr = (CmdFrame*) ckalloc (sizeof (CmdFrame));
  168.     cfPtr->level    = -1;
  169.     cfPtr->type     = context.type;
  170.     cfPtr->line     = (int*) ckalloc (sizeof (int));
  171.     cfPtr->line [0] = context.line [3];
  172.     cfPtr->nline    = 1;
  173.     cfPtr->framePtr = NULL;
  174.     cfPtr->nextPtr  = NULL;
  175.     if (context.type == TCL_LOCATION_SOURCE) {
  176.         cfPtr->data.eval.path = context.data.eval.path;
  177. /* Transfer of reference. The reference going away (release of
  178.  * the context) is replaced by the reference in the
  179.  * constructed cmdframe */
  180.     } else {
  181.         cfPtr->type = TCL_LOCATION_EVAL;
  182. cfPtr->data.eval.path = NULL;
  183.     }
  184.     cfPtr->cmd.str.cmd = NULL;
  185.     cfPtr->cmd.str.len = 0;
  186.     Tcl_SetHashValue (Tcl_CreateHashEntry (iPtr->linePBodyPtr,
  187.    (char*) procPtr, &new),
  188.       cfPtr);
  189. }
  190.     }
  191. #endif
  192.     /*
  193.      * Optimize for noop procs: if the body is not precompiled (like a TclPro
  194.      * procbody), and the argument list is just "args" and the body is empty,
  195.      * define a compileProc to compile a noop.
  196.      *
  197.      * Notes: 
  198.      *   - cannot be done for any argument list without having different
  199.      *     compiled/not-compiled behaviour in the "wrong argument #" case, 
  200.      *     or making this code much more complicated. In any case, it doesn't 
  201.      *     seem to make a lot of sense to verify the number of arguments we 
  202.      *     are about to ignore ...
  203.      *   - could be enhanced to handle also non-empty bodies that contain 
  204.      *     only comments; however, parsing the body will slow down the 
  205.      *     compilation of all procs whose argument list is just _args_ */
  206.     if (objv[3]->typePtr == &tclProcBodyType) {
  207. goto done;
  208.     }
  209.     procArgs = Tcl_GetString(objv[2]);
  210.     
  211.     while (*procArgs == ' ') {
  212. procArgs++;
  213.     }
  214.     
  215.     if ((procArgs[0] == 'a') && (strncmp(procArgs, "args", 4) == 0)) {
  216. procArgs +=4;
  217. while(*procArgs != '') {
  218.     if (*procArgs != ' ') {
  219. goto done;
  220.     }
  221.     procArgs++;
  222. }
  223. /* 
  224.  * The argument list is just "args"; check the body
  225.  */
  226. procBody = Tcl_GetString(objv[3]);
  227. while (*procBody != '') {
  228.     if (!isspace(UCHAR(*procBody))) {
  229. goto done;
  230.     }
  231.     procBody++;
  232. }
  233. /* 
  234.  * The body is just spaces: link the compileProc
  235.  */
  236. ((Command *) cmd)->compileProc = TclCompileNoOp;
  237.     }
  238.  done:
  239.     return TCL_OK;
  240. }
  241. /*
  242.  *----------------------------------------------------------------------
  243.  *
  244.  * TclCreateProc --
  245.  *
  246.  * Creates the data associated with a Tcl procedure definition.
  247.  * This procedure knows how to handle two types of body objects:
  248.  * strings and procbody. Strings are the traditional (and common) value
  249.  * for bodies, procbody are values created by extensions that have
  250.  * loaded a previously compiled script.
  251.  *
  252.  * Results:
  253.  * Returns TCL_OK on success, along with a pointer to a Tcl
  254.  * procedure definition in procPtrPtr.  This definition should
  255.  * be freed by calling TclCleanupProc() when it is no longer
  256.  * needed.  Returns TCL_ERROR if anything goes wrong.
  257.  *
  258.  * Side effects:
  259.  * If anything goes wrong, this procedure returns an error
  260.  * message in the interpreter.
  261.  *
  262.  *----------------------------------------------------------------------
  263.  */
  264. int
  265. TclCreateProc(interp, nsPtr, procName, argsPtr, bodyPtr, procPtrPtr)
  266.     Tcl_Interp *interp;         /* interpreter containing proc */
  267.     Namespace *nsPtr;           /* namespace containing this proc */
  268.     CONST char *procName;       /* unqualified name of this proc */
  269.     Tcl_Obj *argsPtr;           /* description of arguments */
  270.     Tcl_Obj *bodyPtr;           /* command body */
  271.     Proc **procPtrPtr;          /* returns:  pointer to proc data */
  272. {
  273.     Interp *iPtr = (Interp*)interp;
  274.     CONST char **argArray = NULL;
  275.     register Proc *procPtr;
  276.     int i, length, result, numArgs;
  277.     CONST char *args, *bytes, *p;
  278.     register CompiledLocal *localPtr = NULL;
  279.     Tcl_Obj *defPtr;
  280.     int precompiled = 0;
  281.     
  282.     if (bodyPtr->typePtr == &tclProcBodyType) {
  283.         /*
  284.          * Because the body is a TclProProcBody, the actual body is already
  285.          * compiled, and it is not shared with anyone else, so it's OK not to
  286.          * unshare it (as a matter of fact, it is bad to unshare it, because
  287.          * there may be no source code).
  288.          *
  289.          * We don't create and initialize a Proc structure for the procedure;
  290.          * rather, we use what is in the body object. Note that
  291.          * we initialize its cmdPtr field below after we've created the command
  292.          * for the procedure. We increment the ref count of the Proc struct
  293.          * since the command (soon to be created) will be holding a reference
  294.          * to it.
  295.          */
  296.     
  297.         procPtr = (Proc *) bodyPtr->internalRep.otherValuePtr;
  298.         procPtr->iPtr = iPtr;
  299.         procPtr->refCount++;
  300.         precompiled = 1;
  301.     } else {
  302.         /*
  303.          * If the procedure's body object is shared because its string value is
  304.          * identical to, e.g., the body of another procedure, we must create a
  305.          * private copy for this procedure to use. Such sharing of procedure
  306.          * bodies is rare but can cause problems. A procedure body is compiled
  307.          * in a context that includes the number of compiler-allocated "slots"
  308.          * for local variables. Each formal parameter is given a local variable
  309.          * slot (the "procPtr->numCompiledLocals = numArgs" assignment
  310.          * below). This means that the same code can not be shared by two
  311.          * procedures that have a different number of arguments, even if their
  312.          * bodies are identical. Note that we don't use Tcl_DuplicateObj since
  313.          * we would not want any bytecode internal representation.
  314.          */
  315.         if (Tcl_IsShared(bodyPtr)) {
  316.             bytes = Tcl_GetStringFromObj(bodyPtr, &length);
  317.             bodyPtr = Tcl_NewStringObj(bytes, length);
  318.         }
  319.         /*
  320.          * Create and initialize a Proc structure for the procedure. Note that
  321.          * we initialize its cmdPtr field below after we've created the command
  322.          * for the procedure. We increment the ref count of the procedure's
  323.          * body object since there will be a reference to it in the Proc
  324.          * structure.
  325.          */
  326.     
  327.         Tcl_IncrRefCount(bodyPtr);
  328.         procPtr = (Proc *) ckalloc(sizeof(Proc));
  329.         procPtr->iPtr = iPtr;
  330.         procPtr->refCount = 1;
  331.         procPtr->bodyPtr = bodyPtr;
  332.         procPtr->numArgs  = 0; /* actual argument count is set below. */
  333.         procPtr->numCompiledLocals = 0;
  334.         procPtr->firstLocalPtr = NULL;
  335.         procPtr->lastLocalPtr = NULL;
  336.     }
  337.     
  338.     /*
  339.      * Break up the argument list into argument specifiers, then process
  340.      * each argument specifier.
  341.      * If the body is precompiled, processing is limited to checking that
  342.      * the the parsed argument is consistent with the one stored in the
  343.      * Proc.
  344.      * THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULLS.
  345.      */
  346.     args = Tcl_GetStringFromObj(argsPtr, &length);
  347.     result = Tcl_SplitList(interp, args, &numArgs, &argArray);
  348.     if (result != TCL_OK) {
  349.         goto procError;
  350.     }
  351.     if (precompiled) {
  352.         if (numArgs > procPtr->numArgs) {
  353.             char buf[64 + TCL_INTEGER_SPACE + TCL_INTEGER_SPACE];
  354.             sprintf(buf, "": arg list contains %d entries, precompiled header expects %d",
  355.                     numArgs, procPtr->numArgs);
  356.             Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  357.                     "procedure "", procName,
  358.                     buf, (char *) NULL);
  359.             goto procError;
  360.         }
  361.         localPtr = procPtr->firstLocalPtr;
  362.     } else {
  363.         procPtr->numArgs = numArgs;
  364.         procPtr->numCompiledLocals = numArgs;
  365.     }
  366.     for (i = 0;  i < numArgs;  i++) {
  367.         int fieldCount, nameLength, valueLength;
  368.         CONST char **fieldValues;
  369.         /*
  370.          * Now divide the specifier up into name and default.
  371.          */
  372.         result = Tcl_SplitList(interp, argArray[i], &fieldCount,
  373.                 &fieldValues);
  374.         if (result != TCL_OK) {
  375.             goto procError;
  376.         }
  377.         if (fieldCount > 2) {
  378.             ckfree((char *) fieldValues);
  379.             Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  380.                     "too many fields in argument specifier "",
  381.                     argArray[i], """, (char *) NULL);
  382.             goto procError;
  383.         }
  384.         if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
  385.             ckfree((char *) fieldValues);
  386.             Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  387.                     "procedure "", procName,
  388.                     "" has argument with no name", (char *) NULL);
  389.             goto procError;
  390.         }
  391.         nameLength = strlen(fieldValues[0]);
  392.         if (fieldCount == 2) {
  393.             valueLength = strlen(fieldValues[1]);
  394.         } else {
  395.             valueLength = 0;
  396.         }
  397.         /*
  398.          * Check that the formal parameter name is a scalar.
  399.          */
  400.         p = fieldValues[0];
  401.         while (*p != '') {
  402.             if (*p == '(') {
  403.                 CONST char *q = p;
  404.                 do {
  405.     q++;
  406. } while (*q != '');
  407. q--;
  408. if (*q == ')') { /* we have an array element */
  409.     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  410.             "procedure "", procName,
  411.             "" has formal parameter "", fieldValues[0],
  412.     "" that is an array element",
  413.     (char *) NULL);
  414.     ckfree((char *) fieldValues);
  415.     goto procError;
  416. }
  417.     } else if ((*p == ':') && (*(p+1) == ':')) {
  418. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  419.         "procedure "", procName,
  420.         "" has formal parameter "", fieldValues[0],
  421. "" that is not a simple name",
  422. (char *) NULL);
  423. ckfree((char *) fieldValues);
  424. goto procError;
  425.     }
  426.     p++;
  427. }
  428. if (precompiled) {
  429.     /*
  430.      * Compare the parsed argument with the stored one.
  431.      * For the flags, we and out VAR_UNDEFINED to support bridging
  432.      * precompiled <= 8.3 code in 8.4 where this is now used as an
  433.      * optimization indicator. Yes, this is a hack. -- hobbs
  434.      */
  435.     if ((localPtr->nameLength != nameLength)
  436.     || (strcmp(localPtr->name, fieldValues[0]))
  437.     || (localPtr->frameIndex != i)
  438.     || ((localPtr->flags & ~VAR_UNDEFINED)
  439.     != (VAR_SCALAR | VAR_ARGUMENT))
  440.     || ((localPtr->defValuePtr == NULL)
  441.     && (fieldCount == 2))
  442.     || ((localPtr->defValuePtr != NULL)
  443.     && (fieldCount != 2))) {
  444. char buf[80 + TCL_INTEGER_SPACE];
  445. sprintf(buf, "": formal parameter %d is inconsistent with precompiled body",
  446. i);
  447. Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  448. "procedure "", procName,
  449. buf, (char *) NULL);
  450. ckfree((char *) fieldValues);
  451. goto procError;
  452.     }
  453.             /*
  454.              * compare the default value if any
  455.              */
  456.             if (localPtr->defValuePtr != NULL) {
  457.                 int tmpLength;
  458.                 char *tmpPtr = Tcl_GetStringFromObj(localPtr->defValuePtr,
  459.                         &tmpLength);
  460.                 if ((valueLength != tmpLength)
  461.                         || (strncmp(fieldValues[1], tmpPtr,
  462.                                 (size_t) tmpLength))) {
  463.                     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
  464.                             "procedure "", procName,
  465.                             "": formal parameter "",
  466.                             fieldValues[0],
  467.                             "" has default value inconsistent with precompiled body",
  468.                             (char *) NULL);
  469.                     ckfree((char *) fieldValues);
  470.                     goto procError;
  471.                 }
  472.             }
  473.             localPtr = localPtr->nextPtr;
  474.         } else {
  475.             /*
  476.              * Allocate an entry in the runtime procedure frame's array of
  477.              * local variables for the argument. 
  478.              */
  479.             localPtr = (CompiledLocal *) ckalloc((unsigned) 
  480.                     (sizeof(CompiledLocal) - sizeof(localPtr->name)
  481.                             + nameLength+1));
  482.             if (procPtr->firstLocalPtr == NULL) {
  483.                 procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
  484.             } else {
  485.                 procPtr->lastLocalPtr->nextPtr = localPtr;
  486.                 procPtr->lastLocalPtr = localPtr;
  487.             }
  488.             localPtr->nextPtr = NULL;
  489.             localPtr->nameLength = nameLength;
  490.             localPtr->frameIndex = i;
  491.             localPtr->flags = VAR_SCALAR | VAR_ARGUMENT;
  492.             localPtr->resolveInfo = NULL;
  493.             if (fieldCount == 2) {
  494.                 localPtr->defValuePtr =
  495.     Tcl_NewStringObj(fieldValues[1], valueLength);
  496.                 Tcl_IncrRefCount(localPtr->defValuePtr);
  497.             } else {
  498.                 localPtr->defValuePtr = NULL;
  499.             }
  500.             strcpy(localPtr->name, fieldValues[0]);
  501. }
  502.         ckfree((char *) fieldValues);
  503.     }
  504.     /*
  505.      * Now initialize the new procedure's cmdPtr field. This will be used
  506.      * later when the procedure is called to determine what namespace the
  507.      * procedure will run in. This will be different than the current
  508.      * namespace if the proc was renamed into a different namespace.
  509.      */
  510.     
  511.     *procPtrPtr = procPtr;
  512.     ckfree((char *) argArray);
  513.     return TCL_OK;
  514. procError:
  515.     if (precompiled) {
  516.         procPtr->refCount--;
  517.     } else {
  518.         Tcl_DecrRefCount(bodyPtr);
  519.         while (procPtr->firstLocalPtr != NULL) {
  520.             localPtr = procPtr->firstLocalPtr;
  521.             procPtr->firstLocalPtr = localPtr->nextPtr;
  522.             defPtr = localPtr->defValuePtr;
  523.             if (defPtr != NULL) {
  524.                 Tcl_DecrRefCount(defPtr);
  525.             }
  526.             ckfree((char *) localPtr);
  527.         }
  528.         ckfree((char *) procPtr);
  529.     }
  530.     if (argArray != NULL) {
  531. ckfree((char *) argArray);
  532.     }
  533.     return TCL_ERROR;
  534. }
  535. /*
  536.  *----------------------------------------------------------------------
  537.  *
  538.  * TclGetFrame --
  539.  *
  540.  * Given a description of a procedure frame, such as the first
  541.  * argument to an "uplevel" or "upvar" command, locate the
  542.  * call frame for the appropriate level of procedure.
  543.  *
  544.  * Results:
  545.  * The return value is -1 if an error occurred in finding the frame
  546.  * (in this case an error message is left in the interp's result).
  547.  * 1 is returned if string was either a number or a number preceded
  548.  * by "#" and it specified a valid frame.  0 is returned if string
  549.  * isn't one of the two things above (in this case, the lookup
  550.  * acts as if string were "1").  The variable pointed to by
  551.  * framePtrPtr is filled in with the address of the desired frame
  552.  * (unless an error occurs, in which case it isn't modified).
  553.  *
  554.  * Side effects:
  555.  * None.
  556.  *
  557.  *----------------------------------------------------------------------
  558.  */
  559. int
  560. TclGetFrame(interp, string, framePtrPtr)
  561.     Tcl_Interp *interp; /* Interpreter in which to find frame. */
  562.     CONST char *string; /* String describing frame. */
  563.     CallFrame **framePtrPtr; /* Store pointer to frame here (or NULL
  564.  * if global frame indicated). */
  565. {
  566.     register Interp *iPtr = (Interp *) interp;
  567.     int curLevel, level, result;
  568.     CallFrame *framePtr;
  569.     /*
  570.      * Parse string to figure out which level number to go to.
  571.      */
  572.     result = 1;
  573.     curLevel = (iPtr->varFramePtr == NULL) ? 0 : iPtr->varFramePtr->level;
  574.     if (*string == '#') {
  575. if (Tcl_GetInt(interp, string+1, &level) != TCL_OK) {
  576.     return -1;
  577. }
  578. if (level < 0) {
  579.     levelError:
  580.     Tcl_AppendResult(interp, "bad level "", string, """,
  581.     (char *) NULL);
  582.     return -1;
  583. }
  584.     } else if (isdigit(UCHAR(*string))) { /* INTL: digit */
  585. if (Tcl_GetInt(interp, string, &level) != TCL_OK) {
  586.     return -1;
  587. }
  588. level = curLevel - level;
  589.     } else {
  590. level = curLevel - 1;
  591. result = 0;
  592.     }
  593.     /*
  594.      * Figure out which frame to use, and modify the interpreter so
  595.      * its variables come from that frame.
  596.      */
  597.     if (level == 0) {
  598. framePtr = NULL;
  599.     } else {
  600. for (framePtr = iPtr->varFramePtr; framePtr != NULL;
  601. framePtr = framePtr->callerVarPtr) {
  602.     if (framePtr->level == level) {
  603. break;
  604.     }
  605. }
  606. if (framePtr == NULL) {
  607.     goto levelError;
  608. }
  609.     }
  610.     *framePtrPtr = framePtr;
  611.     return result;
  612. }
  613. /*
  614.  *----------------------------------------------------------------------
  615.  *
  616.  * Tcl_UplevelObjCmd --
  617.  *
  618.  * This object procedure is invoked to process the "uplevel" Tcl
  619.  * command. See the user documentation for details on what it does.
  620.  *
  621.  * Results:
  622.  * A standard Tcl object result value.
  623.  *
  624.  * Side effects:
  625.  * See the user documentation.
  626.  *
  627.  *----------------------------------------------------------------------
  628.  */
  629. /* ARGSUSED */
  630. int
  631. Tcl_UplevelObjCmd(dummy, interp, objc, objv)
  632.     ClientData dummy; /* Not used. */
  633.     Tcl_Interp *interp; /* Current interpreter. */
  634.     int objc; /* Number of arguments. */
  635.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  636. {
  637.     register Interp *iPtr = (Interp *) interp;
  638.     char *optLevel;
  639.     int result;
  640.     CallFrame *savedVarFramePtr, *framePtr;
  641.     if (objc < 2) {
  642. uplevelSyntax:
  643. Tcl_WrongNumArgs(interp, 1, objv, "?level? command ?arg ...?");
  644. return TCL_ERROR;
  645.     }
  646.     /*
  647.      * Find the level to use for executing the command.
  648.      */
  649.     optLevel = TclGetString(objv[1]);
  650.     result = TclGetFrame(interp, optLevel, &framePtr);
  651.     if (result == -1) {
  652. return TCL_ERROR;
  653.     }
  654.     objc -= (result+1);
  655.     if (objc == 0) {
  656. goto uplevelSyntax;
  657.     }
  658.     objv += (result+1);
  659.     /*
  660.      * Modify the interpreter state to execute in the given frame.
  661.      */
  662.     savedVarFramePtr = iPtr->varFramePtr;
  663.     iPtr->varFramePtr = framePtr;
  664.     /*
  665.      * Execute the residual arguments as a command.
  666.      */
  667.     if (objc == 1) {
  668. result = Tcl_EvalObjEx(interp, objv[0], TCL_EVAL_DIRECT);
  669.     } else {
  670. /*
  671.  * More than one argument: concatenate them together with spaces
  672.  * between, then evaluate the result.  Tcl_EvalObjEx will delete
  673.  * the object when it decrements its refcount after eval'ing it.
  674.  */
  675. Tcl_Obj *objPtr;
  676. objPtr = Tcl_ConcatObj(objc, objv);
  677. result = Tcl_EvalObjEx(interp, objPtr, TCL_EVAL_DIRECT);
  678.     }
  679.     if (result == TCL_ERROR) {
  680. char msg[32 + TCL_INTEGER_SPACE];
  681. sprintf(msg, "n    ("uplevel" body line %d)", interp->errorLine);
  682. Tcl_AddObjErrorInfo(interp, msg, -1);
  683.     }
  684.     /*
  685.      * Restore the variable frame, and return.
  686.      */
  687.     iPtr->varFramePtr = savedVarFramePtr;
  688.     return result;
  689. }
  690. /*
  691.  *----------------------------------------------------------------------
  692.  *
  693.  * TclFindProc --
  694.  *
  695.  * Given the name of a procedure, return a pointer to the
  696.  * record describing the procedure. The procedure will be
  697.  * looked up using the usual rules: first in the current
  698.  * namespace and then in the global namespace.
  699.  *
  700.  * Results:
  701.  * NULL is returned if the name doesn't correspond to any
  702.  * procedure. Otherwise, the return value is a pointer to
  703.  * the procedure's record. If the name is found but refers
  704.  * to an imported command that points to a "real" procedure
  705.  * defined in another namespace, a pointer to that "real"
  706.  * procedure's structure is returned.
  707.  *
  708.  * Side effects:
  709.  * None.
  710.  *
  711.  *----------------------------------------------------------------------
  712.  */
  713. Proc *
  714. TclFindProc(iPtr, procName)
  715.     Interp *iPtr; /* Interpreter in which to look. */
  716.     CONST char *procName; /* Name of desired procedure. */
  717. {
  718.     Tcl_Command cmd;
  719.     Tcl_Command origCmd;
  720.     Command *cmdPtr;
  721.     
  722.     cmd = Tcl_FindCommand((Tcl_Interp *) iPtr, procName,
  723.             (Tcl_Namespace *) NULL, /*flags*/ 0);
  724.     if (cmd == (Tcl_Command) NULL) {
  725.         return NULL;
  726.     }
  727.     cmdPtr = (Command *) cmd;
  728.     origCmd = TclGetOriginalCommand(cmd);
  729.     if (origCmd != NULL) {
  730. cmdPtr = (Command *) origCmd;
  731.     }
  732.     if (cmdPtr->proc != TclProcInterpProc) {
  733. return NULL;
  734.     }
  735.     return (Proc *) cmdPtr->clientData;
  736. }
  737. /*
  738.  *----------------------------------------------------------------------
  739.  *
  740.  * TclIsProc --
  741.  *
  742.  * Tells whether a command is a Tcl procedure or not.
  743.  *
  744.  * Results:
  745.  * If the given command is actually a Tcl procedure, the
  746.  * return value is the address of the record describing
  747.  * the procedure.  Otherwise the return value is 0.
  748.  *
  749.  * Side effects:
  750.  * None.
  751.  *
  752.  *----------------------------------------------------------------------
  753.  */
  754. Proc *
  755. TclIsProc(cmdPtr)
  756.     Command *cmdPtr; /* Command to test. */
  757. {
  758.     Tcl_Command origCmd;
  759.     origCmd = TclGetOriginalCommand((Tcl_Command) cmdPtr);
  760.     if (origCmd != NULL) {
  761. cmdPtr = (Command *) origCmd;
  762.     }
  763.     if (cmdPtr->proc == TclProcInterpProc) {
  764. return (Proc *) cmdPtr->clientData;
  765.     }
  766.     return (Proc *) 0;
  767. }
  768. /*
  769.  *----------------------------------------------------------------------
  770.  *
  771.  * TclProcInterpProc --
  772.  *
  773.  * When a Tcl procedure gets invoked with an argc/argv array of
  774.  * strings, this routine gets invoked to interpret the procedure.
  775.  *
  776.  * Results:
  777.  * A standard Tcl result value, usually TCL_OK.
  778.  *
  779.  * Side effects:
  780.  * Depends on the commands in the procedure.
  781.  *
  782.  *----------------------------------------------------------------------
  783.  */
  784. int
  785. TclProcInterpProc(clientData, interp, argc, argv)
  786.     ClientData clientData; /* Record describing procedure to be
  787.  * interpreted. */
  788.     Tcl_Interp *interp; /* Interpreter in which procedure was
  789.  * invoked. */
  790.     int argc; /* Count of number of arguments to this
  791.  * procedure. */
  792.     register CONST char **argv; /* Argument values. */
  793. {
  794.     register Tcl_Obj *objPtr;
  795.     register int i;
  796.     int result;
  797.     /*
  798.      * This procedure generates an objv array for object arguments that hold
  799.      * the argv strings. It starts out with stack-allocated space but uses
  800.      * dynamically-allocated storage if needed.
  801.      */
  802. #define NUM_ARGS 20
  803.     Tcl_Obj *(objStorage[NUM_ARGS]);
  804.     register Tcl_Obj **objv = objStorage;
  805.     /*
  806.      * Create the object argument array "objv". Make sure objv is large
  807.      * enough to hold the objc arguments plus 1 extra for the zero
  808.      * end-of-objv word.
  809.      */
  810.     if ((argc + 1) > NUM_ARGS) {
  811. objv = (Tcl_Obj **)
  812.     ckalloc((unsigned)(argc + 1) * sizeof(Tcl_Obj *));
  813.     }
  814.     for (i = 0;  i < argc;  i++) {
  815. objv[i] = Tcl_NewStringObj(argv[i], -1);
  816. Tcl_IncrRefCount(objv[i]);
  817.     }
  818.     objv[argc] = 0;
  819.     /*
  820.      * Use TclObjInterpProc to actually interpret the procedure.
  821.      */
  822.     result = TclObjInterpProc(clientData, interp, argc, objv);
  823.     /*
  824.      * Move the interpreter's object result to the string result, 
  825.      * then reset the object result.
  826.      */
  827.     
  828.     Tcl_SetResult(interp, TclGetString(Tcl_GetObjResult(interp)),
  829.     TCL_VOLATILE);
  830.     /*
  831.      * Decrement the ref counts on the objv elements since we are done
  832.      * with them.
  833.      */
  834.     for (i = 0;  i < argc;  i++) {
  835. objPtr = objv[i];
  836. TclDecrRefCount(objPtr);
  837.     }
  838.     
  839.     /*
  840.      * Free the objv array if malloc'ed storage was used.
  841.      */
  842.     if (objv != objStorage) {
  843. ckfree((char *) objv);
  844.     }
  845.     return result;
  846. #undef NUM_ARGS
  847. }
  848. /*
  849.  *----------------------------------------------------------------------
  850.  *
  851.  * TclObjInterpProc --
  852.  *
  853.  * When a Tcl procedure gets invoked during bytecode evaluation, this 
  854.  * object-based routine gets invoked to interpret the procedure.
  855.  *
  856.  * Results:
  857.  * A standard Tcl object result value.
  858.  *
  859.  * Side effects:
  860.  * Depends on the commands in the procedure.
  861.  *
  862.  *----------------------------------------------------------------------
  863.  */
  864. int
  865. TclObjInterpProc(clientData, interp, objc, objv)
  866.     ClientData clientData;   /* Record describing procedure to be
  867.   * interpreted. */
  868.     register Tcl_Interp *interp; /* Interpreter in which procedure was
  869.   * invoked. */
  870.     int objc;  /* Count of number of arguments to this
  871.   * procedure. */
  872.     Tcl_Obj *CONST objv[];  /* Argument value objects. */
  873. {
  874.     Interp *iPtr = (Interp *) interp;
  875.     Proc *procPtr = (Proc *) clientData;
  876.     Namespace *nsPtr = procPtr->cmdPtr->nsPtr;
  877.     CallFrame frame;
  878.     register CallFrame *framePtr = &frame;
  879.     register Var *varPtr;
  880.     register CompiledLocal *localPtr;
  881.     char *procName;
  882.     int nameLen, localCt, numArgs, argCt, i, result;
  883.     /*
  884.      * This procedure generates an array "compiledLocals" that holds the
  885.      * storage for local variables. It starts out with stack-allocated space
  886.      * but uses dynamically-allocated storage if needed.
  887.      */
  888. #define NUM_LOCALS 20
  889.     Var localStorage[NUM_LOCALS];
  890.     Var *compiledLocals = localStorage;
  891.     /*
  892.      * Get the procedure's name.
  893.      */
  894.     
  895.     procName = Tcl_GetStringFromObj(objv[0], &nameLen);
  896.     /*
  897.      * If necessary, compile the procedure's body. The compiler will
  898.      * allocate frame slots for the procedure's non-argument local
  899.      * variables.  Note that compiling the body might increase
  900.      * procPtr->numCompiledLocals if new local variables are found
  901.      * while compiling.
  902.      */
  903.     result = ProcCompileProc(interp, procPtr, procPtr->bodyPtr, nsPtr,
  904.     "body of proc", procName, &procPtr);
  905.     
  906.     if (result != TCL_OK) {
  907.         return result;
  908.     }
  909.     /*
  910.      * Create the "compiledLocals" array. Make sure it is large enough to
  911.      * hold all the procedure's compiled local variables, including its
  912.      * formal parameters.
  913.      */
  914.     localCt = procPtr->numCompiledLocals;
  915.     if (localCt > NUM_LOCALS) {
  916. compiledLocals = (Var *) ckalloc((unsigned) localCt * sizeof(Var));
  917.     }
  918.     
  919.     /*
  920.      * Set up and push a new call frame for the new procedure invocation.
  921.      * This call frame will execute in the proc's namespace, which might
  922.      * be different than the current namespace. The proc's namespace is
  923.      * that of its command, which can change if the command is renamed
  924.      * from one namespace to another.
  925.      */
  926.     result = Tcl_PushCallFrame(interp, (Tcl_CallFrame *) framePtr,
  927.             (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 1);
  928.     if (result != TCL_OK) {
  929.         return result;
  930.     }
  931.     framePtr->objc = objc;
  932.     framePtr->objv = objv;  /* ref counts for args are incremented below */
  933.     /*
  934.      * Initialize and resolve compiled variable references.
  935.      */
  936.     framePtr->procPtr = procPtr;
  937.     framePtr->numCompiledLocals = localCt;
  938.     framePtr->compiledLocals = compiledLocals;
  939.     TclInitCompiledLocals(interp, framePtr, nsPtr);
  940.     /*
  941.      * Match and assign the call's actual parameters to the procedure's
  942.      * formal arguments. The formal arguments are described by the first
  943.      * numArgs entries in both the Proc structure's local variable list and
  944.      * the call frame's local variable array.
  945.      */
  946.     numArgs = procPtr->numArgs;
  947.     varPtr = framePtr->compiledLocals;
  948.     localPtr = procPtr->firstLocalPtr;
  949.     argCt = objc;
  950.     for (i = 1, argCt -= 1;  i <= numArgs;  i++, argCt--) {
  951. if (!TclIsVarArgument(localPtr)) {
  952.     panic("TclObjInterpProc: local variable %s is not argument but should be",
  953.   localPtr->name);
  954.     return TCL_ERROR;
  955. }
  956. if (TclIsVarTemporary(localPtr)) {
  957.     panic("TclObjInterpProc: local variable %d is temporary but should be an argument", i);
  958.     return TCL_ERROR;
  959. }
  960. /*
  961.  * Handle the special case of the last formal being "args".  When
  962.  * it occurs, assign it a list consisting of all the remaining
  963.  * actual arguments.
  964.  */
  965. if ((i == numArgs) && ((localPtr->name[0] == 'a')
  966.         && (strcmp(localPtr->name, "args") == 0))) {
  967.     Tcl_Obj *listPtr = Tcl_NewListObj(argCt, &(objv[i]));
  968.     varPtr->value.objPtr = listPtr;
  969.     Tcl_IncrRefCount(listPtr); /* local var is a reference */
  970.     TclClearVarUndefined(varPtr);
  971.     argCt = 0;
  972.     break; /* done processing args */
  973. } else if (argCt > 0) {
  974.     Tcl_Obj *objPtr = objv[i];
  975.     varPtr->value.objPtr = objPtr;
  976.     TclClearVarUndefined(varPtr);
  977.     Tcl_IncrRefCount(objPtr);  /* since the local variable now has
  978. * another reference to object. */
  979. } else if (localPtr->defValuePtr != NULL) {
  980.     Tcl_Obj *objPtr = localPtr->defValuePtr;
  981.     varPtr->value.objPtr = objPtr;
  982.     TclClearVarUndefined(varPtr);
  983.     Tcl_IncrRefCount(objPtr);  /* since the local variable now has
  984. * another reference to object. */
  985. } else {
  986.     goto incorrectArgs;
  987. }
  988. varPtr++;
  989. localPtr = localPtr->nextPtr;
  990.     }
  991.     if (argCt > 0) {
  992. Tcl_Obj *objResult;
  993. int len, flags;
  994. incorrectArgs:
  995. /*
  996.  * Build up equivalent to Tcl_WrongNumArgs message for proc
  997.  */
  998. Tcl_ResetResult(interp);
  999. objResult = Tcl_GetObjResult(interp);
  1000. Tcl_AppendToObj(objResult, "wrong # args: should be "", -1);
  1001. /*
  1002.  * Quote the proc name if it contains spaces (Bug 942757).
  1003.  */
  1004. len = Tcl_ScanCountedElement(procName, nameLen, &flags);
  1005. if (len != nameLen) {
  1006.     char *procName1 = ckalloc((unsigned) len);
  1007.     len = Tcl_ConvertCountedElement(procName, nameLen, procName1, flags);
  1008.     Tcl_AppendToObj(objResult, procName1, len);
  1009.     ckfree(procName1);
  1010. } else {
  1011.     Tcl_AppendToObj(objResult, procName, len);
  1012. }
  1013. localPtr = procPtr->firstLocalPtr;
  1014. for (i = 1;  i <= numArgs;  i++) {
  1015.     if (localPtr->defValuePtr != NULL) {
  1016. Tcl_AppendStringsToObj(objResult,
  1017. " ?", localPtr->name, "?", (char *) NULL);
  1018.     } else {
  1019. Tcl_AppendStringsToObj(objResult,
  1020. " ", localPtr->name, (char *) NULL);
  1021.     }
  1022.     localPtr = localPtr->nextPtr;
  1023. }
  1024. Tcl_AppendStringsToObj(objResult, """, (char *) NULL);
  1025. result = TCL_ERROR;
  1026. goto procDone;
  1027.     }
  1028.     /*
  1029.      * Invoke the commands in the procedure's body.
  1030.      */
  1031. #ifdef TCL_COMPILE_DEBUG
  1032.     if (tclTraceExec >= 1) {
  1033. fprintf(stdout, "Calling proc ");
  1034. for (i = 0;  i < objc;  i++) {
  1035.     TclPrintObject(stdout, objv[i], 15);
  1036.     fprintf(stdout, " ");
  1037. }
  1038. fprintf(stdout, "n");
  1039. fflush(stdout);
  1040.     }
  1041. #endif /*TCL_COMPILE_DEBUG*/
  1042.     if (TCL_DTRACE_PROC_ARGS_ENABLED()) {
  1043. char *a[10];
  1044. int i = 0;
  1045. while (i < 10) {
  1046.     a[i] = i < objc ? TclGetString(objv[i]) : NULL; i++;
  1047. }
  1048. TCL_DTRACE_PROC_ARGS(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7],
  1049. a[8], a[9]);
  1050.     }
  1051.     iPtr->returnCode = TCL_OK;
  1052.     procPtr->refCount++;
  1053.     if (TCL_DTRACE_PROC_ENTRY_ENABLED()) {
  1054. TCL_DTRACE_PROC_ENTRY(TclGetString(objv[0]), objc - 1,
  1055. (Tcl_Obj **)(objv + 1));
  1056.     }
  1057. #ifndef TCL_TIP280
  1058.     result = TclCompEvalObj(interp, procPtr->bodyPtr);
  1059. #else
  1060.     /* TIP #280: No need to set the invoking context here. The body has
  1061.      * already been compiled, so the part of CompEvalObj using it is bypassed.
  1062.      */
  1063.     result = TclCompEvalObj(interp, procPtr->bodyPtr, NULL, 0);
  1064. #endif
  1065.     if (TCL_DTRACE_PROC_RETURN_ENABLED()) {
  1066. TCL_DTRACE_PROC_RETURN(TclGetString(objv[0]), result);
  1067.     }
  1068.     procPtr->refCount--;
  1069.     if (procPtr->refCount <= 0) {
  1070. TclProcCleanupProc(procPtr);
  1071.     }
  1072.     if (result != TCL_OK) {
  1073. result = ProcessProcResultCode(interp, procName, nameLen, result);
  1074.     }
  1075.     
  1076.     if (TCL_DTRACE_PROC_RESULT_ENABLED()) {
  1077. Tcl_Obj *r;
  1078. r = Tcl_GetObjResult(interp);
  1079. TCL_DTRACE_PROC_RESULT(TclGetString(objv[0]), result,
  1080. TclGetString(r), r);
  1081.     }
  1082.     /*
  1083.      * Pop and free the call frame for this procedure invocation, then
  1084.      * free the compiledLocals array if malloc'ed storage was used.
  1085.      */
  1086.     
  1087.     procDone:
  1088.     Tcl_PopCallFrame(interp);
  1089.     if (compiledLocals != localStorage) {
  1090. ckfree((char *) compiledLocals);
  1091.     }
  1092.     return result;
  1093. #undef NUM_LOCALS
  1094. }
  1095. /*
  1096.  *----------------------------------------------------------------------
  1097.  *
  1098.  * TclProcCompileProc --
  1099.  *
  1100.  * Called just before a procedure is executed to compile the
  1101.  * body to byte codes.  If the type of the body is not
  1102.  * "byte code" or if the compile conditions have changed
  1103.  * (namespace context, epoch counters, etc.) then the body
  1104.  * is recompiled.  Otherwise, this procedure does nothing.
  1105.  *
  1106.  * Results:
  1107.  * None.
  1108.  *
  1109.  * Side effects:
  1110.  * May change the internal representation of the body object
  1111.  * to compiled code.
  1112.  *
  1113.  *----------------------------------------------------------------------
  1114.  */
  1115.  
  1116. int
  1117. TclProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description, procName)
  1118.     Tcl_Interp *interp; /* Interpreter containing procedure. */
  1119.     Proc *procPtr; /* Data associated with procedure. */
  1120.     Tcl_Obj *bodyPtr; /* Body of proc. (Usually procPtr->bodyPtr,
  1121.    * but could be any code fragment compiled
  1122.    * in the context of this procedure.) */
  1123.     Namespace *nsPtr; /* Namespace containing procedure. */
  1124.     CONST char *description; /* string describing this body of code. */
  1125.     CONST char *procName; /* Name of this procedure. */
  1126. {
  1127.     return ProcCompileProc(interp, procPtr, bodyPtr, nsPtr,
  1128.     description, procName, NULL);
  1129. }
  1130. static int
  1131. ProcCompileProc(interp, procPtr, bodyPtr, nsPtr, description,
  1132. procName, procPtrPtr)
  1133.     Tcl_Interp *interp; /* Interpreter containing procedure. */
  1134.     Proc *procPtr; /* Data associated with procedure. */
  1135.     Tcl_Obj *bodyPtr; /* Body of proc. (Usually procPtr->bodyPtr,
  1136.    * but could be any code fragment compiled
  1137.    * in the context of this procedure.) */
  1138.     Namespace *nsPtr; /* Namespace containing procedure. */
  1139.     CONST char *description; /* string describing this body of code. */
  1140.     CONST char *procName; /* Name of this procedure. */
  1141.     Proc **procPtrPtr; /* points to storage where a replacement
  1142.  * (Proc *) value may be written, when
  1143.  * appropriate */
  1144. {
  1145.     Interp *iPtr = (Interp*)interp;
  1146.     int i, result;
  1147.     Tcl_CallFrame frame;
  1148.     Proc *saveProcPtr;
  1149.     ByteCode *codePtr = (ByteCode *) bodyPtr->internalRep.otherValuePtr;
  1150.     CompiledLocal *localPtr;
  1151.  
  1152.     /*
  1153.      * If necessary, compile the procedure's body. The compiler will
  1154.      * allocate frame slots for the procedure's non-argument local
  1155.      * variables. If the ByteCode already exists, make sure it hasn't been
  1156.      * invalidated by someone redefining a core command (this might make the
  1157.      * compiled code wrong). Also, if the code was compiled in/for a
  1158.      * different interpreter, we recompile it. Note that compiling the body
  1159.      * might increase procPtr->numCompiledLocals if new local variables are
  1160.      * found while compiling.
  1161.      *
  1162.      * Precompiled procedure bodies, however, are immutable and therefore
  1163.      * they are not recompiled, even if things have changed.
  1164.      */
  1165.  
  1166.     if (bodyPtr->typePtr == &tclByteCodeType) {
  1167.   if (((Interp *) *codePtr->interpHandle != iPtr)
  1168.           || (codePtr->compileEpoch != iPtr->compileEpoch)
  1169.           || (codePtr->nsPtr != nsPtr)) {
  1170.             if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
  1171.                 if ((Interp *) *codePtr->interpHandle != iPtr) {
  1172.                     Tcl_AppendResult(interp,
  1173.                             "a precompiled script jumped interps", NULL);
  1174.                     return TCL_ERROR;
  1175.                 }
  1176.         codePtr->compileEpoch = iPtr->compileEpoch;
  1177.                 codePtr->nsPtr = nsPtr;
  1178.             } else {
  1179.                 (*tclByteCodeType.freeIntRepProc)(bodyPtr);
  1180.                 bodyPtr->typePtr = (Tcl_ObjType *) NULL;
  1181.             }
  1182.   }
  1183.     }
  1184.     if (bodyPtr->typePtr != &tclByteCodeType) {
  1185.   int numChars;
  1186.   char *ellipsis;
  1187.  
  1188. #ifdef TCL_COMPILE_DEBUG
  1189.   if (tclTraceCompile >= 1) {
  1190.       /*
  1191.        * Display a line summarizing the top level command we
  1192.        * are about to compile.
  1193.        */
  1194.  
  1195.       numChars = strlen(procName);
  1196.       ellipsis = "";
  1197.       if (numChars > 50) {
  1198.   numChars = 50;
  1199.   ellipsis = "...";
  1200.       }
  1201.       fprintf(stdout, "Compiling %s "%.*s%s"n",
  1202.       description, numChars, procName, ellipsis);
  1203.   }
  1204. #endif
  1205.  
  1206.   /*
  1207.    * Plug the current procPtr into the interpreter and coerce
  1208.    * the code body to byte codes.  The interpreter needs to
  1209.    * know which proc it's compiling so that it can access its
  1210.    * list of compiled locals.
  1211.    *
  1212.    * TRICKY NOTE:  Be careful to push a call frame with the
  1213.    *   proper namespace context, so that the byte codes are
  1214.    *   compiled in the appropriate class context.
  1215.    */
  1216.   saveProcPtr = iPtr->compiledProcPtr;
  1217. if (procPtrPtr != NULL && procPtr->refCount > 1) {
  1218.     Tcl_Command token;
  1219.     Tcl_CmdInfo info;
  1220.     Proc *new = (Proc *) ckalloc(sizeof(Proc));
  1221.     new->iPtr = procPtr->iPtr;
  1222.     new->refCount = 1;
  1223.     new->cmdPtr = procPtr->cmdPtr;
  1224.     token = (Tcl_Command) new->cmdPtr;
  1225.     new->bodyPtr = Tcl_DuplicateObj(bodyPtr);
  1226.     bodyPtr = new->bodyPtr;
  1227.     Tcl_IncrRefCount(bodyPtr);
  1228.     new->numArgs = procPtr->numArgs;
  1229.     new->numCompiledLocals = new->numArgs;
  1230.     new->firstLocalPtr = NULL;
  1231.     new->lastLocalPtr = NULL;
  1232.     localPtr = procPtr->firstLocalPtr;
  1233.     for (i = 0; i < new->numArgs; i++, localPtr = localPtr->nextPtr) {
  1234. CompiledLocal *copy = (CompiledLocal *) ckalloc((unsigned)
  1235. (sizeof(CompiledLocal) -sizeof(localPtr->name)
  1236.  + localPtr->nameLength + 1));
  1237. if (new->firstLocalPtr == NULL) {
  1238.     new->firstLocalPtr = new->lastLocalPtr = copy;
  1239. } else {
  1240.     new->lastLocalPtr->nextPtr = copy;
  1241.     new->lastLocalPtr = copy;
  1242. }
  1243. copy->nextPtr = NULL;
  1244. copy->nameLength = localPtr->nameLength;
  1245. copy->frameIndex = localPtr->frameIndex;
  1246. copy->flags = localPtr->flags;
  1247. copy->defValuePtr = localPtr->defValuePtr;
  1248. if (copy->defValuePtr) {
  1249.     Tcl_IncrRefCount(copy->defValuePtr);
  1250. }
  1251. copy->resolveInfo = localPtr->resolveInfo;
  1252. strcpy(copy->name, localPtr->name);
  1253.     }
  1254.     /* Reset the ClientData */
  1255.     Tcl_GetCommandInfoFromToken(token, &info);
  1256.     if (info.objClientData == (ClientData) procPtr) {
  1257.         info.objClientData = (ClientData) new;
  1258.     }
  1259.     if (info.clientData == (ClientData) procPtr) {
  1260.         info.clientData = (ClientData) new;
  1261.     }
  1262.     if (info.deleteData == (ClientData) procPtr) {
  1263.         info.deleteData = (ClientData) new;
  1264.     }
  1265.     Tcl_SetCommandInfoFromToken(token, &info);
  1266.     procPtr->refCount--;
  1267.     *procPtrPtr = procPtr = new;
  1268. }
  1269.   iPtr->compiledProcPtr = procPtr;
  1270.  
  1271.   result = Tcl_PushCallFrame(interp, &frame,
  1272. (Tcl_Namespace*)nsPtr, /* isProcCallFrame */ 0);
  1273.  
  1274.   if (result == TCL_OK) {
  1275. #ifdef TCL_TIP280
  1276.     /* TIP #280. We get the invoking context from the cmdFrame
  1277.      * which was saved by 'Tcl_ProcObjCmd' (using linePBodyPtr).
  1278.      */
  1279.     Tcl_HashEntry* hePtr = Tcl_FindHashEntry (iPtr->linePBodyPtr, (char *) procPtr);
  1280.     /* Constructed saved frame has body as word 0. See Tcl_ProcObjCmd.
  1281.      */
  1282.     iPtr->invokeWord        = 0;
  1283.     iPtr->invokeCmdFramePtr = (hePtr
  1284.        ? (CmdFrame*) Tcl_GetHashValue (hePtr)
  1285.        : NULL);
  1286. #endif
  1287.     result = tclByteCodeType.setFromAnyProc(interp, bodyPtr);
  1288. #ifdef TCL_TIP280
  1289.     iPtr->invokeCmdFramePtr = NULL;
  1290. #endif
  1291.     Tcl_PopCallFrame(interp);
  1292. }
  1293.  
  1294.   iPtr->compiledProcPtr = saveProcPtr;
  1295.  
  1296.   if (result != TCL_OK) {
  1297.       if (result == TCL_ERROR) {
  1298. char buf[100 + TCL_INTEGER_SPACE];
  1299. numChars = strlen(procName);
  1300.   ellipsis = "";
  1301.   if (numChars > 50) {
  1302.       numChars = 50;
  1303.       ellipsis = "...";
  1304.   }
  1305. while ( (procName[numChars] & 0xC0) == 0x80 ) {
  1306.             /*
  1307.      * Back up truncation point so that we don't truncate
  1308.      * in the middle of a multi-byte character (in UTF-8)
  1309.      */
  1310.     numChars--;
  1311.     ellipsis = "...";
  1312. }
  1313.   sprintf(buf, "n    (compiling %s "%.*s%s", line %d)",
  1314.   description, numChars, procName, ellipsis,
  1315.   interp->errorLine);
  1316.   Tcl_AddObjErrorInfo(interp, buf, -1);
  1317.       }
  1318.       return result;
  1319.   }
  1320.     } else if (codePtr->nsEpoch != nsPtr->resolverEpoch) {
  1321.  
  1322. /*
  1323.  * The resolver epoch has changed, but we only need to invalidate
  1324.  * the resolver cache.
  1325.  */
  1326. for (localPtr = procPtr->firstLocalPtr;  localPtr != NULL;
  1327.     localPtr = localPtr->nextPtr) {
  1328.     localPtr->flags &= ~(VAR_RESOLVED);
  1329.     if (localPtr->resolveInfo) {
  1330. if (localPtr->resolveInfo->deleteProc) {
  1331.     localPtr->resolveInfo->deleteProc(localPtr->resolveInfo);
  1332. } else {
  1333.     ckfree((char*)localPtr->resolveInfo);
  1334. }
  1335. localPtr->resolveInfo = NULL;
  1336.     }
  1337. }
  1338.     }
  1339.     return TCL_OK;
  1340. }
  1341. /*
  1342.  *----------------------------------------------------------------------
  1343.  *
  1344.  * ProcessProcResultCode --
  1345.  *
  1346.  * Procedure called by TclObjInterpProc to process a return code other
  1347.  * than TCL_OK returned by a Tcl procedure.
  1348.  *
  1349.  * Results:
  1350.  * Depending on the argument return code, the result returned is
  1351.  * another return code and the interpreter's result is set to a value
  1352.  * to supplement that return code.
  1353.  *
  1354.  * Side effects:
  1355.  * If the result returned is TCL_ERROR, traceback information about
  1356.  * the procedure just executed is appended to the interpreter's
  1357.  * "errorInfo" variable.
  1358.  *
  1359.  *----------------------------------------------------------------------
  1360.  */
  1361. static int
  1362. ProcessProcResultCode(interp, procName, nameLen, returnCode)
  1363.     Tcl_Interp *interp; /* The interpreter in which the procedure
  1364.  * was called and returned returnCode. */
  1365.     char *procName; /* Name of the procedure. Used for error
  1366.  * messages and trace information. */
  1367.     int nameLen; /* Number of bytes in procedure's name. */
  1368.     int returnCode; /* The unexpected result code. */
  1369. {
  1370.     Interp *iPtr = (Interp *) interp;
  1371.     char msg[100 + TCL_INTEGER_SPACE];
  1372.     char *ellipsis = "";
  1373.     if (returnCode == TCL_OK) {
  1374. return TCL_OK;
  1375.     }
  1376.     if ((returnCode > TCL_CONTINUE) || (returnCode < TCL_OK)) {
  1377. return returnCode;
  1378.     }
  1379.     if (returnCode == TCL_RETURN) {
  1380. return TclUpdateReturnInfo(iPtr);
  1381.     } 
  1382.     if (returnCode != TCL_ERROR) {
  1383. Tcl_ResetResult(interp);
  1384. Tcl_AppendToObj(Tcl_GetObjResult(interp), ((returnCode == TCL_BREAK) 
  1385. ? "invoked "break" outside of a loop"
  1386. : "invoked "continue" outside of a loop"), -1);
  1387.     }
  1388.     if (nameLen > 60) {
  1389. nameLen = 60;
  1390. ellipsis = "...";
  1391.     }
  1392.     while ( (procName[nameLen] & 0xC0) == 0x80 ) {
  1393.         /*
  1394.  * Back up truncation point so that we don't truncate in the
  1395.  * middle of a multi-byte character (in UTF-8)
  1396.  */
  1397. nameLen--;
  1398. ellipsis = "...";
  1399.     }
  1400.     sprintf(msg, "n    (procedure "%.*s%s" line %d)", nameLen, procName,
  1401.     ellipsis, iPtr->errorLine);
  1402.     Tcl_AddObjErrorInfo(interp, msg, -1);
  1403.     return TCL_ERROR;
  1404. }
  1405. /*
  1406.  *----------------------------------------------------------------------
  1407.  *
  1408.  * TclProcDeleteProc --
  1409.  *
  1410.  * This procedure is invoked just before a command procedure is
  1411.  * removed from an interpreter.  Its job is to release all the
  1412.  * resources allocated to the procedure.
  1413.  *
  1414.  * Results:
  1415.  * None.
  1416.  *
  1417.  * Side effects:
  1418.  * Memory gets freed, unless the procedure is actively being
  1419.  * executed.  In this case the cleanup is delayed until the
  1420.  * last call to the current procedure completes.
  1421.  *
  1422.  *----------------------------------------------------------------------
  1423.  */
  1424. void
  1425. TclProcDeleteProc(clientData)
  1426.     ClientData clientData; /* Procedure to be deleted. */
  1427. {
  1428.     Proc *procPtr = (Proc *) clientData;
  1429.     procPtr->refCount--;
  1430.     if (procPtr->refCount <= 0) {
  1431. TclProcCleanupProc(procPtr);
  1432.     }
  1433. }
  1434. /*
  1435.  *----------------------------------------------------------------------
  1436.  *
  1437.  * TclProcCleanupProc --
  1438.  *
  1439.  * This procedure does all the real work of freeing up a Proc
  1440.  * structure.  It's called only when the structure's reference
  1441.  * count becomes zero.
  1442.  *
  1443.  * Results:
  1444.  * None.
  1445.  *
  1446.  * Side effects:
  1447.  * Memory gets freed.
  1448.  *
  1449.  *----------------------------------------------------------------------
  1450.  */
  1451. void
  1452. TclProcCleanupProc(procPtr)
  1453.     register Proc *procPtr; /* Procedure to be deleted. */
  1454. {
  1455.     register CompiledLocal *localPtr;
  1456.     Tcl_Obj *bodyPtr = procPtr->bodyPtr;
  1457.     Tcl_Obj *defPtr;
  1458.     Tcl_ResolvedVarInfo *resVarInfo;
  1459. #ifdef TCL_TIP280
  1460.     Tcl_HashEntry* hePtr = NULL;
  1461.     CmdFrame*      cfPtr = NULL;
  1462.     Interp*        iPtr  = procPtr->iPtr;
  1463. #endif
  1464.     if (bodyPtr != NULL) {
  1465. Tcl_DecrRefCount(bodyPtr);
  1466.     }
  1467.     for (localPtr = procPtr->firstLocalPtr;  localPtr != NULL;  ) {
  1468. CompiledLocal *nextPtr = localPtr->nextPtr;
  1469.         resVarInfo = localPtr->resolveInfo;
  1470. if (resVarInfo) {
  1471.     if (resVarInfo->deleteProc) {
  1472. (*resVarInfo->deleteProc)(resVarInfo);
  1473.     } else {
  1474. ckfree((char *) resVarInfo);
  1475.     }
  1476.         }
  1477. if (localPtr->defValuePtr != NULL) {
  1478.     defPtr = localPtr->defValuePtr;
  1479.     Tcl_DecrRefCount(defPtr);
  1480. }
  1481. ckfree((char *) localPtr);
  1482. localPtr = nextPtr;
  1483.     }
  1484.     ckfree((char *) procPtr);
  1485. #ifdef TCL_TIP280
  1486.     /* TIP #280. Release the location data associated with this Proc
  1487.      * structure, if any. The interpreter may not exist (For example for
  1488.      * procbody structurues created by tbcload.
  1489.      */
  1490.     if (!iPtr) return;
  1491.     hePtr = Tcl_FindHashEntry (iPtr->linePBodyPtr, (char *) procPtr);
  1492.     if (!hePtr) return;
  1493.     cfPtr = (CmdFrame*) Tcl_GetHashValue (hePtr);
  1494.     if (cfPtr->type == TCL_LOCATION_SOURCE) {
  1495.         Tcl_DecrRefCount (cfPtr->data.eval.path);
  1496. cfPtr->data.eval.path = NULL;
  1497.     }
  1498.     ckfree ((char*) cfPtr->line); cfPtr->line = NULL;
  1499.     ckfree ((char*) cfPtr);
  1500.     Tcl_DeleteHashEntry (hePtr);
  1501. #endif
  1502. }
  1503. /*
  1504.  *----------------------------------------------------------------------
  1505.  *
  1506.  * TclUpdateReturnInfo --
  1507.  *
  1508.  * This procedure is called when procedures return, and at other
  1509.  * points where the TCL_RETURN code is used.  It examines fields
  1510.  * such as iPtr->returnCode and iPtr->errorCode and modifies
  1511.  * the real return status accordingly.
  1512.  *
  1513.  * Results:
  1514.  * The return value is the true completion code to use for
  1515.  * the procedure, instead of TCL_RETURN.
  1516.  *
  1517.  * Side effects:
  1518.  * The errorInfo and errorCode variables may get modified.
  1519.  *
  1520.  *----------------------------------------------------------------------
  1521.  */
  1522. int
  1523. TclUpdateReturnInfo(iPtr)
  1524.     Interp *iPtr; /* Interpreter for which TCL_RETURN
  1525.  * exception is being processed. */
  1526. {
  1527.     int code;
  1528.     char *errorCode;
  1529.     Tcl_Obj *objPtr;
  1530.     code = iPtr->returnCode;
  1531.     iPtr->returnCode = TCL_OK;
  1532.     if (code == TCL_ERROR) {
  1533. errorCode = ((iPtr->errorCode != NULL) ? iPtr->errorCode : "NONE");
  1534. objPtr = Tcl_NewStringObj(errorCode, -1);
  1535. Tcl_IncrRefCount(objPtr);
  1536. Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorCode,
  1537.         NULL, objPtr, TCL_GLOBAL_ONLY);
  1538. Tcl_DecrRefCount(objPtr);
  1539. iPtr->flags |= ERROR_CODE_SET;
  1540. if (iPtr->errorInfo != NULL) {
  1541.     objPtr = Tcl_NewStringObj(iPtr->errorInfo, -1);
  1542.     Tcl_IncrRefCount(objPtr);
  1543.     Tcl_ObjSetVar2((Tcl_Interp *) iPtr, iPtr->execEnvPtr->errorInfo,
  1544.     NULL, objPtr, TCL_GLOBAL_ONLY);
  1545.     Tcl_DecrRefCount(objPtr);
  1546.     iPtr->flags |= ERR_IN_PROGRESS;
  1547. }
  1548.     }
  1549.     return code;
  1550. }
  1551. /*
  1552.  *----------------------------------------------------------------------
  1553.  *
  1554.  * TclGetInterpProc --
  1555.  *
  1556.  *  Returns a pointer to the TclProcInterpProc procedure; this is different
  1557.  *  from the value obtained from the TclProcInterpProc reference on systems
  1558.  *  like Windows where import and export versions of a procedure exported
  1559.  *  by a DLL exist.
  1560.  *
  1561.  * Results:
  1562.  *  Returns the internal address of the TclProcInterpProc procedure.
  1563.  *
  1564.  * Side effects:
  1565.  *  None.
  1566.  *
  1567.  *----------------------------------------------------------------------
  1568.  */
  1569. TclCmdProcType
  1570. TclGetInterpProc()
  1571. {
  1572.     return (TclCmdProcType) TclProcInterpProc;
  1573. }
  1574. /*
  1575.  *----------------------------------------------------------------------
  1576.  *
  1577.  * TclGetObjInterpProc --
  1578.  *
  1579.  *  Returns a pointer to the TclObjInterpProc procedure; this is different
  1580.  *  from the value obtained from the TclObjInterpProc reference on systems
  1581.  *  like Windows where import and export versions of a procedure exported
  1582.  *  by a DLL exist.
  1583.  *
  1584.  * Results:
  1585.  *  Returns the internal address of the TclObjInterpProc procedure.
  1586.  *
  1587.  * Side effects:
  1588.  *  None.
  1589.  *
  1590.  *----------------------------------------------------------------------
  1591.  */
  1592. TclObjCmdProcType
  1593. TclGetObjInterpProc()
  1594. {
  1595.     return (TclObjCmdProcType) TclObjInterpProc;
  1596. }
  1597. /*
  1598.  *----------------------------------------------------------------------
  1599.  *
  1600.  * TclNewProcBodyObj --
  1601.  *
  1602.  *  Creates a new object, of type "procbody", whose internal
  1603.  *  representation is the given Proc struct.
  1604.  *  The newly created object's reference count is 0.
  1605.  *
  1606.  * Results:
  1607.  *  Returns a pointer to a newly allocated Tcl_Obj, 0 on error.
  1608.  *
  1609.  * Side effects:
  1610.  *  The reference count in the ByteCode attached to the Proc is bumped up
  1611.  *  by one, since the internal rep stores a pointer to it.
  1612.  *
  1613.  *----------------------------------------------------------------------
  1614.  */
  1615. Tcl_Obj *
  1616. TclNewProcBodyObj(procPtr)
  1617.     Proc *procPtr; /* the Proc struct to store as the internal
  1618.                          * representation. */
  1619. {
  1620.     Tcl_Obj *objPtr;
  1621.     if (!procPtr) {
  1622.         return (Tcl_Obj *) NULL;
  1623.     }
  1624.     
  1625.     objPtr = Tcl_NewStringObj("", 0);
  1626.     if (objPtr) {
  1627.         objPtr->typePtr = &tclProcBodyType;
  1628.         objPtr->internalRep.otherValuePtr = (VOID *) procPtr;
  1629.         procPtr->refCount++;
  1630.     }
  1631.     return objPtr;
  1632. }
  1633. /*
  1634.  *----------------------------------------------------------------------
  1635.  *
  1636.  * ProcBodyDup --
  1637.  *
  1638.  *  Tcl_ObjType's Dup function for the proc body object.
  1639.  *  Bumps the reference count on the Proc stored in the internal
  1640.  *  representation.
  1641.  *
  1642.  * Results:
  1643.  *  None.
  1644.  *
  1645.  * Side effects:
  1646.  *  Sets up the object in dupPtr to be a duplicate of the one in srcPtr.
  1647.  *
  1648.  *----------------------------------------------------------------------
  1649.  */
  1650. static void ProcBodyDup(srcPtr, dupPtr)
  1651.     Tcl_Obj *srcPtr; /* object to copy */
  1652.     Tcl_Obj *dupPtr; /* target object for the duplication */
  1653. {
  1654.     Proc *procPtr = (Proc *) srcPtr->internalRep.otherValuePtr;
  1655.     
  1656.     dupPtr->typePtr = &tclProcBodyType;
  1657.     dupPtr->internalRep.otherValuePtr = (VOID *) procPtr;
  1658.     procPtr->refCount++;
  1659. }
  1660. /*
  1661.  *----------------------------------------------------------------------
  1662.  *
  1663.  * ProcBodyFree --
  1664.  *
  1665.  *  Tcl_ObjType's Free function for the proc body object.
  1666.  *  The reference count on its Proc struct is decreased by 1; if the count
  1667.  *  reaches 0, the proc is freed.
  1668.  *
  1669.  * Results:
  1670.  *  None.
  1671.  *
  1672.  * Side effects:
  1673.  *  If the reference count on the Proc struct reaches 0, the struct is freed.
  1674.  *
  1675.  *----------------------------------------------------------------------
  1676.  */
  1677. static void
  1678. ProcBodyFree(objPtr)
  1679.     Tcl_Obj *objPtr; /* the object to clean up */
  1680. {
  1681.     Proc *procPtr = (Proc *) objPtr->internalRep.otherValuePtr;
  1682.     procPtr->refCount--;
  1683.     if (procPtr->refCount <= 0) {
  1684.         TclProcCleanupProc(procPtr);
  1685.     }
  1686. }
  1687. /*
  1688.  *----------------------------------------------------------------------
  1689.  *
  1690.  * ProcBodySetFromAny --
  1691.  *
  1692.  *  Tcl_ObjType's SetFromAny function for the proc body object.
  1693.  *  Calls panic.
  1694.  *
  1695.  * Results:
  1696.  *  Theoretically returns a TCL result code.
  1697.  *
  1698.  * Side effects:
  1699.  *  Calls panic, since we can't set the value of the object from a string
  1700.  *  representation (or any other internal ones).
  1701.  *
  1702.  *----------------------------------------------------------------------
  1703.  */
  1704. static int
  1705. ProcBodySetFromAny(interp, objPtr)
  1706.     Tcl_Interp *interp; /* current interpreter */
  1707.     Tcl_Obj *objPtr; /* object pointer */
  1708. {
  1709.     panic("called ProcBodySetFromAny");
  1710.     /*
  1711.      * this to keep compilers happy.
  1712.      */
  1713.     
  1714.     return TCL_OK;
  1715. }
  1716. /*
  1717.  *----------------------------------------------------------------------
  1718.  *
  1719.  * ProcBodyUpdateString --
  1720.  *
  1721.  *  Tcl_ObjType's UpdateString function for the proc body object.
  1722.  *  Calls panic.
  1723.  *
  1724.  * Results:
  1725.  *  None.
  1726.  *
  1727.  * Side effects:
  1728.  *  Calls panic, since we this type has no string representation.
  1729.  *
  1730.  *----------------------------------------------------------------------
  1731.  */
  1732. static void
  1733. ProcBodyUpdateString(objPtr)
  1734.     Tcl_Obj *objPtr; /* the object to update */
  1735. {
  1736.     panic("called ProcBodyUpdateString");
  1737. }
  1738. /*
  1739.  *----------------------------------------------------------------------
  1740.  *
  1741.  * TclCompileNoOp --
  1742.  *
  1743.  * Procedure called to compile noOp's
  1744.  *
  1745.  * Results:
  1746.  * The return value is TCL_OK, indicating successful compilation.
  1747.  *
  1748.  * Side effects:
  1749.  * Instructions are added to envPtr to execute a noOp at runtime.
  1750.  *
  1751.  *----------------------------------------------------------------------
  1752.  */
  1753. static int
  1754. TclCompileNoOp(interp, parsePtr, envPtr)
  1755.     Tcl_Interp *interp;         /* Used for error reporting. */
  1756.     Tcl_Parse *parsePtr;        /* Points to a parse structure for the
  1757.                                  * command created by Tcl_ParseCommand. */
  1758.     CompileEnv *envPtr;         /* Holds resulting instructions. */
  1759. {
  1760.     Tcl_Token *tokenPtr;
  1761.     int i, code;
  1762.     int savedStackDepth = envPtr->currStackDepth;
  1763.     tokenPtr = parsePtr->tokenPtr;
  1764.     for(i = 1; i < parsePtr->numWords; i++) {
  1765. tokenPtr = tokenPtr + tokenPtr->numComponents + 1;
  1766. envPtr->currStackDepth = savedStackDepth;
  1767. if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { 
  1768.     code = TclCompileTokens(interp, tokenPtr+1,
  1769.             tokenPtr->numComponents, envPtr);
  1770.     if (code != TCL_OK) {
  1771. return code;
  1772.     }
  1773.     TclEmitOpcode(INST_POP, envPtr);
  1774.     }
  1775.     envPtr->currStackDepth = savedStackDepth;
  1776.     TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0), envPtr);
  1777.     return TCL_OK;
  1778. }
  1779. /*
  1780.  * Local Variables:
  1781.  * mode: c
  1782.  * c-basic-offset: 4
  1783.  * fill-column: 78
  1784.  * End:
  1785.  */