Tcl Source Code

Check-in [4d0f21f455]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Update the command compilers and bytecode execution engine to use new machinery.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | bug-db36fa5122
Files: files | file ages | folders
SHA3-256: 4d0f21f4556ff7dcc723afc728c398a654a33c10e8c35676d9827078daef1957
User & Date: dgp 2018-03-09 20:34:33.246
Context
2018-03-09
20:46
Newer utility routine is more suitable. check-in: b864232e48 user: dgp tags: bug-db36fa5122
20:34
Update the command compilers and bytecode execution engine to use new machinery. check-in: 4d0f21f455 user: dgp tags: bug-db36fa5122
19:40
Use new machinery to repair index value flaws in [lsort]. check-in: c07b8490b6 user: dgp tags: bug-db36fa5122
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclAssembly.c.
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
     
    /* Convert to an integer, advance to the next token and return. */
    /*
     * NOTE: Indexing a list with an index before it yields the
     * same result as indexing after it, and might be more easily portable
     * when list size limits grow.
     */
    status = TclGetIndexFromToken(tokenPtr, result, TCL_INDEX_BEFORE,
	    TCL_INDEX_BEFORE);
    *tokenPtrPtr = TokenAfter(tokenPtr);
    if (status == TCL_ERROR && interp) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad index \"%.*s\"",
		tokenPtr->size, tokenPtr->start));
	Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADINDEX", NULL);
    }
    return status;







|
|







2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
     
    /* Convert to an integer, advance to the next token and return. */
    /*
     * NOTE: Indexing a list with an index before it yields the
     * same result as indexing after it, and might be more easily portable
     * when list size limits grow.
     */
    status = TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE,
	    TCL_INDEX_BEFORE, result);
    *tokenPtrPtr = TokenAfter(tokenPtr);
    if (status == TCL_ERROR && interp) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf("bad index \"%.*s\"",
		tokenPtr->size, tokenPtr->start));
	Tcl_SetErrorCode(interp, "TCL", "ASSEM", "BADINDEX", NULL);
    }
    return status;
Changes to generic/tclCompCmdsGR.c.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

/*
 *----------------------------------------------------------------------
 *
 * TclGetIndexFromToken --
 *
 *	Parse a token to determine if an index value is known at
 *	compile time. Two cases are possible.  The compile time value
 *	of the token might be parsed as an absolute index value
 *	in the C signed int range.  Note that this includes index
 *	values that are integers as presented as well as index
 *	arithmetic expressions that can be fully computed at compile
 *	time. The absolute index values that can be directly meaningful
 *	as an index into either a list or a string are those integer
 *	values >= TCL_INDEX_START (0) and < TCL_INDEX_AFTER (INT_MAX).
 *	The largest string supported in Tcl 8 has bytelength INT_MAX.
 *	This means the largest character supported length is also INT_MAX,
 *	and the index of the last character in a string of length INT_MAX
 *	is INT_MAX-1.
 *
 *	Any absolute index value parsed outside that range is encoded
 *	using the minBoundary and maxBounday values passed in by the
 *	caller as the encoding to use for indices that are either
 *	less than or greater than the usable index range. TCL_INDEX_AFTER
 *	is available as a good choice for most callers to use for
 *	maxBoundary. Likewise, the value TCL_INDEX_BEFORE is good for
 *	most callers to use for minBoundary.  Other values are possible
 *	when the caller knows it is helpful in producing its own behavior
 *	for indices before and after the indexed item.
 *
 *	A token can also be parsed as an end-relative index expression.
 *	All end-relative expressions that indicate an index larger
 *	than end (end+2, end--5) point beyond the end of the indexed
 *	collection, and can be encoded as maxBoundary.  The end-relative
 *	expressions that indicate an index less than or equal to end
 *	are encoded relative to the value TCL_INDEX_END (-2).  The
 *	index "end" is encoded as -2, down to the index "end-0x7ffffffe"
 *	which is encoded as INT_MIN. Since the largest index into a
 *	string possible	in Tcl 8 is 0x7ffffffe, the interpretation of
 *	"end-0x7ffffffe" for that largest string would be 0.  Thus,
 *	if the tokens "end-0x7fffffff" or "end+-0x80000000" are parsed,
 *	they can be encoded with the minBoundary value.
 *
 *	These details will require re-examination whenever string and
 *	list length limits are increased, but that will likely also
 *	mean a revised routine capable of returning Tcl_WideInt values.
 *
 * Returns:
 *	TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
 *
 * Side effects:
 *	When TCL_OK is returned, the encoded index value is written
 *	to *index.
 *
 *----------------------------------------------------------------------
 */

