Tcl Source Code

Check-in [8cadbda624]
Login

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

Overview
Comment:Rework TclGetIndexFromToken to make use of TclGetEndOffsetFromObj, and to lay out the index value encoding cases.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | bug-db36fa5122
Files: files | file ages | folders
SHA3-256: 8cadbda624ef9b7ac006bda76841f72447f13b6975857edc28dca73808797f77
User & Date: dgp 2018-03-07 17:02:50.201
Context
2018-03-07
18:39
Establish 4 symbols for categories of parsed index values: TCL_INDEX_START = 0 The start index.... check-in: 3f026007bd user: dgp tags: bug-db36fa5122
17:02
Rework TclGetIndexFromToken to make use of TclGetEndOffsetFromObj, and to lay out the index value en... check-in: 8cadbda624 user: dgp tags: bug-db36fa5122
13:40
Tests of [assemble] use of compiled index values. check-in: d6534fb386 user: dgp tags: bug-db36fa5122
Changes
Unified Diff Ignore Whitespace Patch
Changes to generic/tclCompCmdsGR.c.
30
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


/*
 *----------------------------------------------------------------------
 *
 * TclGetIndexFromToken --
 *
 *	Parse a token and get the encoded version of the index (as understood
 *	by TEBC), assuming it is at all knowable at compile time. Only handles


 *	indices that are integers or 'end' or 'end-integer'.







 *

























 * Returns:
 *	TCL_OK if parsing succeeded, and TCL_ERROR if it failed.
 *	The return value of *index is:
 *	    >= 0	   -- constant index from start,
 *	    == minBoundary -- (TCL_INDEX_OUT_OF_RANGE, 0) if out of range (before start)
 *	    == maxBoundary -- (INT_MAX, TCL_INDEX_OUT_OF_RANGE) if out of range (after end)
 *	    <= -2	   -- (<= TCL_INDEX_END) negative index from end.
 *
 * Side effects:

 *	Sets *index to the index value if successful.
 *
 *----------------------------------------------------------------------
 */

int
TclGetIndexFromToken(
    Tcl_Token *tokenPtr,







|
|
>
>
|
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


<
<
<
<
<


>
|







30
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


/*
 *----------------------------------------------------------------------
 *
 * 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 >= 0 and < 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. INT_MAX
 *	is available as a good choice for most callers to use for
 *	maxBoundary. Likewise, the value -1 is good for most callers
 *	to use for minBoundary.
 *
 *	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,
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
    if (!TclWordKnownAtCompileTime(tokenPtr, tmpObj)) {
	Tcl_DecrRefCount(tmpObj);
	return TCL_ERROR;
    }

    result = TclGetIntFromObj(NULL, tmpObj, &idx);
    if (result == TCL_OK) {

	/* out of range (..., -2] */
	if (idx <= TCL_INDEX_END) {

	    idx = minBoundary;


	    /* before start */
	}

    } else {
	result = TclGetIntForIndexM(NULL, tmpObj, TCL_INDEX_END, &idx);
	if (result == TCL_OK) {
	    int endSyntax = (tmpObj->length >= 3 && *tmpObj->bytes == 'e');
	    /* 
	     * Check computed index results to out of range (after end or negative constant),
	     * set it to -1 in order to avoid ambiguity with "end[+-integer] syntax"

	     */
	    if (idx > TCL_INDEX_END && endSyntax) {


		/* after end [end+1, ...) */

		idx = maxBoundary; /* may be TCL_INDEX_OUT_OF_RANGE or INT_MAX */
	    } else if (idx < 0 && !endSyntax) {
		/* before start, negative constant (..., -1-1] */
		idx = minBoundary;














	    }
	}
    }
    Tcl_DecrRefCount(tmpObj);

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







>
|
|
>

>
>
|

>

|

<
|
|
<
>

|
>
>
|
>
|
|
|

>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
    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 < 0) {
	    /* 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 alwasy 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;