From 77ed9a126f206b71970125701e8285cc2009b7ff Mon Sep 17 00:00:00 2001
From: dgp <dgp@users.sourceforge.net>
Date: Thu, 28 Apr 2011 20:40:46 +0000
Subject: Rewrite of parts of the [switch] compiler to better use the powers of
 TclFindElement() and do less parsing on its own.  Needs review and testing.

---
 generic/tclCompCmds.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 104 insertions(+), 3 deletions(-)

diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c
index ddd2242..b06b7bf 100644
--- a/generic/tclCompCmds.c
+++ b/generic/tclCompCmds.c
@@ -3907,7 +3907,9 @@ TclCompileSwitchCmd(
     int savedStackDepth = envPtr->currStackDepth;
     int noCase;			/* Has the -nocase flag been given? */
     int foundMode = 0;		/* Have we seen a mode flag yet? */
+#if 0
     int isListedArms = 0;
+#endif
     int i, valueIndex;
     DefineLineInformation;	/* TIP #280 */
     int* clNext = envPtr->clNext;
@@ -4047,6 +4049,7 @@ TclCompileSwitchCmd(
      */
 
     if (numWords == 1) {
+#if 0
 	Tcl_DString bodyList;
 	const char **argv = NULL, *tokenStartPtr, *p;
 	int bline;		/* TIP #280: line of the pattern/action list,
@@ -4085,7 +4088,9 @@ TclCompileSwitchCmd(
 	    return TCL_ERROR;
 	}
 
+#if 0
 	isListedArms = 1;
+#endif
 	bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * numWords);
 	bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * numWords);
 	bodyLines = (int *) ckalloc(sizeof(int) * numWords);
@@ -4178,6 +4183,91 @@ TclCompileSwitchCmd(
 	    ckfree((char *) bodyNext);
 	    return TCL_ERROR;
 	}
+#else
+	CONST char *bytes, *p;
+	int maxLen, braced, numBytes;
+	int bline;		/* TIP #280: line of the pattern/action list,
+				 * and start of list for when tracking the
+				 * location. This list comes immediately after
+				 * the value we switch on. */
+
+	if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
+	    return TCL_ERROR;
+	}
+	bytes = tokenPtr[1].start;
+	numBytes = tokenPtr[1].size;
+
+	/*
+	 * A list can have at most one more element than the number
+	 * of runs of element-separating white space.
+	 */
+
+	maxLen = TclCountSpaceRuns(bytes, numBytes, NULL) + 1;
+	if (maxLen < 2) {
+	    return TCL_ERROR;
+	}
+	bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * maxLen);
+	bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * maxLen);
+	bodyLines = (int *) ckalloc(sizeof(int) * maxLen);
+	bodyNext  = (int **) ckalloc(sizeof(int*) * maxLen);
+
+	bline = mapPtr->loc[eclIndex].line[valueIndex+1];
+	p = bytes;
+	numWords = 0;
+
+	while (numBytes > 0) {
+	    CONST char *start, *prevBytes = bytes;
+	    int size;
+
+	    if (TCL_OK != TclFindElement(NULL, bytes, numBytes, &start,
+		    &bytes, &size, &braced)) {
+	    abort:
+		ckfree((char *) bodyToken);
+		ckfree((char *) bodyTokenArray);
+		ckfree((char *) bodyLines);
+		ckfree((char *) bodyNext);
+		return TCL_ERROR;
+	    }
+	    numBytes -= (bytes - prevBytes);
+
+	    if (numWords == 0 && numBytes == 0) {
+		break;
+	    }
+
+	    bodyTokenArray[numWords].type = TCL_TOKEN_TEXT;
+	    bodyTokenArray[numWords].start = start;
+	    bodyTokenArray[numWords].size = size;
+	    bodyTokenArray[numWords].numComponents = 0;
+	    bodyToken[numWords] = bodyTokenArray + numWords;
+
+	    if (!braced) {
+		while (size--) {
+		    if (*start++ == '\\') {
+			goto abort;
+		    }
+		}
+	    }
+
+	    /*
+	     * TIP #280: Now determine the line the list element starts on
+	     * (there is no need to do it earlier, due to the possibility of
+	     * aborting, see above).
+	     */
+
+	    TclAdvanceLines(&bline, p, bodyTokenArray[numWords].start);
+	    TclAdvanceContinuations (&bline, &clNext,
+		    bodyTokenArray[numWords].start - envPtr->source);
+	    bodyLines[numWords] = bline;
+	    bodyNext[numWords] = clNext;
+	    p = bodyTokenArray[numWords].start;
+
+	    numWords++;
+	}
+	if (numWords % 2) {
+	    goto abort;
+	}
+
+#endif
 
     } else if (numWords % 2 || numWords == 0) {
 	/*
@@ -4205,8 +4295,11 @@ TclCompileSwitchCmd(
 	     * traces, etc.
 	     */
 
-	    if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD ||
-		    tokenPtr->numComponents != 1) {
+	    if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD
+#if 0
+		    || tokenPtr->numComponents != 1
+#endif
+		    ) {
 		ckfree((char *) bodyToken);
 		ckfree((char *) bodyLines);
 		ckfree((char *) bodyNext);
@@ -4255,7 +4348,15 @@ TclCompileSwitchCmd(
      * but it handles the most common case well enough.
      */
 
-    if (isListedArms && mode == Switch_Exact && !noCase) {
+    if (
+#if 0
+	    isListedArms &&
+#endif
+	    mode == Switch_Exact
+#if 0
+	    && !noCase
+#endif
+	    ) {
 	JumptableInfo *jtPtr;
 	int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation;
 	int mustGenerate, jumpToDefault;
-- 
cgit v0.12