int
TclGetIndexFromToken(
    Tcl_Token *tokenPtr,
    int *index,
    int minBoundary,
    int maxBoundary)
{
    Tcl_Obj *tmpObj = Tcl_NewObj();
    int result, idx;

    if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
	Tcl_DecrRefCount(tmpObj);
	return TCL_ERROR;
    }

    result = TclGetIntFromObj(NULL, tmpObj, &idx);
    if (result == TCL_OK) {
	/* We parsed a value in the range INT_MIN...INT_MAX */
    integerEncode:
	if (idx < TCL_INDEX_START) {
	    /* All negative absolute indices are "before the beginning" */
	    idx = minBoundary;
	} else if (idx == INT_MAX) {
	    /* This index value is always "after the end" */
	    idx = maxBoundary;
	}
	/* usual case, the absolute index value encodes itself */
    } else {
	result = TclGetEndOffsetFromObj(NULL, tmpObj, 0, &idx);
	if (result == TCL_OK) {
	    /*
	     * We parsed an end+offset index value. 
	     * idx holds the offset value in the range INT_MIN...INT_MAX.
	     */
	    if (idx > 0) {
		/*
		 * All end+postive or end-negative expressions 
		 * always indicate "after the end".
		 */
		idx = maxBoundary;
	    } else if (idx < INT_MIN - TCL_INDEX_END) {
		/* These indices always indicate "before the beginning */
		idx = minBoundary;
	    } else {
		/* Encoded end-positive (or end+negative) are offset */
		idx += TCL_INDEX_END;
	    }
	} else {
	    result = TclGetIntForIndexM(NULL, tmpObj, 0, &idx);
	    if (result == TCL_OK) {
		/*
		 * Only reach this case when the index value is a
		 * constant index arithmetic expression, and idx
		 * holds the result. Treat it the same as if it were
		 * parsed as an absolute integer value.
		 */
		goto integerEncode;
	    }
	}
    }
    Tcl_DecrRefCount(tmpObj);

    if (result == TCL_OK) {
	*index = idx;
    }

    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileGlobalCmd --







|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














|
|
|


|

|
<
<
<
|
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
<
<
<







31
32
33
34
35
36
37
38






































39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60



61










62


































63





64
65
66
67
68
69
70

/*
 *----------------------------------------------------------------------
 *
 * TclGetIndexFromToken --
 *
 *	Parse a token to determine if an index value is known at
 *	compile time. 






































 *
 * Returns:
 *	TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
 *
 * Side effects:
 *	When TCL_OK is returned, the encoded index value is written
 *	to *index.
 *
 *----------------------------------------------------------------------
 */

int
TclGetIndexFromToken(
    Tcl_Token *tokenPtr,
    int before,
    int after,
    int *indexPtr)
{
    Tcl_Obj *tmpObj = Tcl_NewObj();
    int result = TCL_ERROR;

    if (TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {



	result = TclIndexEncode(NULL, tmpObj, before, after, indexPtr);










    }


































    Tcl_DecrRefCount(tmpObj);





    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileGlobalCmd --
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188

    valTokenPtr = TokenAfter(parsePtr->tokenPtr);
    if (numWords != 3) {
	goto emitComplexLindex;
    }

    idxTokenPtr = TokenAfter(valTokenPtr);
    if (TclGetIndexFromToken(idxTokenPtr, &idx, TCL_INDEX_BEFORE,
	TCL_INDEX_BEFORE) == TCL_OK) {
	/*
	 * The idxTokenPtr parsed as a valid index value and was
	 * encoded as expected by INST_LIST_INDEX_IMM.
	 *
	 * NOTE: that we rely on indexing before a list producing the
	 * same result as indexing after a list.
	 */







|
|







1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098

    valTokenPtr = TokenAfter(parsePtr->tokenPtr);
    if (numWords != 3) {
	goto emitComplexLindex;
    }

    idxTokenPtr = TokenAfter(valTokenPtr);
    if (TclGetIndexFromToken(idxTokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_BEFORE,
	    &idx) == TCL_OK) {
	/*
	 * The idxTokenPtr parsed as a valid index value and was
	 * encoded as expected by INST_LIST_INDEX_IMM.
	 *
	 * NOTE: that we rely on indexing before a list producing the
	 * same result as indexing after a list.
	 */
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427

    if (parsePtr->numWords != 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);

    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx1, TCL_INDEX_START,
	    TCL_INDEX_AFTER) != TCL_OK) {
	return TCL_ERROR;
    }
    /*
     * Token was an index value, and we treat all "first" indices
     * before the list same as the start of the list.
     */

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx2, TCL_INDEX_BEFORE,
	    TCL_INDEX_END) != TCL_OK) {
	return TCL_ERROR;
    }
    /*
     * Token was an index value, and we treat all "last" indices
     * after the list same as the end of the list.
     */








