4 * This file contains compilation procedures that compile various Tcl
5 * commands (beginning with the letters 'g' through 'r') into a sequence
6 * of instructions ("bytecodes").
8 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
9 * Copyright (c) 2001 by Kevin B. Kenny. All rights reserved.
10 * Copyright (c) 2002 ActiveState Corporation.
11 * Copyright (c) 2004-2013 by Donal K. Fellows.
13 * See the file "license.terms" for information on usage and redistribution of
14 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 #include "tclCompile.h"
22 * Prototypes for procedures defined later in this file:
25 static void CompileReturnInternal(CompileEnv *envPtr,
26 unsigned char op, int code, int level,
28 static int IndexTailVarIfKnown(Tcl_Interp *interp,
29 Tcl_Token *varTokenPtr, CompileEnv *envPtr);
33 *----------------------------------------------------------------------
35 * TclGetIndexFromToken --
37 * Parse a token to determine if an index value is known at
41 * TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
44 * When TCL_OK is returned, the encoded index value is written
47 *----------------------------------------------------------------------
57 Tcl_Obj *tmpObj = Tcl_NewObj();
58 int result = TCL_ERROR;
60 if (TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
61 result = TclIndexEncode(NULL, tmpObj, before, after, indexPtr);
63 Tcl_DecrRefCount(tmpObj);
68 *----------------------------------------------------------------------
70 * TclCompileGlobalCmd --
72 * Procedure called to compile the "global" command.
75 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
76 * evaluation to runtime.
79 * Instructions are added to envPtr to execute the "global" command at
82 *----------------------------------------------------------------------
87 Tcl_Interp *interp, /* Used for error reporting. */
88 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
89 * created by Tcl_ParseCommand. */
90 Command *cmdPtr, /* Points to defintion of command being
92 CompileEnv *envPtr) /* Holds resulting instructions. */
94 DefineLineInformation; /* TIP #280 */
95 Tcl_Token *varTokenPtr;
96 int localIndex, numWords, i;
98 /* TODO: Consider support for compiling expanded args. */
99 numWords = parsePtr->numWords;
105 * 'global' has no effect outside of proc bodies; handle that at runtime
108 if (envPtr->procPtr == NULL) {
116 PushStringLiteral(envPtr, "::");
119 * Loop over the variables.
122 varTokenPtr = TokenAfter(parsePtr->tokenPtr);
123 for (i=1; i<numWords; varTokenPtr = TokenAfter(varTokenPtr),i++) {
124 localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);
126 if (localIndex < 0) {
130 /* TODO: Consider what value can pass through the
131 * IndexTailVarIfKnown() screen. Full CompileWord()
132 * likely does not apply here. Push known value instead. */
133 CompileWord(envPtr, varTokenPtr, interp, i);
134 TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
138 * Pop the namespace, and set the result to empty
141 TclEmitOpcode( INST_POP, envPtr);
142 PushStringLiteral(envPtr, "");
147 *----------------------------------------------------------------------
151 * Procedure called to compile the "if" command.
154 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
155 * evaluation to runtime.
158 * Instructions are added to envPtr to execute the "if" command at
161 *----------------------------------------------------------------------
166 Tcl_Interp *interp, /* Used for error reporting. */
167 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
168 * created by Tcl_ParseCommand. */
169 Command *cmdPtr, /* Points to defintion of command being
171 CompileEnv *envPtr) /* Holds resulting instructions. */
173 DefineLineInformation; /* TIP #280 */
174 JumpFixupArray jumpFalseFixupArray;
175 /* Used to fix the ifFalse jump after each
176 * test when its target PC is determined. */
177 JumpFixupArray jumpEndFixupArray;
178 /* Used to fix the jump after each "then" body
179 * to the end of the "if" when that PC is
181 Tcl_Token *tokenPtr, *testTokenPtr;
182 int jumpIndex = 0; /* Avoid compiler warning. */
183 int jumpFalseDist, numWords, wordIdx, numBytes, j, code;
185 int realCond = 1; /* Set to 0 for static conditions:
187 int boolVal; /* Value of static condition. */
188 int compileScripts = 1;
191 * Only compile the "if" command if all arguments are simple words, in
192 * order to insure correct substitution [Bug 219166]
195 tokenPtr = parsePtr->tokenPtr;
197 numWords = parsePtr->numWords;
199 for (wordIdx = 0; wordIdx < numWords; wordIdx++) {
200 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
203 tokenPtr = TokenAfter(tokenPtr);
206 TclInitJumpFixupArray(&jumpFalseFixupArray);
207 TclInitJumpFixupArray(&jumpEndFixupArray);
211 * Each iteration of this loop compiles one "if expr ?then? body" or
212 * "elseif expr ?then? body" clause.
215 tokenPtr = parsePtr->tokenPtr;
217 while (wordIdx < numWords) {
219 * Stop looping if the token isn't "if" or "elseif".
222 word = tokenPtr[1].start;
223 numBytes = tokenPtr[1].size;
224 if ((tokenPtr == parsePtr->tokenPtr)
225 || ((numBytes == 6) && (strncmp(word, "elseif", 6) == 0))) {
226 tokenPtr = TokenAfter(tokenPtr);
231 if (wordIdx >= numWords) {
237 * Compile the test expression then emit the conditional jump around
241 testTokenPtr = tokenPtr;
245 * Find out if the condition is a constant.
248 Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start,
249 testTokenPtr[1].size);
251 Tcl_IncrRefCount(boolObj);
252 code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
253 TclDecrRefCount(boolObj);
254 if (code == TCL_OK) {
256 * A static condition.
264 SetLineInformation(wordIdx);
265 Tcl_ResetResult(interp);
266 TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
267 if (jumpFalseFixupArray.next >= jumpFalseFixupArray.end) {
268 TclExpandJumpFixupArray(&jumpFalseFixupArray);
270 jumpIndex = jumpFalseFixupArray.next;
271 jumpFalseFixupArray.next++;
272 TclEmitForwardJump(envPtr, TCL_FALSE_JUMP,
273 jumpFalseFixupArray.fixup+jumpIndex);
279 * Skip over the optional "then" before the then clause.
282 tokenPtr = TokenAfter(testTokenPtr);
284 if (wordIdx >= numWords) {
288 if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
289 word = tokenPtr[1].start;
290 numBytes = tokenPtr[1].size;
291 if ((numBytes == 4) && (strncmp(word, "then", 4) == 0)) {
292 tokenPtr = TokenAfter(tokenPtr);
294 if (wordIdx >= numWords) {
302 * Compile the "then" command body.
305 if (compileScripts) {
306 BODY(tokenPtr, wordIdx);
311 * Jump to the end of the "if" command. Both jumpFalseFixupArray
312 * and jumpEndFixupArray are indexed by "jumpIndex".
315 if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
316 TclExpandJumpFixupArray(&jumpEndFixupArray);
318 jumpEndFixupArray.next++;
319 TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
320 jumpEndFixupArray.fixup+jumpIndex);
323 * Fix the target of the jumpFalse after the test. Generate a 4
324 * byte jump if the distance is > 120 bytes. This is conservative,
325 * and ensures that we won't have to replace this jump if we later
326 * also need to replace the proceeding jump to the end of the "if"
327 * with a 4 byte jump.
330 TclAdjustStackDepth(-1, envPtr);
331 if (TclFixupForwardJumpToHere(envPtr,
332 jumpFalseFixupArray.fixup+jumpIndex, 120)) {
334 * Adjust the code offset for the proceeding jump to the end
335 * of the "if" command.
338 jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
340 } else if (boolVal) {
342 * We were processing an "if 1 {...}"; stop compiling scripts.
348 * We were processing an "if 0 {...}"; reset so that the rest
349 * (elseif, else) is compiled correctly.
356 tokenPtr = TokenAfter(tokenPtr);
361 * Check for the optional else clause. Do not compile anything if this was
362 * an "if 1 {...}" case.
365 if ((wordIdx < numWords) && (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD)) {
367 * There is an else clause. Skip over the optional "else" word.
370 word = tokenPtr[1].start;
371 numBytes = tokenPtr[1].size;
372 if ((numBytes == 4) && (strncmp(word, "else", 4) == 0)) {
373 tokenPtr = TokenAfter(tokenPtr);
375 if (wordIdx >= numWords) {
381 if (compileScripts) {
383 * Compile the else command body.
386 BODY(tokenPtr, wordIdx);
390 * Make sure there are no words after the else clause.
394 if (wordIdx < numWords) {
400 * No else clause: the "if" command's result is an empty string.
403 if (compileScripts) {
404 PushStringLiteral(envPtr, "");
409 * Fix the unconditional jumps to the end of the "if" command.
412 for (j = jumpEndFixupArray.next; j > 0; j--) {
413 jumpIndex = (j - 1); /* i.e. process the closest jump first. */
414 if (TclFixupForwardJumpToHere(envPtr,
415 jumpEndFixupArray.fixup+jumpIndex, 127)) {
417 * Adjust the immediately preceeding "ifFalse" jump. We moved it's
418 * target (just after this jump) down three bytes.
421 unsigned char *ifFalsePc = envPtr->codeStart
422 + jumpFalseFixupArray.fixup[jumpIndex].codeOffset;
423 unsigned char opCode = *ifFalsePc;
425 if (opCode == INST_JUMP_FALSE1) {
426 jumpFalseDist = TclGetInt1AtPtr(ifFalsePc + 1);
428 TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
429 } else if (opCode == INST_JUMP_FALSE4) {
430 jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
432 TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
434 Tcl_Panic("TclCompileIfCmd: unexpected opcode \"%d\" updating ifFalse jump", (int) opCode);
440 * Free the jumpFixupArray array if malloc'ed storage was used.
444 TclFreeJumpFixupArray(&jumpFalseFixupArray);
445 TclFreeJumpFixupArray(&jumpEndFixupArray);
450 *----------------------------------------------------------------------
452 * TclCompileIncrCmd --
454 * Procedure called to compile the "incr" command.
457 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
458 * evaluation to runtime.
461 * Instructions are added to envPtr to execute the "incr" command at
464 *----------------------------------------------------------------------
469 Tcl_Interp *interp, /* Used for error reporting. */
470 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
471 * created by Tcl_ParseCommand. */
472 Command *cmdPtr, /* Points to defintion of command being
474 CompileEnv *envPtr) /* Holds resulting instructions. */
476 DefineLineInformation; /* TIP #280 */
477 Tcl_Token *varTokenPtr, *incrTokenPtr;
478 int isScalar, localIndex, haveImmValue, immValue;
480 if ((parsePtr->numWords != 2) && (parsePtr->numWords != 3)) {
484 varTokenPtr = TokenAfter(parsePtr->tokenPtr);
486 PushVarNameWord(interp, varTokenPtr, envPtr, TCL_NO_LARGE_INDEX,
487 &localIndex, &isScalar, 1);
490 * If an increment is given, push it, but see first if it's a small
496 if (parsePtr->numWords == 3) {
497 incrTokenPtr = TokenAfter(varTokenPtr);
498 if (incrTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
499 const char *word = incrTokenPtr[1].start;
500 int numBytes = incrTokenPtr[1].size;
502 Tcl_Obj *intObj = Tcl_NewStringObj(word, numBytes);
504 Tcl_IncrRefCount(intObj);
505 code = TclGetIntFromObj(NULL, intObj, &immValue);
506 TclDecrRefCount(intObj);
507 if ((code == TCL_OK) && (-127 <= immValue) && (immValue <= 127)) {
511 PushLiteral(envPtr, word, numBytes);
514 SetLineInformation(2);
515 CompileTokens(envPtr, incrTokenPtr, interp);
517 } else { /* No incr amount given so use 1. */
522 * Emit the instruction to increment the variable.
525 if (isScalar) { /* Simple scalar variable. */
526 if (localIndex >= 0) {
528 TclEmitInstInt1(INST_INCR_SCALAR1_IMM, localIndex, envPtr);
529 TclEmitInt1(immValue, envPtr);
531 TclEmitInstInt1(INST_INCR_SCALAR1, localIndex, envPtr);
535 TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr);
537 TclEmitOpcode( INST_INCR_STK, envPtr);
540 } else { /* Simple array variable. */
541 if (localIndex >= 0) {
543 TclEmitInstInt1(INST_INCR_ARRAY1_IMM, localIndex, envPtr);
544 TclEmitInt1(immValue, envPtr);
546 TclEmitInstInt1(INST_INCR_ARRAY1, localIndex, envPtr);
550 TclEmitInstInt1(INST_INCR_ARRAY_STK_IMM, immValue, envPtr);
552 TclEmitOpcode( INST_INCR_ARRAY_STK, envPtr);
561 *----------------------------------------------------------------------
563 * TclCompileInfo*Cmd --
565 * Procedures called to compile "info" subcommands.
568 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
569 * evaluation to runtime.
572 * Instructions are added to envPtr to execute the "info" subcommand at
575 *----------------------------------------------------------------------
579 TclCompileInfoCommandsCmd(
580 Tcl_Interp *interp, /* Used for error reporting. */
581 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
582 * created by Tcl_ParseCommand. */
583 Command *cmdPtr, /* Points to defintion of command being
587 DefineLineInformation; /* TIP #280 */
593 * We require one compile-time known argument for the case we can compile.
596 if (parsePtr->numWords == 1) {
597 return TclCompileBasic0ArgCmd(interp, parsePtr, cmdPtr, envPtr);
598 } else if (parsePtr->numWords != 2) {
601 tokenPtr = TokenAfter(parsePtr->tokenPtr);
602 objPtr = Tcl_NewObj();
603 Tcl_IncrRefCount(objPtr);
604 if (!TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
607 bytes = Tcl_GetString(objPtr);
610 * We require that the argument start with "::" and not have any of "*\[?"
611 * in it. (Theoretically, we should look in only the final component, but
612 * the difference is so slight given current naming practices.)
615 if (bytes[0] != ':' || bytes[1] != ':' || !TclMatchIsTrivial(bytes)) {
618 Tcl_DecrRefCount(objPtr);
621 * Confirmed as a literal that will not frighten the horses. Compile. Note
622 * that the result needs to be list-ified.
625 /* TODO: Just push the known value */
626 CompileWord(envPtr, tokenPtr, interp, 1);
627 TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
628 TclEmitOpcode( INST_DUP, envPtr);
629 TclEmitOpcode( INST_STR_LEN, envPtr);
630 TclEmitInstInt1( INST_JUMP_FALSE1, 7, envPtr);
631 TclEmitInstInt4( INST_LIST, 1, envPtr);
635 Tcl_DecrRefCount(objPtr);
636 return TclCompileBasic1ArgCmd(interp, parsePtr, cmdPtr, envPtr);
640 TclCompileInfoCoroutineCmd(
641 Tcl_Interp *interp, /* Used for error reporting. */
642 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
643 * created by Tcl_ParseCommand. */
644 Command *cmdPtr, /* Points to defintion of command being
646 CompileEnv *envPtr) /* Holds resulting instructions. */
649 * Only compile [info coroutine] without arguments.
652 if (parsePtr->numWords != 1) {
657 * Not much to do; we compile to a single instruction...
660 TclEmitOpcode( INST_COROUTINE_NAME, envPtr);
665 TclCompileInfoExistsCmd(
666 Tcl_Interp *interp, /* Used for error reporting. */
667 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
668 * created by Tcl_ParseCommand. */
669 Command *cmdPtr, /* Points to defintion of command being
671 CompileEnv *envPtr) /* Holds resulting instructions. */
673 DefineLineInformation; /* TIP #280 */
675 int isScalar, localIndex;
677 if (parsePtr->numWords != 2) {
682 * Decide if we can use a frame slot for the var/array name or if we need
683 * to emit code to compute and push the name at runtime. We use a frame
684 * slot (entry in the array of local vars) if we are compiling a procedure
685 * body and if the name is simple text that does not include namespace
689 tokenPtr = TokenAfter(parsePtr->tokenPtr);
690 PushVarNameWord(interp, tokenPtr, envPtr, 0, &localIndex, &isScalar, 1);
693 * Emit instruction to check the variable for existence.
697 if (localIndex < 0) {
698 TclEmitOpcode( INST_EXIST_STK, envPtr);
700 TclEmitInstInt4( INST_EXIST_SCALAR, localIndex, envPtr);
703 if (localIndex < 0) {
704 TclEmitOpcode( INST_EXIST_ARRAY_STK, envPtr);
706 TclEmitInstInt4( INST_EXIST_ARRAY, localIndex, envPtr);
714 TclCompileInfoLevelCmd(
715 Tcl_Interp *interp, /* Used for error reporting. */
716 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
717 * created by Tcl_ParseCommand. */
718 Command *cmdPtr, /* Points to defintion of command being
720 CompileEnv *envPtr) /* Holds resulting instructions. */
723 * Only compile [info level] without arguments or with a single argument.
726 if (parsePtr->numWords == 1) {
728 * Not much to do; we compile to a single instruction...
731 TclEmitOpcode( INST_INFO_LEVEL_NUM, envPtr);
732 } else if (parsePtr->numWords != 2) {
735 DefineLineInformation; /* TIP #280 */
738 * Compile the argument, then add the instruction to convert it into a
742 CompileWord(envPtr, TokenAfter(parsePtr->tokenPtr), interp, 1);
743 TclEmitOpcode( INST_INFO_LEVEL_ARGS, envPtr);
749 TclCompileInfoObjectClassCmd(
750 Tcl_Interp *interp, /* Used for error reporting. */
751 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
752 * created by Tcl_ParseCommand. */
753 Command *cmdPtr, /* Points to defintion of command being
757 DefineLineInformation; /* TIP #280 */
758 Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
760 if (parsePtr->numWords != 2) {
763 CompileWord(envPtr, tokenPtr, interp, 1);
764 TclEmitOpcode( INST_TCLOO_CLASS, envPtr);
769 TclCompileInfoObjectIsACmd(
770 Tcl_Interp *interp, /* Used for error reporting. */
771 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
772 * created by Tcl_ParseCommand. */
773 Command *cmdPtr, /* Points to defintion of command being
777 DefineLineInformation; /* TIP #280 */
778 Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
781 * We only handle [info object isa object <somevalue>]. The first three
782 * words are compressed to a single token by the ensemble compilation
786 if (parsePtr->numWords != 3) {
789 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size < 1
790 || strncmp(tokenPtr[1].start, "object", tokenPtr[1].size)) {
793 tokenPtr = TokenAfter(tokenPtr);
799 CompileWord(envPtr, tokenPtr, interp, 2);
800 TclEmitOpcode( INST_TCLOO_IS_OBJECT, envPtr);
805 TclCompileInfoObjectNamespaceCmd(
806 Tcl_Interp *interp, /* Used for error reporting. */
807 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
808 * created by Tcl_ParseCommand. */
809 Command *cmdPtr, /* Points to defintion of command being
813 DefineLineInformation; /* TIP #280 */
814 Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
816 if (parsePtr->numWords != 2) {
819 CompileWord(envPtr, tokenPtr, interp, 1);
820 TclEmitOpcode( INST_TCLOO_NS, envPtr);
825 *----------------------------------------------------------------------
827 * TclCompileLappendCmd --
829 * Procedure called to compile the "lappend" command.
832 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
833 * evaluation to runtime.
836 * Instructions are added to envPtr to execute the "lappend" command at
839 *----------------------------------------------------------------------
843 TclCompileLappendCmd(
844 Tcl_Interp *interp, /* Used for error reporting. */
845 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
846 * created by Tcl_ParseCommand. */
847 Command *cmdPtr, /* Points to defintion of command being
849 CompileEnv *envPtr) /* Holds resulting instructions. */
851 DefineLineInformation; /* TIP #280 */
852 Tcl_Token *varTokenPtr, *valueTokenPtr;
853 int isScalar, localIndex, numWords, i;
855 /* TODO: Consider support for compiling expanded args. */
856 numWords = parsePtr->numWords;
861 if (numWords != 3 || envPtr->procPtr == NULL) {
862 goto lappendMultiple;
866 * Decide if we can use a frame slot for the var/array name or if we
867 * need to emit code to compute and push the name at runtime. We use a
868 * frame slot (entry in the array of local vars) if we are compiling a
869 * procedure body and if the name is simple text that does not include
870 * namespace qualifiers.
873 varTokenPtr = TokenAfter(parsePtr->tokenPtr);
875 PushVarNameWord(interp, varTokenPtr, envPtr, 0,
876 &localIndex, &isScalar, 1);
879 * If we are doing an assignment, push the new value. In the no values
880 * case, create an empty object.
884 valueTokenPtr = TokenAfter(varTokenPtr);
886 CompileWord(envPtr, valueTokenPtr, interp, 2);
890 * Emit instructions to set/get the variable.
894 * The *_STK opcodes should be refactored to make better use of existing
895 * LOAD/STORE instructions.
899 if (localIndex < 0) {
900 TclEmitOpcode( INST_LAPPEND_STK, envPtr);
902 Emit14Inst( INST_LAPPEND_SCALAR, localIndex, envPtr);
905 if (localIndex < 0) {
906 TclEmitOpcode( INST_LAPPEND_ARRAY_STK, envPtr);
908 Emit14Inst( INST_LAPPEND_ARRAY, localIndex, envPtr);
915 varTokenPtr = TokenAfter(parsePtr->tokenPtr);
916 PushVarNameWord(interp, varTokenPtr, envPtr, 0,
917 &localIndex, &isScalar, 1);
918 valueTokenPtr = TokenAfter(varTokenPtr);
919 for (i = 2 ; i < numWords ; i++) {
920 CompileWord(envPtr, valueTokenPtr, interp, i);
921 valueTokenPtr = TokenAfter(valueTokenPtr);
923 TclEmitInstInt4( INST_LIST, numWords-2, envPtr);
925 if (localIndex < 0) {
926 TclEmitOpcode( INST_LAPPEND_LIST_STK, envPtr);
928 TclEmitInstInt4(INST_LAPPEND_LIST, localIndex, envPtr);
931 if (localIndex < 0) {
932 TclEmitOpcode( INST_LAPPEND_LIST_ARRAY_STK, envPtr);
934 TclEmitInstInt4(INST_LAPPEND_LIST_ARRAY, localIndex,envPtr);
941 *----------------------------------------------------------------------
943 * TclCompileLassignCmd --
945 * Procedure called to compile the "lassign" command.
948 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
949 * evaluation to runtime.
952 * Instructions are added to envPtr to execute the "lassign" command at
955 *----------------------------------------------------------------------
959 TclCompileLassignCmd(
960 Tcl_Interp *interp, /* Used for error reporting. */
961 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
962 * created by Tcl_ParseCommand. */
963 Command *cmdPtr, /* Points to defintion of command being
965 CompileEnv *envPtr) /* Holds resulting instructions. */
967 DefineLineInformation; /* TIP #280 */
969 int isScalar, localIndex, numWords, idx;
971 numWords = parsePtr->numWords;
974 * Check for command syntax error, but we'll punt that to runtime.
982 * Generate code to push list being taken apart by [lassign].
985 tokenPtr = TokenAfter(parsePtr->tokenPtr);
986 CompileWord(envPtr, tokenPtr, interp, 1);
989 * Generate code to assign values from the list to variables.
992 for (idx=0 ; idx<numWords-2 ; idx++) {
993 tokenPtr = TokenAfter(tokenPtr);
996 * Generate the next variable name.
999 PushVarNameWord(interp, tokenPtr, envPtr, 0, &localIndex,
1003 * Emit instructions to get the idx'th item out of the list value on
1004 * the stack and assign it to the variable.
1008 if (localIndex >= 0) {
1009 TclEmitOpcode( INST_DUP, envPtr);
1010 TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
1011 Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
1012 TclEmitOpcode( INST_POP, envPtr);
1014 TclEmitInstInt4(INST_OVER, 1, envPtr);
1015 TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
1016 TclEmitOpcode( INST_STORE_STK, envPtr);
1017 TclEmitOpcode( INST_POP, envPtr);
1020 if (localIndex >= 0) {
1021 TclEmitInstInt4(INST_OVER, 1, envPtr);
1022 TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
1023 Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
1024 TclEmitOpcode( INST_POP, envPtr);
1026 TclEmitInstInt4(INST_OVER, 2, envPtr);
1027 TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
1028 TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
1029 TclEmitOpcode( INST_POP, envPtr);
1035 * Generate code to leave the rest of the list on the stack.
1038 TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
1039 TclEmitInt4( TCL_INDEX_END, envPtr);
1045 *----------------------------------------------------------------------
1047 * TclCompileLindexCmd --
1049 * Procedure called to compile the "lindex" command.
1052 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
1053 * evaluation to runtime.
1056 * Instructions are added to envPtr to execute the "lindex" command at
1059 *----------------------------------------------------------------------
1063 TclCompileLindexCmd(
1064 Tcl_Interp *interp, /* Used for error reporting. */
1065 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1066 * created by Tcl_ParseCommand. */
1067 Command *cmdPtr, /* Points to defintion of command being
1069 CompileEnv *envPtr) /* Holds resulting instructions. */
1071 DefineLineInformation; /* TIP #280 */
1072 Tcl_Token *idxTokenPtr, *valTokenPtr;
1073 int i, idx, numWords = parsePtr->numWords;
1076 * Quit if not enough args.
1079 /* TODO: Consider support for compiling expanded args. */
1080 if (numWords <= 1) {
1084 valTokenPtr = TokenAfter(parsePtr->tokenPtr);
1085 if (numWords != 3) {
1086 goto emitComplexLindex;
1089 idxTokenPtr = TokenAfter(valTokenPtr);
1090 if (TclGetIndexFromToken(idxTokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_BEFORE,
1093 * The idxTokenPtr parsed as a valid index value and was
1094 * encoded as expected by INST_LIST_INDEX_IMM.
1096 * NOTE: that we rely on indexing before a list producing the
1097 * same result as indexing after a list.
1100 CompileWord(envPtr, valTokenPtr, interp, 1);
1101 TclEmitInstInt4( INST_LIST_INDEX_IMM, idx, envPtr);
1106 * If the value was not known at compile time, the conversion failed or
1107 * the value was negative, we just keep on going with the more complex
1112 * Push the operands onto the stack.
1116 for (i=1 ; i<numWords ; i++) {
1117 CompileWord(envPtr, valTokenPtr, interp, i);
1118 valTokenPtr = TokenAfter(valTokenPtr);
1122 * Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI if there are
1123 * multiple index args.
1126 if (numWords == 3) {
1127 TclEmitOpcode( INST_LIST_INDEX, envPtr);
1129 TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr);
1136 *----------------------------------------------------------------------
1138 * TclCompileListCmd --
1140 * Procedure called to compile the "list" command.
1143 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
1144 * evaluation to runtime.
1147 * Instructions are added to envPtr to execute the "list" command at
1150 *----------------------------------------------------------------------
1155 Tcl_Interp *interp, /* Used for error reporting. */
1156 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1157 * created by Tcl_ParseCommand. */
1158 Command *cmdPtr, /* Points to defintion of command being
1160 CompileEnv *envPtr) /* Holds resulting instructions. */
1162 DefineLineInformation; /* TIP #280 */
1163 Tcl_Token *valueTokenPtr;
1164 int i, numWords, concat, build;
1165 Tcl_Obj *listObj, *objPtr;
1167 if (parsePtr->numWords == 1) {
1169 * [list] without arguments just pushes an empty object.
1172 PushStringLiteral(envPtr, "");
1177 * Test if all arguments are compile-time known. If they are, we can
1178 * implement with a simple push.
1181 numWords = parsePtr->numWords;
1182 valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
1183 listObj = Tcl_NewObj();
1184 for (i = 1; i < numWords && listObj != NULL; i++) {
1185 objPtr = Tcl_NewObj();
1186 if (TclWordKnownAtCompileTime(valueTokenPtr, objPtr)) {
1187 (void) Tcl_ListObjAppendElement(NULL, listObj, objPtr);
1189 Tcl_DecrRefCount(objPtr);
1190 Tcl_DecrRefCount(listObj);
1193 valueTokenPtr = TokenAfter(valueTokenPtr);
1195 if (listObj != NULL) {
1196 TclEmitPush(TclAddLiteralObj(envPtr, listObj, NULL), envPtr);
1201 * Push the all values onto the stack.
1204 numWords = parsePtr->numWords;
1205 valueTokenPtr = TokenAfter(parsePtr->tokenPtr);
1207 for (i = 1; i < numWords; i++) {
1208 if (valueTokenPtr->type == TCL_TOKEN_EXPAND_WORD && build > 0) {
1209 TclEmitInstInt4( INST_LIST, build, envPtr);
1211 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1216 CompileWord(envPtr, valueTokenPtr, interp, i);
1217 if (valueTokenPtr->type == TCL_TOKEN_EXPAND_WORD) {
1219 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1226 valueTokenPtr = TokenAfter(valueTokenPtr);
1229 TclEmitInstInt4( INST_LIST, build, envPtr);
1231 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1236 * If there was just one expanded word, we must ensure that it is a list
1237 * at this point. We use an [lrange ... 0 end] for this (instead of
1238 * [llength], as with literals) as we must drop any string representation
1239 * that might be hanging around.
1242 if (concat && numWords == 2) {
1243 TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
1244 TclEmitInt4( TCL_INDEX_END, envPtr);
1250 *----------------------------------------------------------------------
1252 * TclCompileLlengthCmd --
1254 * Procedure called to compile the "llength" command.
1257 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
1258 * evaluation to runtime.
1261 * Instructions are added to envPtr to execute the "llength" command at
1264 *----------------------------------------------------------------------
1268 TclCompileLlengthCmd(
1269 Tcl_Interp *interp, /* Used for error reporting. */
1270 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1271 * created by Tcl_ParseCommand. */
1272 Command *cmdPtr, /* Points to defintion of command being
1274 CompileEnv *envPtr) /* Holds resulting instructions. */
1276 DefineLineInformation; /* TIP #280 */
1277 Tcl_Token *varTokenPtr;
1279 if (parsePtr->numWords != 2) {
1282 varTokenPtr = TokenAfter(parsePtr->tokenPtr);
1284 CompileWord(envPtr, varTokenPtr, interp, 1);
1285 TclEmitOpcode( INST_LIST_LENGTH, envPtr);
1290 *----------------------------------------------------------------------
1292 * TclCompileLrangeCmd --
1294 * How to compile the "lrange" command. We only bother because we needed
1295 * the opcode anyway for "lassign".
1297 *----------------------------------------------------------------------
1301 TclCompileLrangeCmd(
1302 Tcl_Interp *interp, /* Tcl interpreter for context. */
1303 Tcl_Parse *parsePtr, /* Points to a parse structure for the
1305 Command *cmdPtr, /* Points to defintion of command being
1307 CompileEnv *envPtr) /* Holds the resulting instructions. */
1309 DefineLineInformation; /* TIP #280 */
1310 Tcl_Token *tokenPtr, *listTokenPtr;
1313 if (parsePtr->numWords != 4) {
1316 listTokenPtr = TokenAfter(parsePtr->tokenPtr);
1318 tokenPtr = TokenAfter(listTokenPtr);
1319 if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
1324 * Token was an index value, and we treat all "first" indices
1325 * before the list same as the start of the list.
1328 tokenPtr = TokenAfter(tokenPtr);
1329 if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
1334 * Token was an index value, and we treat all "last" indices
1335 * after the list same as the end of the list.
1339 * Issue instructions. It's not safe to skip doing the LIST_RANGE, as
1340 * we've not proved that the 'list' argument is really a list. Not that it
1341 * is worth trying to do that given current knowledge.
1344 CompileWord(envPtr, listTokenPtr, interp, 1);
1345 TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr);
1346 TclEmitInt4( idx2, envPtr);
1351 *----------------------------------------------------------------------
1353 * TclCompileLinsertCmd --
1355 * How to compile the "linsert" command. We only bother with the case
1356 * where the index is constant.
1358 *----------------------------------------------------------------------
1362 TclCompileLinsertCmd(
1363 Tcl_Interp *interp, /* Tcl interpreter for context. */
1364 Tcl_Parse *parsePtr, /* Points to a parse structure for the
1366 Command *cmdPtr, /* Points to defintion of command being
1368 CompileEnv *envPtr) /* Holds the resulting instructions. */
1370 DefineLineInformation; /* TIP #280 */
1371 Tcl_Token *tokenPtr, *listTokenPtr;
1374 if (parsePtr->numWords < 3) {
1377 listTokenPtr = TokenAfter(parsePtr->tokenPtr);
1380 * Parse the index. Will only compile if it is constant and not an
1381 * _integer_ less than zero (since we reserve negative indices here for
1382 * end-relative indexing) or an end-based index greater than 'end' itself.
1385 tokenPtr = TokenAfter(listTokenPtr);
1388 * NOTE: This command treats all inserts at indices before the list
1389 * the same as inserts at the start of the list, and all inserts
1390 * after the list the same as inserts at the end of the list. We
1391 * make that transformation here so we can use the optimized bytecode
1392 * as much as possible.
1394 if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_END,
1400 * There are four main cases. If there are no values to insert, this is
1401 * just a confirm-listiness check. If the index is '0', this is a prepend.
1402 * If the index is 'end' (== TCL_INDEX_END), this is an append. Otherwise,
1403 * this is a splice (== split, insert values as list, concat-3).
1406 CompileWord(envPtr, listTokenPtr, interp, 1);
1407 if (parsePtr->numWords == 3) {
1408 TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
1409 TclEmitInt4( TCL_INDEX_END, envPtr);
1413 for (i=3 ; i<parsePtr->numWords ; i++) {
1414 tokenPtr = TokenAfter(tokenPtr);
1415 CompileWord(envPtr, tokenPtr, interp, i);
1417 TclEmitInstInt4( INST_LIST, i-3, envPtr);
1419 if (idx == TCL_INDEX_START) {
1420 TclEmitInstInt4( INST_REVERSE, 2, envPtr);
1421 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1422 } else if (idx == TCL_INDEX_END) {
1423 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1426 * Here we handle two ranges for idx. First when idx > 0, we
1427 * want the first half of the split to end at index idx-1 and
1428 * the second half to start at index idx.
1429 * Second when idx < TCL_INDEX_END, indicating "end-N" indexing,
1430 * we want the first half of the split to end at index end-N and
1431 * the second half to start at index end-N+1. We accomplish this
1432 * with a pre-adjustment of the end-N value.
1433 * The root of this is that the commands [lrange] and [linsert]
1434 * differ in their interpretation of the "end" index.
1437 if (idx < TCL_INDEX_END) {
1440 TclEmitInstInt4( INST_OVER, 1, envPtr);
1441 TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
1442 TclEmitInt4( idx-1, envPtr);
1443 TclEmitInstInt4( INST_REVERSE, 3, envPtr);
1444 TclEmitInstInt4( INST_LIST_RANGE_IMM, idx, envPtr);
1445 TclEmitInt4( TCL_INDEX_END, envPtr);
1446 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1447 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1454 *----------------------------------------------------------------------
1456 * TclCompileLreplaceCmd --
1458 * How to compile the "lreplace" command. We only bother with the case
1459 * where the indices are constant.
1461 *----------------------------------------------------------------------
1465 TclCompileLreplaceCmd(
1466 Tcl_Interp *interp, /* Tcl interpreter for context. */
1467 Tcl_Parse *parsePtr, /* Points to a parse structure for the
1469 Command *cmdPtr, /* Points to defintion of command being
1471 CompileEnv *envPtr) /* Holds the resulting instructions. */
1473 DefineLineInformation; /* TIP #280 */
1474 Tcl_Token *tokenPtr, *listTokenPtr;
1476 int emptyPrefix=1, suffixStart = 0;
1478 if (parsePtr->numWords < 4) {
1481 listTokenPtr = TokenAfter(parsePtr->tokenPtr);
1483 tokenPtr = TokenAfter(listTokenPtr);
1484 if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
1489 tokenPtr = TokenAfter(tokenPtr);
1490 if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
1496 * General structure of the [lreplace] result is
1497 * prefix replacement suffix
1498 * In a few cases we can predict various parts will be empty and
1501 * The proper suffix begins with the greater of indices idx1 or
1502 * idx2 + 1. If we cannot tell at compile time which is greater,
1503 * we must defer to direct evaluation.
1506 if (idx1 == TCL_INDEX_AFTER) {
1508 } else if (idx2 == TCL_INDEX_BEFORE) {
1510 } else if (idx2 == TCL_INDEX_END) {
1511 suffixStart = TCL_INDEX_AFTER;
1512 } else if (((idx2 < TCL_INDEX_END) && (idx1 <= TCL_INDEX_END))
1513 || ((idx2 >= TCL_INDEX_START) && (idx1 >= TCL_INDEX_START))) {
1514 suffixStart = (idx1 > idx2 + 1) ? idx1 : idx2 + 1;
1519 /* All paths start with computing/pushing the original value. */
1520 CompileWord(envPtr, listTokenPtr, interp, 1);
1523 * Push all the replacement values next so any errors raised in
1524 * creating them get raised first.
1526 if (parsePtr->numWords > 4) {
1527 /* Push the replacement arguments */
1528 tokenPtr = TokenAfter(tokenPtr);
1529 for (i=4 ; i<parsePtr->numWords ; i++) {
1530 CompileWord(envPtr, tokenPtr, interp, i);
1531 tokenPtr = TokenAfter(tokenPtr);
1534 /* Make a list of them... */
1535 TclEmitInstInt4( INST_LIST, i - 4, envPtr);
1540 if ((idx1 == suffixStart) && (parsePtr->numWords == 4)) {
1542 * This is a "no-op". Example: [lreplace {a b c} 2 0]
1543 * We still do a list operation to get list-verification
1544 * and canonicalization side effects.
1546 TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
1547 TclEmitInt4( TCL_INDEX_END, envPtr);
1551 if (idx1 != TCL_INDEX_START) {
1552 /* Prefix may not be empty; generate bytecode to push it */
1554 TclEmitOpcode( INST_DUP, envPtr);
1556 TclEmitInstInt4( INST_OVER, 1, envPtr);
1558 TclEmitInstInt4( INST_LIST_RANGE_IMM, 0, envPtr);
1559 TclEmitInt4( idx1 - 1, envPtr);
1561 TclEmitInstInt4( INST_REVERSE, 2, envPtr);
1562 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1568 TclEmitInstInt4( INST_REVERSE, 2, envPtr);
1571 if (suffixStart == TCL_INDEX_AFTER) {
1572 TclEmitOpcode( INST_POP, envPtr);
1574 PushStringLiteral(envPtr, "");
1577 /* Suffix may not be empty; generate bytecode to push it */
1578 TclEmitInstInt4( INST_LIST_RANGE_IMM, suffixStart, envPtr);
1579 TclEmitInt4( TCL_INDEX_END, envPtr);
1581 TclEmitOpcode( INST_LIST_CONCAT, envPtr);
1589 *----------------------------------------------------------------------
1591 * TclCompileLsetCmd --
1593 * Procedure called to compile the "lset" command.
1596 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
1597 * evaluation to runtime.
1600 * Instructions are added to envPtr to execute the "lset" command at
1603 * The general template for execution of the "lset" command is:
1604 * (1) Instructions to push the variable name, unless the variable is
1605 * local to the stack frame.
1606 * (2) If the variable is an array element, instructions to push the
1607 * array element name.
1608 * (3) Instructions to push each of zero or more "index" arguments to the
1609 * stack, followed with the "newValue" element.
1610 * (4) Instructions to duplicate the variable name and/or array element
1611 * name onto the top of the stack, if either was pushed at steps (1)
1613 * (5) The appropriate INST_LOAD_* instruction to place the original
1614 * value of the list variable at top of stack.
1615 * (6) At this point, the stack contains:
1616 * varName? arrayElementName? index1 index2 ... newValue oldList
1617 * The compiler emits one of INST_LSET_FLAT or INST_LSET_LIST
1618 * according as whether there is exactly one index element (LIST) or
1619 * either zero or else two or more (FLAT). This instruction removes
1620 * everything from the stack except for the two names and pushes the
1621 * new value of the variable.
1622 * (7) Finally, INST_STORE_* stores the new value in the variable and
1623 * cleans up the stack.
1625 *----------------------------------------------------------------------
1630 Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
1631 Tcl_Parse *parsePtr, /* Points to a parse structure for the
1633 Command *cmdPtr, /* Points to defintion of command being
1635 CompileEnv *envPtr) /* Holds the resulting instructions. */
1637 DefineLineInformation; /* TIP #280 */
1638 int tempDepth; /* Depth used for emitting one part of the
1640 Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing the
1641 * parse of the variable name. */
1642 int localIndex; /* Index of var in local var table. */
1643 int isScalar; /* Flag == 1 if scalar, 0 if array. */
1647 * Check argument count.
1650 /* TODO: Consider support for compiling expanded args. */
1651 if (parsePtr->numWords < 3) {
1653 * Fail at run time, not in compilation.
1660 * Decide if we can use a frame slot for the var/array name or if we need
1661 * to emit code to compute and push the name at runtime. We use a frame
1662 * slot (entry in the array of local vars) if we are compiling a procedure
1663 * body and if the name is simple text that does not include namespace
1667 varTokenPtr = TokenAfter(parsePtr->tokenPtr);
1668 PushVarNameWord(interp, varTokenPtr, envPtr, 0,
1669 &localIndex, &isScalar, 1);
1672 * Push the "index" args and the new element value.
1675 for (i=2 ; i<parsePtr->numWords ; ++i) {
1676 varTokenPtr = TokenAfter(varTokenPtr);
1677 CompileWord(envPtr, varTokenPtr, interp, i);
1681 * Duplicate the variable name if it's been pushed.
1684 if (localIndex < 0) {
1686 tempDepth = parsePtr->numWords - 2;
1688 tempDepth = parsePtr->numWords - 1;
1690 TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
1694 * Duplicate an array index if one's been pushed.
1698 if (localIndex < 0) {
1699 tempDepth = parsePtr->numWords - 1;
1701 tempDepth = parsePtr->numWords - 2;
1703 TclEmitInstInt4( INST_OVER, tempDepth, envPtr);
1707 * Emit code to load the variable's value.
1711 if (localIndex < 0) {
1712 TclEmitOpcode( INST_LOAD_STK, envPtr);
1714 Emit14Inst( INST_LOAD_SCALAR, localIndex, envPtr);
1717 if (localIndex < 0) {
1718 TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr);
1720 Emit14Inst( INST_LOAD_ARRAY, localIndex, envPtr);
1725 * Emit the correct variety of 'lset' instruction.
1728 if (parsePtr->numWords == 4) {
1729 TclEmitOpcode( INST_LSET_LIST, envPtr);
1731 TclEmitInstInt4( INST_LSET_FLAT, parsePtr->numWords-1, envPtr);
1735 * Emit code to put the value back in the variable.
1739 if (localIndex < 0) {
1740 TclEmitOpcode( INST_STORE_STK, envPtr);
1742 Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
1745 if (localIndex < 0) {
1746 TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr);
1748 Emit14Inst( INST_STORE_ARRAY, localIndex, envPtr);
1756 *----------------------------------------------------------------------
1758 * TclCompileNamespace*Cmd --
1760 * Procedures called to compile the "namespace" command; currently, only
1761 * the subcommands "namespace current" and "namespace upvar" are compiled
1762 * to bytecodes, and the latter only inside a procedure(-like) context.
1765 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
1766 * evaluation to runtime.
1769 * Instructions are added to envPtr to execute the "namespace upvar"
1770 * command at runtime.
1772 *----------------------------------------------------------------------
1776 TclCompileNamespaceCurrentCmd(
1777 Tcl_Interp *interp, /* Used for error reporting. */
1778 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1779 * created by Tcl_ParseCommand. */
1780 Command *cmdPtr, /* Points to defintion of command being
1782 CompileEnv *envPtr) /* Holds resulting instructions. */
1785 * Only compile [namespace current] without arguments.
1788 if (parsePtr->numWords != 1) {
1793 * Not much to do; we compile to a single instruction...
1796 TclEmitOpcode( INST_NS_CURRENT, envPtr);
1801 TclCompileNamespaceCodeCmd(
1802 Tcl_Interp *interp, /* Used for error reporting. */
1803 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1804 * created by Tcl_ParseCommand. */
1805 Command *cmdPtr, /* Points to defintion of command being
1807 CompileEnv *envPtr) /* Holds resulting instructions. */
1809 DefineLineInformation; /* TIP #280 */
1810 Tcl_Token *tokenPtr;
1812 if (parsePtr->numWords != 2) {
1815 tokenPtr = TokenAfter(parsePtr->tokenPtr);
1818 * The specification of [namespace code] is rather shocking, in that it is
1819 * supposed to check if the argument is itself the result of [namespace
1820 * code] and not apply itself in that case. Which is excessively cautious,
1821 * but what the test suite checks for.
1824 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || (tokenPtr[1].size > 20
1825 && strncmp(tokenPtr[1].start, "::namespace inscope ", 20) == 0)) {
1827 * Technically, we could just pass a literal '::namespace inscope '
1828 * term through, but that's something which really shouldn't be
1829 * occurring as something that the user writes so we'll just punt it.
1836 * Now we can compile using the same strategy as [namespace code]'s normal
1837 * implementation does internally. Note that we can't bind the namespace
1838 * name directly here, because TclOO plays complex games with namespaces;
1839 * the value needs to be determined at runtime for safety.
1842 PushStringLiteral(envPtr, "::namespace");
1843 PushStringLiteral(envPtr, "inscope");
1844 TclEmitOpcode( INST_NS_CURRENT, envPtr);
1845 CompileWord(envPtr, tokenPtr, interp, 1);
1846 TclEmitInstInt4( INST_LIST, 4, envPtr);
1851 TclCompileNamespaceOriginCmd(
1852 Tcl_Interp *interp, /* Used for error reporting. */
1853 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1854 * created by Tcl_ParseCommand. */
1855 Command *cmdPtr, /* Points to defintion of command being
1857 CompileEnv *envPtr) /* Holds resulting instructions. */
1859 DefineLineInformation; /* TIP #280 */
1860 Tcl_Token *tokenPtr;
1862 if (parsePtr->numWords != 2) {
1865 tokenPtr = TokenAfter(parsePtr->tokenPtr);
1867 CompileWord(envPtr, tokenPtr, interp, 1);
1868 TclEmitOpcode( INST_ORIGIN_COMMAND, envPtr);
1873 TclCompileNamespaceQualifiersCmd(
1874 Tcl_Interp *interp, /* Used for error reporting. */
1875 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1876 * created by Tcl_ParseCommand. */
1877 Command *cmdPtr, /* Points to defintion of command being
1879 CompileEnv *envPtr) /* Holds resulting instructions. */
1881 DefineLineInformation; /* TIP #280 */
1882 Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
1885 if (parsePtr->numWords != 2) {
1889 CompileWord(envPtr, tokenPtr, interp, 1);
1890 PushStringLiteral(envPtr, "0");
1891 PushStringLiteral(envPtr, "::");
1892 TclEmitInstInt4( INST_OVER, 2, envPtr);
1893 TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
1894 off = CurrentOffset(envPtr);
1895 PushStringLiteral(envPtr, "1");
1896 TclEmitOpcode( INST_SUB, envPtr);
1897 TclEmitInstInt4( INST_OVER, 2, envPtr);
1898 TclEmitInstInt4( INST_OVER, 1, envPtr);
1899 TclEmitOpcode( INST_STR_INDEX, envPtr);
1900 PushStringLiteral(envPtr, ":");
1901 TclEmitOpcode( INST_STR_EQ, envPtr);
1902 off = off - CurrentOffset(envPtr);
1903 TclEmitInstInt1( INST_JUMP_TRUE1, off, envPtr);
1904 TclEmitOpcode( INST_STR_RANGE, envPtr);
1909 TclCompileNamespaceTailCmd(
1910 Tcl_Interp *interp, /* Used for error reporting. */
1911 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1912 * created by Tcl_ParseCommand. */
1913 Command *cmdPtr, /* Points to defintion of command being
1915 CompileEnv *envPtr) /* Holds resulting instructions. */
1917 DefineLineInformation; /* TIP #280 */
1918 Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr);
1919 JumpFixup jumpFixup;
1921 if (parsePtr->numWords != 2) {
1926 * Take care; only add 2 to found index if the string was actually found.
1929 CompileWord(envPtr, tokenPtr, interp, 1);
1930 PushStringLiteral(envPtr, "::");
1931 TclEmitInstInt4( INST_OVER, 1, envPtr);
1932 TclEmitOpcode( INST_STR_FIND_LAST, envPtr);
1933 TclEmitOpcode( INST_DUP, envPtr);
1934 PushStringLiteral(envPtr, "0");
1935 TclEmitOpcode( INST_GE, envPtr);
1936 TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFixup);
1937 PushStringLiteral(envPtr, "2");
1938 TclEmitOpcode( INST_ADD, envPtr);
1939 TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127);
1940 PushStringLiteral(envPtr, "end");
1941 TclEmitOpcode( INST_STR_RANGE, envPtr);
1946 TclCompileNamespaceUpvarCmd(
1947 Tcl_Interp *interp, /* Used for error reporting. */
1948 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
1949 * created by Tcl_ParseCommand. */
1950 Command *cmdPtr, /* Points to defintion of command being
1952 CompileEnv *envPtr) /* Holds resulting instructions. */
1954 DefineLineInformation; /* TIP #280 */
1955 Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr;
1956 int localIndex, numWords, i;
1958 if (envPtr->procPtr == NULL) {
1963 * Only compile [namespace upvar ...]: needs an even number of args, >=4
1966 numWords = parsePtr->numWords;
1967 if ((numWords % 2) || (numWords < 4)) {
1972 * Push the namespace
1975 tokenPtr = TokenAfter(parsePtr->tokenPtr);
1976 CompileWord(envPtr, tokenPtr, interp, 1);
1979 * Loop over the (otherVar, thisVar) pairs. If any of the thisVar is not a
1980 * local variable, return an error so that the non-compiled command will
1981 * be called at runtime.
1984 localTokenPtr = tokenPtr;
1985 for (i=2; i<numWords; i+=2) {
1986 otherTokenPtr = TokenAfter(localTokenPtr);
1987 localTokenPtr = TokenAfter(otherTokenPtr);
1989 CompileWord(envPtr, otherTokenPtr, interp, i);
1990 localIndex = LocalScalarFromToken(localTokenPtr, envPtr);
1991 if (localIndex < 0) {
1994 TclEmitInstInt4( INST_NSUPVAR, localIndex, envPtr);
1998 * Pop the namespace, and set the result to empty
2001 TclEmitOpcode( INST_POP, envPtr);
2002 PushStringLiteral(envPtr, "");
2007 TclCompileNamespaceWhichCmd(
2008 Tcl_Interp *interp, /* Used for error reporting. */
2009 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2010 * created by Tcl_ParseCommand. */
2011 Command *cmdPtr, /* Points to defintion of command being
2013 CompileEnv *envPtr) /* Holds resulting instructions. */
2015 DefineLineInformation; /* TIP #280 */
2016 Tcl_Token *tokenPtr, *opt;
2019 if (parsePtr->numWords < 2 || parsePtr->numWords > 3) {
2022 tokenPtr = TokenAfter(parsePtr->tokenPtr);
2026 * If there's an option, check that it's "-command". We don't handle
2027 * "-variable" (currently) and anything else is an error.
2030 if (parsePtr->numWords == 3) {
2031 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
2035 if (opt->size < 2 || opt->size > 8
2036 || strncmp(opt->start, "-command", opt->size) != 0) {
2039 tokenPtr = TokenAfter(tokenPtr);
2044 * Issue the bytecode.
2047 CompileWord(envPtr, tokenPtr, interp, idx);
2048 TclEmitOpcode( INST_RESOLVE_COMMAND, envPtr);
2053 *----------------------------------------------------------------------
2055 * TclCompileRegexpCmd --
2057 * Procedure called to compile the "regexp" command.
2060 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
2061 * evaluation to runtime.
2064 * Instructions are added to envPtr to execute the "regexp" command at
2067 *----------------------------------------------------------------------
2071 TclCompileRegexpCmd(
2072 Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
2073 Tcl_Parse *parsePtr, /* Points to a parse structure for the
2075 Command *cmdPtr, /* Points to defintion of command being
2077 CompileEnv *envPtr) /* Holds the resulting instructions. */
2079 DefineLineInformation; /* TIP #280 */
2080 Tcl_Token *varTokenPtr; /* Pointer to the Tcl_Token representing the
2081 * parse of the RE or string. */
2082 int i, len, nocase, exact, sawLast, simple;
2086 * We are only interested in compiling simple regexp cases. Currently
2087 * supported compile cases are:
2088 * regexp ?-nocase? ?--? staticString $var
2089 * regexp ?-nocase? ?--? {^staticString$} $var
2092 if (parsePtr->numWords < 3) {
2099 varTokenPtr = parsePtr->tokenPtr;
2102 * We only look for -nocase and -- as options. Everything else gets pushed
2103 * to runtime execution. This is different than regexp's runtime option
2104 * handling, but satisfies our stricter needs.
2107 for (i = 1; i < parsePtr->numWords - 2; i++) {
2108 varTokenPtr = TokenAfter(varTokenPtr);
2109 if (varTokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
2111 * Not a simple string, so punt to runtime.
2116 str = varTokenPtr[1].start;
2117 len = varTokenPtr[1].size;
2118 if ((len == 2) && (str[0] == '-') && (str[1] == '-')) {
2122 } else if ((len > 1) && (strncmp(str, "-nocase", len) == 0)) {
2126 * Not an option we recognize.
2133 if ((parsePtr->numWords - i) != 2) {
2135 * We don't support capturing to variables.
2142 * Get the regexp string. If it is not a simple string or can't be
2143 * converted to a glob pattern, push the word for the INST_REGEXP.
2144 * Keep changes here in sync with TclCompileSwitchCmd Switch_Regexp.
2147 varTokenPtr = TokenAfter(varTokenPtr);
2149 if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
2152 str = varTokenPtr[1].start;
2153 len = varTokenPtr[1].size;
2156 * If it has a '-', it could be an incorrectly formed regexp command.
2159 if ((*str == '-') && !sawLast) {
2165 * The semantics of regexp are always match on re == "".
2168 PushStringLiteral(envPtr, "1");
2173 * Attempt to convert pattern to glob. If successful, push the
2174 * converted pattern as a literal.
2177 if (TclReToGlob(NULL, varTokenPtr[1].start, len, &ds, &exact, NULL)
2180 PushLiteral(envPtr, Tcl_DStringValue(&ds),Tcl_DStringLength(&ds));
2181 Tcl_DStringFree(&ds);
2186 CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords-2);
2190 * Push the string arg.
2193 varTokenPtr = TokenAfter(varTokenPtr);
2194 CompileWord(envPtr, varTokenPtr, interp, parsePtr->numWords-1);
2197 if (exact && !nocase) {
2198 TclEmitOpcode( INST_STR_EQ, envPtr);
2200 TclEmitInstInt1( INST_STR_MATCH, nocase, envPtr);
2204 * Pass correct RE compile flags. We use only Int1 (8-bit), but
2205 * that handles all the flags we want to pass.
2206 * Don't use TCL_REG_NOSUB as we may have backrefs.
2209 int cflags = TCL_REG_ADVANCED | (nocase ? TCL_REG_NOCASE : 0);
2211 TclEmitInstInt1( INST_REGEXP, cflags, envPtr);
2218 *----------------------------------------------------------------------
2220 * TclCompileRegsubCmd --
2222 * Procedure called to compile the "regsub" command.
2225 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
2226 * evaluation to runtime.
2229 * Instructions are added to envPtr to execute the "regsub" command at
2232 *----------------------------------------------------------------------
2236 TclCompileRegsubCmd(
2237 Tcl_Interp *interp, /* Tcl interpreter for error reporting. */
2238 Tcl_Parse *parsePtr, /* Points to a parse structure for the
2240 Command *cmdPtr, /* Points to defintion of command being
2242 CompileEnv *envPtr) /* Holds the resulting instructions. */
2245 * We only compile the case with [regsub -all] where the pattern is both
2246 * known at compile time and simple (i.e., no RE metacharacters). That is,
2247 * the pattern must be translatable into a glob like "*foo*" with no other
2248 * glob metacharacters inside it; there must be some "foo" in there too.
2249 * The substitution string must also be known at compile time and free of
2250 * metacharacters ("\digit" and "&"). Finally, there must not be a
2251 * variable mentioned in the [regsub] to write the result back to (because
2252 * we can't get the count of substitutions that would be the result in
2253 * that case). The key is that these are the conditions under which a
2254 * [string map] could be used instead, in particular a [string map] of the
2255 * form we can compile to bytecode.
2257 * In short, we look for:
2259 * regsub -all [--] simpleRE string simpleReplacement
2261 * The only optional part is the "--", and no other options are handled.
2264 DefineLineInformation; /* TIP #280 */
2265 Tcl_Token *tokenPtr, *stringTokenPtr;
2266 Tcl_Obj *patternObj = NULL, *replacementObj = NULL;
2267 Tcl_DString pattern;
2269 int len, exact, quantified, result = TCL_ERROR;
2271 if (parsePtr->numWords < 5 || parsePtr->numWords > 6) {
2276 * Parse the "-all", which must be the first argument (other options not
2277 * supported, non-"-all" substitution we can't compile).
2280 tokenPtr = TokenAfter(parsePtr->tokenPtr);
2281 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size != 4
2282 || strncmp(tokenPtr[1].start, "-all", 4)) {
2287 * Get the pattern into patternObj, checking for "--" in the process.
2290 Tcl_DStringInit(&pattern);
2291 tokenPtr = TokenAfter(tokenPtr);
2292 patternObj = Tcl_NewObj();
2293 if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
2296 if (Tcl_GetString(patternObj)[0] == '-') {
2297 if (strcmp(Tcl_GetString(patternObj), "--") != 0
2298 || parsePtr->numWords == 5) {
2301 tokenPtr = TokenAfter(tokenPtr);
2302 Tcl_DecrRefCount(patternObj);
2303 patternObj = Tcl_NewObj();
2304 if (!TclWordKnownAtCompileTime(tokenPtr, patternObj)) {
2307 } else if (parsePtr->numWords == 6) {
2312 * Identify the code which produces the string to apply the substitution
2313 * to (stringTokenPtr), and the replacement string (into replacementObj).
2316 stringTokenPtr = TokenAfter(tokenPtr);
2317 tokenPtr = TokenAfter(stringTokenPtr);
2318 replacementObj = Tcl_NewObj();
2319 if (!TclWordKnownAtCompileTime(tokenPtr, replacementObj)) {
2324 * Next, higher-level checks. Is the RE a very simple glob? Is the
2325 * replacement "simple"?
2328 bytes = Tcl_GetStringFromObj(patternObj, &len);
2329 if (TclReToGlob(NULL, bytes, len, &pattern, &exact, &quantified)
2330 != TCL_OK || exact || quantified) {
2333 bytes = Tcl_DStringValue(&pattern);
2334 if (*bytes++ != '*') {
2340 if (bytes[1] == '\0') {
2342 * OK, we've proved there are no metacharacters except for the
2346 len = Tcl_DStringLength(&pattern) - 2;
2352 * The pattern is "**"! I believe that should be impossible,
2353 * but we definitely can't handle that at all.
2356 case '\0': case '?': case '[': case '\\':
2362 for (bytes = Tcl_GetString(replacementObj); *bytes; bytes++) {
2364 case '\\': case '&':
2370 * Proved the simplicity constraints! Time to issue the code.
2374 bytes = Tcl_DStringValue(&pattern) + 1;
2375 PushLiteral(envPtr, bytes, len);
2376 bytes = Tcl_GetStringFromObj(replacementObj, &len);
2377 PushLiteral(envPtr, bytes, len);
2378 CompileWord(envPtr, stringTokenPtr, interp, parsePtr->numWords-2);
2379 TclEmitOpcode( INST_STR_MAP, envPtr);
2382 Tcl_DStringFree(&pattern);
2384 Tcl_DecrRefCount(patternObj);
2386 if (replacementObj) {
2387 Tcl_DecrRefCount(replacementObj);
2393 *----------------------------------------------------------------------
2395 * TclCompileReturnCmd --
2397 * Procedure called to compile the "return" command.
2400 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
2401 * evaluation to runtime.
2404 * Instructions are added to envPtr to execute the "return" command at
2407 *----------------------------------------------------------------------
2411 TclCompileReturnCmd(
2412 Tcl_Interp *interp, /* Used for error reporting. */
2413 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2414 * created by Tcl_ParseCommand. */
2415 Command *cmdPtr, /* Points to defintion of command being
2417 CompileEnv *envPtr) /* Holds resulting instructions. */
2419 DefineLineInformation; /* TIP #280 */
2421 * General syntax: [return ?-option value ...? ?result?]
2422 * An even number of words means an explicit result argument is present.
2424 int level, code, objc, size, status = TCL_OK;
2425 int numWords = parsePtr->numWords;
2426 int explicitResult = (0 == (numWords % 2));
2427 int numOptionWords = numWords - 1 - explicitResult;
2428 Tcl_Obj *returnOpts, **objv;
2429 Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
2432 * Check for special case which can always be compiled:
2433 * return -options <opts> <msg>
2434 * Unlike the normal [return] compilation, this version does everything at
2435 * runtime so it can handle arbitrary words and not just literals. Note
2436 * that if INST_RETURN_STK wasn't already needed for something else
2437 * ('finally' clause processing) this piece of code would not be present.
2440 if ((numWords == 4) && (wordTokenPtr->type == TCL_TOKEN_SIMPLE_WORD)
2441 && (wordTokenPtr[1].size == 8)
2442 && (strncmp(wordTokenPtr[1].start, "-options", 8) == 0)) {
2443 Tcl_Token *optsTokenPtr = TokenAfter(wordTokenPtr);
2444 Tcl_Token *msgTokenPtr = TokenAfter(optsTokenPtr);
2446 CompileWord(envPtr, optsTokenPtr, interp, 2);
2447 CompileWord(envPtr, msgTokenPtr, interp, 3);
2448 TclEmitInvoke(envPtr, INST_RETURN_STK);
2453 * Allocate some working space.
2456 objv = TclStackAlloc(interp, numOptionWords * sizeof(Tcl_Obj *));
2459 * Scan through the return options. If any are unknown at compile time,
2460 * there is no value in bytecompiling. Save the option values known in an
2461 * objv array for merging into a return options dictionary.
2463 * TODO: There is potential for improvement if all option keys are known
2464 * at compile time and all option values relating to '-code' and '-level'
2465 * are known at compile time.
2468 for (objc = 0; objc < numOptionWords; objc++) {
2469 objv[objc] = Tcl_NewObj();
2470 Tcl_IncrRefCount(objv[objc]);
2471 if (!TclWordKnownAtCompileTime(wordTokenPtr, objv[objc])) {
2473 * Non-literal, so punt to run-time assembly of the dictionary.
2476 for (; objc>=0 ; objc--) {
2477 TclDecrRefCount(objv[objc]);
2479 TclStackFree(interp, objv);
2480 goto issueRuntimeReturn;
2482 wordTokenPtr = TokenAfter(wordTokenPtr);
2484 status = TclMergeReturnOptions(interp, objc, objv,
2485 &returnOpts, &code, &level);
2486 while (--objc >= 0) {
2487 TclDecrRefCount(objv[objc]);
2489 TclStackFree(interp, objv);
2490 if (TCL_ERROR == status) {
2492 * Something was bogus in the return options. Clear the error message,
2493 * and report back to the compiler that this must be interpreted at
2497 Tcl_ResetResult(interp);
2502 * All options are known at compile time, so we're going to bytecompile.
2503 * Emit instructions to push the result on the stack.
2506 if (explicitResult) {
2507 CompileWord(envPtr, wordTokenPtr, interp, numWords-1);
2510 * No explict result argument, so default result is empty string.
2513 PushStringLiteral(envPtr, "");
2517 * Check for optimization: When [return] is in a proc, and there's no
2518 * enclosing [catch], and there are no return options, then the INST_DONE
2519 * instruction is equivalent, and may be more efficient.
2522 if (numOptionWords == 0 && envPtr->procPtr != NULL) {
2524 * We have default return options and we're in a proc ...
2527 int index = envPtr->exceptArrayNext - 1;
2528 int enclosingCatch = 0;
2530 while (index >= 0) {
2531 ExceptionRange range = envPtr->exceptArrayPtr[index];
2533 if ((range.type == CATCH_EXCEPTION_RANGE)
2534 && (range.catchOffset == -1)) {
2540 if (!enclosingCatch) {
2542 * ... and there is no enclosing catch. Issue the maximally
2543 * efficient exit instruction.
2546 Tcl_DecrRefCount(returnOpts);
2547 TclEmitOpcode(INST_DONE, envPtr);
2548 TclAdjustStackDepth(1, envPtr);
2553 /* Optimize [return -level 0 $x]. */
2554 Tcl_DictObjSize(NULL, returnOpts, &size);
2555 if (size == 0 && level == 0 && code == TCL_OK) {
2556 Tcl_DecrRefCount(returnOpts);
2561 * Could not use the optimization, so we push the return options dict, and
2562 * emit the INST_RETURN_IMM instruction with code and level as operands.
2565 CompileReturnInternal(envPtr, INST_RETURN_IMM, code, level, returnOpts);
2570 * Assemble the option dictionary (as a list as that's good enough).
2573 wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
2574 for (objc=1 ; objc<=numOptionWords ; objc++) {
2575 CompileWord(envPtr, wordTokenPtr, interp, objc);
2576 wordTokenPtr = TokenAfter(wordTokenPtr);
2578 TclEmitInstInt4(INST_LIST, numOptionWords, envPtr);
2584 if (explicitResult) {
2585 CompileWord(envPtr, wordTokenPtr, interp, numWords-1);
2587 PushStringLiteral(envPtr, "");
2591 * Issue the RETURN itself.
2594 TclEmitInvoke(envPtr, INST_RETURN_STK);
2599 CompileReturnInternal(
2604 Tcl_Obj *returnOpts)
2606 if (level == 0 && (code == TCL_BREAK || code == TCL_CONTINUE)) {
2607 ExceptionRange *rangePtr;
2608 ExceptionAux *exceptAux;
2610 rangePtr = TclGetInnermostExceptionRange(envPtr, code, &exceptAux);
2611 if (rangePtr && rangePtr->type == LOOP_EXCEPTION_RANGE) {
2612 TclCleanupStackForBreakContinue(envPtr, exceptAux);
2613 if (code == TCL_BREAK) {
2614 TclAddLoopBreakFixup(envPtr, exceptAux);
2616 TclAddLoopContinueFixup(envPtr, exceptAux);
2618 Tcl_DecrRefCount(returnOpts);
2623 TclEmitPush(TclAddLiteralObj(envPtr, returnOpts, NULL), envPtr);
2624 TclEmitInstInt4(op, code, envPtr);
2625 TclEmitInt4(level, envPtr);
2629 TclCompileSyntaxError(
2633 Tcl_Obj *msg = Tcl_GetObjResult(interp);
2635 const char *bytes = TclGetStringFromObj(msg, &numBytes);
2637 TclErrorStackResetIf(interp, bytes, numBytes);
2638 TclEmitPush(TclRegisterNewLiteral(envPtr, bytes, numBytes), envPtr);
2639 CompileReturnInternal(envPtr, INST_SYNTAX, TCL_ERROR, 0,
2640 TclNoErrorStack(interp, Tcl_GetReturnOptions(interp, TCL_ERROR)));
2641 Tcl_ResetResult(interp);
2645 *----------------------------------------------------------------------
2647 * TclCompileUpvarCmd --
2649 * Procedure called to compile the "upvar" command.
2652 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
2653 * evaluation to runtime.
2656 * Instructions are added to envPtr to execute the "upvar" command at
2659 *----------------------------------------------------------------------
2664 Tcl_Interp *interp, /* Used for error reporting. */
2665 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2666 * created by Tcl_ParseCommand. */
2667 Command *cmdPtr, /* Points to defintion of command being
2669 CompileEnv *envPtr) /* Holds resulting instructions. */
2671 DefineLineInformation; /* TIP #280 */
2672 Tcl_Token *tokenPtr, *otherTokenPtr, *localTokenPtr;
2673 int localIndex, numWords, i;
2676 if (envPtr->procPtr == NULL) {
2680 numWords = parsePtr->numWords;
2686 * Push the frame index if it is known at compile time
2689 objPtr = Tcl_NewObj();
2690 tokenPtr = TokenAfter(parsePtr->tokenPtr);
2691 if (TclWordKnownAtCompileTime(tokenPtr, objPtr)) {
2692 CallFrame *framePtr;
2693 const Tcl_ObjType *newTypePtr, *typePtr = objPtr->typePtr;
2696 * Attempt to convert to a level reference. Note that TclObjGetFrame
2697 * only changes the obj type when a conversion was successful.
2700 TclObjGetFrame(interp, objPtr, &framePtr);
2701 newTypePtr = objPtr->typePtr;
2702 Tcl_DecrRefCount(objPtr);
2704 if (newTypePtr != typePtr) {
2708 /* TODO: Push the known value instead? */
2709 CompileWord(envPtr, tokenPtr, interp, 1);
2710 otherTokenPtr = TokenAfter(tokenPtr);
2713 if (!(numWords%2)) {
2716 PushStringLiteral(envPtr, "1");
2717 otherTokenPtr = tokenPtr;
2721 Tcl_DecrRefCount(objPtr);
2726 * Loop over the (otherVar, thisVar) pairs. If any of the thisVar is not a
2727 * local variable, return an error so that the non-compiled command will
2728 * be called at runtime.
2731 for (; i<numWords; i+=2, otherTokenPtr = TokenAfter(localTokenPtr)) {
2732 localTokenPtr = TokenAfter(otherTokenPtr);
2734 CompileWord(envPtr, otherTokenPtr, interp, i);
2735 localIndex = LocalScalarFromToken(localTokenPtr, envPtr);
2736 if (localIndex < 0) {
2739 TclEmitInstInt4( INST_UPVAR, localIndex, envPtr);
2743 * Pop the frame index, and set the result to empty
2746 TclEmitOpcode( INST_POP, envPtr);
2747 PushStringLiteral(envPtr, "");
2752 *----------------------------------------------------------------------
2754 * TclCompileVariableCmd --
2756 * Procedure called to compile the "variable" command.
2759 * Returns TCL_OK for a successful compile. Returns TCL_ERROR to defer
2760 * evaluation to runtime.
2763 * Instructions are added to envPtr to execute the "variable" command at
2766 *----------------------------------------------------------------------
2770 TclCompileVariableCmd(
2771 Tcl_Interp *interp, /* Used for error reporting. */
2772 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2773 * created by Tcl_ParseCommand. */
2774 Command *cmdPtr, /* Points to defintion of command being
2776 CompileEnv *envPtr) /* Holds resulting instructions. */
2778 DefineLineInformation; /* TIP #280 */
2779 Tcl_Token *varTokenPtr, *valueTokenPtr;
2780 int localIndex, numWords, i;
2782 numWords = parsePtr->numWords;
2788 * Bail out if not compiling a proc body
2791 if (envPtr->procPtr == NULL) {
2796 * Loop over the (var, value) pairs.
2799 valueTokenPtr = parsePtr->tokenPtr;
2800 for (i=1; i<numWords; i+=2) {
2801 varTokenPtr = TokenAfter(valueTokenPtr);
2802 valueTokenPtr = TokenAfter(varTokenPtr);
2804 localIndex = IndexTailVarIfKnown(interp, varTokenPtr, envPtr);
2806 if (localIndex < 0) {
2810 /* TODO: Consider what value can pass through the
2811 * IndexTailVarIfKnown() screen. Full CompileWord()
2812 * likely does not apply here. Push known value instead. */
2813 CompileWord(envPtr, varTokenPtr, interp, i);
2814 TclEmitInstInt4( INST_VARIABLE, localIndex, envPtr);
2816 if (i+1 < numWords) {
2818 * A value has been given: set the variable, pop the value
2821 CompileWord(envPtr, valueTokenPtr, interp, i+1);
2822 Emit14Inst( INST_STORE_SCALAR, localIndex, envPtr);
2823 TclEmitOpcode( INST_POP, envPtr);
2828 * Set the result to empty
2831 PushStringLiteral(envPtr, "");
2836 *----------------------------------------------------------------------
2838 * IndexTailVarIfKnown --
2840 * Procedure used in compiling [global] and [variable] commands. It
2841 * inspects the variable name described by varTokenPtr and, if the tail
2842 * is known at compile time, defines a corresponding local variable.
2845 * Returns the variable's index in the table of compiled locals if the
2846 * tail is known at compile time, or -1 otherwise.
2851 *----------------------------------------------------------------------
2855 IndexTailVarIfKnown(
2857 Tcl_Token *varTokenPtr, /* Token representing the variable name */
2858 CompileEnv *envPtr) /* Holds resulting instructions. */
2861 const char *tailName, *p;
2862 int len, n = varTokenPtr->numComponents;
2863 Tcl_Token *lastTokenPtr;
2864 int full, localIndex;
2867 * Determine if the tail is (a) known at compile time, and (b) not an
2868 * array element. Should any of these fail, return an error so that the
2869 * non-compiled command will be called at runtime.
2871 * In order for the tail to be known at compile time, the last token in
2872 * the word has to be constant and contain "::" if it is not the only one.
2875 if (!EnvHasLVT(envPtr)) {
2880 if (TclWordKnownAtCompileTime(varTokenPtr, tailPtr)) {
2882 lastTokenPtr = varTokenPtr;
2885 lastTokenPtr = varTokenPtr + n;
2887 if (lastTokenPtr->type != TCL_TOKEN_TEXT) {
2888 Tcl_DecrRefCount(tailPtr);
2891 Tcl_SetStringObj(tailPtr, lastTokenPtr->start, lastTokenPtr->size);
2894 tailName = TclGetStringFromObj(tailPtr, &len);
2897 if (*(tailName+len-1) == ')') {
2899 * Possible array: bail out
2902 Tcl_DecrRefCount(tailPtr);
2907 * Get the tail: immediately after the last '::'
2910 for (p = tailName + len -1; p > tailName; p--) {
2911 if ((*p == ':') && (*(p-1) == ':')) {
2916 if (!full && (p == tailName)) {
2918 * No :: in the last component.
2921 Tcl_DecrRefCount(tailPtr);
2924 len -= p - tailName;
2928 localIndex = TclFindCompiledLocal(tailName, len, 1, envPtr);
2929 Tcl_DecrRefCount(tailPtr);
2934 * ----------------------------------------------------------------------
2936 * TclCompileObjectNextCmd, TclCompileObjectSelfCmd --
2938 * Compilations of the TclOO utility commands [next] and [self].
2940 * ----------------------------------------------------------------------
2944 TclCompileObjectNextCmd(
2945 Tcl_Interp *interp, /* Used for error reporting. */
2946 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2947 * created by Tcl_ParseCommand. */
2948 Command *cmdPtr, /* Points to defintion of command being
2950 CompileEnv *envPtr) /* Holds resulting instructions. */
2952 DefineLineInformation; /* TIP #280 */
2953 Tcl_Token *tokenPtr = parsePtr->tokenPtr;
2956 if (parsePtr->numWords > 255) {
2960 for (i=0 ; i<parsePtr->numWords ; i++) {
2961 CompileWord(envPtr, tokenPtr, interp, i);
2962 tokenPtr = TokenAfter(tokenPtr);
2964 TclEmitInstInt1( INST_TCLOO_NEXT, i, envPtr);
2969 TclCompileObjectNextToCmd(
2970 Tcl_Interp *interp, /* Used for error reporting. */
2971 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2972 * created by Tcl_ParseCommand. */
2973 Command *cmdPtr, /* Points to defintion of command being
2975 CompileEnv *envPtr) /* Holds resulting instructions. */
2977 DefineLineInformation; /* TIP #280 */
2978 Tcl_Token *tokenPtr = parsePtr->tokenPtr;
2981 if (parsePtr->numWords < 2 || parsePtr->numWords > 255) {
2985 for (i=0 ; i<parsePtr->numWords ; i++) {
2986 CompileWord(envPtr, tokenPtr, interp, i);
2987 tokenPtr = TokenAfter(tokenPtr);
2989 TclEmitInstInt1( INST_TCLOO_NEXT_CLASS, i, envPtr);
2994 TclCompileObjectSelfCmd(
2995 Tcl_Interp *interp, /* Used for error reporting. */
2996 Tcl_Parse *parsePtr, /* Points to a parse structure for the command
2997 * created by Tcl_ParseCommand. */
2998 Command *cmdPtr, /* Points to defintion of command being
3000 CompileEnv *envPtr) /* Holds resulting instructions. */
3003 * We only handle [self] and [self object] (which is the same operation).
3004 * These are the only very common operations on [self] for which
3005 * bytecoding is at all reasonable.
3008 if (parsePtr->numWords == 1) {
3009 goto compileSelfObject;
3010 } else if (parsePtr->numWords == 2) {
3011 Tcl_Token *tokenPtr = TokenAfter(parsePtr->tokenPtr), *subcmd;
3013 if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || tokenPtr[1].size==0) {
3017 subcmd = tokenPtr + 1;
3018 if (strncmp(subcmd->start, "object", subcmd->size) == 0) {
3019 goto compileSelfObject;
3020 } else if (strncmp(subcmd->start, "namespace", subcmd->size) == 0) {
3021 goto compileSelfNamespace;
3026 * Can't compile; handle with runtime call.
3034 * This delegates the entire problem to a single opcode.
3037 TclEmitOpcode( INST_TCLOO_SELF, envPtr);
3040 compileSelfNamespace:
3043 * This is formally only correct with TclOO methods as they are currently
3044 * implemented; it assumes that the current namespace is invariably when a
3045 * TclOO context is present is the object's namespace, and that's
3046 * technically only something that's a matter of current policy. But it
3047 * avoids creating another opcode, so that's all good!
3050 TclEmitOpcode( INST_TCLOO_SELF, envPtr);
3051 TclEmitOpcode( INST_POP, envPtr);
3052 TclEmitOpcode( INST_NS_CURRENT, envPtr);