summaryrefslogtreecommitdiffstats
path: root/generic/tclCompCmdsSZ.c
diff options
context:
space:
mode:
authorferrieux <ferrieux@users.sourceforge.net>2014-08-05 10:34:10 (GMT)
committerferrieux <ferrieux@users.sourceforge.net>2014-08-05 10:34:10 (GMT)
commit60a802acb616e77ccf3cab5328dccaea820f3e66 (patch)
tree78912e3ce83f66463eb83ec50472313478e41a1a /generic/tclCompCmdsSZ.c
parent93a502d2ff6f6a849b8307bd531f5b55dea69e24 (diff)
downloadtcl-60a802acb616e77ccf3cab5328dccaea820f3e66.zip
tcl-60a802acb616e77ccf3cab5328dccaea820f3e66.tar.gz
tcl-60a802acb616e77ccf3cab5328dccaea820f3e66.tar.bz2
Add constant folding to [string cat]. Mixed-quote idiom is now compiled to a single push.
Diffstat (limited to 'generic/tclCompCmdsSZ.c')
-rw-r--r--generic/tclCompCmdsSZ.c62
1 files changed, 46 insertions, 16 deletions
diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c
index 8ade6a5..bd8b463 100644
--- a/generic/tclCompCmdsSZ.c
+++ b/generic/tclCompCmdsSZ.c
@@ -277,27 +277,57 @@ TclCompileStringCatCmd(
* compiled. */
CompileEnv *envPtr) /* Holds resulting instructions. */
{
- int numWords = parsePtr->numWords;
- Tcl_Token *wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
+ int i,numWords = parsePtr->numWords;
+ Tcl_Token *wordTokenPtr;
+ Tcl_Obj *obj, *folded;
DefineLineInformation; /* TIP #280 */
- if (numWords>=2) {
- int i;
+ /* Trivial case, no arg */
- for (i = 1; i < numWords; i++) {
- CompileWord(envPtr, wordTokenPtr, interp, i);
- wordTokenPtr = TokenAfter(wordTokenPtr);
- }
- while (numWords > 256) {
- TclEmitInstInt1(INST_STR_CONCAT1, 255, envPtr);
- numWords -= 254; /* concat pushes 1 obj, the result */
- }
- if (numWords > 2) {
- TclEmitInstInt1(INST_STR_CONCAT1, numWords - 1, envPtr);
- }
- } else {
+ if (numWords<2) {
PushStringLiteral(envPtr, "");
+ return TCL_OK;
}
+
+ /* Detection of foldable constants. Often used for mixed quoting. */
+
+ folded = Tcl_NewObj();
+ wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
+ for (i = 1; i < numWords; i++) {
+ obj = Tcl_NewObj();
+ if (TclWordKnownAtCompileTime(wordTokenPtr, obj)) {
+ Tcl_AppendObjToObj(folded, obj);
+ } else {
+ Tcl_DecrRefCount(obj);
+ Tcl_DecrRefCount(folded);
+ folded = NULL;
+ break;
+ }
+ wordTokenPtr = TokenAfter(wordTokenPtr);
+ }
+ if (folded) {
+ int len;
+ const char *bytes = Tcl_GetStringFromObj(folded, &len);
+
+ PushLiteral(envPtr, bytes, len);
+ return TCL_OK;
+ }
+
+ /* General case: just issue CONCAT1's (by chunks of 255 if needed) */
+
+ wordTokenPtr = TokenAfter(parsePtr->tokenPtr);
+ for (i = 1; i < numWords; i++) {
+ CompileWord(envPtr, wordTokenPtr, interp, i);
+ wordTokenPtr = TokenAfter(wordTokenPtr);
+ }
+ while (numWords > 256) {
+ TclEmitInstInt1(INST_STR_CONCAT1, 255, envPtr);
+ numWords -= 254; /* concat pushes 1 obj, the result */
+ }
+ if (numWords > 2) {
+ TclEmitInstInt1(INST_STR_CONCAT1, numWords - 1, envPtr);
+ }
+
return TCL_OK;
}