diff options
author | andreas_kupries <akupries@shaw.ca> | 2009-08-25 20:59:09 (GMT) |
---|---|---|
committer | andreas_kupries <akupries@shaw.ca> | 2009-08-25 20:59:09 (GMT) |
commit | 290495c7ce8eaa67ffe2fa4fc3b8106742148a27 (patch) | |
tree | 4a737e378aa3ed2c71519eae3320f02faabfcc2c /generic/tclCompile.c | |
parent | f9ad150a1ad924f9775cf6d740e1bd5018acc492 (diff) | |
download | tcl-290495c7ce8eaa67ffe2fa4fc3b8106742148a27.zip tcl-290495c7ce8eaa67ffe2fa4fc3b8106742148a27.tar.gz tcl-290495c7ce8eaa67ffe2fa4fc3b8106742148a27.tar.bz2 |
* generic/tclBasic.c (Tcl_CreateInterp, Tcl_EvalTokensStandard,
EvalTokensStandard, Tcl_EvalEx, EvalEx, TclAdvanceContinuations,
TclEvalObjEx):
* generic/tclCmdMZ.c (Tcl_SwitchObjCmd, ListLines):
* generic/tclCompCmds.c (*):
* generic/tclCompile.c (TclSetByteCodeFromAny, TclInitCompileEnv,
TclFreeCompileEnv, TclCompileScript):
* generic/tclCompile.h (CompileEnv):
* generic/tclInt.h (ContLineLoc, Interp):
* generic/tclObj.c (ThreadSpecificData, ContLineLocFree,
TclThreadFinalizeObjects, TclInitObjSubsystem,
TclContinuationsEnter, TclContinuationsEnterDerived,
TclContinuationsCopy, TclContinuationsGet, TclFreeObj):
* generic/tclProc.c (TclCreateProc):
* generic/tclVar.c (TclPtrSetVar):
* tests/info.test (info-30.0-22):
Extended parser, compiler, and execution with code and attendant
data structures tracking the positions of continuation lines which
are not visible in script's, to properly account for them while
counting lines for #280, during direct and compiled execution.
Diffstat (limited to 'generic/tclCompile.c')
-rw-r--r-- | generic/tclCompile.c | 183 |
1 files changed, 170 insertions, 13 deletions
diff --git a/generic/tclCompile.c b/generic/tclCompile.c index b6d486e..aa25f26 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.43.2.15 2009/07/14 16:31:49 andreas_kupries Exp $ + * RCS: @(#) $Id: tclCompile.c,v 1.43.2.16 2009/08/25 20:59:10 andreas_kupries Exp $ */ #include "tclInt.h" @@ -307,7 +307,7 @@ static int SetByteCodeFromAny _ANSI_ARGS_((Tcl_Interp *interp, static void EnterCmdWordData _ANSI_ARGS_(( ExtCmdLoc *eclPtr, int srcOffset, Tcl_Token* tokenPtr, CONST char* cmd, int len, int numWords, int line, - int** lines)); + int* clNext, int** lines, CompileEnv* envPtr)); #endif @@ -367,7 +367,9 @@ TclSetByteCodeFromAny(interp, objPtr, hookProc, clientData) register int i; int length, nested, result; char *string; - +#ifdef TCL_TIP280 + ContLineLoc* clLocPtr; +#endif #ifdef TCL_COMPILE_DEBUG if (!traceInitialized) { if (Tcl_LinkVar(interp, "tcl_traceCompile", @@ -396,6 +398,24 @@ TclSetByteCodeFromAny(interp, objPtr, hookProc, clientData) TclInitCompileEnv(interp, &compEnv, string, 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); + } #endif result = TclCompileScript(interp, string, length, nested, &compEnv); @@ -872,6 +892,15 @@ TclInitCompileEnv(interp, envPtr, string, numBytes, invoker, word) /* ctx going out of scope */ } + + /* + * 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; #endif envPtr->auxDataArrayPtr = envPtr->staticAuxDataArraySpace; @@ -921,6 +950,17 @@ TclFreeCompileEnv(envPtr) if (envPtr->mallocedAuxDataArray) { ckfree((char *) envPtr->auxDataArrayPtr); } +#ifdef TCL_TIP280 + /* + * 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); + } +#endif } #ifdef TCL_TIP280 @@ -1030,6 +1070,7 @@ TclCompileScript(interp, script, numBytes, nested, envPtr) ExtCmdLoc* eclPtr = envPtr->extCmdMapPtr; int* wlines; int wlineat, cmdLine; + int* clNext; #endif Tcl_DStringInit(&ds); @@ -1050,6 +1091,7 @@ TclCompileScript(interp, script, numBytes, nested, envPtr) gotParse = 0; #ifdef TCL_TIP280 cmdLine = envPtr->line; + clNext = envPtr->clNext; #endif do { @@ -1169,10 +1211,13 @@ TclCompileScript(interp, script, numBytes, nested, envPtr) * 'wlines'. */ - TclAdvanceLines (&cmdLine, p, parse.commandStart); + TclAdvanceLines (&cmdLine, p, parse.commandStart); + TclAdvanceContinuations (&cmdLine, &clNext, + parse.commandStart - envPtr->source); EnterCmdWordData (eclPtr, (parse.commandStart - envPtr->source), - parse.tokenPtr, parse.commandStart, parse.commandSize, - parse.numWords, cmdLine, &wlines); + parse.tokenPtr, parse.commandStart, + parse.commandSize, parse.numWords, + cmdLine, clNext, &wlines, envPtr); wlineat = eclPtr->nuloc - 1; #endif @@ -1180,7 +1225,8 @@ TclCompileScript(interp, script, numBytes, nested, envPtr) wordIdx < parse.numWords; wordIdx++, tokenPtr += (tokenPtr->numComponents + 1)) { #ifdef TCL_TIP280 - envPtr->line = eclPtr->loc [wlineat].line [wordIdx]; + envPtr->line = eclPtr->loc [wlineat].line [wordIdx]; + envPtr->clNext = eclPtr->loc [wlineat].next [wordIdx]; #endif if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) { /* @@ -1268,6 +1314,13 @@ TclCompileScript(interp, script, numBytes, nested, envPtr) objIndex = TclRegisterNewLiteral(envPtr, tokenPtr[1].start, tokenPtr[1].size); +#ifdef TCL_TIP280 + if (envPtr->clNext) { + TclContinuationsEnterDerived (envPtr->literalArrayPtr[objIndex].objPtr, + tokenPtr[1].start - envPtr->source, + eclPtr->loc [wlineat].next [wordIdx]); + } +#endif } TclEmitPush(objIndex, envPtr); } else { @@ -1320,7 +1373,9 @@ TclCompileScript(interp, script, numBytes, nested, envPtr) * the reduced form now */ ckfree ((char*) eclPtr->loc [wlineat].line); - eclPtr->loc [wlineat].line = wlines; + ckfree ((char*) eclPtr->loc [wlineat].next); + eclPtr->loc [wlineat].line = wlines; + eclPtr->loc [wlineat].next = NULL; #endif } /* end if parse.numWords > 0 */ @@ -1333,7 +1388,8 @@ TclCompileScript(interp, script, numBytes, nested, envPtr) p = next; #ifdef TCL_TIP280 /* TIP #280 : Track lines in the just compiled command */ - TclAdvanceLines (&cmdLine, parse.commandStart, p); + TclAdvanceLines (&cmdLine, parse.commandStart, p); + TclAdvanceContinuations (&cmdLine, &clNext, p - envPtr->source); #endif Tcl_FreeParse(&parse); gotParse = 0; @@ -1440,6 +1496,43 @@ TclCompileTokens(interp, tokenPtr, count, envPtr) int numObjsToConcat, nameBytes, localVarName, localVar; int length, i, code; unsigned char *entryCodeNext = envPtr->codeNext; +#ifdef TCL_TIP280 +#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)); + } +#endif Tcl_DStringInit(&textBuffer); numObjsToConcat = 0; @@ -1454,6 +1547,38 @@ TclCompileTokens(interp, tokenPtr, count, envPtr) length = Tcl_UtfBackslash(tokenPtr->start, (int *) NULL, buffer); Tcl_DStringAppend(&textBuffer, buffer, length); + +#ifdef TCL_TIP280 + /* + * 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 ++; + } + } +#endif break; case TCL_TOKEN_COMMAND: @@ -1470,6 +1595,13 @@ TclCompileTokens(interp, tokenPtr, count, envPtr) TclEmitPush(literal, envPtr); numObjsToConcat++; Tcl_DStringFree(&textBuffer); +#ifdef TCL_TIP280 + if (numCL) { + TclContinuationsEnter(envPtr->literalArrayPtr[literal].objPtr, + numCL, clPosition); + } + numCL = 0; +#endif } code = TclCompileScript(interp, tokenPtr->start+1, @@ -1594,6 +1726,14 @@ TclCompileTokens(interp, tokenPtr, count, envPtr) Tcl_DStringLength(&textBuffer), /*onHeap*/ 0); TclEmitPush(literal, envPtr); numObjsToConcat++; + +#ifdef TCL_TIP280 + if (numCL) { + TclContinuationsEnter(envPtr->literalArrayPtr[literal].objPtr, + numCL, clPosition); + } + numCL = 0; +#endif } /* @@ -1616,11 +1756,20 @@ TclCompileTokens(interp, tokenPtr, count, envPtr) TclEmitPush(TclRegisterLiteral(envPtr, "", 0, /*onHeap*/ 0), envPtr); } - Tcl_DStringFree(&textBuffer); - return TCL_OK; + code = TCL_OK; error: Tcl_DStringFree(&textBuffer); +#ifdef TCL_TIP280 + /* + * Release the temp table we used to collect the locations of + * continuation lines, if any. + */ + + if (maxNumCL) { + ckfree ((char*) clPosition); + } +#endif return code; } @@ -2426,7 +2575,7 @@ EnterCmdExtentData(envPtr, cmdIndex, numSrcBytes, numCodeBytes) */ static void -EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, wlines) +EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, clNext, wlines, envPtr) ExtCmdLoc *eclPtr; /* Points to the map environment * structure in which to enter command * location information. */ @@ -2436,12 +2585,15 @@ EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, wlines) int len; int numWords; int line; + int* clNext; int** wlines; + CompileEnv* envPtr; { ECL* ePtr; int wordIdx; CONST char* last; int wordLine; + int* wordNext; int* wwlines; if (eclPtr->nuloc >= eclPtr->nloc) { @@ -2475,19 +2627,24 @@ EnterCmdWordData(eclPtr, srcOffset, tokenPtr, cmd, len, numWords, line, wlines) 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) ? wordLine : -1); ePtr->line [wordIdx] = wordLine; + ePtr->next [wordIdx] = wordNext; last = tokenPtr->start; } |