os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclCompCmds.c
First public contribution.
4 * This file contains compilation procedures that compile various
5 * Tcl commands into a sequence of instructions ("bytecodes").
7 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
8 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
9 * Copyright (c) 2002 ActiveState Corporation.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 * RCS: @(#) $Id: tclCompCmds.c,v 1.39.2.6 2007/03/01 16:06:19 dkf Exp $
18 #include "tclCompile.h"
21 * Prototypes for procedures defined later in this file:
24 static ClientData DupForeachInfo _ANSI_ARGS_((ClientData clientData));
25 static void FreeForeachInfo _ANSI_ARGS_((ClientData clientData));
27 static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp,
28 Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags,
29 int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr));
31 static int TclPushVarName _ANSI_ARGS_((Tcl_Interp *interp,
32 Tcl_Token *varTokenPtr, CompileEnv *envPtr, int flags,
33 int *localIndexPtr, int *simpleVarNamePtr, int *isScalarPtr,
38 * Flags bits used by TclPushVarName.
41 #define TCL_CREATE_VAR 1 /* Create a compiled local if none is found */
42 #define TCL_NO_LARGE_INDEX 2 /* Do not return localIndex value > 255 */
45 * The structures below define the AuxData types defined in this file.
48 AuxDataType tclForeachInfoType = {
49 "ForeachInfo", /* name */
50 DupForeachInfo, /* dupProc */
51 FreeForeachInfo /* freeProc */
55 *----------------------------------------------------------------------
57 * TclCompileAppendCmd --
59 * Procedure called to compile the "append" command.
62 * The return value is a standard Tcl result, which is normally TCL_OK
63 * unless there was an error while parsing string. If an error occurs
64 * then the interpreter's result contains a standard error message. If
65 * complation fails because the command requires a second level of
66 * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
67 * command should be compiled "out of line" by emitting code to
68 * invoke its command procedure (Tcl_AppendObjCmd) at runtime.
71 * Instructions are added to envPtr to execute the "append" command
74 *----------------------------------------------------------------------
78 TclCompileAppendCmd(interp, parsePtr, envPtr)
79 Tcl_Interp *interp; /* Used for error reporting. */
80 Tcl_Parse *parsePtr; /* Points to a parse structure for the
81 * command created by Tcl_ParseCommand. */
82 CompileEnv *envPtr; /* Holds resulting instructions. */
84 Tcl_Token *varTokenPtr, *valueTokenPtr;
85 int simpleVarName, isScalar, localIndex, numWords;
89 /* TIP #280 : Remember the per-word line information of the current
90 * command. An index is used instead of a pointer as recursive compilation
91 * may reallocate, i.e. move, the array. This is also the reason to save
92 * the nuloc now, it may change during the course of the function.
94 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
95 int eclIndex = mapPtr->nuloc - 1;
98 numWords = parsePtr->numWords;
100 Tcl_ResetResult(interp);
101 Tcl_AppendToObj(Tcl_GetObjResult(interp),
102 "wrong # args: should be \"append varName ?value value ...?\"",
105 } else if (numWords == 2) {
107 * append varName === set varName
109 return TclCompileSetCmd(interp, parsePtr, envPtr);
110 } else if (numWords > 3) {
112 * APPEND instructions currently only handle one value
114 return TCL_OUT_LINE_COMPILE;
118 * Decide if we can use a frame slot for the var/array name or if we
119 * need to emit code to compute and push the name at runtime. We use a
120 * frame slot (entry in the array of local vars) if we are compiling a
121 * procedure body and if the name is simple text that does not include
122 * namespace qualifiers.
125 varTokenPtr = parsePtr->tokenPtr
126 + (parsePtr->tokenPtr->numComponents + 1);
128 code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR,
130 &localIndex, &simpleVarName, &isScalar);
132 &localIndex, &simpleVarName, &isScalar,
133 mapPtr->loc [eclIndex].line [1]);
135 if (code != TCL_OK) {
140 * We are doing an assignment, otherwise TclCompileSetCmd was called,
141 * so push the new value. This will need to be extended to push a
142 * value for each argument.
146 valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
147 if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
148 TclEmitPush(TclRegisterNewLiteral(envPtr,
149 valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr);
152 envPtr->line = mapPtr->loc [eclIndex].line [2];
154 code = TclCompileTokens(interp, valueTokenPtr+1,
155 valueTokenPtr->numComponents, envPtr);
156 if (code != TCL_OK) {
163 * Emit instructions to set/get the variable.
168 if (localIndex >= 0) {
169 if (localIndex <= 255) {
170 TclEmitInstInt1(INST_APPEND_SCALAR1, localIndex, envPtr);
172 TclEmitInstInt4(INST_APPEND_SCALAR4, localIndex, envPtr);
175 TclEmitOpcode(INST_APPEND_STK, envPtr);
178 if (localIndex >= 0) {
179 if (localIndex <= 255) {
180 TclEmitInstInt1(INST_APPEND_ARRAY1, localIndex, envPtr);
182 TclEmitInstInt4(INST_APPEND_ARRAY4, localIndex, envPtr);
185 TclEmitOpcode(INST_APPEND_ARRAY_STK, envPtr);
189 TclEmitOpcode(INST_APPEND_STK, envPtr);
197 *----------------------------------------------------------------------
199 * TclCompileBreakCmd --
201 * Procedure called to compile the "break" command.
204 * The return value is a standard Tcl result, which is TCL_OK unless
205 * there was an error during compilation. If an error occurs then
206 * the interpreter's result contains a standard error message.
209 * Instructions are added to envPtr to execute the "break" command
212 *----------------------------------------------------------------------
216 TclCompileBreakCmd(interp, parsePtr, envPtr)
217 Tcl_Interp *interp; /* Used for error reporting. */
218 Tcl_Parse *parsePtr; /* Points to a parse structure for the
219 * command created by Tcl_ParseCommand. */
220 CompileEnv *envPtr; /* Holds resulting instructions. */
222 if (parsePtr->numWords != 1) {
223 Tcl_ResetResult(interp);
224 Tcl_AppendToObj(Tcl_GetObjResult(interp),
225 "wrong # args: should be \"break\"", -1);
230 * Emit a break instruction.
233 TclEmitOpcode(INST_BREAK, envPtr);
238 *----------------------------------------------------------------------
240 * TclCompileCatchCmd --
242 * Procedure called to compile the "catch" command.
245 * The return value is a standard Tcl result, which is TCL_OK if
246 * compilation was successful. If an error occurs then the
247 * interpreter's result contains a standard error message and TCL_ERROR
248 * is returned. If the command is too complex for TclCompileCatchCmd,
249 * TCL_OUT_LINE_COMPILE is returned indicating that the catch command
250 * should be compiled "out of line" by emitting code to invoke its
251 * command procedure at runtime.
254 * Instructions are added to envPtr to execute the "catch" command
257 *----------------------------------------------------------------------
261 TclCompileCatchCmd(interp, parsePtr, envPtr)
262 Tcl_Interp *interp; /* Used for error reporting. */
263 Tcl_Parse *parsePtr; /* Points to a parse structure for the
264 * command created by Tcl_ParseCommand. */
265 CompileEnv *envPtr; /* Holds resulting instructions. */
268 Tcl_Token *cmdTokenPtr, *nameTokenPtr;
270 int localIndex, nameChars, range, startOffset, jumpDist;
272 int savedStackDepth = envPtr->currStackDepth;
275 /* TIP #280 : Remember the per-word line information of the current
276 * command. An index is used instead of a pointer as recursive compilation
277 * may reallocate, i.e. move, the array. This is also the reason to save
278 * the nuloc now, it may change during the course of the function.
280 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
281 int eclIndex = mapPtr->nuloc - 1;
284 if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
285 Tcl_ResetResult(interp);
286 Tcl_AppendToObj(Tcl_GetObjResult(interp),
287 "wrong # args: should be \"catch command ?varName?\"", -1);
292 * If a variable was specified and the catch command is at global level
293 * (not in a procedure), don't compile it inline: the payoff is
297 if ((parsePtr->numWords == 3) && (envPtr->procPtr == NULL)) {
298 return TCL_OUT_LINE_COMPILE;
302 * Make sure the variable name, if any, has no substitutions and just
303 * refers to a local scaler.
307 cmdTokenPtr = parsePtr->tokenPtr
308 + (parsePtr->tokenPtr->numComponents + 1);
309 if (parsePtr->numWords == 3) {
310 nameTokenPtr = cmdTokenPtr + (cmdTokenPtr->numComponents + 1);
311 if (nameTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
312 name = nameTokenPtr[1].start;
313 nameChars = nameTokenPtr[1].size;
314 if (!TclIsLocalScalar(name, nameChars)) {
315 return TCL_OUT_LINE_COMPILE;
317 localIndex = TclFindCompiledLocal(nameTokenPtr[1].start,
318 nameTokenPtr[1].size, /*create*/ 1,
319 /*flags*/ VAR_SCALAR, envPtr->procPtr);
321 return TCL_OUT_LINE_COMPILE;
326 * We will compile the catch command. Emit a beginCatch instruction at
327 * the start of the catch body: the subcommand it controls.
330 envPtr->exceptDepth++;
331 envPtr->maxExceptDepth =
332 TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
333 range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
334 TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr);
337 * If the body is a simple word, compile the instructions to
338 * eval it. Otherwise, compile instructions to substitute its
339 * text without catching, a catch instruction that resets the
340 * stack to what it was before substituting the body, and then
341 * an instruction to eval the body. Care has to be taken to
342 * register the correct startOffset for the catch range so that
343 * errors in the substitution are not catched [Bug 219184]
347 envPtr->line = mapPtr->loc [eclIndex].line [1];
349 if (cmdTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
350 startOffset = (envPtr->codeNext - envPtr->codeStart);
351 code = TclCompileCmdWord(interp, cmdTokenPtr+1, 1, envPtr);
353 code = TclCompileTokens(interp, cmdTokenPtr+1,
354 cmdTokenPtr->numComponents, envPtr);
355 startOffset = (envPtr->codeNext - envPtr->codeStart);
356 TclEmitOpcode(INST_EVAL_STK, envPtr);
358 envPtr->exceptArrayPtr[range].codeOffset = startOffset;
360 if (code != TCL_OK) {
361 code = TCL_OUT_LINE_COMPILE;
364 envPtr->exceptArrayPtr[range].numCodeBytes =
365 (envPtr->codeNext - envPtr->codeStart) - startOffset;
368 * The "no errors" epilogue code: store the body's result into the
369 * variable (if any), push "0" (TCL_OK) as the catch's "no error"
370 * result, and jump around the "error case" code.
373 if (localIndex != -1) {
374 if (localIndex <= 255) {
375 TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr);
377 TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr);
380 TclEmitOpcode(INST_POP, envPtr);
381 TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
382 TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup);
385 * The "error case" code: store the body's result into the variable (if
386 * any), then push the error result code. The initial PC offset here is
387 * the catch's error target.
390 envPtr->currStackDepth = savedStackDepth;
391 envPtr->exceptArrayPtr[range].catchOffset =
392 (envPtr->codeNext - envPtr->codeStart);
393 if (localIndex != -1) {
394 TclEmitOpcode(INST_PUSH_RESULT, envPtr);
395 if (localIndex <= 255) {
396 TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr);
398 TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr);
400 TclEmitOpcode(INST_POP, envPtr);
402 TclEmitOpcode(INST_PUSH_RETURN_CODE, envPtr);
406 * Update the target of the jump after the "no errors" code, then emit
407 * an endCatch instruction at the end of the catch command.
410 jumpDist = (envPtr->codeNext - envPtr->codeStart)
411 - jumpFixup.codeOffset;
412 if (TclFixupForwardJump(envPtr, &jumpFixup, jumpDist, 127)) {
413 panic("TclCompileCatchCmd: bad jump distance %d\n", jumpDist);
415 TclEmitOpcode(INST_END_CATCH, envPtr);
418 envPtr->currStackDepth = savedStackDepth + 1;
419 envPtr->exceptDepth--;
424 *----------------------------------------------------------------------
426 * TclCompileContinueCmd --
428 * Procedure called to compile the "continue" command.
431 * The return value is a standard Tcl result, which is TCL_OK unless
432 * there was an error while parsing string. If an error occurs then
433 * the interpreter's result contains a standard error message.
436 * Instructions are added to envPtr to execute the "continue" command
439 *----------------------------------------------------------------------
443 TclCompileContinueCmd(interp, parsePtr, envPtr)
444 Tcl_Interp *interp; /* Used for error reporting. */
445 Tcl_Parse *parsePtr; /* Points to a parse structure for the
446 * command created by Tcl_ParseCommand. */
447 CompileEnv *envPtr; /* Holds resulting instructions. */
450 * There should be no argument after the "continue".
453 if (parsePtr->numWords != 1) {
454 Tcl_ResetResult(interp);
455 Tcl_AppendToObj(Tcl_GetObjResult(interp),
456 "wrong # args: should be \"continue\"", -1);
461 * Emit a continue instruction.
464 TclEmitOpcode(INST_CONTINUE, envPtr);
469 *----------------------------------------------------------------------
471 * TclCompileExprCmd --
473 * Procedure called to compile the "expr" command.
476 * The return value is a standard Tcl result, which is TCL_OK
477 * unless there was an error while parsing string. If an error occurs
478 * then the interpreter's result contains a standard error message.
481 * Instructions are added to envPtr to execute the "expr" command
484 *----------------------------------------------------------------------
488 TclCompileExprCmd(interp, parsePtr, envPtr)
489 Tcl_Interp *interp; /* Used for error reporting. */
490 Tcl_Parse *parsePtr; /* Points to a parse structure for the
491 * command created by Tcl_ParseCommand. */
492 CompileEnv *envPtr; /* Holds resulting instructions. */
494 Tcl_Token *firstWordPtr;
496 if (parsePtr->numWords == 1) {
497 Tcl_ResetResult(interp);
498 Tcl_AppendToObj(Tcl_GetObjResult(interp),
499 "wrong # args: should be \"expr arg ?arg ...?\"", -1);
504 /* TIP #280 : Use the per-word line information of the current command.
506 envPtr->line = envPtr->extCmdMapPtr->loc [envPtr->extCmdMapPtr->nuloc - 1].line [1];
508 firstWordPtr = parsePtr->tokenPtr
509 + (parsePtr->tokenPtr->numComponents + 1);
510 return TclCompileExprWords(interp, firstWordPtr, (parsePtr->numWords-1),
515 *----------------------------------------------------------------------
517 * TclCompileForCmd --
519 * Procedure called to compile the "for" command.
522 * The return value is a standard Tcl result, which is TCL_OK unless
523 * there was an error while parsing string. If an error occurs then
524 * the interpreter's result contains a standard error message.
527 * Instructions are added to envPtr to execute the "for" command
530 *----------------------------------------------------------------------
533 TclCompileForCmd(interp, parsePtr, envPtr)
534 Tcl_Interp *interp; /* Used for error reporting. */
535 Tcl_Parse *parsePtr; /* Points to a parse structure for the
536 * command created by Tcl_ParseCommand. */
537 CompileEnv *envPtr; /* Holds resulting instructions. */
539 Tcl_Token *startTokenPtr, *testTokenPtr, *nextTokenPtr, *bodyTokenPtr;
540 JumpFixup jumpEvalCondFixup;
541 int testCodeOffset, bodyCodeOffset, nextCodeOffset, jumpDist;
542 int bodyRange, nextRange, code;
543 char buffer[32 + TCL_INTEGER_SPACE];
544 int savedStackDepth = envPtr->currStackDepth;
547 /* TIP #280 : Remember the per-word line information of the current
548 * command. An index is used instead of a pointer as recursive compilation
549 * may reallocate, i.e. move, the array. This is also the reason to save
550 * the nuloc now, it may change during the course of the function.
552 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
553 int eclIndex = mapPtr->nuloc - 1;
556 if (parsePtr->numWords != 5) {
557 Tcl_ResetResult(interp);
558 Tcl_AppendToObj(Tcl_GetObjResult(interp),
559 "wrong # args: should be \"for start test next command\"", -1);
564 * If the test expression requires substitutions, don't compile the for
565 * command inline. E.g., the expression might cause the loop to never
566 * execute or execute forever, as in "for {} "$x > 5" {incr x} {}".
569 startTokenPtr = parsePtr->tokenPtr
570 + (parsePtr->tokenPtr->numComponents + 1);
571 testTokenPtr = startTokenPtr + (startTokenPtr->numComponents + 1);
572 if (testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
573 return TCL_OUT_LINE_COMPILE;
577 * Bail out also if the body or the next expression require substitutions
578 * in order to insure correct behaviour [Bug 219166]
581 nextTokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1);
582 bodyTokenPtr = nextTokenPtr + (nextTokenPtr->numComponents + 1);
583 if ((nextTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)
584 || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) {
585 return TCL_OUT_LINE_COMPILE;
589 * Create ExceptionRange records for the body and the "next" command.
590 * The "next" command's ExceptionRange supports break but not continue
591 * (and has a -1 continueOffset).
594 envPtr->exceptDepth++;
595 envPtr->maxExceptDepth =
596 TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
597 bodyRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
598 nextRange = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
601 * Inline compile the initial command.
605 envPtr->line = mapPtr->loc [eclIndex].line [1];
607 code = TclCompileCmdWord(interp, startTokenPtr+1,
608 startTokenPtr->numComponents, envPtr);
609 if (code != TCL_OK) {
610 if (code == TCL_ERROR) {
611 Tcl_AddObjErrorInfo(interp,
612 "\n (\"for\" initial command)", -1);
616 TclEmitOpcode(INST_POP, envPtr);
619 * Jump to the evaluation of the condition. This code uses the "loop
620 * rotation" optimisation (which eliminates one branch from the loop).
621 * "for start cond next body" produces then:
624 * B: body : bodyCodeOffset
625 * next : nextCodeOffset, continueOffset
626 * A: cond -> result : testCodeOffset
630 TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
633 * Compile the loop body.
636 bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart);
639 envPtr->line = mapPtr->loc [eclIndex].line [4];
641 code = TclCompileCmdWord(interp, bodyTokenPtr+1,
642 bodyTokenPtr->numComponents, envPtr);
643 envPtr->currStackDepth = savedStackDepth + 1;
644 if (code != TCL_OK) {
645 if (code == TCL_ERROR) {
646 sprintf(buffer, "\n (\"for\" body line %d)",
648 Tcl_AddObjErrorInfo(interp, buffer, -1);
652 envPtr->exceptArrayPtr[bodyRange].numCodeBytes =
653 (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
654 TclEmitOpcode(INST_POP, envPtr);
658 * Compile the "next" subcommand.
661 nextCodeOffset = (envPtr->codeNext - envPtr->codeStart);
664 envPtr->line = mapPtr->loc [eclIndex].line [3];
666 envPtr->currStackDepth = savedStackDepth;
667 code = TclCompileCmdWord(interp, nextTokenPtr+1,
668 nextTokenPtr->numComponents, envPtr);
669 envPtr->currStackDepth = savedStackDepth + 1;
670 if (code != TCL_OK) {
671 if (code == TCL_ERROR) {
672 Tcl_AddObjErrorInfo(interp,
673 "\n (\"for\" loop-end command)", -1);
677 envPtr->exceptArrayPtr[nextRange].numCodeBytes =
678 (envPtr->codeNext - envPtr->codeStart)
680 TclEmitOpcode(INST_POP, envPtr);
681 envPtr->currStackDepth = savedStackDepth;
684 * Compile the test expression then emit the conditional jump that
685 * terminates the for.
688 testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
690 jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
691 if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
697 envPtr->line = mapPtr->loc [eclIndex].line [2];
699 envPtr->currStackDepth = savedStackDepth;
700 code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
701 if (code != TCL_OK) {
702 if (code == TCL_ERROR) {
703 Tcl_AddObjErrorInfo(interp,
704 "\n (\"for\" test expression)", -1);
708 envPtr->currStackDepth = savedStackDepth + 1;
710 jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
711 if (jumpDist > 127) {
712 TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
714 TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
718 * Set the loop's offsets and break target.
721 envPtr->exceptArrayPtr[bodyRange].codeOffset = bodyCodeOffset;
722 envPtr->exceptArrayPtr[bodyRange].continueOffset = nextCodeOffset;
724 envPtr->exceptArrayPtr[nextRange].codeOffset = nextCodeOffset;
726 envPtr->exceptArrayPtr[bodyRange].breakOffset =
727 envPtr->exceptArrayPtr[nextRange].breakOffset =
728 (envPtr->codeNext - envPtr->codeStart);
731 * The for command's result is an empty string.
734 envPtr->currStackDepth = savedStackDepth;
735 TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
739 envPtr->exceptDepth--;
744 *----------------------------------------------------------------------
746 * TclCompileForeachCmd --
748 * Procedure called to compile the "foreach" command.
751 * The return value is a standard Tcl result, which is TCL_OK if
752 * compilation was successful. If an error occurs then the
753 * interpreter's result contains a standard error message and TCL_ERROR
754 * is returned. If the command is too complex for TclCompileForeachCmd,
755 * TCL_OUT_LINE_COMPILE is returned indicating that the foreach command
756 * should be compiled "out of line" by emitting code to invoke its
757 * command procedure at runtime.
760 * Instructions are added to envPtr to execute the "foreach" command
763 n*----------------------------------------------------------------------
767 TclCompileForeachCmd(interp, parsePtr, envPtr)
768 Tcl_Interp *interp; /* Used for error reporting. */
769 Tcl_Parse *parsePtr; /* Points to a parse structure for the
770 * command created by Tcl_ParseCommand. */
771 CompileEnv *envPtr; /* Holds resulting instructions. */
773 Proc *procPtr = envPtr->procPtr;
774 ForeachInfo *infoPtr; /* Points to the structure describing this
775 * foreach command. Stored in a AuxData
776 * record in the ByteCode. */
777 int firstValueTemp; /* Index of the first temp var in the frame
778 * used to point to a value list. */
779 int loopCtTemp; /* Index of temp var holding the loop's
780 * iteration count. */
781 Tcl_Token *tokenPtr, *bodyTokenPtr;
782 unsigned char *jumpPc;
783 JumpFixup jumpFalseFixup;
784 int jumpDist, jumpBackDist, jumpBackOffset, infoIndex, range;
785 int numWords, numLists, numVars, loopIndex, tempVar, i, j, code;
786 char buffer[32 + TCL_INTEGER_SPACE];
787 int savedStackDepth = envPtr->currStackDepth;
790 /* TIP #280 : Remember the per-word line information of the current
791 * command. An index is used instead of a pointer as recursive compilation
792 * may reallocate, i.e. move, the array. This is also the reason to save
793 * the nuloc now, it may change during the course of the function.
795 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
796 int eclIndex = mapPtr->nuloc - 1;
801 * We parse the variable list argument words and create two arrays:
802 * varcList[i] is number of variables in i-th var list
803 * varvList[i] points to array of var names in i-th var list
806 #define STATIC_VAR_LIST_SIZE 5
807 int varcListStaticSpace[STATIC_VAR_LIST_SIZE];
808 CONST char **varvListStaticSpace[STATIC_VAR_LIST_SIZE];
809 int *varcList = varcListStaticSpace;
810 CONST char ***varvList = varvListStaticSpace;
813 * If the foreach command isn't in a procedure, don't compile it inline:
814 * the payoff is too small.
817 if (procPtr == NULL) {
818 return TCL_OUT_LINE_COMPILE;
821 numWords = parsePtr->numWords;
822 if ((numWords < 4) || (numWords%2 != 0)) {
823 Tcl_ResetResult(interp);
824 Tcl_AppendToObj(Tcl_GetObjResult(interp),
825 "wrong # args: should be \"foreach varList list ?varList list ...? command\"", -1);
830 * Bail out if the body requires substitutions
831 * in order to insure correct behaviour [Bug 219166]
833 for (i = 0, tokenPtr = parsePtr->tokenPtr;
835 i++, tokenPtr += (tokenPtr->numComponents + 1)) {
837 bodyTokenPtr = tokenPtr;
838 if (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
839 return TCL_OUT_LINE_COMPILE;
846 * Allocate storage for the varcList and varvList arrays if necessary.
849 numLists = (numWords - 2)/2;
850 if (numLists > STATIC_VAR_LIST_SIZE) {
851 varcList = (int *) ckalloc(numLists * sizeof(int));
852 varvList = (CONST char ***) ckalloc(numLists * sizeof(CONST char **));
854 for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
855 varcList[loopIndex] = 0;
856 varvList[loopIndex] = NULL;
860 * Set the exception stack depth.
863 envPtr->exceptDepth++;
864 envPtr->maxExceptDepth =
865 TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
868 * Break up each var list and set the varcList and varvList arrays.
869 * Don't compile the foreach inline if any var name needs substitutions
870 * or isn't a scalar, or if any var list needs substitutions.
874 for (i = 0, tokenPtr = parsePtr->tokenPtr;
876 i++, tokenPtr += (tokenPtr->numComponents + 1)) {
878 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
879 code = TCL_OUT_LINE_COMPILE;
882 /* Lots of copying going on here. Need a ListObj wizard
883 * to show a better way. */
887 Tcl_DStringInit(&varList);
888 Tcl_DStringAppend(&varList, tokenPtr[1].start,
890 code = Tcl_SplitList(interp, Tcl_DStringValue(&varList),
891 &varcList[loopIndex], &varvList[loopIndex]);
892 Tcl_DStringFree(&varList);
893 if (code != TCL_OK) {
896 numVars = varcList[loopIndex];
899 * If the variable list is empty, we can enter an infinite
900 * loop when the interpreted version would not. Take care to
901 * ensure this does not happen. [Bug 1671138]
905 code = TCL_OUT_LINE_COMPILE;
909 for (j = 0; j < numVars; j++) {
910 CONST char *varName = varvList[loopIndex][j];
911 if (!TclIsLocalScalar(varName, (int) strlen(varName))) {
912 code = TCL_OUT_LINE_COMPILE;
922 * We will compile the foreach command.
923 * Reserve (numLists + 1) temporary variables:
924 * - numLists temps to hold each value list
925 * - 1 temp for the loop counter (index of next element in each list)
926 * At this time we don't try to reuse temporaries; if there are two
927 * nonoverlapping foreach loops, they don't share any temps.
931 for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
932 tempVar = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
933 /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
934 if (loopIndex == 0) {
935 firstValueTemp = tempVar;
938 loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
939 /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
942 * Create and initialize the ForeachInfo and ForeachVarList data
943 * structures describing this command. Then create a AuxData record
944 * pointing to the ForeachInfo structure.
947 infoPtr = (ForeachInfo *) ckalloc((unsigned)
948 (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
949 infoPtr->numLists = numLists;
950 infoPtr->firstValueTemp = firstValueTemp;
951 infoPtr->loopCtTemp = loopCtTemp;
952 for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
953 ForeachVarList *varListPtr;
954 numVars = varcList[loopIndex];
955 varListPtr = (ForeachVarList *) ckalloc((unsigned)
956 sizeof(ForeachVarList) + (numVars * sizeof(int)));
957 varListPtr->numVars = numVars;
958 for (j = 0; j < numVars; j++) {
959 CONST char *varName = varvList[loopIndex][j];
960 int nameChars = strlen(varName);
961 varListPtr->varIndexes[j] = TclFindCompiledLocal(varName,
962 nameChars, /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
964 infoPtr->varLists[loopIndex] = varListPtr;
966 infoIndex = TclCreateAuxData((ClientData) infoPtr, &tclForeachInfoType, envPtr);
969 * Evaluate then store each value list in the associated temporary.
972 range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
975 for (i = 0, tokenPtr = parsePtr->tokenPtr;
977 i++, tokenPtr += (tokenPtr->numComponents + 1)) {
978 if ((i%2 == 0) && (i > 0)) {
980 envPtr->line = mapPtr->loc [eclIndex].line [i];
982 code = TclCompileTokens(interp, tokenPtr+1,
983 tokenPtr->numComponents, envPtr);
984 if (code != TCL_OK) {
988 tempVar = (firstValueTemp + loopIndex);
989 if (tempVar <= 255) {
990 TclEmitInstInt1(INST_STORE_SCALAR1, tempVar, envPtr);
992 TclEmitInstInt4(INST_STORE_SCALAR4, tempVar, envPtr);
994 TclEmitOpcode(INST_POP, envPtr);
1000 * Initialize the temporary var that holds the count of loop iterations.
1003 TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);
1006 * Top of loop code: assign each loop variable and check whether
1007 * to terminate the loop.
1010 envPtr->exceptArrayPtr[range].continueOffset =
1011 (envPtr->codeNext - envPtr->codeStart);
1012 TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
1013 TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);
1016 * Inline compile the loop body.
1020 envPtr->line = mapPtr->loc [eclIndex].line [bodyIndex];
1022 envPtr->exceptArrayPtr[range].codeOffset =
1023 (envPtr->codeNext - envPtr->codeStart);
1024 code = TclCompileCmdWord(interp, bodyTokenPtr+1,
1025 bodyTokenPtr->numComponents, envPtr);
1026 envPtr->currStackDepth = savedStackDepth + 1;
1027 if (code != TCL_OK) {
1028 if (code == TCL_ERROR) {
1029 sprintf(buffer, "\n (\"foreach\" body line %d)",
1031 Tcl_AddObjErrorInfo(interp, buffer, -1);
1035 envPtr->exceptArrayPtr[range].numCodeBytes =
1036 (envPtr->codeNext - envPtr->codeStart)
1037 - envPtr->exceptArrayPtr[range].codeOffset;
1038 TclEmitOpcode(INST_POP, envPtr);
1041 * Jump back to the test at the top of the loop. Generate a 4 byte jump
1042 * if the distance to the test is > 120 bytes. This is conservative and
1043 * ensures that we won't have to replace this jump if we later need to
1044 * replace the ifFalse jump with a 4 byte jump.
1047 jumpBackOffset = (envPtr->codeNext - envPtr->codeStart);
1049 (jumpBackOffset - envPtr->exceptArrayPtr[range].continueOffset);
1050 if (jumpBackDist > 120) {
1051 TclEmitInstInt4(INST_JUMP4, -jumpBackDist, envPtr);
1053 TclEmitInstInt1(INST_JUMP1, -jumpBackDist, envPtr);
1057 * Fix the target of the jump after the foreach_step test.
1060 jumpDist = (envPtr->codeNext - envPtr->codeStart)
1061 - jumpFalseFixup.codeOffset;
1062 if (TclFixupForwardJump(envPtr, &jumpFalseFixup, jumpDist, 127)) {
1064 * Update the loop body's starting PC offset since it moved down.
1067 envPtr->exceptArrayPtr[range].codeOffset += 3;
1070 * Update the jump back to the test at the top of the loop since it
1071 * also moved down 3 bytes.
1074 jumpBackOffset += 3;
1075 jumpPc = (envPtr->codeStart + jumpBackOffset);
1077 if (jumpBackDist > 120) {
1078 TclUpdateInstInt4AtPc(INST_JUMP4, -jumpBackDist, jumpPc);
1080 TclUpdateInstInt1AtPc(INST_JUMP1, -jumpBackDist, jumpPc);
1085 * Set the loop's break target.
1088 envPtr->exceptArrayPtr[range].breakOffset =
1089 (envPtr->codeNext - envPtr->codeStart);
1092 * The foreach command's result is an empty string.
1095 envPtr->currStackDepth = savedStackDepth;
1096 TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
1097 envPtr->currStackDepth = savedStackDepth + 1;
1100 for (loopIndex = 0; loopIndex < numLists; loopIndex++) {
1101 if (varvList[loopIndex] != (CONST char **) NULL) {
1102 ckfree((char *) varvList[loopIndex]);
1105 if (varcList != varcListStaticSpace) {
1106 ckfree((char *) varcList);
1107 ckfree((char *) varvList);
1109 envPtr->exceptDepth--;
1114 *----------------------------------------------------------------------
1118 * This procedure duplicates a ForeachInfo structure created as
1119 * auxiliary data during the compilation of a foreach command.
1122 * A pointer to a newly allocated copy of the existing ForeachInfo
1123 * structure is returned.
1126 * Storage for the copied ForeachInfo record is allocated. If the
1127 * original ForeachInfo structure pointed to any ForeachVarList
1128 * records, these structures are also copied and pointers to them
1129 * are stored in the new ForeachInfo record.
1131 *----------------------------------------------------------------------
1135 DupForeachInfo(clientData)
1136 ClientData clientData; /* The foreach command's compilation
1137 * auxiliary data to duplicate. */
1139 register ForeachInfo *srcPtr = (ForeachInfo *) clientData;
1140 ForeachInfo *dupPtr;
1141 register ForeachVarList *srcListPtr, *dupListPtr;
1142 int numLists = srcPtr->numLists;
1145 dupPtr = (ForeachInfo *) ckalloc((unsigned)
1146 (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
1147 dupPtr->numLists = numLists;
1148 dupPtr->firstValueTemp = srcPtr->firstValueTemp;
1149 dupPtr->loopCtTemp = srcPtr->loopCtTemp;
1151 for (i = 0; i < numLists; i++) {
1152 srcListPtr = srcPtr->varLists[i];
1153 numVars = srcListPtr->numVars;
1154 dupListPtr = (ForeachVarList *) ckalloc((unsigned)
1155 sizeof(ForeachVarList) + numVars*sizeof(int));
1156 dupListPtr->numVars = numVars;
1157 for (j = 0; j < numVars; j++) {
1158 dupListPtr->varIndexes[j] = srcListPtr->varIndexes[j];
1160 dupPtr->varLists[i] = dupListPtr;
1162 return (ClientData) dupPtr;
1166 *----------------------------------------------------------------------
1168 * FreeForeachInfo --
1170 * Procedure to free a ForeachInfo structure created as auxiliary data
1171 * during the compilation of a foreach command.
1177 * Storage for the ForeachInfo structure pointed to by the ClientData
1178 * argument is freed as is any ForeachVarList record pointed to by the
1179 * ForeachInfo structure.
1181 *----------------------------------------------------------------------
1185 FreeForeachInfo(clientData)
1186 ClientData clientData; /* The foreach command's compilation
1187 * auxiliary data to free. */
1189 register ForeachInfo *infoPtr = (ForeachInfo *) clientData;
1190 register ForeachVarList *listPtr;
1191 int numLists = infoPtr->numLists;
1194 for (i = 0; i < numLists; i++) {
1195 listPtr = infoPtr->varLists[i];
1196 ckfree((char *) listPtr);
1198 ckfree((char *) infoPtr);
1202 *----------------------------------------------------------------------
1204 * TclCompileIfCmd --
1206 * Procedure called to compile the "if" command.
1209 * The return value is a standard Tcl result, which is TCL_OK if
1210 * compilation was successful. If an error occurs then the
1211 * interpreter's result contains a standard error message and TCL_ERROR
1212 * is returned. If the command is too complex for TclCompileIfCmd,
1213 * TCL_OUT_LINE_COMPILE is returned indicating that the if command
1214 * should be compiled "out of line" by emitting code to invoke its
1215 * command procedure at runtime.
1218 * Instructions are added to envPtr to execute the "if" command
1221 *----------------------------------------------------------------------
1224 TclCompileIfCmd(interp, parsePtr, envPtr)
1225 Tcl_Interp *interp; /* Used for error reporting. */
1226 Tcl_Parse *parsePtr; /* Points to a parse structure for the
1227 * command created by Tcl_ParseCommand. */
1228 CompileEnv *envPtr; /* Holds resulting instructions. */
1230 JumpFixupArray jumpFalseFixupArray;
1231 /* Used to fix the ifFalse jump after each
1232 * test when its target PC is determined. */
1233 JumpFixupArray jumpEndFixupArray;
1234 /* Used to fix the jump after each "then"
1235 * body to the end of the "if" when that PC
1237 Tcl_Token *tokenPtr, *testTokenPtr;
1238 int jumpDist, jumpFalseDist;
1239 int jumpIndex = 0; /* avoid compiler warning. */
1240 int numWords, wordIdx, numBytes, j, code;
1243 int savedStackDepth = envPtr->currStackDepth;
1244 /* Saved stack depth at the start of the first
1245 * test; the envPtr current depth is restored
1246 * to this value at the start of each test. */
1247 int realCond = 1; /* set to 0 for static conditions: "if 0 {..}" */
1248 int boolVal; /* value of static condition */
1249 int compileScripts = 1;
1252 /* TIP #280 : Remember the per-word line information of the current
1253 * command. An index is used instead of a pointer as recursive compilation
1254 * may reallocate, i.e. move, the array. This is also the reason to save
1255 * the nuloc now, it may change during the course of the function.
1257 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
1258 int eclIndex = mapPtr->nuloc - 1;
1262 * Only compile the "if" command if all arguments are simple
1263 * words, in order to insure correct substitution [Bug 219166]
1266 tokenPtr = parsePtr->tokenPtr;
1268 numWords = parsePtr->numWords;
1270 for (wordIdx = 0; wordIdx < numWords; wordIdx++) {
1271 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
1272 return TCL_OUT_LINE_COMPILE;
1278 TclInitJumpFixupArray(&jumpFalseFixupArray);
1279 TclInitJumpFixupArray(&jumpEndFixupArray);
1283 * Each iteration of this loop compiles one "if expr ?then? body"
1284 * or "elseif expr ?then? body" clause.
1287 tokenPtr = parsePtr->tokenPtr;
1289 while (wordIdx < numWords) {
1291 * Stop looping if the token isn't "if" or "elseif".
1294 word = tokenPtr[1].start;
1295 numBytes = tokenPtr[1].size;
1296 if ((tokenPtr == parsePtr->tokenPtr)
1297 || ((numBytes == 6) && (strncmp(word, "elseif", 6) == 0))) {
1298 tokenPtr += (tokenPtr->numComponents + 1);
1303 if (wordIdx >= numWords) {
1305 "wrong # args: no expression after \"%.*s\" argument",
1306 (numBytes > 50 ? 50 : numBytes), word);
1307 Tcl_ResetResult(interp);
1308 Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1);
1314 * Compile the test expression then emit the conditional jump
1315 * around the "then" part.
1318 envPtr->currStackDepth = savedStackDepth;
1319 testTokenPtr = tokenPtr;
1324 * Find out if the condition is a constant.
1327 Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start,
1328 testTokenPtr[1].size);
1329 Tcl_IncrRefCount(boolObj);
1330 code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
1331 Tcl_DecrRefCount(boolObj);
1332 if (code == TCL_OK) {
1334 * A static condition
1341 Tcl_ResetResult(interp);
1343 envPtr->line = mapPtr->loc [eclIndex].line [wordIdx];
1345 code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
1346 if (code != TCL_OK) {
1347 if (code == TCL_ERROR) {
1348 Tcl_AddObjErrorInfo(interp,
1349 "\n (\"if\" test expression)", -1);
1353 if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) {
1354 TclExpandJumpFixupArray(&jumpFalseFixupArray);
1356 jumpIndex = jumpFalseFixupArray.next;
1357 jumpFalseFixupArray.next++;
1358 TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
1359 &(jumpFalseFixupArray.fixup[jumpIndex]));
1365 * Skip over the optional "then" before the then clause.
1368 tokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1);
1370 if (wordIdx >= numWords) {
1372 "wrong # args: no script following \"%.*s\" argument",
1373 (testTokenPtr->size > 50 ? 50 : testTokenPtr->size),
1374 testTokenPtr->start);
1375 Tcl_ResetResult(interp);
1376 Tcl_AppendToObj(Tcl_GetObjResult(interp), buffer, -1);
1380 if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
1381 word = tokenPtr[1].start;
1382 numBytes = tokenPtr[1].size;
1383 if ((numBytes == 4) && (strncmp(word, "then", 4) == 0)) {
1384 tokenPtr += (tokenPtr->numComponents + 1);
1386 if (wordIdx >= numWords) {
1387 Tcl_ResetResult(interp);
1388 Tcl_AppendToObj(Tcl_GetObjResult(interp),
1389 "wrong # args: no script following \"then\" argument", -1);
1397 * Compile the "then" command body.
1400 if (compileScripts) {
1402 envPtr->line = mapPtr->loc [eclIndex].line [wordIdx];
1404 envPtr->currStackDepth = savedStackDepth;
1405 code = TclCompileCmdWord(interp, tokenPtr+1,
1406 tokenPtr->numComponents, envPtr);
1407 if (code != TCL_OK) {
1408 if (code == TCL_ERROR) {
1409 sprintf(buffer, "\n (\"if\" then script line %d)",
1411 Tcl_AddObjErrorInfo(interp, buffer, -1);
1419 * Jump to the end of the "if" command. Both jumpFalseFixupArray and
1420 * jumpEndFixupArray are indexed by "jumpIndex".
1423 if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
1424 TclExpandJumpFixupArray(&jumpEndFixupArray);
1426 jumpEndFixupArray.next++;
1427 TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
1428 &(jumpEndFixupArray.fixup[jumpIndex]));
1431 * Fix the target of the jumpFalse after the test. Generate a 4 byte
1432 * jump if the distance is > 120 bytes. This is conservative, and
1433 * ensures that we won't have to replace this jump if we later also
1434 * need to replace the proceeding jump to the end of the "if" with a
1438 jumpDist = (envPtr->codeNext - envPtr->codeStart)
1439 - jumpFalseFixupArray.fixup[jumpIndex].codeOffset;
1440 if (TclFixupForwardJump(envPtr,
1441 &(jumpFalseFixupArray.fixup[jumpIndex]), jumpDist, 120)) {
1443 * Adjust the code offset for the proceeding jump to the end
1444 * of the "if" command.
1447 jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
1449 } else if (boolVal) {
1451 *We were processing an "if 1 {...}"; stop compiling
1458 *We were processing an "if 0 {...}"; reset so that
1459 * the rest (elseif, else) is compiled correctly
1466 tokenPtr += (tokenPtr->numComponents + 1);
1471 * Restore the current stack depth in the environment; the
1472 * "else" clause (or its default) will add 1 to this.
1475 envPtr->currStackDepth = savedStackDepth;
1478 * Check for the optional else clause. Do not compile
1479 * anything if this was an "if 1 {...}" case.
1482 if ((wordIdx < numWords)
1483 && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
1485 * There is an else clause. Skip over the optional "else" word.
1488 word = tokenPtr[1].start;
1489 numBytes = tokenPtr[1].size;
1490 if ((numBytes == 4) && (strncmp(word, "else", 4) == 0)) {
1491 tokenPtr += (tokenPtr->numComponents + 1);
1493 if (wordIdx >= numWords) {
1494 Tcl_ResetResult(interp);
1495 Tcl_AppendToObj(Tcl_GetObjResult(interp),
1496 "wrong # args: no script following \"else\" argument", -1);
1502 if (compileScripts) {
1504 * Compile the else command body.
1507 envPtr->line = mapPtr->loc [eclIndex].line [wordIdx];
1509 code = TclCompileCmdWord(interp, tokenPtr+1,
1510 tokenPtr->numComponents, envPtr);
1511 if (code != TCL_OK) {
1512 if (code == TCL_ERROR) {
1513 sprintf(buffer, "\n (\"if\" else script line %d)",
1515 Tcl_AddObjErrorInfo(interp, buffer, -1);
1522 * Make sure there are no words after the else clause.
1526 if (wordIdx < numWords) {
1527 Tcl_ResetResult(interp);
1528 Tcl_AppendToObj(Tcl_GetObjResult(interp),
1529 "wrong # args: extra words after \"else\" clause in \"if\" command", -1);
1535 * No else clause: the "if" command's result is an empty string.
1538 if (compileScripts) {
1539 TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
1544 * Fix the unconditional jumps to the end of the "if" command.
1547 for (j = jumpEndFixupArray.next; j > 0; j--) {
1548 jumpIndex = (j - 1); /* i.e. process the closest jump first */
1549 jumpDist = (envPtr->codeNext - envPtr->codeStart)
1550 - jumpEndFixupArray.fixup[jumpIndex].codeOffset;
1551 if (TclFixupForwardJump(envPtr,
1552 &(jumpEndFixupArray.fixup[jumpIndex]), jumpDist, 127)) {
1554 * Adjust the immediately preceeding "ifFalse" jump. We moved
1555 * it's target (just after this jump) down three bytes.
1558 unsigned char *ifFalsePc = envPtr->codeStart
1559 + jumpFalseFixupArray.fixup[jumpIndex].codeOffset;
1560 unsigned char opCode = *ifFalsePc;
1561 if (opCode == INST_JUMP_FALSE1) {
1562 jumpFalseDist = TclGetInt1AtPtr(ifFalsePc + 1);
1564 TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
1565 } else if (opCode == INST_JUMP_FALSE4) {
1566 jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
1568 TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
1570 panic("TclCompileIfCmd: unexpected opcode updating ifFalse jump");
1576 * Free the jumpFixupArray array if malloc'ed storage was used.
1580 envPtr->currStackDepth = savedStackDepth + 1;
1581 TclFreeJumpFixupArray(&jumpFalseFixupArray);
1582 TclFreeJumpFixupArray(&jumpEndFixupArray);
1587 *----------------------------------------------------------------------
1589 * TclCompileIncrCmd --
1591 * Procedure called to compile the "incr" command.
1594 * The return value is a standard Tcl result, which is TCL_OK if
1595 * compilation was successful. If an error occurs then the
1596 * interpreter's result contains a standard error message and TCL_ERROR
1597 * is returned. If the command is too complex for TclCompileIncrCmd,
1598 * TCL_OUT_LINE_COMPILE is returned indicating that the incr command
1599 * should be compiled "out of line" by emitting code to invoke its
1600 * command procedure at runtime.
1603 * Instructions are added to envPtr to execute the "incr" command
1606 *----------------------------------------------------------------------
1610 TclCompileIncrCmd(interp, parsePtr, envPtr)
1611 Tcl_Interp *interp; /* Used for error reporting. */
1612 Tcl_Parse *parsePtr; /* Points to a parse structure for the
1613 * command created by Tcl_ParseCommand. */
1614 CompileEnv *envPtr; /* Holds resulting instructions. */
1616 Tcl_Token *varTokenPtr, *incrTokenPtr;
1617 int simpleVarName, isScalar, localIndex, haveImmValue, immValue;
1621 /* TIP #280 : Remember the per-word line information of the current
1622 * command. An index is used instead of a pointer as recursive compilation
1623 * may reallocate, i.e. move, the array. This is also the reason to save
1624 * the nuloc now, it may change during the course of the function.
1626 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
1627 int eclIndex = mapPtr->nuloc - 1;
1630 if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
1631 Tcl_ResetResult(interp);
1632 Tcl_AppendToObj(Tcl_GetObjResult(interp),
1633 "wrong # args: should be \"incr varName ?increment?\"", -1);
1637 varTokenPtr = parsePtr->tokenPtr
1638 + (parsePtr->tokenPtr->numComponents + 1);
1640 code = TclPushVarName(interp, varTokenPtr, envPtr,
1641 (TCL_NO_LARGE_INDEX | TCL_CREATE_VAR),
1643 &localIndex, &simpleVarName, &isScalar);
1645 &localIndex, &simpleVarName, &isScalar,
1646 mapPtr->loc [eclIndex].line [1]);
1648 if (code != TCL_OK) {
1653 * If an increment is given, push it, but see first if it's a small
1659 if (parsePtr->numWords == 3) {
1660 incrTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
1661 if (incrTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
1662 CONST char *word = incrTokenPtr[1].start;
1663 int numBytes = incrTokenPtr[1].size;
1666 * Note there is a danger that modifying the string could have
1667 * undesirable side effects. In this case, TclLooksLikeInt has
1668 * no dependencies on shared strings so we should be safe.
1671 if (TclLooksLikeInt(word, numBytes)) {
1673 Tcl_Obj *intObj = Tcl_NewStringObj(word, numBytes);
1674 Tcl_IncrRefCount(intObj);
1675 code = Tcl_GetIntFromObj(NULL, intObj, &immValue);
1676 Tcl_DecrRefCount(intObj);
1677 if ((code == TCL_OK)
1678 && (-127 <= immValue) && (immValue <= 127)) {
1682 if (!haveImmValue) {
1684 TclRegisterNewLiteral(envPtr, word, numBytes), envPtr);
1688 envPtr->line = mapPtr->loc [eclIndex].line [2];
1690 code = TclCompileTokens(interp, incrTokenPtr+1,
1691 incrTokenPtr->numComponents, envPtr);
1692 if (code != TCL_OK) {
1696 } else { /* no incr amount given so use 1 */
1701 * Emit the instruction to increment the variable.
1704 if (simpleVarName) {
1706 if (localIndex >= 0) {
1708 TclEmitInstInt1(INST_INCR_SCALAR1_IMM, localIndex, envPtr);
1709 TclEmitInt1(immValue, envPtr);
1711 TclEmitInstInt1(INST_INCR_SCALAR1, localIndex, envPtr);
1715 TclEmitInstInt1(INST_INCR_SCALAR_STK_IMM, immValue, envPtr);
1717 TclEmitOpcode(INST_INCR_SCALAR_STK, envPtr);
1721 if (localIndex >= 0) {
1723 TclEmitInstInt1(INST_INCR_ARRAY1_IMM, localIndex, envPtr);
1724 TclEmitInt1(immValue, envPtr);
1726 TclEmitInstInt1(INST_INCR_ARRAY1, localIndex, envPtr);
1730 TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immValue, envPtr);
1732 TclEmitOpcode(INST_INCR_ARRAY_STK, envPtr);
1736 } else { /* non-simple variable name */
1738 TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr);
1740 TclEmitOpcode(INST_INCR_STK, envPtr);
1749 *----------------------------------------------------------------------
1751 * TclCompileLappendCmd --
1753 * Procedure called to compile the "lappend" command.
1756 * The return value is a standard Tcl result, which is normally TCL_OK
1757 * unless there was an error while parsing string. If an error occurs
1758 * then the interpreter's result contains a standard error message. If
1759 * complation fails because the command requires a second level of
1760 * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
1761 * command should be compiled "out of line" by emitting code to
1762 * invoke its command procedure (Tcl_LappendObjCmd) at runtime.
1765 * Instructions are added to envPtr to execute the "lappend" command
1768 *----------------------------------------------------------------------
1772 TclCompileLappendCmd(interp, parsePtr, envPtr)
1773 Tcl_Interp *interp; /* Used for error reporting. */
1774 Tcl_Parse *parsePtr; /* Points to a parse structure for the
1775 * command created by Tcl_ParseCommand. */
1776 CompileEnv *envPtr; /* Holds resulting instructions. */
1778 Tcl_Token *varTokenPtr, *valueTokenPtr;
1779 int simpleVarName, isScalar, localIndex, numWords;
1783 /* TIP #280 : Remember the per-word line information of the current
1784 * command. An index is used instead of a pointer as recursive compilation
1785 * may reallocate, i.e. move, the array. This is also the reason to save
1786 * the nuloc now, it may change during the course of the function.
1788 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
1789 int eclIndex = mapPtr->nuloc - 1;
1793 * If we're not in a procedure, don't compile.
1795 if (envPtr->procPtr == NULL) {
1796 return TCL_OUT_LINE_COMPILE;
1799 numWords = parsePtr->numWords;
1800 if (numWords == 1) {
1801 Tcl_ResetResult(interp);
1802 Tcl_AppendToObj(Tcl_GetObjResult(interp),
1803 "wrong # args: should be \"lappend varName ?value value ...?\"", -1);
1806 if (numWords != 3) {
1808 * LAPPEND instructions currently only handle one value appends
1810 return TCL_OUT_LINE_COMPILE;
1814 * Decide if we can use a frame slot for the var/array name or if we
1815 * need to emit code to compute and push the name at runtime. We use a
1816 * frame slot (entry in the array of local vars) if we are compiling a
1817 * procedure body and if the name is simple text that does not include
1818 * namespace qualifiers.
1821 varTokenPtr = parsePtr->tokenPtr
1822 + (parsePtr->tokenPtr->numComponents + 1);
1824 code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR,
1826 &localIndex, &simpleVarName, &isScalar);
1828 &localIndex, &simpleVarName, &isScalar,
1829 mapPtr->loc [eclIndex].line [1]);
1831 if (code != TCL_OK) {
1836 * If we are doing an assignment, push the new value.
1837 * In the no values case, create an empty object.
1841 valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
1842 if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
1843 TclEmitPush(TclRegisterNewLiteral(envPtr,
1844 valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr);
1847 envPtr->line = mapPtr->loc [eclIndex].line [2];
1849 code = TclCompileTokens(interp, valueTokenPtr+1,
1850 valueTokenPtr->numComponents, envPtr);
1851 if (code != TCL_OK) {
1858 * Emit instructions to set/get the variable.
1862 * The *_STK opcodes should be refactored to make better use of existing
1863 * LOAD/STORE instructions.
1865 if (simpleVarName) {
1867 if (localIndex >= 0) {
1868 if (localIndex <= 255) {
1869 TclEmitInstInt1(INST_LAPPEND_SCALAR1, localIndex, envPtr);
1871 TclEmitInstInt4(INST_LAPPEND_SCALAR4, localIndex, envPtr);
1874 TclEmitOpcode(INST_LAPPEND_STK, envPtr);
1877 if (localIndex >= 0) {
1878 if (localIndex <= 255) {
1879 TclEmitInstInt1(INST_LAPPEND_ARRAY1, localIndex, envPtr);
1881 TclEmitInstInt4(INST_LAPPEND_ARRAY4, localIndex, envPtr);
1884 TclEmitOpcode(INST_LAPPEND_ARRAY_STK, envPtr);
1888 TclEmitOpcode(INST_LAPPEND_STK, envPtr);
1896 *----------------------------------------------------------------------
1898 * TclCompileLindexCmd --
1900 * Procedure called to compile the "lindex" command.
1903 * The return value is a standard Tcl result, which is TCL_OK if the
1904 * compilation was successful. If the command cannot be byte-compiled,
1905 * TCL_OUT_LINE_COMPILE is returned. If an error occurs then the
1906 * interpreter's result contains an error message, and TCL_ERROR is
1910 * Instructions are added to envPtr to execute the "lindex" command
1913 *----------------------------------------------------------------------
1917 TclCompileLindexCmd(interp, parsePtr, envPtr)
1918 Tcl_Interp *interp; /* Used for error reporting. */
1919 Tcl_Parse *parsePtr; /* Points to a parse structure for the
1920 * command created by Tcl_ParseCommand. */
1921 CompileEnv *envPtr; /* Holds resulting instructions. */
1923 Tcl_Token *varTokenPtr;
1927 /* TIP #280 : Remember the per-word line information of the current
1928 * command. An index is used instead of a pointer as recursive compilation
1929 * may reallocate, i.e. move, the array. This is also the reason to save
1930 * the nuloc now, it may change during the course of the function.
1932 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
1933 int eclIndex = mapPtr->nuloc - 1;
1937 numWords = parsePtr->numWords;
1940 * Quit if too few args
1943 if ( numWords <= 1 ) {
1944 return TCL_OUT_LINE_COMPILE;
1947 varTokenPtr = parsePtr->tokenPtr
1948 + (parsePtr->tokenPtr->numComponents + 1);
1951 * Push the operands onto the stack.
1954 for ( i = 1 ; i < numWords ; i++ ) {
1955 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
1957 TclRegisterNewLiteral( envPtr, varTokenPtr[1].start,
1958 varTokenPtr[1].size), envPtr);
1961 envPtr->line = mapPtr->loc [eclIndex].line [i];
1963 code = TclCompileTokens(interp, varTokenPtr+1,
1964 varTokenPtr->numComponents, envPtr);
1965 if (code != TCL_OK) {
1969 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
1973 * Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI
1974 * if there are multiple index args.
1977 if ( numWords == 3 ) {
1978 TclEmitOpcode( INST_LIST_INDEX, envPtr );
1980 TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr );
1987 *----------------------------------------------------------------------
1989 * TclCompileListCmd --
1991 * Procedure called to compile the "list" command.
1994 * The return value is a standard Tcl result, which is normally TCL_OK
1995 * unless there was an error while parsing string. If an error occurs
1996 * then the interpreter's result contains a standard error message. If
1997 * complation fails because the command requires a second level of
1998 * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
1999 * command should be compiled "out of line" by emitting code to
2000 * invoke its command procedure (Tcl_ListObjCmd) at runtime.
2003 * Instructions are added to envPtr to execute the "list" command
2006 *----------------------------------------------------------------------
2010 TclCompileListCmd(interp, parsePtr, envPtr)
2011 Tcl_Interp *interp; /* Used for error reporting. */
2012 Tcl_Parse *parsePtr; /* Points to a parse structure for the
2013 * command created by Tcl_ParseCommand. */
2014 CompileEnv *envPtr; /* Holds resulting instructions. */
2017 /* TIP #280 : Remember the per-word line information of the current
2018 * command. An index is used instead of a pointer as recursive compilation
2019 * may reallocate, i.e. move, the array. This is also the reason to save
2020 * the nuloc now, it may change during the course of the function.
2022 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
2023 int eclIndex = mapPtr->nuloc - 1;
2027 * If we're not in a procedure, don't compile.
2029 if (envPtr->procPtr == NULL) {
2030 return TCL_OUT_LINE_COMPILE;
2033 if (parsePtr->numWords == 1) {
2038 TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
2041 * Push the all values onto the stack.
2043 Tcl_Token *valueTokenPtr;
2044 int i, code, numWords;
2046 numWords = parsePtr->numWords;
2048 valueTokenPtr = parsePtr->tokenPtr
2049 + (parsePtr->tokenPtr->numComponents + 1);
2050 for (i = 1; i < numWords; i++) {
2051 if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2052 TclEmitPush(TclRegisterNewLiteral(envPtr,
2053 valueTokenPtr[1].start, valueTokenPtr[1].size), envPtr);
2056 envPtr->line = mapPtr->loc [eclIndex].line [i];
2058 code = TclCompileTokens(interp, valueTokenPtr+1,
2059 valueTokenPtr->numComponents, envPtr);
2060 if (code != TCL_OK) {
2064 valueTokenPtr = valueTokenPtr + (valueTokenPtr->numComponents + 1);
2066 TclEmitInstInt4(INST_LIST, numWords - 1, envPtr);
2073 *----------------------------------------------------------------------
2075 * TclCompileLlengthCmd --
2077 * Procedure called to compile the "llength" command.
2080 * The return value is a standard Tcl result, which is TCL_OK if the
2081 * compilation was successful. If the command cannot be byte-compiled,
2082 * TCL_OUT_LINE_COMPILE is returned. If an error occurs then the
2083 * interpreter's result contains an error message, and TCL_ERROR is
2087 * Instructions are added to envPtr to execute the "llength" command
2090 *----------------------------------------------------------------------
2094 TclCompileLlengthCmd(interp, parsePtr, envPtr)
2095 Tcl_Interp *interp; /* Used for error reporting. */
2096 Tcl_Parse *parsePtr; /* Points to a parse structure for the
2097 * command created by Tcl_ParseCommand. */
2098 CompileEnv *envPtr; /* Holds resulting instructions. */
2100 Tcl_Token *varTokenPtr;
2104 /* TIP #280 : Remember the per-word line information of the current
2105 * command. An index is used instead of a pointer as recursive compilation
2106 * may reallocate, i.e. move, the array. This is also the reason to save
2107 * the nuloc now, it may change during the course of the function.
2109 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
2110 int eclIndex = mapPtr->nuloc - 1;
2113 if (parsePtr->numWords != 2) {
2114 Tcl_SetResult(interp, "wrong # args: should be \"llength list\"",
2118 varTokenPtr = parsePtr->tokenPtr
2119 + (parsePtr->tokenPtr->numComponents + 1);
2121 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2123 * We could simply count the number of elements here and push
2124 * that value, but that is too rare a case to waste the code space.
2126 TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start,
2127 varTokenPtr[1].size), envPtr);
2130 envPtr->line = mapPtr->loc [eclIndex].line [1];
2132 code = TclCompileTokens(interp, varTokenPtr+1,
2133 varTokenPtr->numComponents, envPtr);
2134 if (code != TCL_OK) {
2138 TclEmitOpcode(INST_LIST_LENGTH, envPtr);
2143 *----------------------------------------------------------------------
2145 * TclCompileLsetCmd --
2147 * Procedure called to compile the "lset" command.
2150 * The return value is a standard Tcl result, which is TCL_OK if
2151 * the compilation was successful. If the "lset" command is too
2152 * complex for this function, then TCL_OUT_LINE_COMPILE is returned,
2153 * indicating that the command should be compiled "out of line"
2154 * (that is, not byte-compiled). If an error occurs, TCL_ERROR is
2155 * returned, and the interpreter result contains an error message.
2158 * Instructions are added to envPtr to execute the "lset" command
2161 * The general template for execution of the "lset" command is:
2162 * (1) Instructions to push the variable name, unless the
2163 * variable is local to the stack frame.
2164 * (2) If the variable is an array element, instructions
2165 * to push the array element name.
2166 * (3) Instructions to push each of zero or more "index" arguments
2167 * to the stack, followed with the "newValue" element.
2168 * (4) Instructions to duplicate the variable name and/or array
2169 * element name onto the top of the stack, if either was
2170 * pushed at steps (1) and (2).
2171 * (5) The appropriate INST_LOAD_* instruction to place the
2172 * original value of the list variable at top of stack.
2173 * (6) At this point, the stack contains:
2174 * varName? arrayElementName? index1 index2 ... newValue oldList
2175 * The compiler emits one of INST_LSET_FLAT or INST_LSET_LIST
2176 * according as whether there is exactly one index element (LIST)
2177 * or either zero or else two or more (FLAT). This instruction
2178 * removes everything from the stack except for the two names
2179 * and pushes the new value of the variable.
2180 * (7) Finally, INST_STORE_* stores the new value in the variable
2181 * and cleans up the stack.
2183 *----------------------------------------------------------------------
2187 TclCompileLsetCmd( interp, parsePtr, envPtr )
2188 Tcl_Interp* interp; /* Tcl interpreter for error reporting */
2189 Tcl_Parse* parsePtr; /* Points to a parse structure for
2191 CompileEnv* envPtr; /* Holds the resulting instructions */
2194 int tempDepth; /* Depth used for emitting one part
2195 * of the code burst. */
2196 Tcl_Token* varTokenPtr; /* Pointer to the Tcl_Token representing
2197 * the parse of the variable name */
2199 int result; /* Status return from library calls */
2201 int localIndex; /* Index of var in local var table */
2202 int simpleVarName; /* Flag == 1 if var name is simple */
2203 int isScalar; /* Flag == 1 if scalar, 0 if array */
2208 /* TIP #280 : Remember the per-word line information of the current
2209 * command. An index is used instead of a pointer as recursive compilation
2210 * may reallocate, i.e. move, the array. This is also the reason to save
2211 * the nuloc now, it may change during the course of the function.
2213 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
2214 int eclIndex = mapPtr->nuloc - 1;
2217 /* Check argument count */
2219 if ( parsePtr->numWords < 3 ) {
2220 /* Fail at run time, not in compilation */
2221 return TCL_OUT_LINE_COMPILE;
2225 * Decide if we can use a frame slot for the var/array name or if we
2226 * need to emit code to compute and push the name at runtime. We use a
2227 * frame slot (entry in the array of local vars) if we are compiling a
2228 * procedure body and if the name is simple text that does not include
2229 * namespace qualifiers.
2232 varTokenPtr = parsePtr->tokenPtr
2233 + (parsePtr->tokenPtr->numComponents + 1);
2234 result = TclPushVarName( interp, varTokenPtr, envPtr,
2236 TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar );
2238 TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar,
2239 mapPtr->loc [eclIndex].line [1]);
2241 if (result != TCL_OK) {
2245 /* Push the "index" args and the new element value. */
2247 for ( i = 2; i < parsePtr->numWords; ++i ) {
2249 /* Advance to next arg */
2251 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
2255 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2256 TclEmitPush(TclRegisterNewLiteral( envPtr, varTokenPtr[1].start,
2257 varTokenPtr[1].size), envPtr);
2260 envPtr->line = mapPtr->loc [eclIndex].line [i];
2262 result = TclCompileTokens(interp, varTokenPtr+1,
2263 varTokenPtr->numComponents, envPtr);
2264 if ( result != TCL_OK ) {
2271 * Duplicate the variable name if it's been pushed.
2274 if ( !simpleVarName || localIndex < 0 ) {
2275 if ( !simpleVarName || isScalar ) {
2276 tempDepth = parsePtr->numWords - 2;
2278 tempDepth = parsePtr->numWords - 1;
2280 TclEmitInstInt4( INST_OVER, tempDepth, envPtr );
2284 * Duplicate an array index if one's been pushed
2287 if ( simpleVarName && !isScalar ) {
2288 if ( localIndex < 0 ) {
2289 tempDepth = parsePtr->numWords - 1;
2291 tempDepth = parsePtr->numWords - 2;
2293 TclEmitInstInt4( INST_OVER, tempDepth, envPtr );
2297 * Emit code to load the variable's value.
2300 if ( !simpleVarName ) {
2301 TclEmitOpcode( INST_LOAD_STK, envPtr );
2302 } else if ( isScalar ) {
2303 if ( localIndex < 0 ) {
2304 TclEmitOpcode( INST_LOAD_SCALAR_STK, envPtr );
2305 } else if ( localIndex < 0x100 ) {
2306 TclEmitInstInt1( INST_LOAD_SCALAR1, localIndex, envPtr );
2308 TclEmitInstInt4( INST_LOAD_SCALAR4, localIndex, envPtr );
2311 if ( localIndex < 0 ) {
2312 TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr );
2313 } else if ( localIndex < 0x100 ) {
2314 TclEmitInstInt1( INST_LOAD_ARRAY1, localIndex, envPtr );
2316 TclEmitInstInt4( INST_LOAD_ARRAY4, localIndex, envPtr );
2321 * Emit the correct variety of 'lset' instruction
2324 if ( parsePtr->numWords == 4 ) {
2325 TclEmitOpcode( INST_LSET_LIST, envPtr );
2327 TclEmitInstInt4( INST_LSET_FLAT, (parsePtr->numWords - 1), envPtr );
2331 * Emit code to put the value back in the variable
2334 if ( !simpleVarName ) {
2335 TclEmitOpcode( INST_STORE_STK, envPtr );
2336 } else if ( isScalar ) {
2337 if ( localIndex < 0 ) {
2338 TclEmitOpcode( INST_STORE_SCALAR_STK, envPtr );
2339 } else if ( localIndex < 0x100 ) {
2340 TclEmitInstInt1( INST_STORE_SCALAR1, localIndex, envPtr );
2342 TclEmitInstInt4( INST_STORE_SCALAR4, localIndex, envPtr );
2345 if ( localIndex < 0 ) {
2346 TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr );
2347 } else if ( localIndex < 0x100 ) {
2348 TclEmitInstInt1( INST_STORE_ARRAY1, localIndex, envPtr );
2350 TclEmitInstInt4( INST_STORE_ARRAY4, localIndex, envPtr );
2359 *----------------------------------------------------------------------
2361 * TclCompileRegexpCmd --
2363 * Procedure called to compile the "regexp" command.
2366 * The return value is a standard Tcl result, which is TCL_OK if
2367 * the compilation was successful. If the "regexp" command is too
2368 * complex for this function, then TCL_OUT_LINE_COMPILE is returned,
2369 * indicating that the command should be compiled "out of line"
2370 * (that is, not byte-compiled). If an error occurs, TCL_ERROR is
2371 * returned, and the interpreter result contains an error message.
2374 * Instructions are added to envPtr to execute the "regexp" command
2377 *----------------------------------------------------------------------
2381 TclCompileRegexpCmd(interp, parsePtr, envPtr)
2382 Tcl_Interp* interp; /* Tcl interpreter for error reporting */
2383 Tcl_Parse* parsePtr; /* Points to a parse structure for
2385 CompileEnv* envPtr; /* Holds the resulting instructions */
2387 Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing
2388 * the parse of the RE or string */
2389 int i, len, code, nocase, anchorLeft, anchorRight, start;
2393 /* TIP #280 : Remember the per-word line information of the current
2394 * command. An index is used instead of a pointer as recursive compilation
2395 * may reallocate, i.e. move, the array. This is also the reason to save
2396 * the nuloc now, it may change during the course of the function.
2398 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
2399 int eclIndex = mapPtr->nuloc - 1;
2403 * We are only interested in compiling simple regexp cases.
2404 * Currently supported compile cases are:
2405 * regexp ?-nocase? ?--? staticString $var
2406 * regexp ?-nocase? ?--? {^staticString$} $var
2408 if (parsePtr->numWords < 3) {
2409 return TCL_OUT_LINE_COMPILE;
2413 varTokenPtr = parsePtr->tokenPtr;
2416 * We only look for -nocase and -- as options. Everything else
2417 * gets pushed to runtime execution. This is different than regexp's
2418 * runtime option handling, but satisfies our stricter needs.
2420 for (i = 1; i < parsePtr->numWords - 2; i++) {
2421 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
2422 if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
2423 /* Not a simple string - punt to runtime. */
2424 return TCL_OUT_LINE_COMPILE;
2426 str = (char *) varTokenPtr[1].start;
2427 len = varTokenPtr[1].size;
2428 if ((len == 2) && (str[0] == '-') && (str[1] == '-')) {
2431 } else if ((len > 1)
2432 && (strncmp(str, "-nocase", (unsigned) len) == 0)) {
2435 /* Not an option we recognize. */
2436 return TCL_OUT_LINE_COMPILE;
2440 if ((parsePtr->numWords - i) != 2) {
2441 /* We don't support capturing to variables */
2442 return TCL_OUT_LINE_COMPILE;
2446 * Get the regexp string. If it is not a simple string, punt to runtime.
2447 * If it has a '-', it could be an incorrectly formed regexp command.
2449 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
2450 str = (char *) varTokenPtr[1].start;
2451 len = varTokenPtr[1].size;
2452 if ((varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) || (*str == '-')) {
2453 return TCL_OUT_LINE_COMPILE;
2458 * The semantics of regexp are always match on re == "".
2460 TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
2465 * Make a copy of the string that is null-terminated for checks which
2468 str = (char *) ckalloc((unsigned) len + 1);
2469 strncpy(str, varTokenPtr[1].start, (size_t) len);
2474 * Check for anchored REs (ie ^foo$), so we can use string equal if
2475 * possible. Do not alter the start of str so we can free it correctly.
2477 if (str[0] == '^') {
2483 if ((str[len-1] == '$') && ((len == 1) || (str[len-2] != '\\'))) {
2491 * On the first (pattern) arg, check to see if any RE special characters
2492 * are in the word. If not, this is the same as 'string equal'.
2494 if ((len > (1+start)) && (str[start] == '.') && (str[start+1] == '*')) {
2498 if ((len > (2+start)) && (str[len-3] != '\\')
2499 && (str[len-2] == '.') && (str[len-1] == '*')) {
2506 * Don't do anything with REs with other special chars. Also check if
2507 * this is a bad RE (do this at the end because it can be expensive).
2508 * If so, let it complain at runtime.
2510 if ((strpbrk(str + start, "*+?{}()[].\\|^$") != NULL)
2511 || (Tcl_RegExpCompile(NULL, str) == NULL)) {
2512 ckfree((char *) str);
2513 return TCL_OUT_LINE_COMPILE;
2516 if (anchorLeft && anchorRight) {
2517 TclEmitPush(TclRegisterNewLiteral(envPtr, str+start, len-start),
2521 * This needs to find the substring anywhere in the string, so
2522 * use string match and *foo*, with appropriate anchoring.
2524 char *newStr = ckalloc((unsigned) len + 3);
2527 strncpy(newStr, str + start, (size_t) len);
2530 strncpy(newStr + 1, str + start, (size_t) len++);
2533 newStr[len++] = '*';
2536 TclEmitPush(TclRegisterNewLiteral(envPtr, newStr, len), envPtr);
2537 ckfree((char *) newStr);
2539 ckfree((char *) str);
2542 * Push the string arg
2544 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
2545 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2546 TclEmitPush(TclRegisterNewLiteral(envPtr,
2547 varTokenPtr[1].start, varTokenPtr[1].size), envPtr);
2550 envPtr->line = mapPtr->loc [eclIndex].line [parsePtr->numWords-1];
2552 code = TclCompileTokens(interp, varTokenPtr+1,
2553 varTokenPtr->numComponents, envPtr);
2554 if (code != TCL_OK) {
2559 if (anchorLeft && anchorRight && !nocase) {
2560 TclEmitOpcode(INST_STR_EQ, envPtr);
2562 TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr);
2569 *----------------------------------------------------------------------
2571 * TclCompileReturnCmd --
2573 * Procedure called to compile the "return" command.
2576 * The return value is a standard Tcl result, which is TCL_OK if the
2577 * compilation was successful. If the particular return command is
2578 * too complex for this function (ie, return with any flags like "-code"
2579 * or "-errorinfo"), TCL_OUT_LINE_COMPILE is returned, indicating that
2580 * the command should be compiled "out of line" (eg, not byte compiled).
2581 * If an error occurs then the interpreter's result contains a standard
2585 * Instructions are added to envPtr to execute the "return" command
2588 *----------------------------------------------------------------------
2592 TclCompileReturnCmd(interp, parsePtr, envPtr)
2593 Tcl_Interp *interp; /* Used for error reporting. */
2594 Tcl_Parse *parsePtr; /* Points to a parse structure for the
2595 * command created by Tcl_ParseCommand. */
2596 CompileEnv *envPtr; /* Holds resulting instructions. */
2598 Tcl_Token *varTokenPtr;
2600 int index = envPtr->exceptArrayNext - 1;
2603 /* TIP #280 : Remember the per-word line information of the current
2604 * command. An index is used instead of a pointer as recursive compilation
2605 * may reallocate, i.e. move, the array. This is also the reason to save
2606 * the nuloc now, it may change during the course of the function.
2608 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
2609 int eclIndex = mapPtr->nuloc - 1;
2613 * If we're not in a procedure, don't compile.
2616 if (envPtr->procPtr == NULL) {
2617 return TCL_OUT_LINE_COMPILE;
2621 * Look back through the ExceptionRanges of the current CompileEnv,
2622 * from exceptArrayPtr[(exceptArrayNext - 1)] down to
2623 * exceptArrayPtr[0] to see if any of them is an enclosing [catch].
2624 * If there's an enclosing [catch], don't compile.
2627 while (index >= 0) {
2628 ExceptionRange range = envPtr->exceptArrayPtr[index];
2629 if ((range.type == CATCH_EXCEPTION_RANGE)
2630 && (range.catchOffset == -1)) {
2631 return TCL_OUT_LINE_COMPILE;
2636 switch (parsePtr->numWords) {
2639 * Simple case: [return]
2640 * Just push the literal string "".
2642 TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
2647 * More complex cases:
2650 * [return [otherCmd]]
2652 varTokenPtr = parsePtr->tokenPtr
2653 + (parsePtr->tokenPtr->numComponents + 1);
2654 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2656 * [return "foo"] case: the parse token is a simple word,
2659 TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start,
2660 varTokenPtr[1].size), envPtr);
2663 * Parse token is more complex, so compile it; this handles the
2664 * variable reference and nested command cases. If the
2665 * parse token can be byte-compiled, then this instance of
2666 * "return" will be byte-compiled; otherwise it will be
2667 * out line compiled.
2670 envPtr->line = mapPtr->loc [eclIndex].line [1];
2672 code = TclCompileTokens(interp, varTokenPtr+1,
2673 varTokenPtr->numComponents, envPtr);
2674 if (code != TCL_OK) {
2682 * Most complex return cases: everything else, including
2683 * [return -code error], etc.
2685 return TCL_OUT_LINE_COMPILE;
2690 * The INST_DONE opcode actually causes the branching out of the
2691 * subroutine, and takes the top stack item as the return result
2692 * (which is why we pushed the value above).
2694 TclEmitOpcode(INST_DONE, envPtr);
2699 *----------------------------------------------------------------------
2701 * TclCompileSetCmd --
2703 * Procedure called to compile the "set" command.
2706 * The return value is a standard Tcl result, which is normally TCL_OK
2707 * unless there was an error while parsing string. If an error occurs
2708 * then the interpreter's result contains a standard error message. If
2709 * complation fails because the set command requires a second level of
2710 * substitutions, TCL_OUT_LINE_COMPILE is returned indicating that the
2711 * set command should be compiled "out of line" by emitting code to
2712 * invoke its command procedure (Tcl_SetCmd) at runtime.
2715 * Instructions are added to envPtr to execute the "set" command
2718 *----------------------------------------------------------------------
2722 TclCompileSetCmd(interp, parsePtr, envPtr)
2723 Tcl_Interp *interp; /* Used for error reporting. */
2724 Tcl_Parse *parsePtr; /* Points to a parse structure for the
2725 * command created by Tcl_ParseCommand. */
2726 CompileEnv *envPtr; /* Holds resulting instructions. */
2728 Tcl_Token *varTokenPtr, *valueTokenPtr;
2729 int isAssignment, isScalar, simpleVarName, localIndex, numWords;
2733 /* TIP #280 : Remember the per-word line information of the current
2734 * command. An index is used instead of a pointer as recursive compilation
2735 * may reallocate, i.e. move, the array. This is also the reason to save
2736 * the nuloc now, it may change during the course of the function.
2738 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
2739 int eclIndex = mapPtr->nuloc - 1;
2742 numWords = parsePtr->numWords;
2743 if ((numWords != 2) && (numWords != 3)) {
2744 Tcl_ResetResult(interp);
2745 Tcl_AppendToObj(Tcl_GetObjResult(interp),
2746 "wrong # args: should be \"set varName ?newValue?\"", -1);
2749 isAssignment = (numWords == 3);
2752 * Decide if we can use a frame slot for the var/array name or if we
2753 * need to emit code to compute and push the name at runtime. We use a
2754 * frame slot (entry in the array of local vars) if we are compiling a
2755 * procedure body and if the name is simple text that does not include
2756 * namespace qualifiers.
2759 varTokenPtr = parsePtr->tokenPtr
2760 + (parsePtr->tokenPtr->numComponents + 1);
2762 code = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR,
2764 &localIndex, &simpleVarName, &isScalar);
2766 &localIndex, &simpleVarName, &isScalar,
2767 mapPtr->loc [eclIndex].line [1]);
2769 if (code != TCL_OK) {
2774 * If we are doing an assignment, push the new value.
2778 valueTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
2779 if (valueTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2780 TclEmitPush(TclRegisterNewLiteral(envPtr, valueTokenPtr[1].start,
2781 valueTokenPtr[1].size), envPtr);
2784 envPtr->line = mapPtr->loc [eclIndex].line [2];
2786 code = TclCompileTokens(interp, valueTokenPtr+1,
2787 valueTokenPtr->numComponents, envPtr);
2788 if (code != TCL_OK) {
2795 * Emit instructions to set/get the variable.
2798 if (simpleVarName) {
2800 if (localIndex >= 0) {
2801 if (localIndex <= 255) {
2802 TclEmitInstInt1((isAssignment?
2803 INST_STORE_SCALAR1 : INST_LOAD_SCALAR1),
2804 localIndex, envPtr);
2806 TclEmitInstInt4((isAssignment?
2807 INST_STORE_SCALAR4 : INST_LOAD_SCALAR4),
2808 localIndex, envPtr);
2811 TclEmitOpcode((isAssignment?
2812 INST_STORE_SCALAR_STK : INST_LOAD_SCALAR_STK), envPtr);
2815 if (localIndex >= 0) {
2816 if (localIndex <= 255) {
2817 TclEmitInstInt1((isAssignment?
2818 INST_STORE_ARRAY1 : INST_LOAD_ARRAY1),
2819 localIndex, envPtr);
2821 TclEmitInstInt4((isAssignment?
2822 INST_STORE_ARRAY4 : INST_LOAD_ARRAY4),
2823 localIndex, envPtr);
2826 TclEmitOpcode((isAssignment?
2827 INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
2831 TclEmitOpcode((isAssignment? INST_STORE_STK : INST_LOAD_STK), envPtr);
2839 *----------------------------------------------------------------------
2841 * TclCompileStringCmd --
2843 * Procedure called to compile the "string" command.
2846 * The return value is a standard Tcl result, which is TCL_OK if the
2847 * compilation was successful. If the command cannot be byte-compiled,
2848 * TCL_OUT_LINE_COMPILE is returned. If an error occurs then the
2849 * interpreter's result contains an error message, and TCL_ERROR is
2853 * Instructions are added to envPtr to execute the "string" command
2856 *----------------------------------------------------------------------
2860 TclCompileStringCmd(interp, parsePtr, envPtr)
2861 Tcl_Interp *interp; /* Used for error reporting. */
2862 Tcl_Parse *parsePtr; /* Points to a parse structure for the
2863 * command created by Tcl_ParseCommand. */
2864 CompileEnv *envPtr; /* Holds resulting instructions. */
2866 Tcl_Token *opTokenPtr, *varTokenPtr;
2871 static CONST char *options[] = {
2872 "bytelength", "compare", "equal", "first",
2873 "index", "is", "last", "length",
2874 "map", "match", "range", "repeat",
2875 "replace", "tolower", "toupper", "totitle",
2876 "trim", "trimleft", "trimright",
2877 "wordend", "wordstart", (char *) NULL
2880 STR_BYTELENGTH, STR_COMPARE, STR_EQUAL, STR_FIRST,
2881 STR_INDEX, STR_IS, STR_LAST, STR_LENGTH,
2882 STR_MAP, STR_MATCH, STR_RANGE, STR_REPEAT,
2883 STR_REPLACE, STR_TOLOWER, STR_TOUPPER, STR_TOTITLE,
2884 STR_TRIM, STR_TRIMLEFT, STR_TRIMRIGHT,
2885 STR_WORDEND, STR_WORDSTART
2889 /* TIP #280 : Remember the per-word line information of the current
2890 * command. An index is used instead of a pointer as recursive compilation
2891 * may reallocate, i.e. move, the array. This is also the reason to save
2892 * the nuloc now, it may change during the course of the function.
2894 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
2895 int eclIndex = mapPtr->nuloc - 1;
2898 if (parsePtr->numWords < 2) {
2899 /* Fail at run time, not in compilation */
2900 return TCL_OUT_LINE_COMPILE;
2902 opTokenPtr = parsePtr->tokenPtr
2903 + (parsePtr->tokenPtr->numComponents + 1);
2905 opObj = Tcl_NewStringObj(opTokenPtr->start, opTokenPtr->size);
2906 if (Tcl_GetIndexFromObj(interp, opObj, options, "option", 0,
2907 &index) != TCL_OK) {
2908 Tcl_DecrRefCount(opObj);
2909 Tcl_ResetResult(interp);
2910 return TCL_OUT_LINE_COMPILE;
2912 Tcl_DecrRefCount(opObj);
2914 varTokenPtr = opTokenPtr + (opTokenPtr->numComponents + 1);
2916 switch ((enum options) index) {
2917 case STR_BYTELENGTH:
2934 * All other cases: compile out of line.
2936 return TCL_OUT_LINE_COMPILE;
2942 * If there are any flags to the command, we can't byte compile it
2943 * because the INST_STR_EQ bytecode doesn't support flags.
2946 if (parsePtr->numWords != 4) {
2947 return TCL_OUT_LINE_COMPILE;
2951 * Push the two operands onto the stack.
2954 for (i = 0; i < 2; i++) {
2955 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2956 TclEmitPush(TclRegisterNewLiteral(envPtr,
2957 varTokenPtr[1].start, varTokenPtr[1].size), envPtr);
2960 envPtr->line = mapPtr->loc [eclIndex].line [i];
2962 code = TclCompileTokens(interp, varTokenPtr+1,
2963 varTokenPtr->numComponents, envPtr);
2964 if (code != TCL_OK) {
2968 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
2971 TclEmitOpcode(((((enum options) index) == STR_COMPARE) ?
2972 INST_STR_CMP : INST_STR_EQ), envPtr);
2978 if (parsePtr->numWords != 4) {
2979 /* Fail at run time, not in compilation */
2980 return TCL_OUT_LINE_COMPILE;
2984 * Push the two operands onto the stack.
2987 for (i = 0; i < 2; i++) {
2988 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2989 TclEmitPush(TclRegisterNewLiteral(envPtr,
2990 varTokenPtr[1].start, varTokenPtr[1].size), envPtr);
2993 envPtr->line = mapPtr->loc [eclIndex].line [i];
2995 code = TclCompileTokens(interp, varTokenPtr+1,
2996 varTokenPtr->numComponents, envPtr);
2997 if (code != TCL_OK) {
3001 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
3004 TclEmitOpcode(INST_STR_INDEX, envPtr);
3008 if (parsePtr->numWords != 3) {
3009 /* Fail at run time, not in compilation */
3010 return TCL_OUT_LINE_COMPILE;
3013 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
3015 * Here someone is asking for the length of a static string.
3016 * Just push the actual character (not byte) length.
3018 char buf[TCL_INTEGER_SPACE];
3019 int len = Tcl_NumUtfChars(varTokenPtr[1].start,
3020 varTokenPtr[1].size);
3021 len = sprintf(buf, "%d", len);
3022 TclEmitPush(TclRegisterNewLiteral(envPtr, buf, len), envPtr);
3026 envPtr->line = mapPtr->loc [eclIndex].line [2];
3028 code = TclCompileTokens(interp, varTokenPtr+1,
3029 varTokenPtr->numComponents, envPtr);
3030 if (code != TCL_OK) {
3034 TclEmitOpcode(INST_STR_LEN, envPtr);
3038 int i, length, exactMatch = 0, nocase = 0;
3041 if (parsePtr->numWords < 4 || parsePtr->numWords > 5) {
3042 /* Fail at run time, not in compilation */
3043 return TCL_OUT_LINE_COMPILE;
3046 if (parsePtr->numWords == 5) {
3047 if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
3048 return TCL_OUT_LINE_COMPILE;
3050 str = varTokenPtr[1].start;
3051 length = varTokenPtr[1].size;
3053 strncmp(str, "-nocase", (size_t) length) == 0) {
3056 /* Fail at run time, not in compilation */
3057 return TCL_OUT_LINE_COMPILE;
3059 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
3062 for (i = 0; i < 2; i++) {
3063 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
3064 str = varTokenPtr[1].start;
3065 length = varTokenPtr[1].size;
3066 if (!nocase && (i == 0)) {
3068 * On the first (pattern) arg, check to see if any
3069 * glob special characters are in the word '*[]?\\'.
3070 * If not, this is the same as 'string equal'. We
3071 * can use strpbrk here because the glob chars are all
3072 * in the ascii-7 range. If -nocase was specified,
3073 * we can't do this because INST_STR_EQ has no support
3076 Tcl_Obj *copy = Tcl_NewStringObj(str, length);
3077 Tcl_IncrRefCount(copy);
3078 exactMatch = (strpbrk(Tcl_GetString(copy),
3080 Tcl_DecrRefCount(copy);
3083 TclRegisterNewLiteral(envPtr, str, length), envPtr);
3086 envPtr->line = mapPtr->loc [eclIndex].line [i];
3088 code = TclCompileTokens(interp, varTokenPtr+1,
3089 varTokenPtr->numComponents, envPtr);
3090 if (code != TCL_OK) {
3094 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
3098 TclEmitOpcode(INST_STR_EQ, envPtr);
3100 TclEmitInstInt1(INST_STR_MATCH, nocase, envPtr);
3110 *----------------------------------------------------------------------
3112 * TclCompileVariableCmd --
3114 * Procedure called to reserve the local variables for the
3115 * "variable" command. The command itself is *not* compiled.
3118 * Always returns TCL_OUT_LINE_COMPILE.
3121 * Indexed local variables are added to the environment.
3123 *----------------------------------------------------------------------
3126 TclCompileVariableCmd(interp, parsePtr, envPtr)
3127 Tcl_Interp *interp; /* Used for error reporting. */
3128 Tcl_Parse *parsePtr; /* Points to a parse structure for the
3129 * command created by Tcl_ParseCommand. */
3130 CompileEnv *envPtr; /* Holds resulting instructions. */
3132 Tcl_Token *varTokenPtr;
3134 CONST char *varName, *tail;
3136 if (envPtr->procPtr == NULL) {
3137 return TCL_OUT_LINE_COMPILE;
3140 numWords = parsePtr->numWords;
3142 varTokenPtr = parsePtr->tokenPtr
3143 + (parsePtr->tokenPtr->numComponents + 1);
3144 for (i = 1; i < numWords; i += 2) {
3145 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
3146 varName = varTokenPtr[1].start;
3147 tail = varName + varTokenPtr[1].size - 1;
3148 if ((*tail == ')') || (tail < varName)) continue;
3149 while ((tail > varName) && ((*tail != ':') || (*(tail-1) != ':'))) {
3152 if ((*tail == ':') && (tail > varName)) {
3155 (void) TclFindCompiledLocal(tail, (tail-varName+1),
3156 /*create*/ 1, /*flags*/ 0, envPtr->procPtr);
3157 varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
3160 return TCL_OUT_LINE_COMPILE;
3164 *----------------------------------------------------------------------
3166 * TclCompileWhileCmd --
3168 * Procedure called to compile the "while" command.
3171 * The return value is a standard Tcl result, which is TCL_OK if
3172 * compilation was successful. If an error occurs then the
3173 * interpreter's result contains a standard error message and TCL_ERROR
3174 * is returned. If compilation failed because the command is too
3175 * complex for TclCompileWhileCmd, TCL_OUT_LINE_COMPILE is returned
3176 * indicating that the while command should be compiled "out of line"
3177 * by emitting code to invoke its command procedure at runtime.
3180 * Instructions are added to envPtr to execute the "while" command
3183 *----------------------------------------------------------------------
3187 TclCompileWhileCmd(interp, parsePtr, envPtr)
3188 Tcl_Interp *interp; /* Used for error reporting. */
3189 Tcl_Parse *parsePtr; /* Points to a parse structure for the
3190 * command created by Tcl_ParseCommand. */
3191 CompileEnv *envPtr; /* Holds resulting instructions. */
3193 Tcl_Token *testTokenPtr, *bodyTokenPtr;
3194 JumpFixup jumpEvalCondFixup;
3195 int testCodeOffset, bodyCodeOffset, jumpDist;
3197 char buffer[32 + TCL_INTEGER_SPACE];
3198 int savedStackDepth = envPtr->currStackDepth;
3199 int loopMayEnd = 1; /* This is set to 0 if it is recognized as
3200 * an infinite loop. */
3205 /* TIP #280 : Remember the per-word line information of the current
3206 * command. An index is used instead of a pointer as recursive compilation
3207 * may reallocate, i.e. move, the array. This is also the reason to save
3208 * the nuloc now, it may change during the course of the function.
3210 ExtCmdLoc* mapPtr = envPtr->extCmdMapPtr;
3211 int eclIndex = mapPtr->nuloc - 1;
3214 if (parsePtr->numWords != 3) {
3215 Tcl_ResetResult(interp);
3216 Tcl_AppendToObj(Tcl_GetObjResult(interp),
3217 "wrong # args: should be \"while test command\"", -1);
3222 * If the test expression requires substitutions, don't compile the
3223 * while command inline. E.g., the expression might cause the loop to
3224 * never execute or execute forever, as in "while "$x < 5" {}".
3226 * Bail out also if the body expression requires substitutions
3227 * in order to insure correct behaviour [Bug 219166]
3230 testTokenPtr = parsePtr->tokenPtr
3231 + (parsePtr->tokenPtr->numComponents + 1);
3232 bodyTokenPtr = testTokenPtr + (testTokenPtr->numComponents + 1);
3233 if ((testTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)
3234 || (bodyTokenPtr->type != TCL_TOKEN_SIMPLE_WORD)) {
3235 return TCL_OUT_LINE_COMPILE;
3239 * Find out if the condition is a constant.
3242 boolObj = Tcl_NewStringObj(testTokenPtr[1].start, testTokenPtr[1].size);
3243 Tcl_IncrRefCount(boolObj);
3244 code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
3245 Tcl_DecrRefCount(boolObj);
3246 if (code == TCL_OK) {
3249 * it is an infinite loop
3255 * This is an empty loop: "while 0 {...}" or such.
3256 * Compile no bytecodes.
3264 * Create a ExceptionRange record for the loop body. This is used to
3265 * implement break and continue.
3268 envPtr->exceptDepth++;
3269 envPtr->maxExceptDepth =
3270 TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
3271 range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
3274 * Jump to the evaluation of the condition. This code uses the "loop
3275 * rotation" optimisation (which eliminates one branch from the loop).
3276 * "while cond body" produces then:
3278 * B: body : bodyCodeOffset
3279 * A: cond -> result : testCodeOffset, continueOffset
3280 * if (result) goto B
3282 * The infinite loop "while 1 body" produces:
3283 * B: body : all three offsets here
3288 TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
3289 testCodeOffset = 0; /* avoid compiler warning */
3291 testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
3296 * Compile the loop body.
3300 envPtr->line = mapPtr->loc [eclIndex].line [2];
3302 bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart);
3303 code = TclCompileCmdWord(interp, bodyTokenPtr+1,
3304 bodyTokenPtr->numComponents, envPtr);
3305 envPtr->currStackDepth = savedStackDepth + 1;
3306 if (code != TCL_OK) {
3307 if (code == TCL_ERROR) {
3308 sprintf(buffer, "\n (\"while\" body line %d)",
3310 Tcl_AddObjErrorInfo(interp, buffer, -1);
3314 envPtr->exceptArrayPtr[range].numCodeBytes =
3315 (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
3316 TclEmitOpcode(INST_POP, envPtr);
3319 * Compile the test expression then emit the conditional jump that
3320 * terminates the while. We already know it's a simple word.
3324 testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
3325 jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
3326 if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
3327 bodyCodeOffset += 3;
3328 testCodeOffset += 3;
3330 envPtr->currStackDepth = savedStackDepth;
3332 envPtr->line = mapPtr->loc [eclIndex].line [1];
3334 code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
3335 if (code != TCL_OK) {
3336 if (code == TCL_ERROR) {
3337 Tcl_AddObjErrorInfo(interp,
3338 "\n (\"while\" test expression)", -1);
3342 envPtr->currStackDepth = savedStackDepth + 1;
3344 jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
3345 if (jumpDist > 127) {
3346 TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
3348 TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
3351 jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
3352 if (jumpDist > 127) {
3353 TclEmitInstInt4(INST_JUMP4, -jumpDist, envPtr);
3355 TclEmitInstInt1(INST_JUMP1, -jumpDist, envPtr);
3361 * Set the loop's body, continue and break offsets.
3364 envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
3365 envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
3366 envPtr->exceptArrayPtr[range].breakOffset =
3367 (envPtr->codeNext - envPtr->codeStart);
3370 * The while command's result is an empty string.
3374 envPtr->currStackDepth = savedStackDepth;
3375 TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
3376 envPtr->exceptDepth--;
3380 envPtr->exceptDepth--;
3385 *----------------------------------------------------------------------
3389 * Procedure used in the compiling where pushing a variable name
3390 * is necessary (append, lappend, set).
3393 * The return value is a standard Tcl result, which is normally TCL_OK
3394 * unless there was an error while parsing string. If an error occurs
3395 * then the interpreter's result contains a standard error message.
3398 * Instructions are added to envPtr to execute the "set" command
3401 *----------------------------------------------------------------------
3405 TclPushVarName(interp, varTokenPtr, envPtr, flags, localIndexPtr,
3407 simpleVarNamePtr, isScalarPtr)
3409 simpleVarNamePtr, isScalarPtr, line)
3411 Tcl_Interp *interp; /* Used for error reporting. */
3412 Tcl_Token *varTokenPtr; /* Points to a variable token. */
3413 CompileEnv *envPtr; /* Holds resulting instructions. */
3414 int flags; /* takes TCL_CREATE_VAR or
3415 * TCL_NO_LARGE_INDEX */
3416 int *localIndexPtr; /* must not be NULL */
3417 int *simpleVarNamePtr; /* must not be NULL */
3418 int *isScalarPtr; /* must not be NULL */
3420 int line; /* line the token starts on */
3423 register CONST char *p;
3424 CONST char *name, *elName;
3426 int nameChars, elNameChars, simpleVarName, localIndex;
3429 Tcl_Token *elemTokenPtr = NULL;
3430 int elemTokenCount = 0;
3431 int allocedTokens = 0;
3432 int removedParen = 0;
3435 * Decide if we can use a frame slot for the var/array name or if we
3436 * need to emit code to compute and push the name at runtime. We use a
3437 * frame slot (entry in the array of local vars) if we are compiling a
3438 * procedure body and if the name is simple text that does not include
3439 * namespace qualifiers.
3443 name = elName = NULL;
3444 nameChars = elNameChars = 0;
3448 * Check not only that the type is TCL_TOKEN_SIMPLE_WORD, but whether
3449 * curly braces surround the variable name.
3450 * This really matters for array elements to handle things like
3452 * which raises an undefined var error if we are not careful here.
3455 if ((varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) &&
3456 (varTokenPtr->start[0] != '{')) {
3458 * A simple variable name. Divide it up into "name" and "elName"
3459 * strings. If it is not a local variable, look it up at runtime.
3463 name = varTokenPtr[1].start;
3464 nameChars = varTokenPtr[1].size;
3465 if ( *(name + nameChars - 1) == ')') {
3467 * last char is ')' => potential array reference.
3470 for (i = 0, p = name; i < nameChars; i++, p++) {
3473 elNameChars = nameChars - i - 2;
3479 if ((elName != NULL) && elNameChars) {
3481 * An array element, the element name is a simple
3482 * string: assemble the corresponding token.
3485 elemTokenPtr = (Tcl_Token *) ckalloc(sizeof(Tcl_Token));
3487 elemTokenPtr->type = TCL_TOKEN_TEXT;
3488 elemTokenPtr->start = elName;
3489 elemTokenPtr->size = elNameChars;
3490 elemTokenPtr->numComponents = 0;
3494 } else if (((n = varTokenPtr->numComponents) > 1)
3495 && (varTokenPtr[1].type == TCL_TOKEN_TEXT)
3496 && (varTokenPtr[n].type == TCL_TOKEN_TEXT)
3497 && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) {
3500 * Check for parentheses inside first token
3504 for (i = 0, p = varTokenPtr[1].start;
3505 i < varTokenPtr[1].size; i++, p++) {
3511 if (simpleVarName) {
3515 * Check the last token: if it is just ')', do not count
3516 * it. Otherwise, remove the ')' and flag so that it is
3517 * restored at the end.
3520 if (varTokenPtr[n].size == 1) {
3523 --varTokenPtr[n].size;
3527 name = varTokenPtr[1].start;
3528 nameChars = p - varTokenPtr[1].start;
3530 remainingChars = (varTokenPtr[2].start - p) - 1;
3531 elNameChars = (varTokenPtr[n].start - p) + varTokenPtr[n].size - 2;
3533 if (remainingChars) {
3535 * Make a first token with the extra characters in the first
3539 elemTokenPtr = (Tcl_Token *) ckalloc(n * sizeof(Tcl_Token));
3541 elemTokenPtr->type = TCL_TOKEN_TEXT;
3542 elemTokenPtr->start = elName;
3543 elemTokenPtr->size = remainingChars;
3544 elemTokenPtr->numComponents = 0;
3548 * Copy the remaining tokens.
3551 memcpy((void *) (elemTokenPtr+1), (void *) (&varTokenPtr[2]),
3552 ((n-1) * sizeof(Tcl_Token)));
3555 * Use the already available tokens.
3558 elemTokenPtr = &varTokenPtr[2];
3559 elemTokenCount = n - 1;
3564 if (simpleVarName) {
3566 * See whether name has any namespace separators (::'s).
3569 int hasNsQualifiers = 0;
3570 for (i = 0, p = name; i < nameChars; i++, p++) {
3571 if ((*p == ':') && ((i+1) < nameChars) && (*(p+1) == ':')) {
3572 hasNsQualifiers = 1;
3578 * Look up the var name's index in the array of local vars in the
3579 * proc frame. If retrieving the var's value and it doesn't already
3580 * exist, push its name and look it up at runtime.
3583 if ((envPtr->procPtr != NULL) && !hasNsQualifiers) {
3584 localIndex = TclFindCompiledLocal(name, nameChars,
3585 /*create*/ (flags & TCL_CREATE_VAR),
3586 /*flags*/ ((elName==NULL)? VAR_SCALAR : VAR_ARRAY),
3588 if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
3589 /* we'll push the name */
3593 if (localIndex < 0) {
3594 TclEmitPush(TclRegisterNewLiteral(envPtr, name, nameChars), envPtr);
3598 * Compile the element script, if any.
3601 if (elName != NULL) {
3604 envPtr->line = line;
3606 code = TclCompileTokens(interp, elemTokenPtr,
3607 elemTokenCount, envPtr);
3608 if (code != TCL_OK) {
3612 TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
3617 * The var name isn't simple: compile and push it.
3621 envPtr->line = line;
3623 code = TclCompileTokens(interp, varTokenPtr+1,
3624 varTokenPtr->numComponents, envPtr);
3625 if (code != TCL_OK) {
3632 ++varTokenPtr[removedParen].size;
3634 if (allocedTokens) {
3635 ckfree((char *) elemTokenPtr);
3637 *localIndexPtr = localIndex;
3638 *simpleVarNamePtr = simpleVarName;
3639 *isScalarPtr = (elName == NULL);