|
|








|
|







1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337

    if (parsePtr->numWords != 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);

    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	return TCL_ERROR;
    }
    /*
     * Token was an index value, and we treat all "first" indices
     * before the list same as the start of the list.
     */

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	return TCL_ERROR;
    }
    /*
     * Token was an index value, and we treat all "last" indices
     * after the list same as the end of the list.
     */

1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
    /*
     * NOTE: This command treats all inserts at indices before the list
     * the same as inserts at the start of the list, and all inserts
     * after the list the same as inserts at the end of the list. We
     * make that transformation here so we can use the optimized bytecode
     * as much as possible.
     */
    if (TclGetIndexFromToken(tokenPtr, &idx, TCL_INDEX_START,
	    TCL_INDEX_END) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * There are four main cases. If there are no values to insert, this is
     * just a confirm-listiness check. If the index is '0', this is a prepend.
     * If the index is 'end' (== TCL_INDEX_END), this is an append. Otherwise,







|
|







1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
    /*
     * NOTE: This command treats all inserts at indices before the list
     * the same as inserts at the start of the list, and all inserts
     * after the list the same as inserts at the end of the list. We
     * make that transformation here so we can use the optimized bytecode
     * as much as possible.
     */
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_END,
	    &idx) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * There are four main cases. If there are no values to insert, this is
     * just a confirm-listiness check. If the index is '0', this is a prepend.
     * If the index is 'end' (== TCL_INDEX_END), this is an append. Otherwise,
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588

    if (parsePtr->numWords < 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);

    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx1, TCL_INDEX_START,
	    TCL_INDEX_AFTER) != TCL_OK) {
	return TCL_ERROR;
    }

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx2, TCL_INDEX_BEFORE,
	    TCL_INDEX_END) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * idx1, idx2 are the conventional encoded forms of the tokens parsed
     * as all forms of index values.  Values of idx1 that come before the
     * list are treated the same as if they were the start of the list.







|
|




|
|







1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498

    if (parsePtr->numWords < 4) {
	return TCL_ERROR;
    }
    listTokenPtr = TokenAfter(parsePtr->tokenPtr);

    tokenPtr = TokenAfter(listTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	return TCL_ERROR;
    }

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * idx1, idx2 are the conventional encoded forms of the tokens parsed
     * as all forms of index values.  Values of idx1 that come before the
     * list are treated the same as if they were the start of the list.
Changes to generic/tclCompCmdsSZ.c.
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
    /* Every path must push the string argument */
    CompileWord(envPtr, stringTokenPtr,			interp, 1);

    /*
     * Parse the two indices.
     */

    if (TclGetIndexFromToken(fromTokenPtr, &idx1, TCL_INDEX_START,
	    TCL_INDEX_AFTER) != TCL_OK) {
	goto nonConstantIndices;
    }
    /*
     * Token parsed as an index expression. We treat all indices before
     * the string the same as the start of the string.
     */

    if (idx1 == TCL_INDEX_AFTER) {
	/* [string range $s end+1 $last] must be empty string */
	OP(		POP);
	PUSH(		"");
	return TCL_OK;
    }

    if (TclGetIndexFromToken(toTokenPtr, &idx2, TCL_INDEX_BEFORE,
	    TCL_INDEX_END) != TCL_OK) {
	goto nonConstantIndices;
    }
    /*
     * Token parsed as an index expression. We treat all indices after
     * the string the same as the end of the string.
     */
    if (idx2 == TCL_INDEX_BEFORE) {







|
|














|
|







933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
    /* Every path must push the string argument */
    CompileWord(envPtr, stringTokenPtr,			interp, 1);

    /*
     * Parse the two indices.
     */

    if (TclGetIndexFromToken(fromTokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	goto nonConstantIndices;
    }
    /*
     * Token parsed as an index expression. We treat all indices before
     * the string the same as the start of the string.
     */

    if (idx1 == TCL_INDEX_AFTER) {
	/* [string range $s end+1 $last] must be empty string */
	OP(		POP);
	PUSH(		"");
	return TCL_OK;
    }

    if (TclGetIndexFromToken(toTokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	goto nonConstantIndices;
    }
    /*
     * Token parsed as an index expression. We treat all indices after
     * the string the same as the end of the string.
     */
    if (idx2 == TCL_INDEX_BEFORE) {
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
    if (parsePtr->numWords == 5) {
	tokenPtr = TokenAfter(valueTokenPtr);
	tokenPtr = TokenAfter(tokenPtr);
	replacementTokenPtr = TokenAfter(tokenPtr);
    }

    tokenPtr = TokenAfter(valueTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx1, TCL_INDEX_START,
	    TCL_INDEX_AFTER) != TCL_OK) {
	goto genericReplace;
    }
    /*
     * Token parsed as an index value. Indices before the string are
     * treated as index of start of string.
     */

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, &idx2, TCL_INDEX_BEFORE,
	    TCL_INDEX_END) != TCL_OK) {
	goto genericReplace;
    }
    /*
     * Token parsed as an index value. Indices after the string are
     * treated as index of end of string.
     */








|
|








|
|







1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
    if (parsePtr->numWords == 5) {
	tokenPtr = TokenAfter(valueTokenPtr);
	tokenPtr = TokenAfter(tokenPtr);
	replacementTokenPtr = TokenAfter(tokenPtr);
    }

    tokenPtr = TokenAfter(valueTokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_START, TCL_INDEX_AFTER,
	    &idx1) != TCL_OK) {
	goto genericReplace;
    }
    /*
     * Token parsed as an index value. Indices before the string are
     * treated as index of start of string.
     */

    tokenPtr = TokenAfter(tokenPtr);
    if (TclGetIndexFromToken(tokenPtr, TCL_INDEX_BEFORE, TCL_INDEX_END,
	    &idx2) != TCL_OK) {
	goto genericReplace;
    }
    /*
     * Token parsed as an index value. Indices after the string are
     * treated as index of end of string.
     */

