summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorferrieux <ferrieux@noemail.net>2014-08-05 10:34:10 (GMT)
committerferrieux <ferrieux@noemail.net>2014-08-05 10:34:10 (GMT)
commitdc287d51a5c69c7d202eb2d8a4dceedb1ac752cf (patch)
tree0cf71820f94feb8b18dc09fd6c0dbbf9976f2034 /generic
parent7ac11073ec7916f589bb3e5d6d21793f68464fcd (diff)
downloadtcl-dc287d51a5c69c7d202eb2d8a4dceedb1ac752cf.zip
tcl-dc287d51a5c69c7d202eb2d8a4dceedb1ac752cf.tar.gz
tcl-dc287d51a5c69c7d202eb2d8a4dceedb1ac752cf.tar.bz2
Add constant folding to [string cat]. Mixed-quote idiom is now compiled to a single push.
FossilOrigin-Name: a321e41d540908f3ad060c842ae592e238a21a82
Diffstat (limited to 'generic')
-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;
}