? a
? expand1.patch
? expand1b.patch
? expand1c.patch
Index: tcl.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tcl.h,v
retrieving revision 1.277
diff -u -r1.277 tcl.h
--- tcl.h	22 Oct 2008 20:23:59 -0000	1.277
+++ tcl.h	16 Nov 2008 11:16:11 -0000
@@ -2004,6 +2004,7 @@
 #define TCL_TOKEN_SUB_EXPR	64
 #define TCL_TOKEN_OPERATOR	128
 #define TCL_TOKEN_EXPAND_WORD	256
+#define TCL_TOKEN_UNCOLLAPSED_TEXT 512
 
 /*
  * Parsing error types. On any parsing error, one of these values will be
Index: tclCompCmds.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompCmds.c,v
retrieving revision 1.148
diff -u -r1.148 tclCompCmds.c
--- tclCompCmds.c	5 Oct 2008 20:47:52 -0000	1.148
+++ tclCompCmds.c	16 Nov 2008 11:16:18 -0000
@@ -4438,7 +4438,7 @@
 		 * Keep in sync with TclCompileRegexpCmd.
 		 */
 
-		if (bodyToken[i]->type == TCL_TOKEN_TEXT) {
+		if (bodyToken[i]->type & (TCL_TOKEN_TEXT|TCL_TOKEN_UNCOLLAPSED_TEXT)) {
 		    Tcl_DString ds;
 
 		    if (bodyToken[i]->size == 0) {
@@ -4983,8 +4983,8 @@
 	    }
 	}
     } else if (((n = varTokenPtr->numComponents) > 1)
-	    && (varTokenPtr[1].type == TCL_TOKEN_TEXT)
-	    && (varTokenPtr[n].type == TCL_TOKEN_TEXT)
+	    && (varTokenPtr[1].type & (TCL_TOKEN_TEXT|TCL_TOKEN_UNCOLLAPSED_TEXT))
+	    && (varTokenPtr[n].type & (TCL_TOKEN_TEXT|TCL_TOKEN_UNCOLLAPSED_TEXT))
 	    && (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) {
 
 	/*
Index: tclCompile.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCompile.c,v
retrieving revision 1.160
diff -u -r1.160 tclCompile.c
--- tclCompile.c	26 Oct 2008 18:34:04 -0000	1.160
+++ tclCompile.c	16 Nov 2008 11:16:24 -0000
@@ -1077,6 +1077,7 @@
 {
     int numComponents = tokenPtr->numComponents;
     Tcl_Obj *tempPtr = NULL;
+    char *collapsed=NULL;
 
     if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
 	if (valuePtr != NULL) {
@@ -1100,6 +1101,17 @@
 	    }
 	    break;
 
+	case TCL_TOKEN_UNCOLLAPSED_TEXT:
+	    if (tempPtr != NULL) {
+		if (collapsed)
+		    collapsed=ckrealloc(collapsed,tokenPtr->size);
+		else
+		    collapsed=ckalloc(tokenPtr->size);
+		Tcl_AppendToObj(tempPtr, collapsed, TclCopyAndCollapse(tokenPtr->size,tokenPtr->start,collapsed));
+	    }
+	    break;
+
+
 	case TCL_TOKEN_BS:
 	    if (tempPtr != NULL) {
 		char utfBuf[TCL_UTF_MAX];
@@ -1110,12 +1122,14 @@
 
 	default:
 	    if (tempPtr != NULL) {
+		if (collapsed) ckfree(collapsed);
 		Tcl_DecrRefCount(tempPtr);
 	    }
 	    return 0;
 	}
 	tokenPtr++;
     }
+    if (collapsed) ckfree(collapsed);
     if (valuePtr != NULL) {
 	Tcl_AppendObjToObj(valuePtr, tempPtr);
 	Tcl_DecrRefCount(tempPtr);
@@ -1447,8 +1461,20 @@
 		     * namespaces to reduce shimmering.
 		     */
 
-		    objIndex = TclRegisterNewNSLiteral(envPtr,
-			    tokenPtr[1].start, tokenPtr[1].size);
+		    if (tokenPtr[1].type & TCL_TOKEN_UNCOLLAPSED_TEXT)
+			{
+			    char *s;
+			    int n;
+
+			    s=ckalloc(tokenPtr[1].size);
+			    n=TclCopyAndCollapse(tokenPtr[1].size,tokenPtr[1].start,s);
+			    objIndex = TclRegisterLiteral(envPtr,s,n,LITERAL_NS_SCOPE|LITERAL_ON_HEAP);
+			}
+		    else
+			{
+			    objIndex = TclRegisterNewNSLiteral(envPtr,
+							       tokenPtr[1].start, tokenPtr[1].size);
+			}
 		    if (cmdPtr != NULL) {
 			TclSetCmdNameObj(interp,
 			      envPtr->literalArrayPtr[objIndex].objPtr,cmdPtr);
@@ -1471,8 +1497,20 @@
 		     * unmodified. We care only if the we are in a context
 		     * which already allows absolute counting.
 		     */
-		    objIndex = TclRegisterNewLiteral(envPtr,
-			    tokenPtr[1].start, tokenPtr[1].size);
+		    if (tokenPtr[1].type & TCL_TOKEN_UNCOLLAPSED_TEXT)
+			{
+			    char *s;
+			    int n;
+
+			    s=ckalloc(tokenPtr[1].size);
+			    n=TclCopyAndCollapse(tokenPtr[1].size,tokenPtr[1].start,s);
+			    objIndex = TclRegisterLiteral(envPtr,s,n,LITERAL_ON_HEAP);
+			}
+		    else
+			{
+			    objIndex = TclRegisterNewLiteral(envPtr,
+							     tokenPtr[1].start, tokenPtr[1].size);
+			}
 
 		    if (eclPtr->type == TCL_LOCATION_SOURCE) {
 			EnterCmdWordIndex(eclPtr,
@@ -1609,6 +1647,7 @@
     int numObjsToConcat, nameBytes, localVarName, localVar;
     int length, i;
     unsigned char *entryCodeNext = envPtr->codeNext;
+    char *collapsed=NULL;
 
     Tcl_DStringInit(&textBuffer);
     numObjsToConcat = 0;
@@ -1618,6 +1657,14 @@
 	    Tcl_DStringAppend(&textBuffer, tokenPtr->start, tokenPtr->size);
 	    break;
 
+	case TCL_TOKEN_UNCOLLAPSED_TEXT:
+	    if (collapsed)
+		collapsed=ckrealloc(collapsed,tokenPtr->size);
+	    else
+		collapsed=ckalloc(tokenPtr->size);
+	    Tcl_DStringAppend(&textBuffer, collapsed, TclCopyAndCollapse(tokenPtr->size,tokenPtr->start,collapsed));
+	    break;
+
 	case TCL_TOKEN_BS:
 	    length = Tcl_UtfBackslash(tokenPtr->start, NULL, buffer);
 	    Tcl_DStringAppend(&textBuffer, buffer, length);
@@ -1733,6 +1780,8 @@
 	}
     }
 
+    if (collapsed) ckfree(collapsed);
+
     /*
      * Push any accumulated characters appearing at the end.
      */
Index: tclParse.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclParse.c,v
retrieving revision 1.73
diff -u -r1.73 tclParse.c
--- tclParse.c	26 Oct 2008 18:34:04 -0000	1.73
+++ tclParse.c	16 Nov 2008 11:16:27 -0000
@@ -532,6 +532,28 @@
 			    tokenPtr[-1].size += (isspace(UCHAR(
 				tokenPtr->start[tokenPtr->size])) == 0);
 			}
+			if (tokenPtr[-1].start[0]!='{')
+			    {
+				const char *s;
+				int n;
+
+				for(n=tokenPtr->size,s=tokenPtr->start;n>0;n--,s++)
+				    {
+					if ((*s)=='\\') {
+					    tokenPtr->type = TCL_TOKEN_UNCOLLAPSED_TEXT;
+					    /*
+					     * In this case we also demote the
+					     * enclosing token from
+					     * SIMPLE_WORD to WORD in order to
+					     * preserve the simplicity of all
+					     * shortcuts made on SIMPLE_WORDs
+					     * in clients.
+					     */
+					    tokenPtr[-1].type = TCL_TOKEN_WORD;
+					    break;
+					}
+				    }
+			    }
 
 			tokenPtr++;
 		    }
@@ -546,7 +568,7 @@
 		tokenPtr->type = TCL_TOKEN_EXPAND_WORD;
 	    }
 	} else if ((tokenPtr->numComponents == 1)
-		&& (tokenPtr[1].type == TCL_TOKEN_TEXT)) {
+		   && (tokenPtr[1].type & (TCL_TOKEN_TEXT|TCL_TOKEN_UNCOLLAPSED_TEXT))) {
 	    tokenPtr->type = TCL_TOKEN_SIMPLE_WORD;
 	}
 