Changes to generic/tclCompile.h.
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
MODULE_SCOPE int	TclFindCompiledLocal(const char *name, int nameChars,
			    int create, CompileEnv *envPtr);
MODULE_SCOPE int	TclFixupForwardJump(CompileEnv *envPtr,
			    JumpFixup *jumpFixupPtr, int jumpDist,
			    int distThreshold);
MODULE_SCOPE void	TclFreeCompileEnv(CompileEnv *envPtr);
MODULE_SCOPE void	TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE int	TclGetIndexFromToken(Tcl_Token *tokenPtr, int *index,
			    int minBoundary, int maxBoundary);
MODULE_SCOPE void	TclInitByteCodeObj(Tcl_Obj *objPtr,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclInitCompileEnv(Tcl_Interp *interp,
			    CompileEnv *envPtr, const char *string,
			    int numBytes, const CmdFrame *invoker, int word);
MODULE_SCOPE void	TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE void	TclInitLiteralTable(LiteralTable *tablePtr);







|
|







1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
MODULE_SCOPE int	TclFindCompiledLocal(const char *name, int nameChars,
			    int create, CompileEnv *envPtr);
MODULE_SCOPE int	TclFixupForwardJump(CompileEnv *envPtr,
			    JumpFixup *jumpFixupPtr, int jumpDist,
			    int distThreshold);
MODULE_SCOPE void	TclFreeCompileEnv(CompileEnv *envPtr);
MODULE_SCOPE void	TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE int	TclGetIndexFromToken(Tcl_Token *tokenPtr,
			    int before, int after, int *indexPtr);
MODULE_SCOPE void	TclInitByteCodeObj(Tcl_Obj *objPtr,
			    CompileEnv *envPtr);
MODULE_SCOPE void	TclInitCompileEnv(Tcl_Interp *interp,
			    CompileEnv *envPtr, const char *string,
			    int numBytes, const CmdFrame *invoker, int word);
MODULE_SCOPE void	TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr);
MODULE_SCOPE void	TclInitLiteralTable(LiteralTable *tablePtr);
Changes to generic/tclExecute.c.
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
	    goto gotError;
	}

	/*
	 * Decode end-offset index values.
	 */

	if (index <= TCL_INDEX_END) {
	    index += (objc - 1 - TCL_INDEX_END);
	}
	pcAdjustment = 5;

    lindexFastPath:
	if (index >= 0 && index < objc) {
	    objResultPtr = objv[index];
	} else {
	    TclNewObj(objResultPtr);







<
|
<







5089
5090
5091
5092
5093
5094
5095

5096

5097
5098
5099
5100
5101
5102
5103
	    goto gotError;
	}

	/*
	 * Decode end-offset index values.
	 */


	index = TclIndexDecode(index, objc - 1);

	pcAdjustment = 5;

    lindexFastPath:
	if (index >= 0 && index < objc) {
	    objResultPtr = objv[index];
	} else {
	    TclNewObj(objResultPtr);
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
	/* Decode index value operands. */

	assert ( toIdx != TCL_INDEX_AFTER);

	if ((toIdx == TCL_INDEX_BEFORE) || (fromIdx == TCL_INDEX_AFTER)) {
	    goto emptyList;
	}
	if (toIdx <= TCL_INDEX_END) {
	    toIdx += (objc - 1 - TCL_INDEX_END);
	    if (toIdx < 0) {
		goto emptyList;
	    }
	} else if (toIdx >= objc) {
	    toIdx = objc - 1;
	}

	assert ( toIdx >= 0 && toIdx < objc);
	assert ( fromIdx != TCL_INDEX_BEFORE );
	assert ( fromIdx != TCL_INDEX_AFTER);

	if (fromIdx <= TCL_INDEX_END) {
	    fromIdx += (objc - 1 - TCL_INDEX_END);
	    if (fromIdx < 0) {
		fromIdx = 0;
	    }
	}
	assert ( fromIdx >= 0 );

	if (fromIdx <= toIdx) {
	    /* Construct the subsquence list */
	    /* unshared optimization */
	    if (Tcl_IsShared(valuePtr)) {
		objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx);
	    } else {







<
|
|
|
<








|
<
|
|
|
<
<







5244
5245
5246
5247
5248
5249
5250

5251
5252
5253

5254
5255
5256
5257
5258
5259
5260
5261
5262

5263
5264
5265


5266
5267
5268
5269
5270
5271
5272
	/* Decode index value operands. */

	assert ( toIdx != TCL_INDEX_AFTER);

	if ((toIdx == TCL_INDEX_BEFORE) || (fromIdx == TCL_INDEX_AFTER)) {
	    goto emptyList;
	}

	toIdx = TclIndexDecode(toIdx, objc - 1);
	if (toIdx < 0) {
	    goto emptyList;

	} else if (toIdx >= objc) {
	    toIdx = objc - 1;
	}

	assert ( toIdx >= 0 && toIdx < objc);
	assert ( fromIdx != TCL_INDEX_BEFORE );
	assert ( fromIdx != TCL_INDEX_AFTER);

	fromIdx = TclIndexDecode(fromIdx, objc - 1);

	if (fromIdx < 0) {
	    fromIdx = 0;
	}



	if (fromIdx <= toIdx) {
	    /* Construct the subsquence list */
	    /* unshared optimization */
	    if (Tcl_IsShared(valuePtr)) {
		objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, objv+fromIdx);
	    } else {
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
	}

	/* Decode index operands. */

	assert ( toIdx != TCL_INDEX_BEFORE );
	assert ( toIdx != TCL_INDEX_AFTER);

	if (toIdx <= TCL_INDEX_END) {
	    toIdx += (length - 1 - TCL_INDEX_END);
	    if (toIdx < 0) {
		goto emptyRange;
	    }
	} else if (toIdx >= length) {
	    toIdx = length - 1;
	}

	assert ( toIdx >= 0 && toIdx < length );

	assert ( fromIdx != TCL_INDEX_BEFORE );
	assert ( fromIdx != TCL_INDEX_AFTER);

	if (fromIdx <= TCL_INDEX_END) {
	    fromIdx += (length - 1 - TCL_INDEX_END);
	    if (fromIdx < 0) {
		fromIdx = 0;
	    }
	}

	assert ( fromIdx >= 0 );

	if (fromIdx <= toIdx) {
	    objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
	} else {
	emptyRange:
	    TclNewObj(objResultPtr);
	}







|
<
|
|
<









|
<
|
|
|
<
<
<







5632
5633
5634
5635
5636
5637
5638
5639

5640
5641

5642
5643
5644
5645
5646
5647
5648
5649
5650
5651

5652
5653
5654



5655
5656
5657
5658
5659
5660
5661
	}

	/* Decode index operands. */

	assert ( toIdx != TCL_INDEX_BEFORE );
	assert ( toIdx != TCL_INDEX_AFTER);

	toIdx = TclIndexDecode(toIdx, length - 1);

	if (toIdx < 0) {
	    goto emptyRange;

	} else if (toIdx >= length) {
	    toIdx = length - 1;
	}

	assert ( toIdx >= 0 && toIdx < length );

	assert ( fromIdx != TCL_INDEX_BEFORE );
	assert ( fromIdx != TCL_INDEX_AFTER);

	fromIdx = TclIndexDecode(fromIdx, length - 1);

	if (fromIdx < 0) {
	    fromIdx = 0;
	}




	if (fromIdx <= toIdx) {
	    objResultPtr = Tcl_GetRange(valuePtr, fromIdx, toIdx);
	} else {
	emptyRange:
	    TclNewObj(objResultPtr);
	}