summaryrefslogtreecommitdiffstats
path: root/generic/tclCompCmdsGR.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclCompCmdsGR.c')
-rw-r--r--generic/tclCompCmdsGR.c65
1 files changed, 55 insertions, 10 deletions
diff --git a/generic/tclCompCmdsGR.c b/generic/tclCompCmdsGR.c
index e674fb0..ffe39ba 100644
--- a/generic/tclCompCmdsGR.c
+++ b/generic/tclCompCmdsGR.c
@@ -1488,8 +1488,27 @@ TclCompileLreplaceCmd(
return TCL_ERROR;
}
- if(idx2 != INDEX_END && idx2 >= 0 && idx2 < idx1) {
- idx2 = idx1-1;
+ /*
+ * idx1, idx2 are now in canonical form:
+ *
+ * - integer: [0,len+1]
+ * - end index: INDEX_END
+ * - -ive offset: INDEX_END-[len-1,0]
+ * - +ive offset: INDEX_END+1
+ */
+
+ /*
+ * Compilation fails when one index is end-based but the other isn't.
+ * Fixing this will require more bytecodes, but this is a workaround for
+ * now. [Bug 47ac84309b]
+ */
+
+ if ((idx1 <= INDEX_END) != (idx2 <= INDEX_END)) {
+ return TCL_ERROR;
+ }
+
+ if (idx2 != INDEX_END && idx2 >= 0 && idx2 < idx1) {
+ idx2 = idx1 - 1;
}
/*
@@ -1511,6 +1530,9 @@ TclCompileLreplaceCmd(
idx1 = 0;
goto dropEnd;
} else {
+ if (idx2 < idx1) {
+ idx2 = idx1 - 1;
+ }
if (idx1 > 0) {
tmpObj = Tcl_NewIntObj(idx1);
Tcl_IncrRefCount(tmpObj);
@@ -1538,9 +1560,7 @@ TclCompileLreplaceCmd(
idx1 = 0;
goto replaceTail;
} else {
- if (idx1 > 0 && idx2 > 0 && idx2 < idx1) {
- idx2 = idx1 - 1;
- } else if (idx1 < 0 && idx2 < 0 && idx2 < idx1) {
+ if (idx2 < idx1) {
idx2 = idx1 - 1;
}
if (idx1 > 0) {
@@ -1556,7 +1576,7 @@ TclCompileLreplaceCmd(
* operate on.
*/
- dropAll:
+ dropAll: /* This just ensures the arg is a list. */
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
TclEmitOpcode( INST_POP, envPtr);
PushStringLiteral(envPtr, "");
@@ -1569,12 +1589,21 @@ TclCompileLreplaceCmd(
dropRange:
if (tmpObj != NULL) {
+ /*
+ * Emit bytecode to check the list length.
+ */
+
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL), envPtr);
- TclEmitOpcode( INST_GT, envPtr);
+ TclEmitOpcode( INST_GE, envPtr);
offset = CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
+
+ /*
+ * Emit an error if we've been given an empty list.
+ */
+
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
offset2 = CurrentOffset(envPtr);
@@ -1625,16 +1654,30 @@ TclCompileLreplaceCmd(
replaceRange:
if (tmpObj != NULL) {
+ /*
+ * Emit bytecode to check the list length.
+ */
+
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
+
+ /*
+ * Check the list length vs idx1.
+ */
+
TclEmitPush(TclAddLiteralObj(envPtr, tmpObj, NULL), envPtr);
- TclEmitOpcode( INST_GT, envPtr);
+ TclEmitOpcode( INST_GE, envPtr);
offset = CurrentOffset(envPtr);
TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
+
+ /*
+ * Emit an error if we've been given an empty list.
+ */
+
TclEmitOpcode( INST_DUP, envPtr);
TclEmitOpcode( INST_LIST_LENGTH, envPtr);
offset2 = CurrentOffset(envPtr);
- TclEmitInstInt1( INST_JUMP_TRUE1, 0, envPtr);
+ TclEmitInstInt1( INST_JUMP_FALSE1, 0, envPtr);
TclEmitPush(TclAddLiteralObj(envPtr, Tcl_ObjPrintf(
"list doesn't contain element %d", idx1), NULL), envPtr);
CompileReturnInternal(envPtr, INST_RETURN_IMM, TCL_ERROR, 0,
@@ -2966,10 +3009,12 @@ IndexTailVarIfKnown(
} else {
full = 0;
lastTokenPtr = varTokenPtr + n;
- if (!TclWordKnownAtCompileTime(lastTokenPtr, tailPtr)) {
+
+ if (lastTokenPtr->type != TCL_TOKEN_TEXT) {
Tcl_DecrRefCount(tailPtr);
return -1;
}
+ Tcl_SetStringObj(tailPtr, lastTokenPtr->start, lastTokenPtr->size);
}
tailName = TclGetStringFromObj(tailPtr, &len);