Compare commits

...
Author SHA1 Message Date
sebres 7ff8596830 fixed test parse-12.26 - variable now 2019-03-08 01:17:11 +00:00
sebres 6ac8a0660b fixes [408568] "variable substitution parsing limited to ASCII alphanumerics" 2019-03-08 00:44:23 +00:00
sebres 0a81110aee test case for [408568] "variable substitution parsing limited to ASCII alphanumerics":
illustrating breaking down of dollar-substitution on alnum-unichar.
2019-03-08 00:34:48 +00:00
sebres 860175c879 resolves large discrepancies in proc/lambda between 8.5 and 8.6;
coverage for [e3f481f187] regression to lookup non-ASCII proc/lambda formal arguments (TclCreateProc/TclPushVarName);
cherry-picked from [c9251294d9b8b14d] (pyk-backport-to-8-6) and amend [3e12442cb7829c9f] (fix-comp-local-utf-regres).
2019-03-08 00:04:00 +00:00
10 changed files with 504 additions and 443 deletions
+32 -28
View File
@@ -4783,10 +4783,10 @@ PushVarName(
int* clNext) /* Reference to offset of next hidden cont. line */
{
register const char *p;
const char *name, *elName;
register int i, n;
const char *last, *name, *elName;
register int n;
Tcl_Token *elemTokenPtr = NULL;
int nameChars, elNameChars, simpleVarName, localIndex;
int nameLen, elNameLen, simpleVarName, localIndex;
int elemTokenCount = 0, allocedTokens = 0, removedParen = 0;
/*
@@ -4799,7 +4799,7 @@ PushVarName(
simpleVarName = 0;
name = elName = NULL;
nameChars = elNameChars = 0;
nameLen = elNameLen = 0;
localIndex = -1;
if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
@@ -4811,22 +4811,25 @@ PushVarName(
simpleVarName = 1;
name = varTokenPtr[1].start;
nameChars = varTokenPtr[1].size;
if (name[nameChars-1] == ')') {
nameLen = varTokenPtr[1].size;
if (name[nameLen-1] == ')') {
/*
* last char is ')' => potential array reference.
*/
last = Tcl_UtfPrev(name + nameLen, name);
for (i=0,p=name ; i<nameChars ; i++,p++) {
if (*p == '(') {
elName = p + 1;
elNameChars = nameChars - i - 2;
nameChars = i;
break;
if (*last == ')') {
for (p = name; p < last; p = Tcl_UtfNext(p)) {
if (*p == '(') {
elName = p + 1;
elNameLen = last - elName;
nameLen = p - name;
break;
}
}
}
if (interp && (elName != NULL) && elNameChars) {
if (interp && elNameLen) {
/*
* An array element, the element name is a simple string:
* assemble the corresponding token.
@@ -4837,7 +4840,7 @@ PushVarName(
allocedTokens = 1;
elemTokenPtr->type = TCL_TOKEN_TEXT;
elemTokenPtr->start = elName;
elemTokenPtr->size = elNameChars;
elemTokenPtr->size = elNameLen;
elemTokenPtr->numComponents = 0;
elemTokenCount = 1;
}
@@ -4845,22 +4848,23 @@ PushVarName(
} else if (interp && ((n = varTokenPtr->numComponents) > 1)
&& (varTokenPtr[1].type == TCL_TOKEN_TEXT)
&& (varTokenPtr[n].type == TCL_TOKEN_TEXT)
&& (varTokenPtr[n].start[varTokenPtr[n].size - 1] == ')')) {
&& (*((p = varTokenPtr[n].start + varTokenPtr[n].size)-1) == ')')
&& (*Tcl_UtfPrev(p, varTokenPtr[n].start) == ')')) {
/*
* Check for parentheses inside first token.
*/
simpleVarName = 0;
for (i = 0, p = varTokenPtr[1].start;
i < varTokenPtr[1].size; i++, p++) {
for (p = varTokenPtr[1].start,
last = p + varTokenPtr[1].size; p < last; p = Tcl_UtfNext(p)) {
if (*p == '(') {
simpleVarName = 1;
break;
}
}
if (simpleVarName) {
int remainingChars;
int remainingLen;
/*
* Check the last token: if it is just ')', do not count it.
@@ -4876,12 +4880,12 @@ PushVarName(
}
name = varTokenPtr[1].start;
nameChars = p - varTokenPtr[1].start;
nameLen = p - varTokenPtr[1].start;
elName = p + 1;
remainingChars = (varTokenPtr[2].start - p) - 1;
elNameChars = (varTokenPtr[n].start-p) + varTokenPtr[n].size - 1;
remainingLen = (varTokenPtr[2].start - p) - 1;
elNameLen = (varTokenPtr[n].start-p) + varTokenPtr[n].size - 1;
if (remainingChars) {
if (remainingLen) {
/*
* Make a first token with the extra characters in the first
* token.
@@ -4892,7 +4896,7 @@ PushVarName(
allocedTokens = 1;
elemTokenPtr->type = TCL_TOKEN_TEXT;
elemTokenPtr->start = elName;
elemTokenPtr->size = remainingChars;
elemTokenPtr->size = remainingLen;
elemTokenPtr->numComponents = 0;
elemTokenCount = n;
@@ -4919,8 +4923,8 @@ PushVarName(
*/
int hasNsQualifiers = 0;
for (i = 0, p = name; i < nameChars; i++, p++) {
if ((*p == ':') && ((i+1) < nameChars) && (*(p+1) == ':')) {
for (p = name, last = p + nameLen-1; p < last; p = Tcl_UtfNext(p)) {
if ((*p == ':') && (*(p+1) == ':')) {
hasNsQualifiers = 1;
break;
}
@@ -4933,7 +4937,7 @@ PushVarName(
*/
if ((envPtr->procPtr != NULL) && !hasNsQualifiers) {
localIndex = TclFindCompiledLocal(name, nameChars,
localIndex = TclFindCompiledLocal(name, nameLen,
/*create*/ flags & TCL_CREATE_VAR,
envPtr->procPtr);
if ((flags & TCL_NO_LARGE_INDEX) && (localIndex > 255)) {
@@ -4945,7 +4949,7 @@ PushVarName(
}
}
if (interp && localIndex < 0) {
PushLiteral(envPtr, name, nameChars);
PushLiteral(envPtr, name, nameLen);
}
/*
@@ -4953,7 +4957,7 @@ PushVarName(
*/
if (interp && elName != NULL) {
if (elNameChars) {
if (elNameLen) {
envPtr->line = line;
envPtr->clNext = clNext;
TclCompileTokens(interp, elemTokenPtr, elemTokenCount, envPtr);
+2 -2
View File
@@ -1105,12 +1105,12 @@ TclStackAlloc(
int numBytes)
{
Interp *iPtr = (Interp *) interp;
int numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
int numWords;
if (iPtr == NULL || iPtr->execEnvPtr == NULL) {
return (void *) ckalloc(numBytes);
}
numWords = (numBytes + (sizeof(Tcl_Obj *) - 1))/sizeof(Tcl_Obj *);
return (void *) StackAllocWords(interp, numWords);
}
+4 -4
View File
@@ -803,9 +803,8 @@ typedef struct CompiledLocal {
/* Next compiler-recognized local variable for
* this procedure, or NULL if this is the last
* local. */
int nameLength; /* The number of characters in local
* variable's name. Used to speed up variable
* lookups. */
int nameLength; /* The number of bytes in local variable's name.
* Among others used to speed up var lookups. */
int frameIndex; /* Index in the array of compiler-assigned
* variables in the procedure call frame. */
int flags; /* Flag bits for the local variable. Same as
@@ -2581,6 +2580,7 @@ MODULE_SCOPE char * TclGetStringStorage(Tcl_Obj *objPtr,
MODULE_SCOPE int TclGlob(Tcl_Interp *interp, char *pattern,
Tcl_Obj *unquotedPrefix, int globFlags,
Tcl_GlobTypeData *types);
MODULE_SCOPE size_t TclFindUtfBarewordEnd(const char *src, size_t numBytes);
MODULE_SCOPE int TclIncrObj(Tcl_Interp *interp, Tcl_Obj *valuePtr,
Tcl_Obj *incrPtr);
MODULE_SCOPE Tcl_Obj * TclIncrObjVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr,
@@ -3728,7 +3728,7 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, CONST char *file,
/*
*----------------------------------------------------------------
* Macro used by the Tcl core to increment a namespace's export export epoch
* Macro used by the Tcl core to increment a namespace's export epoch
* counter. The ANSI C "prototype" for this macro is:
*
* MODULE_SCOPE void TclInvalidateNsCmdLookup(Namespace *nsPtr);
+278 -300
View File
@@ -51,20 +51,22 @@ Tcl_ObjType tclListType = {
*
* NewListIntRep --
*
* Creates a list internal rep with space for objc elements. objc
* must be > 0. If objv!=NULL, initializes with the first objc values
* in that array. If objv==NULL, initalize list internal rep to have
* 0 elements, with space to add objc more. Flag value "p" indicates
* Creates a 'List' structure with space for 'objc' elements. 'objc' must
* be > 0. If 'objv' is not NULL, The list is initialized with first
* 'objc' values in that array. Otherwise the list is initialized to have
* 0 elements, with space to add 'objc' more. Flag value 'p' indicates
* how to behave on failure.
*
* Results:
* A new List struct with refCount 0 is returned. If some failure
* prevents this then if p=0, NULL is returned and otherwise the
* routine panics.
* Value
*
* Side effects:
* The ref counts of the elements in objv are incremented since the
* resulting list now refers to them.
* A new 'List' structure with refCount 0. If some failure
* prevents this NULL is returned if 'p' is 0 , and 'Tcl_Panic'
* is called if it is not.
*
* Effect
*
* The refCount of each value in 'objv' is incremented as it is added
* to the list.
*
*----------------------------------------------------------------------
*/
@@ -129,22 +131,10 @@ NewListIntRep(
/*
*----------------------------------------------------------------------
*
* AttemptNewList --
*
* Creates a list internal rep with space for objc elements. objc
* must be > 0. If objv!=NULL, initializes with the first objc values
* in that array. If objv==NULL, initalize list internal rep to have
* 0 elements, with space to add objc more.
*
* Results:
* A new List struct with refCount 0 is returned. If some failure
* prevents this then NULL is returned, and an error message is left
* in the interp result, unless interp is NULL.
*
* Side effects:
* The ref counts of the elements in objv are incremented since the
* resulting list now refers to them.
* AttemptNewList --
*
* Like NewListIntRep, but additionally sets an error message on failure.
*
*----------------------------------------------------------------------
*/
@@ -175,23 +165,20 @@ AttemptNewList(
*
* Tcl_NewListObj --
*
* This function is normally called when not debugging: i.e., when
* TCL_MEM_DEBUG is not defined. It creates a new list object from an
* (objc,objv) array: that is, each of the objc elements of the array
* referenced by objv is inserted as an element into a new Tcl object.
* Creates a new list object and adds values to it. When TCL_MEM_DEBUG is
* defined, 'Tcl_DbNewListObj' is called instead.
*
* When TCL_MEM_DEBUG is defined, this function just returns the result
* of calling the debugging version Tcl_DbNewListObj.
* Value
*
* Results:
* A new list object is returned that is initialized from the object
* pointers in objv. If objc is less than or equal to zero, an empty
* object is returned. The new object's string representation is left
* NULL. The resulting new list object has ref count 0.
* A new list 'Tcl_Obj' to which is appended values from 'objv', or if
* 'objc' is less than or equal to zero, a list 'Tcl_Obj' having no
* elements. The string representation of the new 'Tcl_Obj' is set to
* NULL. The refCount of the list is 0.
*
* Side effects:
* The ref counts of the elements in objv are incremented since the
* resulting list now refers to them.
* Effect
*
* The refCount of each elements in 'objv' is incremented as it is added
* to the list.
*
*----------------------------------------------------------------------
*/
@@ -242,28 +229,14 @@ Tcl_NewListObj(
/*
*----------------------------------------------------------------------
*
* Tcl_DbNewListObj --
*
* This function is normally called when debugging: i.e., when
* TCL_MEM_DEBUG is defined. It creates new list objects. It is the same
* as the Tcl_NewListObj function above except that it calls
* Tcl_DbCkalloc directly with the file name and line number from its
* caller. This simplifies debugging since then the [memory active]
* command will report the correct file name and line number when
* reporting objects that haven't been freed.
*
* When TCL_MEM_DEBUG is not defined, this function just returns the
* result of calling Tcl_NewListObj.
*
* Results:
* A new list object is returned that is initialized from the object
* pointers in objv. If objc is less than or equal to zero, an empty
* object is returned. The new object's string representation is left
* NULL. The new list object has ref count 0.
*
* Side effects:
* The ref counts of the elements in objv are incremented since the
* resulting list now refers to them.
* Tcl_DbNewListObj --
*
* Like 'Tcl_NewListObj', but it calls Tcl_DbCkalloc directly with the
* file name and line number from its caller. This simplifies debugging
* since the [memory active] command will report the correct file
* name and line number when reporting objects that haven't been freed.
*
* When TCL_MEM_DEBUG is not defined, 'Tcl_NewListObj' is called instead.
*
*----------------------------------------------------------------------
*/
@@ -324,19 +297,8 @@ Tcl_DbNewListObj(
*
* Tcl_SetListObj --
*
* Modify an object to be a list containing each of the objc elements of
* the object array referenced by objv.
*
* Results:
* None.
*
* Side effects:
* The object is made a list object and is initialized from the object
* pointers in objv. If objc is less than or equal to zero, an empty
* object is returned. The new object's string representation is left
* NULL. The ref counts of the elements in objv are incremented since the
* list now refers to them. The object's old string and internal
* representations are freed and its type is set NULL.
* Like 'Tcl_NewListObj', but operates on an existing 'Tcl_Obj'instead of
* creating a new one.
*
*----------------------------------------------------------------------
*/
@@ -381,18 +343,20 @@ Tcl_SetListObj(
*
* TclListObjCopy --
*
* Makes a "pure list" copy of a list value. This provides for the C
* level a counterpart of the [lrange $list 0 end] command, while using
* internals details to be as efficient as possible.
* Creates a new 'Tcl_Obj' which is a pure copy of a list value. This
* provides for the C level a counterpart of the [lrange $list 0 end]
* command, while using internals details to be as efficient as possible.
*
* Results:
* Normally returns a pointer to a new Tcl_Obj, that contains the same
* list value as *listPtr does. The returned Tcl_Obj has a refCount of
* zero. If *listPtr does not hold a list, NULL is returned, and if
* interp is non-NULL, an error message is recorded there.
* Value
*
* Side effects:
* None.
* The address of the new 'Tcl_Obj' which shares its internal
* representation with 'listPtr', and whose refCount is 0. If 'listPtr'
* is not actually a list, the value is NULL, and an error message is left
* in 'interp' if it is not NULL.
*
* Effect
*
* 'listPtr' is converted to a list if it isn't one already.
*
*----------------------------------------------------------------------
*/
@@ -422,27 +386,30 @@ TclListObjCopy(
*
* Tcl_ListObjGetElements --
*
* This function returns an (objc,objv) array of the elements in a list
* object.
* Retreive the elements in a list 'Tcl_Obj'.
*
* Results:
* The return value is normally TCL_OK; in this case *objcPtr is set to
* the count of list elements and *objvPtr is set to a pointer to an
* array of (*objcPtr) pointers to each list element. If listPtr does not
* refer to a list object and the object can not be converted to one,
* TCL_ERROR is returned and an error message will be left in the
* interpreter's result if interp is not NULL.
* Value
*
* The objects referenced by the returned array should be treated as
* readonly and their ref counts are _not_ incremented; the caller must
* do that if it holds on to a reference. Furthermore, the pointer and
* length returned by this function may change as soon as any function is
* called on the list object; be careful about retaining the pointer in a
* local data structure.
* TCL_OK
*
* Side effects:
* The possible conversion of the object referenced by listPtr
* to a list object.
* A count of list elements is stored, 'objcPtr', And a pointer to the
* array of elements in the list is stored in 'objvPtr'.
*
* The elements accessible via 'objvPtr' should be treated as readonly
* and the refCount for each object is _not_ incremented; the caller
* must do that if it holds on to a reference. Furthermore, the
* pointer and length returned by this function may change as soon as
* any function is called on the list object. Be careful about
* retaining the pointer in a local data structure.
*
* TCL_ERROR
*
* 'listPtr' is not a valid list. An error message is left in the
* interpreter's result if 'interp' is not NULL.
*
* Effect
*
* 'listPtr' is converted to a list object if it isn't one already.
*
*----------------------------------------------------------------------
*/
@@ -483,23 +450,27 @@ Tcl_ListObjGetElements(
*
* Tcl_ListObjAppendList --
*
* This function appends the objects in the list referenced by
* elemListPtr to the list object referenced by listPtr. If listPtr is
* not already a list object, an attempt will be made to convert it to
* one.
* Appends the elements of elemListPtr to those of listPtr.
*
* Results:
* The return value is normally TCL_OK. If listPtr or elemListPtr do not
* refer to list objects and they can not be converted to one, TCL_ERROR
* is returned and an error message is left in the interpreter's result
* if interp is not NULL.
* Value
*
* Side effects:
* The reference counts of the elements in elemListPtr are incremented
* since the list now refers to them. listPtr and elemListPtr are
* converted, if necessary, to list objects. Also, appending the new
* elements may cause listObj's array of element pointers to grow.
* listPtr's old string representation, if any, is invalidated.
* TCL_OK
*
* Success.
*
* TCL_ERROR
*
* 'listPtr' or 'elemListPtr' are not valid lists. An error
* message is left in the interpreter's result if 'interp' is not NULL.
*
* Effect
*
* The reference count of each element of 'elemListPtr' as it is added to
* 'listPtr'. 'listPtr' and 'elemListPtr' are converted to 'tclListType'
* if they are not already. Appending the new elements may cause the
* array of element pointers in 'listObj' to grow. If any objects are
* appended to 'listPtr'. Any preexisting string representation of
* 'listPtr' is invalidated.
*
*----------------------------------------------------------------------
*/
@@ -540,24 +511,27 @@ Tcl_ListObjAppendList(
*
* Tcl_ListObjAppendElement --
*
* This function is a special purpose version of Tcl_ListObjAppendList:
* it appends a single object referenced by objPtr to the list object
* referenced by listPtr. If listPtr is not already a list object, an
* attempt will be made to convert it to one.
* Like 'Tcl_ListObjAppendList', but Appends a single value to a list.
*
* Results:
* The return value is normally TCL_OK; in this case objPtr is added to
* the end of listPtr's list. If listPtr does not refer to a list object
* and the object can not be converted to one, TCL_ERROR is returned and
* an error message will be left in the interpreter's result if interp is
* not NULL.
* Value
*
* Side effects:
* The ref count of objPtr is incremented since the list now refers to
* it. listPtr will be converted, if necessary, to a list object. Also,
* appending the new element may cause listObj's array of element
* pointers to grow. listPtr's old string representation, if any, is
* invalidated.
* TCL_OK
*
* 'objPtr' is appended to the elements of 'listPtr'.
*
* TCL_ERROR
*
* listPtr does not refer to a list object and the object can not be
* converted to one. An error message will be left in the
* interpreter's result if interp is not NULL.
*
* Effect
*
* If 'listPtr' is not already of type 'tclListType', it is converted.
* The 'refCount' of 'objPtr' is incremented as it is added to 'listPtr'.
* Appending the new element may cause the the array of element pointers
* in 'listObj' to grow. Any preexisting string representation of
* 'listPtr' is invalidated.
*
*----------------------------------------------------------------------
*/
@@ -654,23 +628,27 @@ Tcl_ListObjAppendElement(
*
* Tcl_ListObjIndex --
*
* This function returns a pointer to the index'th object from the list
* referenced by listPtr. The first element has index 0. If index is
* negative or greater than or equal to the number of elements in the
* list, a NULL is returned. If listPtr is not a list object, an attempt
* will be made to convert it to a list.
* Retrieve a pointer to the element of 'listPtr' at 'index'. The index
* of the first element is 0.
*
* Results:
* The return value is normally TCL_OK; in this case objPtrPtr is set to
* the Tcl_Obj pointer for the index'th list element or NULL if index is
* out of range. This object should be treated as readonly and its ref
* count is _not_ incremented; the caller must do that if it holds on to
* the reference. If listPtr does not refer to a list and can't be
* converted to one, TCL_ERROR is returned and an error message is left
* in the interpreter's result if interp is not NULL.
* Value
*
* Side effects:
* listPtr will be converted, if necessary, to a list object.
* TCL_OK
*
* A pointer to the element at 'index' is stored in 'objPtrPtr'. If
* 'index' is out of range, NULL is stored in 'objPtrPtr'. This
* object should be treated as readonly and its 'refCount' is _not_
* incremented. The caller must do that if it holds on to the
* reference.
*
* TCL_ERROR
*
* 'listPtr' is not a valid list. An an error message is left in the
* interpreter's result if 'interp' is not NULL.
*
* Effect
*
* If 'listPtr' is not already of type 'tclListType', it is converted.
*
*----------------------------------------------------------------------
*/
@@ -712,19 +690,20 @@ Tcl_ListObjIndex(
*
* Tcl_ListObjLength --
*
* This function returns the number of elements in a list object. If the
* object is not already a list object, an attempt will be made to
* convert it to one.
* Retrieve the number of elements in a list.
*
* Results:
* The return value is normally TCL_OK; in this case *intPtr will be set
* to the integer count of list elements. If listPtr does not refer to a
* list object and the object can not be converted to one, TCL_ERROR is
* returned and an error message will be left in the interpreter's result
* if interp is not NULL.
* Value
*
* Side effects:
* The possible conversion of the argument object to a list object.
* TCL_OK
*
* A count of list elements is stored at the address provided by
* 'intPtr'. If 'listPtr' is not already of type 'tclListPtr', it is
* converted.
*
* TCL_ERROR
*
* 'listPtr' is not a valid list. An error message will be left in
* the interpreter's result if 'interp' is not NULL.
*
*----------------------------------------------------------------------
*/
@@ -760,35 +739,36 @@ Tcl_ListObjLength(
*
* Tcl_ListObjReplace --
*
* This function replaces zero or more elements of the list referenced by
* listPtr with the objects from an (objc,objv) array. The objc elements
* of the array referenced by objv replace the count elements in listPtr
* starting at first.
* Replace values in a list.
*
* If the argument first is zero or negative, it refers to the first
* element. If first is greater than or equal to the number of elements
* in the list, then no elements are deleted; the new elements are
* appended to the list. Count gives the number of elements to replace.
* If count is zero or negative then no elements are deleted; the new
* elements are simply inserted before first.
* If 'first' is zero or negative, it refers to the first element. If
* 'first' outside the range of elements in the list, no elements are
* deleted.
*
* The argument objv refers to an array of objc pointers to the new
* elements to be added to listPtr in place of those that were deleted.
* If objv is NULL, no new elements are added. If listPtr is not a list
* object, an attempt will be made to convert it to one.
* If 'count' is zero or negative no elements are deleted, and any new
* elements are inserted at the beginning of the list.
*
* Results:
* The return value is normally TCL_OK. If listPtr does not refer to a
* list object and can not be converted to one, TCL_ERROR is returned and
* an error message will be left in the interpreter's result if interp is
* not NULL.
* Value
*
* Side effects:
* The ref counts of the objc elements in objv are incremented since the
* resulting list now refers to them. Similarly, the ref counts for
* replaced objects are decremented. listPtr is converted, if necessary,
* to a list object. listPtr's old string representation, if any, is
* freed.
* TCL_OK
*
* The first 'objc' values of 'objv' replaced 'count' elements in 'listPtr'
* starting at 'first'. If 'objc' 0, no new elements are added.
*
* TCL_ERROR
*
* 'listPtr' is not a valid list. An error message is left in the
* interpreter's result if 'interp' is not NULL.
*
* Effect
*
* If 'listPtr' is not of type 'tclListType', it is converted if possible.
*
* The 'refCount' of each element appended to the list is incremented.
* Similarly, the 'refCount' for each replaced element is decremented.
*
* If 'listPtr' is modified, any previous string representation is
* invalidated.
*
*----------------------------------------------------------------------
*/
@@ -1011,22 +991,19 @@ Tcl_ListObjReplace(
*
* TclLindexList --
*
* This procedure handles the 'lindex' command when objc==3.
* Implements the 'lindex' command when objc==3.
*
* Results:
* Returns a pointer to the object extracted, or NULL if an error
* occurred. The returned object already includes one reference count for
* the pointer returned.
* Implemented entirely as a wrapper around 'TclLindexFlat'. Reconfigures
* the argument format into required form while taking care to manage
* shimmering so as to tend to keep the most useful intreps
* and/or avoid the most expensive conversions.
*
* Side effects:
* None.
* Value
*
* Notes:
* This procedure is implemented entirely as a wrapper around
* TclLindexFlat. All it does is reconfigure the argument format into the
* form required by TclLindexFlat, while taking care to manage shimmering
* in such a way that we tend to keep the most useful intreps and/or
* avoid the most expensive conversions.
* A pointer to the specified element, with its 'refCount' incremented, or
* NULL if an error occurred.
*
* Notes
*
*----------------------------------------------------------------------
*/
@@ -1089,25 +1066,20 @@ TclLindexList(
/*
*----------------------------------------------------------------------
*
* TclLindexFlat --
* TclLindexFlat --
*
* This procedure is the core of the 'lindex' command, with all index
* arguments presented as a flat list.
* The core of the 'lindex' command, with all index
* arguments presented as a flat list.
*
* Results:
* Returns a pointer to the object extracted, or NULL if an error
* occurred. The returned object already includes one reference count for
* the pointer returned.
* Value
*
* Side effects:
* None.
* A pointer to the object extracted, with its 'refCount' incremented, or
* NULL if an error occurred. Thus, the calling code will usually do
* something like:
*
* Tcl_SetObjResult(interp, result);
* Tcl_DecrRefCount(result);
*
* Notes:
* The reference count of the returned object includes one reference
* corresponding to the pointer returned. Thus, the calling code will
* usually do something like:
* Tcl_SetObjResult(interp, result);
* Tcl_DecrRefCount(result);
*
*----------------------------------------------------------------------
*/
@@ -1183,23 +1155,16 @@ TclLindexFlat(
*
* TclLsetList --
*
* Core of the 'lset' command when objc == 4. Objv[2] may be either a
* The core of [lset] when objc == 4. Objv[2] may be either a
* scalar index or a list of indices.
*
* Results:
* Returns the new value of the list variable, or NULL if there was an
* error. The returned object includes one reference count for the
* pointer returned.
* Implemented entirely as a wrapper around 'TclLindexFlat', as described
* for 'TclLindexList'.
*
* Side effects:
* None.
* Value
*
* Notes:
* This procedure is implemented entirely as a wrapper around
* TclLsetFlat. All it does is reconfigure the argument format into the
* form required by TclLsetFlat, while taking care to manage shimmering
* in such a way that we tend to keep the most useful intreps and/or
* avoid the most expensive conversions.
* The new list, with the 'refCount' of 'valuPtr' incremented, or NULL if
* there was an error.
*
*----------------------------------------------------------------------
*/
@@ -1261,36 +1226,39 @@ TclLsetList(
*
* Core engine of the 'lset' command.
*
* Results:
* Returns the new value of the list variable, or NULL if an error
* occurred. The returned object includes one reference count for
* the pointer returned.
* Value
*
* Side effects:
* On entry, the reference count of the variable value does not reflect
* any references held on the stack. The first action of this function is
* to determine whether the object is shared, and to duplicate it if it
* is. The reference count of the duplicate is incremented. At this
* point, the reference count will be 1 for either case, so that the
* object will appear to be unshared.
* The resulting list
*
* If an error occurs, and the object has been duplicated, the reference
* count on the duplicate is decremented so that it is now 0: this
* dismisses any memory that was allocated by this function.
* The 'refCount' of 'valuePtr' is incremented. If 'listPtr' was not
* duplicated, its 'refCount' is incremented. The reference count of
* an unduplicated object is therefore 2 (one for the returned pointer
* and one for the variable that holds it). The reference count of a
* duplicate object is 1, reflecting that result is the only active
* reference. The caller is expected to store the result in the
* variable and decrement its reference count. (INST_STORE_* does
* exactly this.)
*
* NULL
*
* An error occurred. If 'listPtr' was duplicated, the reference
* count on the duplicate is decremented so that it is 0, causing any
* memory allocated by this function to be freed.
*
* If no error occurs, the reference count of the original object is
* incremented if the object has not been duplicated, and nothing is done
* to a reference count of the duplicate. Now the reference count of an
* unduplicated object is 2 (the returned pointer, plus the one stored in
* the variable). The reference count of a duplicate object is 1,
* reflecting that the returned pointer is the only active reference. The
* caller is expected to store the returned value back in the variable
* and decrement its reference count. (INST_STORE_* does exactly this.)
*
* Surgery is performed on the unshared list value to produce the result.
* TclLsetFlat maintains a linked list of Tcl_Obj's whose string
* Effect
*
* On entry, the reference count of 'listPtr' does not reflect any
* references held on the stack. The first action of this function is to
* determine whether 'listPtr' is shared and to create a duplicate
* unshared copy if it is. The reference count of the duplicate is
* incremented. At this point, the reference count is 1 in either case so
* that the object is considered unshared.
*
* The unshared list is altered directly to produce the result.
* 'TclLsetFlat' maintains a linked list of 'Tcl_Obj' values whose string
* representations must be spoilt by threading via 'ptr2' of the
* two-pointer internal representation. On entry to TclLsetFlat, the
* two-pointer internal representation. On entry to 'TclLsetFlat', the
* values of 'ptr2' are immaterial; on exit, the 'ptr2' field of any
* Tcl_Obj that has been modified is set to NULL.
*
@@ -1476,26 +1444,38 @@ TclLsetFlat(
*
* TclListObjSetElement --
*
* Set a single element of a list to a specified value
*
* Results:
* The return value is normally TCL_OK. If listPtr does not refer to a
* list object and cannot be converted to one, TCL_ERROR is returned and
* an error message will be left in the interpreter result if interp is
* not NULL. Similarly, if index designates an element outside the range
* [0..listLength-1], where listLength is the count of elements in the
* list object designated by listPtr, TCL_ERROR is returned and an error
* message is left in the interpreter result.
*
* Side effects:
* Tcl_Panic if listPtr designates a shared object. Otherwise, attempts
* to convert it to a list with a non-shared internal rep. Decrements the
* ref count of the object at the specified index within the list,
* replaces with the object designated by valuePtr, and increments the
* ref count of the replacement object.
* Set a single element of a list to a specified value.
*
* It is the caller's responsibility to invalidate the string
* representation of the object.
* representation of the 'listPtr'.
*
* Value
*
* TCL_OK
*
* Success.
*
* TCL_ERROR
*
* 'listPtr' does not refer to a list object and cannot be converted
* to one. An error message will be left in the interpreter result if
* interp is not NULL.
*
* TCL_ERROR
*
* An index designates an element outside the range [0..listLength-1],
* where 'listLength' is the count of elements in the list object
* designated by 'listPtr'. An error message is left in the
* interpreter result.
*
* Effect
*
* If 'listPtr' designates a shared object, 'Tcl_Panic' is called. If
* 'listPtr' is not already of type 'tclListType', it is converted and the
* internal representation is unshared. The 'refCount' of the element at
* 'index' is decremented and replaced in the list with the 'valuePtr',
* whose 'refCount' in turn is incremented.
*
*
*----------------------------------------------------------------------
*/
@@ -1605,16 +1585,14 @@ TclListObjSetElement(
*
* FreeListInternalRep --
*
* Deallocate the storage associated with a list object's internal
* representation.
* Deallocate the storage associated with the internal representation of a
* a list object.
*
* Results:
* None.
* Effect
*
* Side effects:
* Frees listPtr's List* internal representation and sets listPtr's
* internalRep.twoPtrValue.ptr1 to NULL. Decrements the ref counts of all
* element objects, which may free them.
* The storage for the internal 'List' pointer of 'listPtr' is freed, the
* 'internalRep.twoPtrValue.ptr1' of 'listPtr' is set to NULL, and the 'refCount'
* of each element of the list is decremented.
*
*----------------------------------------------------------------------
*/
@@ -1643,14 +1621,12 @@ FreeListInternalRep(
*
* DupListInternalRep --
*
* Initialize the internal representation of a list Tcl_Obj to share the
* Initialize the internal representation of a list 'Tcl_Obj' to share the
* internal representation of an existing list object.
*
* Results:
* None.
* Effect
*
* Side effects:
* The reference count of the List internal rep is incremented.
* The 'refCount' of the List internal rep is incremented.
*
*----------------------------------------------------------------------
*/
@@ -1670,16 +1646,20 @@ DupListInternalRep(
*
* SetListFromAny --
*
* Attempt to generate a list internal form for the Tcl object "objPtr".
* Convert any object to a list.
*
* Results:
* The return value is TCL_OK or TCL_ERROR. If an error occurs during
* conversion, an error message is left in the interpreter's result
* unless "interp" is NULL.
* Value
*
* TCL_OK
*
* Success. The internal representation of 'objPtr' is set, and the type
* of 'objPtr' is 'tclListType'.
*
* TCL_ERROR
*
* An error occured during conversion. An error message is left in the
* interpreter's result if 'interp' is not NULL.
*
* Side effects:
* If no error occurs, a list is stored as "objPtr"s internal
* representation.
*
*----------------------------------------------------------------------
*/
@@ -1800,18 +1780,16 @@ SetListFromAny(
*
* UpdateStringOfList --
*
* Update the string representation for a list object. Note: This
* function does not invalidate an existing old string rep so storage
* will be lost if this has not already been done.
* Update the string representation for a list object.
*
* Results:
* None.
* Any previously-exising string representation is not invalidated, so
* storage is lost if this has not been taken care of.
*
* Side effects:
* The object's string is set to a valid string that results from the
* list-to-string conversion. This string will be empty if the list has
* no elements. The list internal representation should not be NULL and
* we assume it is not NULL.
* Effect
*
* The string representation of 'listPtr' is set to the resulting string.
* This string will be empty if the list has no elements. It is assumed
* that the list internal representation is not NULL.
*
*----------------------------------------------------------------------
*/
+17 -14
View File
@@ -2444,23 +2444,26 @@ Tcl_SetIntObj(
*
* Tcl_GetIntFromObj --
*
* Attempt to return an int from the Tcl object "objPtr". If the object
* is not already an int, an attempt will be made to convert it to one.
* Retrieve the integer value of 'objPtr'.
*
* Integer and long integer objects share the same "integer" type
* implementation. We store all integers as longs and Tcl_GetIntFromObj
* checks whether the current value of the long can be represented by an
* int.
* Value
*
* Results:
* The return value is a standard Tcl object result. If an error occurs
* during conversion or if the long integer held by the object can not be
* represented by an int, an error message is left in the interpreter's
* result unless "interp" is NULL.
* TCL_OK
*
* Side effects:
* If the object is not already an int, the conversion will free any old
* internal representation.
* Success.
*
* TCL_ERROR
*
* An error occurred during conversion or the integral value can not
* be represented as an integer (it might be too large). An error
* message is left in the interpreter's result if 'interp' is not
* NULL.
*
* Effect
*
* 'objPtr' is converted to an integer if necessary if it is not one
* already. The conversion frees any previously-existing internal
* representation.
*
*----------------------------------------------------------------------
*/
+53 -5
View File
@@ -628,7 +628,7 @@ TclIsSpaceProc(
/*
*----------------------------------------------------------------------
*
* TclIsBareword--
* TclIsBareword --
*
* Report whether byte is one that can be part of a "bareword".
* This concept is named in expression parsing, where it determines
@@ -666,6 +666,52 @@ TclIsBareword(
return 1;
}
/*
*----------------------------------------------------------------------
*
* TclFindBarewordEndUni --
*
* Scan src to the end of a "bareword".
* The set of chars that are accepted is alnum (UTF-8 compatible)
* and underscore ('_').
*
* Results:
* Returns length of word (equal offset in bytes to position after the
* end of word, 0 if not found).
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
size_t
TclFindUtfBarewordEnd(
const char *src,
size_t numBytes)
{
size_t p = 0, l;
Tcl_UniChar ch;
while (p < numBytes) {
/* 0-9,A-Z,a-Z,_ */
if (TclIsBareword(src[p])) {
p++;
continue;
}
if (!(src[p] & 0x80) || numBytes <= 1) { /* single byte or end reached */
break;
}
/* test unicode alnum (consider NTS-char) */
l = TclUtfToUniChar(src+p, &ch);
if (!Tcl_UniCharIsAlnum(ch) || p+l > numBytes) {
break;
}
p += l;
}
return p;
}
/*
*----------------------------------------------------------------------
*
@@ -1470,10 +1516,12 @@ Tcl_ParseVarName(
tokenPtr->numComponents = 0;
while (numBytes) {
if (TclIsBareword(*src)) {
src += 1;
numBytes -= 1;
continue;
size_t wordlen = TclFindUtfBarewordEnd(src, numBytes);
src += wordlen;
numBytes -= wordlen;
if (!numBytes) {
break;
}
if ((src[0] == ':') && (numBytes != 1) && (src[1] == ':')) {
src += 2;
+55 -72
View File
@@ -384,13 +384,11 @@ TclCreateProc(
Proc **procPtrPtr) /* Returns: pointer to proc data. */
{
Interp *iPtr = (Interp *) interp;
CONST char **argArray = NULL;
register Proc *procPtr;
int i, length, result, numArgs;
CONST char *args, *bytes, *p;
int i, result, numArgs;
register CompiledLocal *localPtr = NULL;
Tcl_Obj *defPtr;
Tcl_Obj **argArray;
int precompiled = 0;
if (bodyPtr->typePtr == &tclProcBodyType) {
@@ -427,7 +425,9 @@ TclCreateProc(
*/
if (Tcl_IsShared(bodyPtr)) {
Tcl_Obj* sharedBodyPtr = bodyPtr;
const char *bytes;
int length;
Tcl_Obj *sharedBodyPtr = bodyPtr;
bytes = TclGetStringFromObj(bodyPtr, &length);
bodyPtr = Tcl_NewStringObj(bytes, length);
@@ -438,7 +438,7 @@ TclCreateProc(
* not lost and applies to the new body as well.
*/
TclContinuationsCopy (bodyPtr, sharedBodyPtr);
TclContinuationsCopy(bodyPtr, sharedBodyPtr);
}
/*
@@ -464,12 +464,9 @@ TclCreateProc(
* argument specifier. If the body is precompiled, processing is limited
* to checking that the parsed argument is consistent with the one stored
* in the Proc.
*
* THIS FAILS IF THE ARG LIST OBJECT'S STRING REP CONTAINS NULS.
*/
args = TclGetStringFromObj(argsPtr, &length);
result = Tcl_SplitList(interp, args, &numArgs, &argArray);
result = Tcl_ListObjGetElements(interp , argsPtr ,&numArgs ,&argArray);
if (result != TCL_OK) {
goto procError;
}
@@ -489,65 +486,58 @@ TclCreateProc(
}
for (i = 0; i < numArgs; i++) {
int fieldCount, nameLength, valueLength;
CONST char **fieldValues;
const char *argname, *argnamei, *argnamelast;
int fieldCount, nameLength;
Tcl_Obj **fieldValues;
/*
* Now divide the specifier up into name and default.
*/
result = Tcl_SplitList(interp, argArray[i], &fieldCount,
result = Tcl_ListObjGetElements(interp, argArray[i], &fieldCount,
&fieldValues);
if (result != TCL_OK) {
goto procError;
}
if (fieldCount > 2) {
ckfree((char *) fieldValues);
Tcl_AppendResult(interp,
"too many fields in argument specifier \"",
argArray[i], "\"", NULL);
Tcl_Obj *errorObj = Tcl_NewStringObj(
"too many fields in argument specifier \"", -1);
Tcl_AppendObjToObj(errorObj, argArray[i]);
Tcl_AppendToObj(errorObj, "\"", -1);
Tcl_SetObjResult(interp, errorObj);
goto procError;
}
if ((fieldCount == 0) || (*fieldValues[0] == 0)) {
ckfree((char *) fieldValues);
Tcl_AppendResult(interp, "argument with no name", NULL);
if ((fieldCount == 0) || (fieldValues[0]->length == 0)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"argument with no name", -1));
goto procError;
}
nameLength = strlen(fieldValues[0]);
if (fieldCount == 2) {
valueLength = strlen(fieldValues[1]);
} else {
valueLength = 0;
}
argname = Tcl_GetStringFromObj(fieldValues[0], &nameLength);
/*
* Check that the formal parameter name is a scalar.
*/
p = fieldValues[0];
while (*p != '\0') {
if (*p == '(') {
CONST char *q = p;
do {
q++;
} while (*q != '\0');
q--;
if (*q == ')') { /* We have an array element. */
Tcl_AppendResult(interp, "formal parameter \"",
fieldValues[0],
"\" is an array element", NULL);
ckfree((char *) fieldValues);
argnamei = argname;
argnamelast = Tcl_UtfPrev(argname + nameLength, argname);
while (argnamei < argnamelast) {
if (*argnamei == '(') {
if (*argnamelast == ')') { /* We have an array element. */
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"formal parameter \"%s\" is an array element",
Tcl_GetString(fieldValues[0])));
goto procError;
}
} else if ((*p == ':') && (*(p+1) == ':')) {
Tcl_AppendResult(interp, "formal parameter \"",
fieldValues[0],
"\" is not a simple name", NULL);
ckfree((char *) fieldValues);
} else if (*argnamei == ':' && *(argnamei+1) == ':') {
Tcl_Obj *errorObj = Tcl_NewStringObj(
"formal parameter \"", -1);
Tcl_AppendObjToObj(errorObj, fieldValues[0]);
Tcl_AppendToObj(errorObj, "\" is not a simple name", -1);
Tcl_SetObjResult(interp, errorObj);
goto procError;
}
p++;
argnamei = Tcl_UtfNext(argnamei);
}
if (precompiled) {
@@ -563,7 +553,7 @@ TclCreateProc(
*/
if ((localPtr->nameLength != nameLength)
|| (strcmp(localPtr->name, fieldValues[0]))
|| (memcmp(localPtr->name, argname, nameLength) != 0)
|| (localPtr->frameIndex != i)
|| !(localPtr->flags & VAR_ARGUMENT)
|| (localPtr->defValuePtr == NULL && fieldCount == 2)
@@ -571,7 +561,6 @@ TclCreateProc(
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"procedure \"%s\": formal parameter %d is "
"inconsistent with precompiled body", procName, i));
ckfree((char *) fieldValues);
goto procError;
}
@@ -580,17 +569,21 @@ TclCreateProc(
*/
if (localPtr->defValuePtr != NULL) {
int tmpLength;
char *tmpPtr = TclGetStringFromObj(localPtr->defValuePtr,
int tmpLength, valueLength;
const char *tmpPtr = TclGetStringFromObj(localPtr->defValuePtr,
&tmpLength);
const char *value = TclGetStringFromObj(fieldValues[1],
&valueLength);
if ((valueLength != tmpLength) ||
strncmp(fieldValues[1], tmpPtr, (size_t) tmpLength)) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"procedure \"%s\": formal parameter \"%s\" has "
"default value inconsistent with precompiled body",
procName, fieldValues[0]));
ckfree((char *) fieldValues);
if ((valueLength != tmpLength)
|| memcmp(value, tmpPtr, tmpLength) != 0
) {
Tcl_Obj *errorObj = Tcl_ObjPrintf(
"procedure \"%s\": formal parameter \"", procName);
Tcl_AppendObjToObj(errorObj, fieldValues[0]);
Tcl_AppendToObj(errorObj, "\" has "
"default value inconsistent with precompiled body", -1);
Tcl_SetObjResult(interp, errorObj);
goto procError;
}
}
@@ -608,9 +601,7 @@ TclCreateProc(
* local variables for the argument.
*/
localPtr = (CompiledLocal *) ckalloc((unsigned)
(sizeof(CompiledLocal) - sizeof(localPtr->name)
+ nameLength + 1));
localPtr = (CompiledLocal *)ckalloc(TclOffset(CompiledLocal, name) + fieldValues[0]->length +1);
if (procPtr->firstLocalPtr == NULL) {
procPtr->firstLocalPtr = procPtr->lastLocalPtr = localPtr;
} else {
@@ -624,26 +615,22 @@ TclCreateProc(
localPtr->resolveInfo = NULL;
if (fieldCount == 2) {
localPtr->defValuePtr =
Tcl_NewStringObj(fieldValues[1], valueLength);
localPtr->defValuePtr = fieldValues[1];
Tcl_IncrRefCount(localPtr->defValuePtr);
} else {
localPtr->defValuePtr = NULL;
}
memcpy(localPtr->name, fieldValues[0], nameLength + 1);
memcpy(localPtr->name, argname, fieldValues[0]->length + 1);
if ((i == numArgs - 1)
&& (localPtr->nameLength == 4)
&& (localPtr->name[0] == 'a')
&& (strcmp(localPtr->name, "args") == 0)) {
&& (memcmp(localPtr->name, "args", 4) == 0)) {
localPtr->flags |= VAR_IS_ARGS;
}
}
ckfree((char *) fieldValues);
}
*procPtrPtr = procPtr;
ckfree((char *) argArray);
return TCL_OK;
procError:
@@ -655,18 +642,14 @@ TclCreateProc(
localPtr = procPtr->firstLocalPtr;
procPtr->firstLocalPtr = localPtr->nextPtr;
defPtr = localPtr->defValuePtr;
if (defPtr != NULL) {
Tcl_DecrRefCount(defPtr);
if (localPtr->defValuePtr != NULL) {
Tcl_DecrRefCount(localPtr->defValuePtr);
}
ckfree((char *) localPtr);
}
ckfree((char *) procPtr);
}
if (argArray != NULL) {
ckfree((char *) argArray);
}
return TCL_ERROR;
}
+20 -15
View File
@@ -3377,22 +3377,27 @@ TclFormatInt(buffer, n)
*
* TclGetIntForIndex --
*
* This function returns an integer corresponding to the list index held
* in a Tcl object. The Tcl object's value is expected to be in the
* format integer([+-]integer)? or the format end([+-]integer)?.
*
* Results:
* The return value is normally TCL_OK, which means that the index was
* successfully stored into the location referenced by "indexPtr". If the
* Tcl object referenced by "objPtr" has the value "end", the value
* stored is "endValue". If "objPtr"s values is not of one of the
* expected formats, TCL_ERROR is returned and, if "interp" is non-NULL,
* an error message is left in the interpreter's result object.
*
* Side effects:
* The object referenced by "objPtr" might be converted to an integer,
* wide integer, or end-based-index object.
* Provides an integer corresponding to the list index held in a Tcl
* object. The string value 'objPtr' is expected have the format
* integer([+-]integer)? or end([+-]integer)?.
*
* Value
* TCL_OK
*
* The index is stored at the address given by by 'indexPtr'. If
* 'objPtr' has the value "end", the value stored is 'endValue'.
*
* TCL_ERROR
*
* The value of 'objPtr' does not have one of the expected formats. If
* 'interp' is non-NULL, an error message is left in the interpreter's
* result object.
*
* Effect
*
* The object referenced by 'objPtr' is converted, as needed, to an
* integer, wide integer, or end-based-index object.
*
*----------------------------------------------------------------------
*/
+1 -1
View File
@@ -658,7 +658,7 @@ test parse-12.25 {Tcl_ParseVarName procedure, nested array reference} testparser
} {- {$x(a$y(b$z))} 1 word {$x(a$y(b$z))} 8 variable {$x(a$y(b$z))} 7 text x 0 text a 0 variable {$y(b$z)} 4 text y 0 text b 0 variable {$z} 1 text z 0 {}}
test parse-12.26 {Tcl_ParseVarName [d2ffcca163] non-ascii} testparser {
testparser "$\u0433" -1
} "- {$\u0433} 1 word {$\u0433} 2 text {$} 0 text \u0433 0 {}"
} "- {$\u0433} 1 word {$\u0433} 2 variable {$\u0433} 1 text \u0433 0 {}"
test parse-13.1 {Tcl_ParseVar procedure} testparsevar {
set abc 24
+42 -2
View File
@@ -47,13 +47,15 @@ catch {unset i}
catch {unset a}
catch {unset arr}
test var-1.1 {TclLookupVar, Array handling} {
test var-1.1 {TclLookupVar, Array handling} -body {
catch {unset a}
set x "incr" ;# force no compilation and runtime call to Tcl_IncrCmd
set i 10
set arr(foo) 37
list [$x i] $i [$x arr(foo)] $arr(foo)
} {11 11 38 38}
} -cleanup {
unset -nocomplain arr
} -result {11 11 38 38}
test var-1.2 {TclLookupVar, TCL_GLOBAL_ONLY implies global namespace var} {
set x "global value"
namespace eval test_ns_var {
@@ -192,6 +194,44 @@ test var-1.18 {TclLookupVar, resurrect array element via upvar to deleted array:
test var-1.19 {TclLookupVar, right error message when parsing variable name} {
list [catch {[format set] thisvar(doesntexist)} msg] $msg
} {1 {can't read "thisvar(doesntexist)": no such variable}}
test var-1.20 {TclLookupVar, regression on utf-8 variable names} -setup {
proc p [list \u20ac \xe4] {info vars}
} -body {
# test variable with non-ascii name is available (euro and a-uml chars here):
list \
[p 1 2] \
[apply [list [list \u20ac \xe4] {info vars}] 1 2] \
[apply [list [list [list \u20ac \u20ac] [list \xe4 \xe4]] {info vars}]] \
} -cleanup {
rename p {}
} -result [lrepeat 3 [list \u20ac \xe4]]
test var-1.21 {TclLookupVar, regression on utf-8 variable names} -setup {
proc p [list [list \u20ac v\u20ac] [list \xe4 v\xe4]] {list [set \u20ac] [set \xe4]}
} -body {
# test variable with non-ascii name (and default) is resolvable (euro and a-uml chars here):
list \
[p] \
[apply [list [list \u20ac \xe4] {list [set \u20ac] [set \xe4]}] v\u20ac v\xe4] \
[apply [list [list [list \u20ac v\u20ac] [list \xe4 v\xe4]] {list [set \u20ac] [set \xe4]}]] \
} -cleanup {
rename p {}
} -result [lrepeat 3 [list v\u20ac v\xe4]]
test var-1.30 {TclLookupVar, direct substitution of utf-8 var name} -body {
namespace eval test_ns_var {
set vn \u0422\u0438\u043a\u043b\u044c
set $vn Tcl
set arr($vn) Tcl-In-Arr
set ${vn}_${vn}($vn) Tcl-In-Tcl
list [list [set $vn] [set arr($vn)] [set ${vn}_${vn}($vn)]] \
[eval "list \${$vn} \${arr($vn)} \${${vn}_${vn}($vn)}"] \
[eval "list \$$vn \$arr($vn) \$${vn}_${vn}($vn)"] \
[eval "list \$[namespace current]::$vn \
\$[namespace current]::arr($vn) \$[namespace current]::${vn}_${vn}($vn)"]
}
} -cleanup {
catch {namespace delete test_ns_var}
} -result [lrepeat 4 {Tcl Tcl-In-Arr Tcl-In-Tcl}]
test var-2.1 {Tcl_LappendObjCmd, create var if new} {
catch {unset x}