diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2012-02-17 09:10:06 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2012-02-17 09:10:06 (GMT) |
commit | 9c3e75d3d4c2a5b80155880c80b8f204cf88c896 (patch) | |
tree | c8141a88d55fd40ae5d43ac48c9446d40abd2730 /generic | |
parent | cd02dd95be672a172c811469fc845123dc936477 (diff) | |
parent | efe1cdd5b7f7aed22c2c4f10c0a2d77604ab5b7e (diff) | |
download | tcl-9c3e75d3d4c2a5b80155880c80b8f204cf88c896.zip tcl-9c3e75d3d4c2a5b80155880c80b8f204cf88c896.tar.gz tcl-9c3e75d3d4c2a5b80155880c80b8f204cf88c896.tar.bz2 |
merge trunk
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tclBasic.c | 4 | ||||
-rw-r--r-- | generic/tclCompCmds.c | 240 | ||||
-rw-r--r-- | generic/tclExecute.c | 25 | ||||
-rw-r--r-- | generic/tclIOUtil.c | 3 | ||||
-rw-r--r-- | generic/tclInt.h | 6 |
5 files changed, 270 insertions, 8 deletions
diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 0365966..c07fa70 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -230,9 +230,9 @@ static const CmdInfo builtInCmds[] = { {"linsert", Tcl_LinsertObjCmd, NULL, NULL, 1}, {"list", Tcl_ListObjCmd, TclCompileListCmd, NULL, 1}, {"llength", Tcl_LlengthObjCmd, TclCompileLlengthCmd, NULL, 1}, - {"lrange", Tcl_LrangeObjCmd, NULL, NULL, 1}, + {"lrange", Tcl_LrangeObjCmd, TclCompileLrangeCmd, NULL, 1}, {"lrepeat", Tcl_LrepeatObjCmd, NULL, NULL, 1}, - {"lreplace", Tcl_LreplaceObjCmd, NULL, NULL, 1}, + {"lreplace", Tcl_LreplaceObjCmd, TclCompileLreplaceCmd, NULL, 1}, {"lreverse", Tcl_LreverseObjCmd, NULL, NULL, 1}, {"lsearch", Tcl_LsearchObjCmd, NULL, NULL, 1}, {"lset", Tcl_LsetObjCmd, TclCompileLsetCmd, NULL, 1}, diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 57a5370..5b7e0a5 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -906,7 +906,7 @@ TclCompileDictForCmd( * Compile the loop body itself. It should be stack-neutral. */ - SetLineInformation(4); + SetLineInformation(3); CompileBody(envPtr, bodyTokenPtr, interp); TclEmitOpcode( INST_POP, envPtr); @@ -1112,6 +1112,7 @@ TclCompileDictUpdateCmd( ExceptionRangeStarts(envPtr, range); envPtr->currStackDepth++; + SetLineInformation(parsePtr->numWords - 1); CompileBody(envPtr, bodyTokenPtr, interp); envPtr->currStackDepth = savedStackDepth; ExceptionRangeEnds(envPtr, range); @@ -3146,13 +3147,24 @@ TclCompileLindexCmd( tmpObj = Tcl_NewStringObj(idxTokenPtr[1].start, idxTokenPtr[1].size); result = TclGetIntFromObj(NULL, tmpObj, &idx); + if (result == TCL_OK) { + if (idx < 0) { + result = TCL_ERROR; + } + } else { + result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx); + if (result == TCL_OK && idx > -2) { + result = TCL_ERROR; + } + } TclDecrRefCount(tmpObj); - if (result == TCL_OK && idx >= 0) { + if (result == TCL_OK) { /* - * All checks have been completed, and we have exactly this - * construct: + * All checks have been completed, and we have exactly one of + * these constructs: * lindex <arbitraryValue> <posInt> + * lindex <arbitraryValue> end-<posInt> * This is best compiled as a push of the arbitrary value followed * by an "immediate lindex" which is the most efficient variety. */ @@ -3297,6 +3309,226 @@ TclCompileLlengthCmd( /* *---------------------------------------------------------------------- * + * TclCompileLrangeCmd -- + * + * How to compile the "lrange" command. We only bother because we needed + * the opcode anyway for "lassign". + * + *---------------------------------------------------------------------- + */ + +int +TclCompileLrangeCmd( + Tcl_Interp *interp, /* Tcl interpreter for context. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the + * command. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds the resulting instructions. */ +{ + Tcl_Token *tokenPtr, *listTokenPtr; + DefineLineInformation; /* TIP #280 */ + Tcl_Obj *tmpObj; + int idx1, idx2, result; + + if (parsePtr->numWords != 4) { + return TCL_ERROR; + } + listTokenPtr = TokenAfter(parsePtr->tokenPtr); + + /* + * Parse the first index. Will only compile if it is constant and not an + * _integer_ less than zero (since we reserve negative indices here for + * end-relative indexing). + */ + + tokenPtr = TokenAfter(listTokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size); + result = TclGetIntFromObj(NULL, tmpObj, &idx1); + if (result == TCL_OK) { + if (idx1 < 0) { + result = TCL_ERROR; + } + } else { + result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx1); + if (result == TCL_OK && idx1 > -2) { + result = TCL_ERROR; + } + } + TclDecrRefCount(tmpObj); + if (result != TCL_OK) { + return TCL_ERROR; + } + + /* + * Parse the second index. Will only compile if it is constant and not an + * _integer_ less than zero (since we reserve negative indices here for + * end-relative indexing). + */ + + tokenPtr = TokenAfter(tokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size); + result = TclGetIntFromObj(NULL, tmpObj, &idx2); + if (result == TCL_OK) { + if (idx2 < 0) { + result = TCL_ERROR; + } + } else { + result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx2); + if (result == TCL_OK && idx2 > -2) { + result = TCL_ERROR; + } + } + TclDecrRefCount(tmpObj); + if (result != TCL_OK) { + return TCL_ERROR; + } + + /* + * Issue instructions. It's not safe to skip doing the LIST_RANGE, as + * we've not proved that the 'list' argument is really a list. Not that it + * is worth trying to do that given current knowledge. + */ + + CompileWord(envPtr, listTokenPtr, interp, 1); + TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr); + TclEmitInt4( idx2, envPtr); + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * TclCompileLreplaceCmd -- + * + * How to compile the "lreplace" command. We only bother with the case + * where there are no elements to insert and where both the 'first' and + * 'last' arguments are constant and one can be deterined to be at the + * end of the list. (This is the case that could also be written with + * "lrange".) + * + *---------------------------------------------------------------------- + */ + +int +TclCompileLreplaceCmd( + Tcl_Interp *interp, /* Tcl interpreter for context. */ + Tcl_Parse *parsePtr, /* Points to a parse structure for the + * command. */ + Command *cmdPtr, /* Points to defintion of command being + * compiled. */ + CompileEnv *envPtr) /* Holds the resulting instructions. */ +{ + Tcl_Token *tokenPtr, *listTokenPtr; + DefineLineInformation; /* TIP #280 */ + Tcl_Obj *tmpObj; + int idx1, idx2, result, guaranteedDropAll = 0; + + if (parsePtr->numWords != 4) { + return TCL_ERROR; + } + listTokenPtr = TokenAfter(parsePtr->tokenPtr); + + /* + * Parse the first index. Will only compile if it is constant and not an + * _integer_ less than zero (since we reserve negative indices here for + * end-relative indexing). + */ + + tokenPtr = TokenAfter(listTokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size); + result = TclGetIntFromObj(NULL, tmpObj, &idx1); + if (result == TCL_OK) { + if (idx1 < 0) { + result = TCL_ERROR; + } + } else { + result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx1); + if (result == TCL_OK && idx1 > -2) { + result = TCL_ERROR; + } + } + TclDecrRefCount(tmpObj); + if (result != TCL_OK) { + return TCL_ERROR; + } + + /* + * Parse the second index. Will only compile if it is constant and not an + * _integer_ less than zero (since we reserve negative indices here for + * end-relative indexing). + */ + + tokenPtr = TokenAfter(tokenPtr); + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + tmpObj = Tcl_NewStringObj(tokenPtr[1].start, tokenPtr[1].size); + result = TclGetIntFromObj(NULL, tmpObj, &idx2); + if (result == TCL_OK) { + if (idx2 < 0) { + result = TCL_ERROR; + } + } else { + result = TclGetIntForIndexM(NULL, tmpObj, -2, &idx2); + if (result == TCL_OK && idx2 > -2) { + result = TCL_ERROR; + } + } + TclDecrRefCount(tmpObj); + if (result != TCL_OK) { + return TCL_ERROR; + } + + /* + * Sanity check: can only issue when we're removing a range at one or + * other end of the list. If we're at one end or the other, convert the + * indices into the equivalent for an [lrange]. + */ + + if (idx1 == 0) { + if (idx2 == -2) { + guaranteedDropAll = 1; + } + idx1 = idx2 + 1; + idx2 = -2; + } else if (idx2 == -2) { + idx2 = idx1 - 1; + idx1 = 0; + } else { + return TCL_ERROR; + } + + /* + * Issue instructions. It's not safe to skip doing the LIST_RANGE, as + * we've not proved that the 'list' argument is really a list. Not that it + * is worth trying to do that given current knowledge. + */ + + CompileWord(envPtr, listTokenPtr, interp, 1); + if (guaranteedDropAll) { + TclEmitOpcode( INST_LIST_LENGTH, envPtr); + TclEmitOpcode( INST_POP, envPtr); + PushLiteral(envPtr, "", 0); + } else { + TclEmitInstInt4( INST_LIST_RANGE_IMM, idx1, envPtr); + TclEmitInt4( idx2, envPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * * TclCompileLsetCmd -- * * Procedure called to compile the "lset" command. diff --git a/generic/tclExecute.c b/generic/tclExecute.c index 92b6612..e402634 100644 --- a/generic/tclExecute.c +++ b/generic/tclExecute.c @@ -4310,12 +4310,33 @@ TEBCresume( */ if (fromIdx<=toIdx && fromIdx<objc && toIdx>=0) { - if (fromIdx<0) { + if (fromIdx < 0) { fromIdx = 0; } if (toIdx >= objc) { toIdx = objc-1; } + if (fromIdx == 0 && toIdx != objc-1 && !Tcl_IsShared(valuePtr)) { + /* + * BEWARE! This is looking inside the implementation of the + * list type. + */ + + List *listPtr = valuePtr->internalRep.twoPtrValue.ptr1; + + if (listPtr->refCount == 1) { + TRACE(("\"%.30s\" %d %d => ", O2S(valuePtr), + TclGetInt4AtPtr(pc+1), TclGetInt4AtPtr(pc+5))); + for (index=toIdx+1 ; index<objc-1 ; index++) { + TclDecrRefCount(objv[index]); + } + listPtr->elemCount = toIdx+1; + listPtr->canonicalFlag = 1; + TclInvalidateStringRep(valuePtr); + TRACE_APPEND(("%.30s\n", O2S(valuePtr))); + NEXT_INST_F(9, 0, 0); + } + } objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx); } else { TclNewObj(objResultPtr); @@ -5716,7 +5737,7 @@ TEBCresume( } result = TclIncrObj(interp, valuePtr, value2Ptr); if (result == TCL_OK) { - Tcl_InvalidateStringRep(dictPtr); + TclInvalidateStringRep(dictPtr); } TclDecrRefCount(value2Ptr); } diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c index 17e50fa..0837070 100644 --- a/generic/tclIOUtil.c +++ b/generic/tclIOUtil.c @@ -18,6 +18,9 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif #include "tclInt.h" #ifdef __WIN32__ # include "tclWinInt.h" diff --git a/generic/tclInt.h b/generic/tclInt.h index feede54..08b3f70 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3547,6 +3547,12 @@ MODULE_SCOPE int TclCompileListCmd(Tcl_Interp *interp, MODULE_SCOPE int TclCompileLlengthCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileLrangeCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); +MODULE_SCOPE int TclCompileLreplaceCmd(Tcl_Interp *interp, + Tcl_Parse *parsePtr, Command *cmdPtr, + struct CompileEnv *envPtr); MODULE_SCOPE int TclCompileLsetCmd(Tcl_Interp *interp, Tcl_Parse *parsePtr, Command *cmdPtr, struct CompileEnv *envPtr); |