Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Spare developers the burden and error risk of counting bytes in string literals, or having to type them twice. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b89a07c1fc92356e1d73deebdb3eda36 |
User & Date: | dgp 2013-05-23 20:24:56 |
Context
2013-05-24
| ||
18:37 |
3613854 - Fixup stack maintenance /code generation for [array set x $oddList].
Postscript - I see... check-in: 77f74854f9 user: dgp tags: trunk | |
10:39 | merge trunk check-in: 6604e2cb37 user: dgp tags: dgp-refactor | |
2013-05-23
| ||
20:24 | Spare developers the burden and error risk of counting bytes in string literals, or having to type t... check-in: b89a07c1fc user: dgp tags: trunk | |
18:32 | Eliminate code duplication. check-in: 948546755c user: dgp tags: trunk | |
Changes
Changes to generic/tclCompCmds.c.
︙ | ︙ | |||
291 292 293 294 295 296 297 | TclEmitInstInt1(INST_JUMP_TRUE1, 5, envPtr); savedStackDepth = envPtr->currStackDepth; TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr); TclEmitInstInt1(INST_JUMP1, 3, envPtr); envPtr->currStackDepth = savedStackDepth; TclEmitOpcode( INST_POP, envPtr); } | | | < | < | | 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | TclEmitInstInt1(INST_JUMP_TRUE1, 5, envPtr); savedStackDepth = envPtr->currStackDepth; TclEmitOpcode( INST_ARRAY_MAKE_STK, envPtr); TclEmitInstInt1(INST_JUMP1, 3, envPtr); envPtr->currStackDepth = savedStackDepth; TclEmitOpcode( INST_POP, envPtr); } PushStringLiteral(envPtr, ""); goto done; } /* * Special case: literal odd-length argument is always an error. */ if (isDataValid && !isDataEven) { savedStackDepth = envPtr->currStackDepth; PushStringLiteral(envPtr, "list must have an even number of elements"); PushStringLiteral(envPtr, "-errorCode {TCL ARGUMENT FORMAT}"); TclEmitInstInt4(INST_RETURN_IMM, 1, envPtr); TclEmitInt4( 0, envPtr); envPtr->currStackDepth = savedStackDepth; PushStringLiteral(envPtr, ""); goto done; } /* * Prepare for the internal foreach. */ |
︙ | ︙ | |||
372 373 374 375 376 377 378 | * containing an invalid literal; with valid list literals, we've * already checked (worth it because literals are a very common * use-case with [array set]). */ TclEmitOpcode( INST_DUP, envPtr); TclEmitOpcode( INST_LIST_LENGTH, envPtr); | | | < | < | 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | * containing an invalid literal; with valid list literals, we've * already checked (worth it because literals are a very common * use-case with [array set]). */ TclEmitOpcode( INST_DUP, envPtr); TclEmitOpcode( INST_LIST_LENGTH, envPtr); PushStringLiteral(envPtr, "1"); TclEmitOpcode( INST_BITAND, envPtr); offsetFwd = CurrentOffset(envPtr); TclEmitInstInt1(INST_JUMP_FALSE1, 0, envPtr); savedStackDepth = envPtr->currStackDepth; PushStringLiteral(envPtr, "list must have an even number of elements"); PushStringLiteral(envPtr, "-errorCode {TCL ARGUMENT FORMAT}"); TclEmitInstInt4(INST_RETURN_IMM, 1, envPtr); TclEmitInt4( 0, envPtr); envPtr->currStackDepth = savedStackDepth; fwd = CurrentOffset(envPtr) - offsetFwd; TclStoreInt1AtPtr(fwd, envPtr->codeStart+offsetFwd+1); } Emit14Inst( INST_STORE_SCALAR, dataVar, envPtr); |
︙ | ︙ | |||
437 438 439 440 441 442 443 | envPtr->currStackDepth = savedStackDepth; TclEmitOpcode( INST_POP, envPtr); } if (!isDataLiteral) { TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); TclEmitInt4( dataVar, envPtr); } | | | 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | envPtr->currStackDepth = savedStackDepth; TclEmitOpcode( INST_POP, envPtr); } if (!isDataLiteral) { TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); TclEmitInt4( dataVar, envPtr); } PushStringLiteral(envPtr, ""); done: Tcl_DecrRefCount(literalObj); return TCL_OK; } int TclCompileArrayUnsetCmd( |
︙ | ︙ | |||
481 482 483 484 485 486 487 | TclEmitInstInt1(INST_JUMP_FALSE1, 6, envPtr); savedStackDepth = envPtr->currStackDepth; TclEmitInstInt1(INST_UNSET_STK, 1, envPtr); TclEmitInstInt1(INST_JUMP1, 3, envPtr); envPtr->currStackDepth = savedStackDepth; TclEmitOpcode( INST_POP, envPtr); } | | | 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 | TclEmitInstInt1(INST_JUMP_FALSE1, 6, envPtr); savedStackDepth = envPtr->currStackDepth; TclEmitInstInt1(INST_UNSET_STK, 1, envPtr); TclEmitInstInt1(INST_JUMP1, 3, envPtr); envPtr->currStackDepth = savedStackDepth; TclEmitOpcode( INST_POP, envPtr); } PushStringLiteral(envPtr, ""); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileBreakCmd -- |
︙ | ︙ | |||
521 522 523 524 525 526 527 | } /* * Emit a break instruction. */ TclEmitOpcode(INST_BREAK, envPtr); | | | 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | } /* * Emit a break instruction. */ TclEmitOpcode(INST_BREAK, envPtr); PushStringLiteral(envPtr, ""); /* Evil hack! */ return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileCatchCmd -- |
︙ | ︙ | |||
670 671 672 673 674 675 676 | * Special case when neither result nor options are being saved. In * that case, we can skip quite a bit of the command epilogue; all we * have to do is drop the result and push the return code (and, of * course, finish the catch context). */ TclEmitOpcode( INST_POP, envPtr); | | | 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 | * Special case when neither result nor options are being saved. In * that case, we can skip quite a bit of the command epilogue; all we * have to do is drop the result and push the return code (and, of * course, finish the catch context). */ TclEmitOpcode( INST_POP, envPtr); PushStringLiteral(envPtr, "0"); TclEmitInstInt1( INST_JUMP1, 3, envPtr); envPtr->currStackDepth = savedStackDepth; ExceptionRangeTarget(envPtr, range, catchOffset); TclEmitOpcode( INST_PUSH_RETURN_CODE, envPtr); ExceptionRangeEnds(envPtr, range); TclEmitOpcode( INST_END_CATCH, envPtr); |
︙ | ︙ | |||
692 693 694 695 696 697 698 | } /* * Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch result, * and jump around the "error case" code. */ | | | 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 | } /* * Emit the "no errors" epilogue: push "0" (TCL_OK) as the catch result, * and jump around the "error case" code. */ PushStringLiteral(envPtr, "0"); TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpFixup); /* Stack at this point: ?script? <mark> result TCL_OK */ /* * Emit the "error case" epilogue. Push the interpreter result and the * return code. */ |
︙ | ︙ | |||
828 829 830 831 832 833 834 | } /* * Emit a continue instruction. */ TclEmitOpcode(INST_CONTINUE, envPtr); | | | 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | } /* * Emit a continue instruction. */ TclEmitOpcode(INST_CONTINUE, envPtr); PushStringLiteral(envPtr, ""); /* Evil hack! */ return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileDict*Cmd -- |
︙ | ︙ | |||
1204 1205 1206 1207 1208 1209 1210 | nonConstant: worker = TclFindCompiledLocal(NULL, 0, 1, envPtr); if (worker < 0) { return TclCompileBasicMin0ArgCmd(interp, parsePtr, cmdPtr, envPtr); } | | | 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 | nonConstant: worker = TclFindCompiledLocal(NULL, 0, 1, envPtr); if (worker < 0) { return TclCompileBasicMin0ArgCmd(interp, parsePtr, cmdPtr, envPtr); } PushStringLiteral(envPtr, ""); Emit14Inst( INST_STORE_SCALAR, worker, envPtr); TclEmitOpcode( INST_POP, envPtr); tokenPtr = TokenAfter(parsePtr->tokenPtr); for (i=1 ; i<parsePtr->numWords ; i+=2) { CompileWord(envPtr, tokenPtr, interp, i); tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, i+1); |
︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 | /* * Deal with some special edge cases. Note that in the case with one * argument, the only thing to do is to verify the dict-ness. */ if (parsePtr->numWords < 2) { | | | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 | /* * Deal with some special edge cases. Note that in the case with one * argument, the only thing to do is to verify the dict-ness. */ if (parsePtr->numWords < 2) { PushStringLiteral(envPtr, ""); return TCL_OK; } else if (parsePtr->numWords == 2) { tokenPtr = TokenAfter(parsePtr->tokenPtr); CompileWord(envPtr, tokenPtr, interp, 1); TclEmitOpcode( INST_DUP, envPtr); TclEmitOpcode( INST_DICT_VERIFY, envPtr); return TCL_OK; |
︙ | ︙ | |||
1473 1474 1475 1476 1477 1478 1479 | * Preparation complete; issue instructions. Note that this code issues * fixed-sized jumps. That simplifies things a lot! * * First up, initialize the accumulator dictionary if needed. */ if (collect == TCL_EACH_COLLECT) { | | | 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 | * Preparation complete; issue instructions. Note that this code issues * fixed-sized jumps. That simplifies things a lot! * * First up, initialize the accumulator dictionary if needed. */ if (collect == TCL_EACH_COLLECT) { PushStringLiteral(envPtr, ""); Emit14Inst( INST_STORE_SCALAR, collectVar, envPtr); TclEmitOpcode( INST_POP, envPtr); } /* * Get the dictionary and start the iteration. No catching of errors at * this point. |
︙ | ︙ | |||
1611 1612 1613 1614 1615 1616 1617 | TclUpdateInstInt4AtPc(INST_JUMP4, jumpDisplacement, envPtr->codeStart + endTargetOffset); if (collect == TCL_EACH_COLLECT) { Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr); TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); TclEmitInt4( collectVar, envPtr); } else { | | | 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 | TclUpdateInstInt4AtPc(INST_JUMP4, jumpDisplacement, envPtr->codeStart + endTargetOffset); if (collect == TCL_EACH_COLLECT) { Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr); TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); TclEmitInt4( collectVar, envPtr); } else { PushStringLiteral(envPtr, ""); } return TCL_OK; } int TclCompileDictUpdateCmd( Tcl_Interp *interp, /* Used for looking up stuff. */ |
︙ | ︙ | |||
1987 1988 1989 1990 1991 1992 1993 | tokenPtr = TokenAfter(tokenPtr); } TclEmitInstInt4(INST_LIST, parsePtr->numWords-3,envPtr); Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr); TclEmitInstInt4(INST_OVER, 1, envPtr); TclEmitOpcode( INST_DICT_EXPAND, envPtr); TclEmitInstInt4(INST_DICT_RECOMBINE_IMM, dictVar, envPtr); | | | | | | | | | | 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 | tokenPtr = TokenAfter(tokenPtr); } TclEmitInstInt4(INST_LIST, parsePtr->numWords-3,envPtr); Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr); TclEmitInstInt4(INST_OVER, 1, envPtr); TclEmitOpcode( INST_DICT_EXPAND, envPtr); TclEmitInstInt4(INST_DICT_RECOMBINE_IMM, dictVar, envPtr); PushStringLiteral(envPtr, ""); } else { /* * Case: Direct dict in LVT with empty body. */ PushStringLiteral(envPtr, ""); Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr); PushStringLiteral(envPtr, ""); TclEmitOpcode( INST_DICT_EXPAND, envPtr); TclEmitInstInt4(INST_DICT_RECOMBINE_IMM, dictVar, envPtr); PushStringLiteral(envPtr, ""); } } else { if (gotPath) { /* * Case: Path into dict in non-simple var with empty body. */ tokenPtr = varTokenPtr; for (i=1 ; i<parsePtr->numWords-1 ; i++) { CompileWord(envPtr, tokenPtr, interp, i-1); tokenPtr = TokenAfter(tokenPtr); } TclEmitInstInt4(INST_LIST, parsePtr->numWords-3,envPtr); TclEmitInstInt4(INST_OVER, 1, envPtr); TclEmitOpcode( INST_LOAD_STK, envPtr); TclEmitInstInt4(INST_OVER, 1, envPtr); TclEmitOpcode( INST_DICT_EXPAND, envPtr); TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr); PushStringLiteral(envPtr, ""); } else { /* * Case: Direct dict in non-simple var with empty body. */ CompileWord(envPtr, varTokenPtr, interp, 0); TclEmitOpcode( INST_DUP, envPtr); TclEmitOpcode( INST_LOAD_STK, envPtr); PushStringLiteral(envPtr, ""); TclEmitOpcode( INST_DICT_EXPAND, envPtr); PushStringLiteral(envPtr, ""); TclEmitInstInt4(INST_REVERSE, 2, envPtr); TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr); PushStringLiteral(envPtr, ""); } } envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } /* |
︙ | ︙ | |||
2084 2085 2086 2087 2088 2089 2090 | TclEmitOpcode( INST_LOAD_STK, envPtr); } else { Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr); } if (gotPath) { Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr); } else { | | | 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 | TclEmitOpcode( INST_LOAD_STK, envPtr); } else { Emit14Inst( INST_LOAD_SCALAR, dictVar, envPtr); } if (gotPath) { Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr); } else { PushStringLiteral(envPtr, ""); } TclEmitOpcode( INST_DICT_EXPAND, envPtr); Emit14Inst( INST_STORE_SCALAR, keysTmp, envPtr); TclEmitOpcode( INST_POP, envPtr); /* * Now the body of the [dict with]. |
︙ | ︙ | |||
2115 2116 2117 2118 2119 2120 2121 | TclEmitOpcode( INST_END_CATCH, envPtr); if (varNameTmp > -1) { Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr); } if (gotPath) { Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr); } else { | | | 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 | TclEmitOpcode( INST_END_CATCH, envPtr); if (varNameTmp > -1) { Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr); } if (gotPath) { Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr); } else { PushStringLiteral(envPtr, ""); } Emit14Inst( INST_LOAD_SCALAR, keysTmp, envPtr); if (dictVar == -1) { TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr); } else { TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr); } |
︙ | ︙ | |||
2139 2140 2141 2142 2143 2144 2145 | TclEmitOpcode( INST_END_CATCH, envPtr); if (varNameTmp > -1) { Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr); } if (parsePtr->numWords > 3) { Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr); } else { | | | 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 | TclEmitOpcode( INST_END_CATCH, envPtr); if (varNameTmp > -1) { Emit14Inst( INST_LOAD_SCALAR, varNameTmp, envPtr); } if (parsePtr->numWords > 3) { Emit14Inst( INST_LOAD_SCALAR, pathTmp, envPtr); } else { PushStringLiteral(envPtr, ""); } Emit14Inst( INST_LOAD_SCALAR, keysTmp, envPtr); if (dictVar == -1) { TclEmitOpcode( INST_DICT_RECOMBINE_STK, envPtr); } else { TclEmitInstInt4( INST_DICT_RECOMBINE_IMM, dictVar, envPtr); } |
︙ | ︙ | |||
2261 2262 2263 2264 2265 2266 2267 | DefineLineInformation; /* TIP #280 */ if (parsePtr->numWords != 2) { return TCL_ERROR; } messageTokenPtr = TokenAfter(parsePtr->tokenPtr); | | | 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 | DefineLineInformation; /* TIP #280 */ if (parsePtr->numWords != 2) { return TCL_ERROR; } messageTokenPtr = TokenAfter(parsePtr->tokenPtr); PushStringLiteral(envPtr, "-code error -level 0"); CompileWord(envPtr, messageTokenPtr, interp, 1); TclEmitOpcode(INST_RETURN_STK, envPtr); envPtr->currStackDepth = savedStackDepth + 1; return TCL_OK; } /* |
︙ | ︙ | |||
2474 2475 2476 2477 2478 2479 2480 | ExceptionRangeTarget(envPtr, nextRange, breakOffset); /* * The for command's result is an empty string. */ envPtr->currStackDepth = savedStackDepth; | | | 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 | ExceptionRangeTarget(envPtr, nextRange, breakOffset); /* * The for command's result is an empty string. */ envPtr->currStackDepth = savedStackDepth; PushStringLiteral(envPtr, ""); return TCL_OK; } /* *---------------------------------------------------------------------- * |
︙ | ︙ | |||
2784 2785 2786 2787 2788 2789 2790 | } /* * Create temporary variable to capture return values from loop body. */ if (collect == TCL_EACH_COLLECT) { | | | 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 | } /* * Create temporary variable to capture return values from loop body. */ if (collect == TCL_EACH_COLLECT) { PushStringLiteral(envPtr, ""); Emit14Inst( INST_STORE_SCALAR, collectVar, envPtr); TclEmitOpcode( INST_POP, envPtr); } /* * Initialize the temporary var that holds the count of loop iterations. */ |
︙ | ︙ | |||
2877 2878 2879 2880 2881 2882 2883 | envPtr->currStackDepth = savedStackDepth; if (collect == TCL_EACH_COLLECT) { Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr); TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); TclEmitInt4( collectVar, envPtr); } else { | | | 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 | envPtr->currStackDepth = savedStackDepth; if (collect == TCL_EACH_COLLECT) { Emit14Inst( INST_LOAD_SCALAR, collectVar, envPtr); TclEmitInstInt1(INST_UNSET_SCALAR, 0, envPtr); TclEmitInt4( collectVar, envPtr); } else { PushStringLiteral(envPtr, ""); } envPtr->currStackDepth = savedStackDepth + 1; done: for (loopIndex = 0; loopIndex < numLists; loopIndex++) { if (varvList[loopIndex] != NULL) { ckfree(varvList[loopIndex]); |
︙ | ︙ | |||
3249 3250 3251 3252 3253 3254 3255 | /* * EVIL HACK! Force there to be a string representation in the case * where there's just a "%s" in the format; case covered by the test * format-20.1 (and it is horrible...) */ TclEmitOpcode(INST_DUP, envPtr); | | | 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 | /* * EVIL HACK! Force there to be a string representation in the case * where there's just a "%s" in the format; case covered by the test * format-20.1 (and it is horrible...) */ TclEmitOpcode(INST_DUP, envPtr); PushStringLiteral(envPtr, ""); TclEmitOpcode(INST_STR_EQ, envPtr); TclEmitOpcode(INST_POP, envPtr); } return TCL_OK; } /* |
︙ | ︙ | |||
3472 3473 3474 3475 3476 3477 3478 | if (elName != NULL && !(flags & TCL_NO_ELEMENT)) { if (elNameChars) { envPtr->line = line; envPtr->clNext = clNext; TclCompileTokens(interp, elemTokenPtr, elemTokenCount, envPtr); } else { | | | 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 | if (elName != NULL && !(flags & TCL_NO_ELEMENT)) { if (elNameChars) { envPtr->line = line; envPtr->clNext = clNext; TclCompileTokens(interp, elemTokenPtr, elemTokenCount, envPtr); } else { PushStringLiteral(envPtr, ""); } } } else { /* * The var name isn't simple: compile and push it. */ |
︙ | ︙ |
Changes to generic/tclCompCmdsGR.c.
︙ | ︙ | |||
73 74 75 76 77 78 79 | return TCL_ERROR; } /* * Push the namespace */ | | | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | return TCL_ERROR; } /* * Push the namespace */ PushStringLiteral(envPtr, "::"); /* * Loop over the variables. */ varTokenPtr = TokenAfter(parsePtr->tokenPtr); for (i=2; i<=numWords; varTokenPtr = TokenAfter(varTokenPtr),i++) { |
︙ | ︙ | |||
96 97 98 99 100 101 102 | } /* * Pop the namespace, and set the result to empty */ TclEmitOpcode( INST_POP, envPtr); | | | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | } /* * Pop the namespace, and set the result to empty */ TclEmitOpcode( INST_POP, envPtr); PushStringLiteral(envPtr, ""); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileIfCmd -- |
︙ | ︙ | |||
372 373 374 375 376 377 378 | } } else { /* * No else clause: the "if" command's result is an empty string. */ if (compileScripts) { | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 | } } else { /* * No else clause: the "if" command's result is an empty string. */ if (compileScripts) { PushStringLiteral(envPtr, ""); } } /* * Fix the unconditional jumps to the end of the "if" command. */ |
︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 | Tcl_Obj *listObj, *objPtr; if (parsePtr->numWords == 1) { /* * [list] without arguments just pushes an empty object. */ | | | 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 | Tcl_Obj *listObj, *objPtr; if (parsePtr->numWords == 1) { /* * [list] without arguments just pushes an empty object. */ PushStringLiteral(envPtr, ""); return TCL_OK; } /* * Test if all arguments are compile-time known. If they are, we can * implement with a simple push. */ |
︙ | ︙ | |||
1541 1542 1543 1544 1545 1546 1547 | * is worth trying to do that given current knowledge. */ CompileWord(envPtr, listTokenPtr, interp, 1); if (guaranteedDropAll) { TclEmitOpcode( INST_LIST_LENGTH, envPtr); TclEmitOpcode( INST_POP, envPtr); | | | 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | * is worth trying to do that given current knowledge. */ CompileWord(envPtr, listTokenPtr, interp, 1); if (guaranteedDropAll) { TclEmitOpcode( INST_LIST_LENGTH, envPtr); TclEmitOpcode( INST_POP, envPtr); PushStringLiteral(envPtr, ""); } else { TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr); TclEmitInt4( idx2, envPtr); } return TCL_OK; } |
︙ | ︙ | |||
1807 1808 1809 1810 1811 1812 1813 | /* * Now we can compile using the same strategy as [namespace code]'s normal * implementation does internally. Note that we can't bind the namespace * name directly here, because TclOO plays complex games with namespaces; * the value needs to be determined at runtime for safety. */ | | | | 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 | /* * Now we can compile using the same strategy as [namespace code]'s normal * implementation does internally. Note that we can't bind the namespace * name directly here, because TclOO plays complex games with namespaces; * the value needs to be determined at runtime for safety. */ PushStringLiteral(envPtr, "::namespace"); PushStringLiteral(envPtr, "inscope"); TclEmitOpcode( INST_NS_CURRENT, envPtr); CompileWord(envPtr, tokenPtr, interp, 1); TclEmitInstInt4( INST_LIST, 4, envPtr); return TCL_OK; } int |
︙ | ︙ | |||
1833 1834 1835 1836 1837 1838 1839 | int off; if (parsePtr->numWords != 2) { return TCL_ERROR; } CompileWord(envPtr, tokenPtr, interp, 1); | | | | | | 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 | int off; if (parsePtr->numWords != 2) { return TCL_ERROR; } CompileWord(envPtr, tokenPtr, interp, 1); PushStringLiteral(envPtr, "0"); PushStringLiteral(envPtr, "::"); TclEmitInstInt4( INST_OVER, 2, envPtr); TclEmitOpcode( INST_STR_FIND_LAST, envPtr); off = CurrentOffset(envPtr); PushStringLiteral(envPtr, "1"); TclEmitOpcode( INST_SUB, envPtr); TclEmitInstInt4( INST_OVER, 2, envPtr); TclEmitInstInt4( INST_OVER, 1, envPtr); TclEmitOpcode( INST_STR_INDEX, envPtr); PushStringLiteral(envPtr, ":"); TclEmitOpcode( INST_STR_EQ, envPtr); off = off - CurrentOffset(envPtr); TclEmitInstInt1( INST_JUMP_TRUE1, off, envPtr); TclEmitOpcode( INST_STR_RANGE, envPtr); return TCL_OK; } |
︙ | ︙ | |||
1873 1874 1875 1876 1877 1878 1879 | } /* * Take care; only add 2 to found index if the string was actually found. */ CompileWord(envPtr, tokenPtr, interp, 1); | | | | | | 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 | } /* * Take care; only add 2 to found index if the string was actually found. */ CompileWord(envPtr, tokenPtr, interp, 1); PushStringLiteral(envPtr, "::"); TclEmitInstInt4( INST_OVER, 1, envPtr); TclEmitOpcode( INST_STR_FIND_LAST, envPtr); TclEmitOpcode( INST_DUP, envPtr); PushStringLiteral(envPtr, "0"); TclEmitOpcode( INST_GE, envPtr); TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFixup); PushStringLiteral(envPtr, "2"); TclEmitOpcode( INST_ADD, envPtr); TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127); PushStringLiteral(envPtr, "end"); TclEmitOpcode( INST_STR_RANGE, envPtr); return TCL_OK; } int TclCompileNamespaceUpvarCmd( Tcl_Interp *interp, /* Used for error reporting. */ |
︙ | ︙ | |||
1947 1948 1949 1950 1951 1952 1953 | } /* * Pop the namespace, and set the result to empty */ TclEmitOpcode( INST_POP, envPtr); | | | 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 | } /* * Pop the namespace, and set the result to empty */ TclEmitOpcode( INST_POP, envPtr); PushStringLiteral(envPtr, ""); return TCL_OK; } int TclCompileNamespaceWhichCmd( Tcl_Interp *interp, /* Used for error reporting. */ Tcl_Parse *parsePtr, /* Points to a parse structure for the command |
︙ | ︙ | |||
2113 2114 2115 2116 2117 2118 2119 | } if (len == 0) { /* * The semantics of regexp are always match on re == "". */ | | | 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 | } if (len == 0) { /* * The semantics of regexp are always match on re == "". */ PushStringLiteral(envPtr, "1"); return TCL_OK; } /* * Attempt to convert pattern to glob. If successful, push the * converted pattern as a literal. */ |
︙ | ︙ | |||
2455 2456 2457 2458 2459 2460 2461 | if (explicitResult) { CompileWord(envPtr, wordTokenPtr, interp, numWords-1); } else { /* * No explict result argument, so default result is empty string. */ | | | 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 | if (explicitResult) { CompileWord(envPtr, wordTokenPtr, interp, numWords-1); } else { /* * No explict result argument, so default result is empty string. */ PushStringLiteral(envPtr, ""); } /* * Check for optimization: When [return] is in a proc, and there's no * enclosing [catch], and there are no return options, then the INST_DONE * instruction is equivalent, and may be more efficient. */ |
︙ | ︙ | |||
2530 2531 2532 2533 2534 2535 2536 | /* * Push the result. */ if (explicitResult) { CompileWord(envPtr, wordTokenPtr, interp, numWords-1); } else { | | | 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 | /* * Push the result. */ if (explicitResult) { CompileWord(envPtr, wordTokenPtr, interp, numWords-1); } else { PushStringLiteral(envPtr, ""); } /* * Issue the RETURN itself. */ TclEmitOpcode(INST_RETURN_STK, envPtr); |
︙ | ︙ | |||
2642 2643 2644 2645 2646 2647 2648 | CompileWord(envPtr, tokenPtr, interp, 1); otherTokenPtr = TokenAfter(tokenPtr); i = 4; } else { if (!(numWords%2)) { return TCL_ERROR; } | | | 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 | CompileWord(envPtr, tokenPtr, interp, 1); otherTokenPtr = TokenAfter(tokenPtr); i = 4; } else { if (!(numWords%2)) { return TCL_ERROR; } PushStringLiteral(envPtr, "1"); otherTokenPtr = tokenPtr; i = 3; } } else { Tcl_DecrRefCount(objPtr); return TCL_ERROR; } |
︙ | ︙ | |||
2675 2676 2677 2678 2679 2680 2681 | } /* * Pop the frame index, and set the result to empty */ TclEmitOpcode( INST_POP, envPtr); | | | 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 | } /* * Pop the frame index, and set the result to empty */ TclEmitOpcode( INST_POP, envPtr); PushStringLiteral(envPtr, ""); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileVariableCmd -- |
︙ | ︙ | |||
2756 2757 2758 2759 2760 2761 2762 | } } /* * Set the result to empty */ | | | 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 | } } /* * Set the result to empty */ PushStringLiteral(envPtr, ""); return TCL_OK; } /* *---------------------------------------------------------------------- * * IndexTailVarIfKnown -- |
︙ | ︙ |
Changes to generic/tclCompCmdsSZ.c.
︙ | ︙ | |||
84 85 86 87 88 89 90 | #define OP14(name,val1,val2) \ TclEmitInstInt1(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr) #define OP44(name,val1,val2) \ TclEmitInstInt4(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr) #define BODY(token,index) \ SetLineInformation((index));CompileBody(envPtr,(token),interp) #define PUSH(str) \ | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #define OP14(name,val1,val2) \ TclEmitInstInt1(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr) #define OP44(name,val1,val2) \ TclEmitInstInt4(INST_##name,(val1),envPtr);TclEmitInt4((val2),envPtr) #define BODY(token,index) \ SetLineInformation((index));CompileBody(envPtr,(token),interp) #define PUSH(str) \ PushStringLiteral(envPtr, str) #define JUMP(var,name) \ (var) = CurrentOffset(envPtr);TclEmitInstInt4(INST_##name,0,envPtr) #define FIXJUMP(var) \ TclStoreInt4AtPtr(CurrentOffset(envPtr)-(var),envPtr->codeStart+(var)+1) #define LOAD(idx) \ if ((idx)<256) {OP1(LOAD_SCALAR1,(idx));} else {OP4(LOAD_SCALAR4,(idx));} #define STORE(idx) \ |
︙ | ︙ | |||
753 754 755 756 757 758 759 | * is possible to get to an INST_CONCAT1 or INST_DONE without enough * values on the stack, resulting in a crash. Thanks to Joe Mistachkin for * identifying a script that could trigger this case. */ tokenPtr = parse.tokenPtr; if (tokenPtr->type != TCL_TOKEN_TEXT && tokenPtr->type != TCL_TOKEN_BS) { | | | 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | * is possible to get to an INST_CONCAT1 or INST_DONE without enough * values on the stack, resulting in a crash. Thanks to Joe Mistachkin for * identifying a script that could trigger this case. */ tokenPtr = parse.tokenPtr; if (tokenPtr->type != TCL_TOKEN_TEXT && tokenPtr->type != TCL_TOKEN_BS) { PUSH(""); count++; } for (endTokenPtr = tokenPtr + parse.numTokens; tokenPtr < endTokenPtr; tokenPtr = TokenAfter(tokenPtr)) { int length, literal, catchRange, breakJump; char buf[TCL_UTF_MAX]; |
︙ | ︙ | |||
1416 1417 1418 1419 1420 1421 1422 | if (bodyToken[i]->size == 0) { /* * The semantics of regexps are that they always match * when the RE == "". */ | | | 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 | if (bodyToken[i]->size == 0) { /* * The semantics of regexps are that they always match * when the RE == "". */ PUSH("1"); break; } /* * Attempt to convert pattern to glob. If successful, push * the converted pattern. */ |
︙ | ︙ | |||
1541 1542 1543 1544 1545 1546 1547 | * clause (in which case it will already be gone due to the code at the * start of processing an arm, guaranteed) and make the result of the * command an empty string. */ if (!foundDefault) { OP( POP); | | | 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 | * clause (in which case it will already be gone due to the code at the * start of processing an arm, guaranteed) and make the result of the * command an empty string. */ if (!foundDefault) { OP( POP); PUSH(""); } /* * Do jump fixups for arms that were executed. First, fill in the jumps of * all jumps that don't point elsewhere to point to here. */ |
︙ | ︙ | |||
1760 1761 1762 1763 1764 1765 1766 | * now. */ if (!foundDefault) { envPtr->currStackDepth = savedStackDepth; TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault, envPtr->codeStart+jumpToDefault+1); | | | 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 | * now. */ if (!foundDefault) { envPtr->currStackDepth = savedStackDepth; TclStoreInt4AtPtr(CurrentOffset(envPtr)-jumpToDefault, envPtr->codeStart+jumpToDefault+1); PUSH(""); } /* * No more instructions to be issued; everything that needs to jump to the * end of the command is fixed up at this point. */ |
︙ | ︙ | |||
2334 2335 2336 2337 2338 2339 2340 | addrsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); forwardsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); for (i=0 ; i<numHandlers ; i++) { sprintf(buf, "%d", matchCodes[i]); OP( DUP); | | > | > | 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 | addrsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); forwardsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); for (i=0 ; i<numHandlers ; i++) { sprintf(buf, "%d", matchCodes[i]); OP( DUP); PushLiteral(envPtr, buf, strlen(buf)); OP( EQ); JUMP(notCodeJumpSource, JUMP_FALSE4); if (matchClauses[i]) { const char *p; Tcl_ListObjLength(NULL, matchClauses[i], &len); /* * Match the errorcode according to try/trap rules. */ LOAD( optionsVar); PUSH( "-errorcode"); OP4( DICT_GET, 1); TclAdjustStackDepth(-1, envPtr); OP44( LIST_RANGE_IMM, 0, len-1); p = Tcl_GetStringFromObj(matchClauses[i], &len); PushLiteral(envPtr, p, len); OP( STR_EQ); JUMP(notECJumpSource, JUMP_FALSE4); } else { notECJumpSource = -1; /* LINT */ } OP( POP); |
︙ | ︙ | |||
2489 2490 2491 2492 2493 2494 2495 | addrsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); forwardsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); for (i=0 ; i<numHandlers ; i++) { sprintf(buf, "%d", matchCodes[i]); OP( DUP); | | > | > | 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 | addrsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); forwardsToFix = TclStackAlloc(interp, sizeof(int)*numHandlers); for (i=0 ; i<numHandlers ; i++) { sprintf(buf, "%d", matchCodes[i]); OP( DUP); PushLiteral(envPtr, buf, strlen(buf)); OP( EQ); JUMP(notCodeJumpSource, JUMP_FALSE4); if (matchClauses[i]) { const char *p; Tcl_ListObjLength(NULL, matchClauses[i], &len); /* * Match the errorcode according to try/trap rules. */ LOAD( optionsVar); PUSH( "-errorcode"); OP4( DICT_GET, 1); TclAdjustStackDepth(-1, envPtr); OP44( LIST_RANGE_IMM, 0, len-1); p = Tcl_GetStringFromObj(matchClauses[i], &len); PushLiteral(envPtr, p, len); OP( STR_EQ); JUMP(notECJumpSource, JUMP_FALSE4); } else { notECJumpSource = -1; /* LINT */ } /* |
︙ | ︙ | |||
2740 2741 2742 2743 2744 2745 2746 | } else { OP14( UNSET_ARRAY, flags, localIndex); } } varTokenPtr = TokenAfter(varTokenPtr); } | | | 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 | } else { OP14( UNSET_ARRAY, flags, localIndex); } } varTokenPtr = TokenAfter(varTokenPtr); } PUSH(""); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileWhileCmd -- |
︙ | ︙ | |||
2919 2920 2921 2922 2923 2924 2925 | /* * The while command's result is an empty string. */ pushResult: envPtr->currStackDepth = savedStackDepth; | | | 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 | /* * The while command's result is an empty string. */ pushResult: envPtr->currStackDepth = savedStackDepth; PUSH(""); return TCL_OK; } /* *---------------------------------------------------------------------- * * TclCompileYieldCmd -- |
︙ | ︙ | |||
2955 2956 2957 2958 2959 2960 2961 | CompileEnv *envPtr) /* Holds resulting instructions. */ { if (parsePtr->numWords < 1 || parsePtr->numWords > 2) { return TCL_ERROR; } if (parsePtr->numWords == 1) { | | | 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 | CompileEnv *envPtr) /* Holds resulting instructions. */ { if (parsePtr->numWords < 1 || parsePtr->numWords > 2) { return TCL_ERROR; } if (parsePtr->numWords == 1) { PUSH(""); } else { DefineLineInformation; /* TIP #280 */ Tcl_Token *valueTokenPtr = TokenAfter(parsePtr->tokenPtr); CompileWord(envPtr, valueTokenPtr, interp, 1); } OP( YIELD); |
︙ | ︙ | |||
3121 3122 3123 3124 3125 3126 3127 | int instruction, CompileEnv *envPtr) { Tcl_Token *tokenPtr; DefineLineInformation; /* TIP #280 */ if (parsePtr->numWords < 3) { | | | 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 | int instruction, CompileEnv *envPtr) { Tcl_Token *tokenPtr; DefineLineInformation; /* TIP #280 */ if (parsePtr->numWords < 3) { PUSH("1"); } else if (parsePtr->numWords == 3) { tokenPtr = TokenAfter(parsePtr->tokenPtr); CompileWord(envPtr, tokenPtr, interp, 1); tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, 2); TclEmitOpcode(instruction, envPtr); } else if (envPtr->procPtr == NULL) { |
︙ | ︙ | |||
3292 3293 3294 3295 3296 3297 3298 | int words; for (words=1 ; words<parsePtr->numWords ; words++) { tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, words); } if (parsePtr->numWords <= 2) { | | | 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 | int words; for (words=1 ; words<parsePtr->numWords ; words++) { tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, words); } if (parsePtr->numWords <= 2) { PUSH("1"); words++; } while (--words > 1) { TclEmitOpcode(INST_EXPON, envPtr); } return TCL_OK; } |
︙ | ︙ | |||
3510 3511 3512 3513 3514 3515 3516 | /* * Fallback to direct eval to report syntax error. */ return TCL_ERROR; } if (parsePtr->numWords == 2) { | | | 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 | /* * Fallback to direct eval to report syntax error. */ return TCL_ERROR; } if (parsePtr->numWords == 2) { PUSH("1.0"); } for (words=1 ; words<parsePtr->numWords ; words++) { tokenPtr = TokenAfter(tokenPtr); CompileWord(envPtr, tokenPtr, interp, words); } if (words <= 3) { TclEmitOpcode(INST_DIV, envPtr); |
︙ | ︙ |
Changes to generic/tclCompile.h.
︙ | ︙ | |||
1354 1355 1356 1357 1358 1359 1360 | * Tcl_Interp *interp); */ #define CompileTokens(envPtr, tokenPtr, interp) \ TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \ (envPtr)); /* | | | > > > > | 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 | * Tcl_Interp *interp); */ #define CompileTokens(envPtr, tokenPtr, interp) \ TclCompileTokens((interp), (tokenPtr)+1, (tokenPtr)->numComponents, \ (envPtr)); /* * Convenience macros for use when pushing literals. The ANSI C "prototype" for * these macros are: * * static void PushLiteral(CompileEnv *envPtr, * const char *string, int length); * static void PushStringLiteral(CompileEnv *envPtr, * const char *string); */ #define PushLiteral(envPtr, string, length) \ TclEmitPush(TclRegisterNewLiteral((envPtr), (string), (length)), (envPtr)) #define PushStringLiteral(envPtr, string) \ PushLiteral((envPtr), (string), (int) (sizeof(string "") - 1)) /* * Macro to advance to the next token; it is more mnemonic than the address * arithmetic that it replaces. The ANSI C "prototype" for this macro is: * * static Tcl_Token * TokenAfter(Tcl_Token *tokenPtr); */ |
︙ | ︙ |