diff options
Diffstat (limited to 'generic/tclCompile.c')
-rw-r--r-- | generic/tclCompile.c | 163 |
1 files changed, 156 insertions, 7 deletions
diff --git a/generic/tclCompile.c b/generic/tclCompile.c index 2ea99ac..403e487 100644 --- a/generic/tclCompile.c +++ b/generic/tclCompile.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.c,v 1.146.2.10 2009/07/16 20:50:54 dgp Exp $ + * RCS: @(#) $Id: tclCompile.c,v 1.146.2.11 2009/08/25 21:01:05 andreas_kupries Exp $ */ #include "tclInt.h" @@ -431,7 +431,8 @@ static void PrintSourceToObj(Tcl_Obj *appendObj, */ static void EnterCmdWordData(ExtCmdLoc *eclPtr, int srcOffset, Tcl_Token *tokenPtr, const char *cmd, int len, - int numWords, int line, int **lines); + int numWords, int line, int* clNext, int **lines, + CompileEnv* envPtr); /* * The structure below defines the bytecode Tcl object type by means of @@ -487,6 +488,7 @@ TclSetByteCodeFromAny( register int i; int length, result = TCL_OK; const char *stringPtr; + ContLineLoc* clLocPtr; #ifdef TCL_COMPILE_DEBUG if (!traceInitialized) { @@ -508,6 +510,25 @@ TclSetByteCodeFromAny( TclInitCompileEnv(interp, &compEnv, stringPtr, length, iPtr->invokeCmdFramePtr, iPtr->invokeWord); + /* + * Now we check if we have data about invisible continuation lines for the + * script, and make it available to the compile environment, if so. + * + * It is not clear if the script Tcl_Obj* can be free'd while the compiler + * is using it, leading to the release of the associated ContLineLoc + * structure as well. To ensure that the latter doesn't happen we set a + * lock on it. We release this lock in the function TclFreeCompileEnv (), + * found in this file. The "lineCLPtr" hashtable is managed in the file + * "tclObj.c". + */ + + clLocPtr = TclContinuationsGet (objPtr); + if (clLocPtr) { + compEnv.clLoc = clLocPtr; + compEnv.clNext = &compEnv.clLoc->loc[0]; + Tcl_Preserve (compEnv.clLoc); + } + TclCompileScript(interp, stringPtr, length, &compEnv); /* @@ -982,6 +1003,15 @@ TclInitCompileEnv( TclStackFree(interp, ctxPtr); } + /* + * Initialize the data about invisible continuation lines as empty, + * i.e. not used. The caller (TclSetByteCodeFromAny) will set this up, if + * such data is available. + */ + + envPtr->clLoc = NULL; + envPtr->clNext = NULL; + envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace; envPtr->auxDataArrayNext = 0; envPtr->auxDataArrayEnd = COMPILEENV_INIT_AUX_DATA_SIZE; @@ -1036,6 +1066,16 @@ TclFreeCompileEnv( if (envPtr->extCmdMapPtr) { ckfree((char *) envPtr->extCmdMapPtr); } + + /* + * If we used data about invisible continuation lines, then now is the + * time to release on our hold on it. The lock was set in function + * TclSetByteCodeFromAny(), found in this file. + */ + + if (envPtr->clLoc) { + Tcl_Release (envPtr->clLoc); + } } /* @@ -1163,6 +1203,7 @@ TclCompileScript( /* TIP #280 */ ExtCmdLoc *eclPtr = envPtr->extCmdMapPtr; int *wlines, wlineat, cmdLine; + int* clNext; Tcl_Parse *parsePtr = (Tcl_Parse *) TclStackAlloc(interp, sizeof(Tcl_Parse)); @@ -1188,6 +1229,7 @@ TclCompileScript( p = script; bytesLeft = numBytes; cmdLine = envPtr->line; + clNext = envPtr->clNext; do { if (Tcl_ParseCommand(interp, p, bytesLeft, 0, parsePtr) != TCL_OK) { /* @@ -1287,10 +1329,12 @@ TclCompileScript( */ TclAdvanceLines(&cmdLine, p, parsePtr->commandStart); + TclAdvanceContinuations (&cmdLine, &clNext, + parsePtr->commandStart - envPtr->source); EnterCmdWordData(eclPtr, parsePtr->commandStart - envPtr->source, - parsePtr->tokenPtr, parsePtr->commandStart, - parsePtr->commandSize, parsePtr->numWords, cmdLine, - &wlines); + parsePtr->tokenPtr, parsePtr->commandStart, + parsePtr->commandSize, parsePtr->numWords, cmdLine, + clNext, &wlines, envPtr); wlineat = eclPtr->nuloc - 1; /* @@ -1303,6 +1347,8 @@ TclCompileScript( tokenPtr += (tokenPtr->numComponents + 1)) { envPtr->line = eclPtr->loc[wlineat].line[wordIdx]; + envPtr->clNext = eclPtr->loc [wlineat].next [wordIdx]; + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { /* * The word is not a simple string of characters. @@ -1463,6 +1509,12 @@ TclCompileScript( */ objIndex = TclRegisterNewLiteral(envPtr, tokenPtr[1].start, tokenPtr[1].size); + + if (envPtr->clNext) { + TclContinuationsEnterDerived (envPtr->literalArrayPtr[objIndex].objPtr, + tokenPtr[1].start - envPtr->source, + eclPtr->loc [wlineat].next [wordIdx]); + } } TclEmitPush(objIndex, envPtr); } /* for loop */ @@ -1524,7 +1576,9 @@ TclCompileScript( */ ckfree((char *) eclPtr->loc[wlineat].line); + ckfree((char *) eclPtr->loc[wlineat].next); eclPtr->loc[wlineat].line = wlines; + eclPtr->loc[wlineat].next = NULL; } /* end if parsePtr->numWords > 0 */ /* @@ -1540,6 +1594,7 @@ TclCompileScript( */ TclAdvanceLines(&cmdLine, parsePtr->commandStart, p); + TclAdvanceContinuations (&cmdLine, &clNext, p - envPtr->source); Tcl_FreeParse(parsePtr); } while (bytesLeft > 0); @@ -1600,6 +1655,41 @@ TclCompileTokens( int numObjsToConcat, nameBytes, localVarName, localVar; int length, i; unsigned char *entryCodeNext = envPtr->codeNext; +#define NUM_STATIC_POS 20 + int isLiteral, maxNumCL, numCL; + int* clPosition; + + /* + * For the handling of continuation lines in literals we first check if + * this is actually a literal. For if not we can forego the additional + * processing. Otherwise we pre-allocate a small table to store the + * locations of all continuation lines we find in this literal, if + * any. The table is extended if needed. + * + * Note: Different to the equivalent code in function + * 'EvalTokensStandard()' (see file "tclBasic.c") we do not seem to need + * the 'adjust' variable. We also do not seem to need code which merges + * continuation line information of multiple words which concat'd at + * runtime. Either that or I have not managed to find a test case for + * these two possibilities yet. It might be a difference between compile- + * versus runtime processing. + */ + + numCL = 0; + maxNumCL = 0; + isLiteral = 1; + for (i=0 ; i < count; i++) { + if ((tokenPtr[i].type != TCL_TOKEN_TEXT) && + (tokenPtr[i].type != TCL_TOKEN_BS)) { + isLiteral = 0; + break; + } + } + + if (isLiteral) { + maxNumCL = NUM_STATIC_POS; + clPosition = (int*) ckalloc (maxNumCL*sizeof(int)); + } Tcl_DStringInit(&textBuffer); numObjsToConcat = 0; @@ -1612,6 +1702,36 @@ TclCompileTokens( case TCL_TOKEN_BS: length = Tcl_UtfBackslash(tokenPtr->start, NULL, buffer); Tcl_DStringAppend(&textBuffer, buffer, length); + + /* + * If the backslash sequence we found is in a literal, and + * represented a continuation line, we compute and store its + * location (as char offset to the beginning of the _result_ + * script). We may have to extend the table of locations. + * + * Note that the continuation line information is relevant even if + * the word we are processing is not a literal, as it can affect + * nested commands. See the branch for TCL_TOKEN_COMMAND below, + * where the adjustment we are tracking here is taken into + * account. The good thing is that we do not need a table of + * everything, just the number of lines we have to add as + * correction. + */ + + if ((length == 1) && (buffer[0] == ' ') && + (tokenPtr->start[1] == '\n')) { + if (isLiteral) { + int clPos = Tcl_DStringLength (&textBuffer); + + if (numCL >= maxNumCL) { + maxNumCL *= 2; + clPosition = (int*) ckrealloc ((char*)clPosition, + maxNumCL*sizeof(int)); + } + clPosition[numCL] = clPos; + numCL ++; + } + } break; case TCL_TOKEN_COMMAND: @@ -1627,6 +1747,12 @@ TclCompileTokens( TclEmitPush(literal, envPtr); numObjsToConcat++; Tcl_DStringFree(&textBuffer); + + if (numCL) { + TclContinuationsEnter(envPtr->literalArrayPtr[literal].objPtr, + numCL, clPosition); + } + numCL = 0; } TclCompileScript(interp, tokenPtr->start+1, @@ -1737,6 +1863,12 @@ TclCompileTokens( Tcl_DStringLength(&textBuffer)); TclEmitPush(literal, envPtr); numObjsToConcat++; + + if (numCL) { + TclContinuationsEnter(envPtr->literalArrayPtr[literal].objPtr, + numCL, clPosition); + } + numCL = 0; } /* @@ -1759,6 +1891,15 @@ TclCompileTokens( TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr); } Tcl_DStringFree(&textBuffer); + + /* + * Release the temp table we used to collect the locations of + * continuation lines, if any. + */ + + if (maxNumCL) { + ckfree ((char*) clPosition); + } } /* @@ -2397,11 +2538,14 @@ EnterCmdWordData( int len, int numWords, int line, - int **wlines) + int* clNext, + int **wlines, + CompileEnv* envPtr) { ECL *ePtr; const char *last; int wordIdx, wordLine, *wwlines; + int* wordNext; if (eclPtr->nuloc >= eclPtr->nloc) { /* @@ -2421,17 +2565,22 @@ EnterCmdWordData( ePtr = &eclPtr->loc[eclPtr->nuloc]; ePtr->srcOffset = srcOffset; ePtr->line = (int *) ckalloc(numWords * sizeof(int)); + ePtr->next = (int**) ckalloc (numWords * sizeof (int*)); ePtr->nline = numWords; wwlines = (int *) ckalloc(numWords * sizeof(int)); last = cmd; wordLine = line; + wordNext = clNext; for (wordIdx=0 ; wordIdx<numWords; wordIdx++, tokenPtr += tokenPtr->numComponents + 1) { - TclAdvanceLines(&wordLine, last, tokenPtr->start); + TclAdvanceLines (&wordLine, last, tokenPtr->start); + TclAdvanceContinuations (&wordLine, &wordNext, + tokenPtr->start - envPtr->source); wwlines[wordIdx] = (TclWordKnownAtCompileTime(tokenPtr, NULL) ? wordLine : -1); ePtr->line[wordIdx] = wordLine; + ePtr->next[wordIdx] = wordNext; last = tokenPtr->start; } |