@@ -1961,7 +1983,7 @@
 		if (varTokenPtr->type != TCL_TOKEN_VARIABLE) {
 		    Tcl_Panic("Tcl_SubstObj: programming error");
 		}
-		if (varTokenPtr[1].type != TCL_TOKEN_TEXT) {
+		if (!(varTokenPtr[1].type & (TCL_TOKEN_TEXT|TCL_TOKEN_UNCOLLAPSED_TEXT))) {
 		    Tcl_Panic("Tcl_SubstObj: programming error");
 		}
 		parsePtr->numTokens -= 2;
@@ -2134,6 +2156,7 @@
 {
     Tcl_Obj *result;
     int code = TCL_OK;
+    char *collapsed = NULL;
 
     /*
      * Each pass through this loop will substitute one token, and its
@@ -2158,6 +2181,15 @@
 	    appendByteLength = tokenPtr->size;
 	    break;
 
+	case TCL_TOKEN_UNCOLLAPSED_TEXT:
+	    if (collapsed)
+		collapsed=ckrealloc(collapsed,tokenPtr->size);
+	    else
+		collapsed=ckalloc(tokenPtr->size);
+	    appendByteLength=TclCopyAndCollapse(tokenPtr->size,tokenPtr->start,collapsed);
+	    append=collapsed;
+	    break;
+
 	case TCL_TOKEN_BS:
 	    appendByteLength = Tcl_UtfBackslash(tokenPtr->start, NULL,
 		    utfCharBytes);
@@ -2270,6 +2302,7 @@
 	    }
 	}
     }
+    if (collapsed) ckfree(collapsed);
 
     if (code != TCL_ERROR) {		/* Keep error message in result! */
 	if (result != NULL) {
Index: tclTest.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclTest.c,v
retrieving revision 1.129
diff -u -r1.129 tclTest.c
--- tclTest.c	17 Oct 2008 16:32:58 -0000	1.129
+++ tclTest.c	16 Nov 2008 11:16:35 -0000
@@ -3452,6 +3452,9 @@
 	case TCL_TOKEN_TEXT:
 	    typeString = "text";
 	    break;
+	case TCL_TOKEN_UNCOLLAPSED_TEXT:
+	    typeString = "text-to-collapse";
+	    break;
 	case TCL_TOKEN_BS:
 	    typeString = "backslash";
 	    break;
