tclquadcode

Check-in [55314ea72f]
Login

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

Overview
Comment:[7907c1c801] Make [dict update] work with NEXIST and ARRAY.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:55314ea72f08a5c453a0a348733234f7ee8da786feff0ea84bf51113eb278435
User & Date: dkf 2017-12-19 23:57:26
References
2017-12-27
18:33 New ticket [4f8bd5f5b2] new failures: dictest3 and dictest7. artifact: 49daafb713 user: kbk
Context
2017-12-25
17:56
Corrections so that errors are reported more usefully. Don't const-fold anything that necessarily interacts with an interp. check-in: a86e497781 user: dkf tags: trunk
2017-12-20
09:25
Resolution context passed to invoke. Still need to stop quadcode engine from pre-resolving (at least in error cases). check-in: 4f606de75c user: dkf tags: fix-call-resolution
2017-12-19
23:57
[7907c1c801] Make [dict update] work with NEXIST and ARRAY. check-in: 55314ea72f user: dkf tags: trunk
23:55
Make [dict update] handle ARRAYs Closed-Leaf check-in: 691e663c5f user: dkf tags: dkf-dict-update
21:28
Rearranging the 'invoke' code to conceptually separate resolution from the command invocation core. check-in: 8a771984d2 user: dkf tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to codegen/build.tcl.

2144
2145
2146
2147
2148
2149
2150






















2151
2152
2153
2154
2155
2156
2157
....
2321
2322
2323
2324
2325
2326
2327



































































2328
2329
2330
2331
2332
2333
2334
....
2937
2938
2939
2940
2941
2942
2943
















2944
2945
2946
2947
2948
2949
2950
....
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383


















4384
4385
4386
4387
4388
4389
4390
....
6051
6052
6053
6054
6055
6056
6057


















6058
6059
6060
6061
6062
6063
6064
    #
    # Results:
    #	The retrieved value as an LLVM value reference, or a FAIL.

    method dictGet(STRING,STRING) {dict key ec {name ""}} {
	my call ${tcl.dict.get1} [list $dict $key $ec] $name
    }























    # Builder:dictIncr(STRING,STRING,INT) --
    #
    #	Increment the value for a key in a dictionary. NOTE: this operation
    #	can fail (e.g., because it can be given an invalid dictionary) so it
    #	produces a STRING FAIL. Quadcode implementation ('dictIncr').
    #
................................................................................
    #
    # Results:
    #	The new dictionary value.

    method dictSet(STRING,STRING,STRING) {dict key value ec {name ""}} {
	my call ${tcl.dict.set1} [list $dict $key $value $ec] $name
    }




































































    # Builder:dictSize(STRING) --
    #
    #	Get the size of a dictionary, i.e., the number of key-value pairs.
    #
    # Parameters:
    #	value -	The STRING LLVM value reference to a dict to get the size of.
................................................................................
    # Results:
    #	None.

    method dropReference(NEXIST\040STRING) {value} {
	my Call tcl.dropNExistReference $value
	return
    }

















    # Builder:dropReference(NEXIST EMPTY) --
    #
    #	Generate code to decrement the reference count of a value and delete
    #	the value if it has ceased to be used.
    #
    # Parameters:
................................................................................
    #	arguments -
    #		The arguments as an LLVM vector value reference. Note that
    #		this includes the function name as the first argument.
    #	havecf -
    #		Tcl boolean indicating if we have a valid callframe.
    #	cf -	The reference to the current callframe if 'havecf' is true.
    #	ec -	Location to write the Tcl return code into, as an LLVM int*
    #		reference. (TODO: Not yet used because we give the wrong type
    #		to command signatures.)
    #	resultName (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An LLVM value reference.

    method invoke {arguments havecf cf ec {resultName ""}} {
	my ExtractVector $arguments
	if {!$havecf} {
	    set cf {}
	}
	my call ${tcl.invoke.command} [list $len $ary $cf $ec] $resultName
    }



















    method invokeExpanded {arguments flags ec {resultName ""}} {
	my ExtractVector $arguments
	my call ${tcl.invoke.expanded} [list $len $ary $flags $ec] $resultName
    }

    # Builder:isBoolean(INT BOOLEAN) --
................................................................................
	set overflow [expr {[string length $command] > $limit}]
	set length [Const [expr {$overflow ? $limit : [string length $command]}]]
	set cmd [my constString $command]
	set ellipsis [my constString [if {$overflow} {string cat "..."}]]
	my Call tcl.setErrorLine $test $errorCode $line $length $cmd $ellipsis
	return
    }



















    method storeInStruct {structPointer fieldOffset value} {
	set field [my gep $structPointer 0 $fieldOffset]
	set fieldName [regsub {.*\.} $fieldOffset ""]
	SetValueName $field [GetValueName $structPointer].$fieldName
	my store $value $field
    }







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







 







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







 







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







 







|
<













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







 







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







2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
....
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
....
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
....
4467
4468
4469
4470
4471
4472
4473
4474

4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
....
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
    #
    # Results:
    #	The retrieved value as an LLVM value reference, or a FAIL.

    method dictGet(STRING,STRING) {dict key ec {name ""}} {
	my call ${tcl.dict.get1} [list $dict $key $ec] $name
    }

    # Builder:dictGetOrNexist(STRING,STRING) --
    #
    #	Retrieve a value from a dictionary, or NEXIST if the key doesn't map
    #	to a value in the dict. This version uses a single simple key. NOTE:
    #	this operation can fail (e.g., because it can be given an invalid
    #	dictionary) so it produces a FAIL NEXIST STRING. Quadcode
    #	implementation ('dictGetOrNexist').
    #
    # Parameters:
    #	dict -	The dictionary as an LLVM value reference.
    #	key -	The key as an LLVM value reference.
    #	ec -	Where to write the error code if an error happens.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	The retrieved value as an LLVM value reference, or a NEXIST or FAIL.

    method dictGetOrNexist(STRING,STRING) {dict key ec {name ""}} {
	my call ${tcl.dict.get1.empty} [list $dict $key $ec] $name
    }

    # Builder:dictIncr(STRING,STRING,INT) --
    #
    #	Increment the value for a key in a dictionary. NOTE: this operation
    #	can fail (e.g., because it can be given an invalid dictionary) so it
    #	produces a STRING FAIL. Quadcode implementation ('dictIncr').
    #
................................................................................
    #
    # Results:
    #	The new dictionary value.

    method dictSet(STRING,STRING,STRING) {dict key value ec {name ""}} {
	my call ${tcl.dict.set1} [list $dict $key $value $ec] $name
    }

    # Builder:dictSetOrUnset(STRING,STRING,NEXIST) --
    #
    #	Remove a value in a dictionary. This version uses a single simple key.
    #	NOTE: this operation can fail (e.g., because it can be given an
    #	invalid dictionary) so it produces a STRING FAIL. Quadcode
    #	implementation ('dictSetOrUnset').
    #
    # Parameters:
    #	dict -	The dictionary as an LLVM value reference.
    #	key -	The key as an LLVM value reference.
    #	value -	The NEXIST value (actually ignored).
    #	ec -	Where to write the error code if an error happens.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	The new dictionary value, or FAIL.

    method dictSetOrUnset(STRING,STRING,NEXIST) {dict key value ec {name ""}} {
	my call ${tcl.dict.set1.empty} [list $dict $key [my nothing STRING] $ec] $name
    }

    # Builder:dictSetOrUnset(STRING,STRING,NEXIST STRING) --
    #
    #	Set, create or remove a value in a dictionary. This version uses a
    #	single simple key, and the value can be NEXIST to remove the key.
    #	NOTE: this operation can fail (e.g., because it can be given an
    #	invalid dictionary) so it produces a STRING FAIL. Quadcode
    #	implementation ('dictSetOrUnset').
    #
    # Parameters:
    #	dict -	The dictionary as an LLVM value reference.
    #	key -	The key as an LLVM value reference.
    #	value -	The value as an LLVM value reference, or NEXIST.
    #	ec -	Where to write the error code if an error happens.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	The new dictionary value, or FAIL.

    method dictSetOrUnset(STRING,STRING,NEXIST\040STRING) {dict key value ec {name ""}} {
	my call ${tcl.dict.set1.empty} [list $dict $key $value $ec] $name
    }

    # Builder:dictSetOrUnset(STRING,STRING,NEXIST STRING) --
    #
    #	Set or create a value in a dictionary. This version uses a single
    #	simple key.  NOTE: this operation can fail (e.g., because it can be
    #	given an invalid dictionary) so it produces a STRING FAIL. Quadcode
    #	implementation ('dictSetOrUnset').
    #
    # Parameters:
    #	dict -	The dictionary as an LLVM value reference.
    #	key -	The key as an LLVM value reference.
    #	value -	The value as an LLVM value reference.
    #	ec -	Where to write the error code if an error happens.
    #	name (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	The new dictionary value, or FAIL.

    method dictSetOrUnset(STRING,STRING,STRING) {dict key value ec {name ""}} {
	my call ${tcl.dict.set1.empty} [list $dict $key [my just $value] $ec] $name
    }

    # Builder:dictSize(STRING) --
    #
    #	Get the size of a dictionary, i.e., the number of key-value pairs.
    #
    # Parameters:
    #	value -	The STRING LLVM value reference to a dict to get the size of.
................................................................................
    # Results:
    #	None.

    method dropReference(NEXIST\040STRING) {value} {
	my Call tcl.dropNExistReference $value
	return
    }

    # Builder:dropReference(NEXIST FAIL STRING) --
    #
    #	Generate code to decrement the reference count of a value and delete
    #	the value if it has ceased to be used.
    #
    # Parameters:
    #	value -	The NEXIST FAIL STRING LLVM value reference for the operand.
    #
    # Results:
    #	None.

    method dropReference(NEXIST\040FAIL\040STRING) {value} {
	my Call tcl.dropFailNExistReference $value
	return
    }

    # Builder:dropReference(NEXIST EMPTY) --
    #
    #	Generate code to decrement the reference count of a value and delete
    #	the value if it has ceased to be used.
    #
    # Parameters:
................................................................................
    #	arguments -
    #		The arguments as an LLVM vector value reference. Note that
    #		this includes the function name as the first argument.
    #	havecf -
    #		Tcl boolean indicating if we have a valid callframe.
    #	cf -	The reference to the current callframe if 'havecf' is true.
    #	ec -	Location to write the Tcl return code into, as an LLVM int*
    #		reference.

    #	resultName (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An LLVM value reference.

    method invoke {arguments havecf cf ec {resultName ""}} {
	my ExtractVector $arguments
	if {!$havecf} {
	    set cf {}
	}
	my call ${tcl.invoke.command} [list $len $ary $cf $ec] $resultName
    }

    # Builder:invokeExpanded --
    #
    #	Generate code to call a Tcl command while doing argument expansion.
    #	Quadcode implementation ('invokeExpanded').
    #
    # Parameters:
    #	arguments -
    #		The arguments as an LLVM vector value reference. Note that
    #		this includes the function name as the first argument.
    #	flags -	LLVM bit array indicating which arguments to expand.
    #	ec -	Location to write the Tcl return code into, as an LLVM int*
    #		reference.
    #	resultName (optional) -
    #		A name to give to the result value.
    #
    # Results:
    #	An LLVM value reference.

    method invokeExpanded {arguments flags ec {resultName ""}} {
	my ExtractVector $arguments
	my call ${tcl.invoke.expanded} [list $len $ary $flags $ec] $resultName
    }

    # Builder:isBoolean(INT BOOLEAN) --
................................................................................
	set overflow [expr {[string length $command] > $limit}]
	set length [Const [expr {$overflow ? $limit : [string length $command]}]]
	set cmd [my constString $command]
	set ellipsis [my constString [if {$overflow} {string cat "..."}]]
	my Call tcl.setErrorLine $test $errorCode $line $length $cmd $ellipsis
	return
    }

    # Builder:storeInStruct --
    #
    #	Generate code to write a value into a structure that is pointed to by
    #	the first argument.
    #
    # Parameters:
    #	structPointer -
    #		The LLVM pointer value reference to the structure to be
    #		written to.
    #	fieldOffset -
    #		The description of which field of the structure to update. See
    #		the 'gep' (or 'insert') method for a description of what forms
    #		this may take.
    #	value -	The value to write into the field. Must type-match.
    #
    # Results:
    #	None.

    method storeInStruct {structPointer fieldOffset value} {
	set field [my gep $structPointer 0 $fieldOffset]
	set fieldName [regsub {.*\.} $fieldOffset ""]
	SetValueName $field [GetValueName $structPointer].$fieldName
	my store $value $field
    }

Changes to codegen/compile.tcl.

528
529
530
531
532
533
534
535

536
537
538
539
540
541
542
....
1933
1934
1935
1936
1937
1938
1939




1940
1941
1942
1943
1944
1945
1946
		"directLappendList" - "directUnset" -
		"directArrayGet" - "directArraySet" - "directArrayAppend" -
		"directArrayLappend" - "directArrayLappendList" -
		"directArrayUnset" - "directIsArray" - "directMakeArray" -
		"regexp" - "listAppend" - "listConcat" - "listLength" -
		"listRange" - "listIn" - "listNotIn" - "dictIterStart" -
		"dictAppend" - "dictIncr" - "dictLappend" - "dictSize" -
		"div" - "expon" - "mod" - "not" - "verifyList" {

		    set srcs [lassign $l opcode tgt]
		    set name [my LocalVarName $tgt]
		    append opcode ( [my ValueTypes {*}$srcs] )
		    set srcs [lmap s $srcs {my LoadOrLiteral $s}]
		    set res [$b $opcode {*}$srcs $errorCode $name]
		    if {"FAIL" in [my ValueTypes $tgt]} {
			my SetErrorLine $errorCode [$b maybe $res]
................................................................................
    #
    # Results:
    #	The name.

    method LoadOrLiteral {desc} {
	if {[info exist variables($desc)]} {
	    return $variables($desc)




	}
	lassign $desc kind value
	if {$kind ne "literal"} {
	    return -code error "unsubstitutable argument: $desc"
	}
	set type [nameOfType [typeOfLiteral $value]]
	return [my LoadTypedLiteral $value $type]







|
>







 







>
>
>
>







528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
....
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
		"directLappendList" - "directUnset" -
		"directArrayGet" - "directArraySet" - "directArrayAppend" -
		"directArrayLappend" - "directArrayLappendList" -
		"directArrayUnset" - "directIsArray" - "directMakeArray" -
		"regexp" - "listAppend" - "listConcat" - "listLength" -
		"listRange" - "listIn" - "listNotIn" - "dictIterStart" -
		"dictAppend" - "dictIncr" - "dictLappend" - "dictSize" -
		"div" - "expon" - "mod" - "not" - "verifyList" -
		"dictGetOrNexist" - "dictSetOrUnset" {
		    set srcs [lassign $l opcode tgt]
		    set name [my LocalVarName $tgt]
		    append opcode ( [my ValueTypes {*}$srcs] )
		    set srcs [lmap s $srcs {my LoadOrLiteral $s}]
		    set res [$b $opcode {*}$srcs $errorCode $name]
		    if {"FAIL" in [my ValueTypes $tgt]} {
			my SetErrorLine $errorCode [$b maybe $res]
................................................................................
    #
    # Results:
    #	The name.

    method LoadOrLiteral {desc} {
	if {[info exist variables($desc)]} {
	    return $variables($desc)
	}
	if {$desc eq "Nothing"} {
	    # NEXIST special case
	    return "Nothing"
	}
	lassign $desc kind value
	if {$kind ne "literal"} {
	    return -code error "unsubstitutable argument: $desc"
	}
	set type [nameOfType [typeOfLiteral $value]]
	return [my LoadTypedLiteral $value $type]

Changes to codegen/stdlib.tcl.

18
19
20
21
22
23
24

25
26
27
28
29
30
31
..
44
45
46
47
48
49
50

51
52
53
54
55
56
57
...
233
234
235
236
237
238
239


















240
241
242
243
244
245
246
....
2995
2996
2997
2998
2999
3000
3001






























3002
3003
3004
3005
3006
3007
3008
....
3107
3108
3109
3110
3111
3112
3113























3114
3115
3116
3117
3118
3119
3120
....
4160
4161
4162
4163
4164
4165
4166
4167

4168
4169

4170
4171
4172
4173
4174
4175
4176
4177
 
oo::define Builder {
    # Variables holding implementations of Tcl's string operators
    variable tcl.stringify.double tcl.stringify.int tcl.stringify.numeric
    variable tcl.addReference tcl.dropReference
    variable tcl.addFailReference tcl.dropFailReference
    variable tcl.addNExistReference tcl.dropNExistReference

    variable tcl.dropReference.failImpureInt tcl.dropReference.failImpureDouble
    variable tcl.unshare tcl.unshare.copy
    variable tcl.strlen tcl.append.string tcl.streq tcl.strcmp tcl.strmatch
    variable tcl.stridx tcl.stridx.idx
    variable tcl.strrange tcl.strrange.idx tcl.strreplace tcl.strreplace.idx
    variable tcl.strfind.fwd tcl.strfind.rev
    variable tcl.strmap tcl.strtrim tcl.strcase tcl.strclass
................................................................................
    variable tcl.dict.get1 tcl.dict.get tcl.dict.set1 tcl.dict.set
    variable tcl.dict.exists1 tcl.dict.exists tcl.dict.unset1 tcl.dict.unset
    variable tcl.dict.iterStart tcl.dict.iterNext tcl.dict.iterDone
    variable tcl.dict.iterKey tcl.dict.iterValue tcl.dict.addIterReference
    variable tcl.dict.addIterFailReference
    variable tcl.dict.dropIterReference tcl.dict.dropIterFailReference
    variable tcl.dict.append tcl.dict.lappend tcl.dict.incr tcl.dict.size

    variable tcl.maptoint

    # Variables holding implementations of Tcl's exception-handling machinery
    variable tcl.getresult tcl.getreturnopts tcl.initExceptionOptions
    variable tcl.initExceptionSimple tcl.processReturn tcl.procedure.return
    variable tcl.setErrorLine tcl.existsOrError tcl.logCommandInfo
    variable tcl.handleExceptionResult tcl.invoke.command tcl.invoke.expanded
................................................................................
	params value:maybeObjPtr
	build {
	    my condBr [my maybe $value] $nothing $decr
	label decr "action.required"
	    set value [my unmaybe $value "objPtr"]
	    $api Tcl_DecrRefCount $value
	    my ret


















	label nothing "nothing.to.do"
	    my ret
	}

	##### tcl.dropReference.failImpureInt #####
	#
	# Type signature: objPtr:<INT>? -> void
................................................................................
		[my constString TCL] [my constString LOOKUP] \
		[my constString DICT] $keyval {}
	    my br $notOK
	label notOK:
	    my store $1 $ecvar
	    my ret [my fail STRING]
	}































	##### Function tcl.dict.set1 #####
	#
	# Type signature: dict:STRING * key:STRING * value:STRING
	#			* ecvar:int32* -> STRING?
	#
	# Sets a key in a dictionary to map to a value.  Can fail if the
................................................................................
	label OK:
	    my ret [my ok $dict]
	label notOK:
	    my Call obj.cleanup $dd
	    my store $1 $ecvar
	    my ret [my fail STRING]
	}
























	##### Function tcl.dict.addIterReference #####
	#
	# Type signature: iter:DICTITER -> void
	#
	# Increments the reference count inside a dictionary iteration state.

................................................................................
	    set code [my phi [list $code1 $code2] [list $stdInvoke $frameInvoke] "code"]
	    my store $code $ecvar
	    my ret [my fail STRING $code]
	}

	##### Function tcl.invoke.expanded #####
	#
	# Type signature: objc:int * objv:STRING* * ecvar:int* -> STRING?

	#
	# Calls the Tcl interpreter to invoke a Tcl command, and packs the

	# result into a STRING FAIL.

	set f [$module local "tcl.invoke.expanded" \
		   STRING?<-int,STRING*,bool*,int*]
	params objc objv flags ecvar
	build {
	    noalias $objv $flags $ecvar
	    nonnull $objv $flags $ecvar







>







 







>







 







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







 







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







 







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







 







|
>

|
>
|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
....
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
....
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
....
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
 
oo::define Builder {
    # Variables holding implementations of Tcl's string operators
    variable tcl.stringify.double tcl.stringify.int tcl.stringify.numeric
    variable tcl.addReference tcl.dropReference
    variable tcl.addFailReference tcl.dropFailReference
    variable tcl.addNExistReference tcl.dropNExistReference
    variable tcl.dropFailNExistReference
    variable tcl.dropReference.failImpureInt tcl.dropReference.failImpureDouble
    variable tcl.unshare tcl.unshare.copy
    variable tcl.strlen tcl.append.string tcl.streq tcl.strcmp tcl.strmatch
    variable tcl.stridx tcl.stridx.idx
    variable tcl.strrange tcl.strrange.idx tcl.strreplace tcl.strreplace.idx
    variable tcl.strfind.fwd tcl.strfind.rev
    variable tcl.strmap tcl.strtrim tcl.strcase tcl.strclass
................................................................................
    variable tcl.dict.get1 tcl.dict.get tcl.dict.set1 tcl.dict.set
    variable tcl.dict.exists1 tcl.dict.exists tcl.dict.unset1 tcl.dict.unset
    variable tcl.dict.iterStart tcl.dict.iterNext tcl.dict.iterDone
    variable tcl.dict.iterKey tcl.dict.iterValue tcl.dict.addIterReference
    variable tcl.dict.addIterFailReference
    variable tcl.dict.dropIterReference tcl.dict.dropIterFailReference
    variable tcl.dict.append tcl.dict.lappend tcl.dict.incr tcl.dict.size
    variable tcl.dict.get1.empty tcl.dict.set1.empty
    variable tcl.maptoint

    # Variables holding implementations of Tcl's exception-handling machinery
    variable tcl.getresult tcl.getreturnopts tcl.initExceptionOptions
    variable tcl.initExceptionSimple tcl.processReturn tcl.procedure.return
    variable tcl.setErrorLine tcl.existsOrError tcl.logCommandInfo
    variable tcl.handleExceptionResult tcl.invoke.command tcl.invoke.expanded
................................................................................
	params value:maybeObjPtr
	build {
	    my condBr [my maybe $value] $nothing $decr
	label decr "action.required"
	    set value [my unmaybe $value "objPtr"]
	    $api Tcl_DecrRefCount $value
	    my ret
	label nothing "nothing.to.do"
	    my ret
	}

	##### tcl.dropFailNExistReference #####
	#
	# Type signature: objPtr:Tcl_Obj*!? -> void
	#
	# Decrement the reference count of a Maybe Maybe containing a Tcl_Obj
	# reference, and delete it if the reference count drops to zero.

	set f [$m local "tcl.dropFailNExistReference" void<-Tcl_Obj*!?]
	params value:maybeObjPtr
	build {
	    my condBr [my maybe $value] $nothing $decr
	label decr "action.required"
	    my Call tcl.dropNExistReference [my unmaybe $value]
	    my ret
	label nothing "nothing.to.do"
	    my ret
	}

	##### tcl.dropReference.failImpureInt #####
	#
	# Type signature: objPtr:<INT>? -> void
................................................................................
		[my constString TCL] [my constString LOOKUP] \
		[my constString DICT] $keyval {}
	    my br $notOK
	label notOK:
	    my store $1 $ecvar
	    my ret [my fail STRING]
	}

	##### Function tcl.dict.get1.empty #####
	#
	# Type signature: dict:STRING * key:STRING * ecvar:int32* -> STRING!?
	#
	# Gets a value by key from a dictionary. Can only fail if the "dict"
	# is not a valid dictionary; an absent key in the terminal dictionary
	# is reported as an NEXIST result.

	set f [$m local "tcl.dict.get1.empty" STRING!?<-STRING,STRING,int*]
	params dict key ecvar
	build {
	    noalias $ecvar
	    nonnull $dict $key $ecvar
	    set interp [$api tclInterp]
	    set resvar [my alloc STRING "valueVar"]
	    set result [$api Tcl_DictObjGet $interp $dict $key $resvar]
	    my condBr [my eq $result $0] $OK $notOK
	label OK:
	    set value [my load $resvar "value"]
	    my condBr [my nonnull $value] $return $empty
	label return:
	    my addReference(STRING) $value
	    my ret [my ok [my just $value]]
	label empty:
	    my ret [my ok [my nothing STRING]]
	label notOK:
	    my store $1 $ecvar
	    my ret [my fail STRING!]
	}

	##### Function tcl.dict.set1 #####
	#
	# Type signature: dict:STRING * key:STRING * value:STRING
	#			* ecvar:int32* -> STRING?
	#
	# Sets a key in a dictionary to map to a value.  Can fail if the
................................................................................
	label OK:
	    my ret [my ok $dict]
	label notOK:
	    my Call obj.cleanup $dd
	    my store $1 $ecvar
	    my ret [my fail STRING]
	}

	##### Function tcl.dict.set1.empty #####
	#
	# Type signature: dict:STRING * key:STRING * value:STRING!
	#			* ecvar:int32* -> STRING?
	#
	# Sets a key in a dictionary to map to a value, or removes the mapping
	# if the value is NEXIST. Can fail if the "dict" is not a valid
	# dictionary.

	set f [$m local "tcl.dict.set1.empty" \
		   STRING?<-STRING,STRING,STRING!,int*]
	params dict key value ecvar
	build {
	    noalias $ecvar
	    nonnull $dict $key $ecvar
	    my condBr [my exists $value] $reallySet $reallyUnset
	label reallySet "real.set"
	    set value [my unmaybe $value]
	    my ret [my Call tcl.dict.set1 $dict $key $value $ecvar]
	label reallyUnset "real.unset"
	    my ret [my Call tcl.dict.unset1 $dict $key $ecvar]
	}

	##### Function tcl.dict.addIterReference #####
	#
	# Type signature: iter:DICTITER -> void
	#
	# Increments the reference count inside a dictionary iteration state.

................................................................................
	    set code [my phi [list $code1 $code2] [list $stdInvoke $frameInvoke] "code"]
	    my store $code $ecvar
	    my ret [my fail STRING $code]
	}

	##### Function tcl.invoke.expanded #####
	#
	# Type signature: objc:int * objv:STRING* * flags:bool* * ecvar:int*
	#			-> STRING?
	#
	# Calls the Tcl interpreter to invoke a Tcl command, first expanding
	# the arguments indicate by the flags array (which will have objc
	# elements in it), and packs the result into a STRING FAIL.

	set f [$module local "tcl.invoke.expanded" \
		   STRING?<-int,STRING*,bool*,int*]
	params objc objv flags ecvar
	build {
	    noalias $objv $flags $ecvar
	    nonnull $objv $flags $ecvar

Changes to codegen/struct.tcl.

1578
1579
1580
1581
1582
1583
1584


1585
1586
1587
1588
1589
1590
1591
	    DBTY impure <- $rt struct $rt1! $i32 $t
	    set rt [linsert $rt1 0 FAIL]
	    DBTY fail <- $rt struct $rt1? $bool $t
	    set rt [linsert $rt1 0 NEXIST IMPURE]
	    DBTY dummy <- $rt struct <$rt1>! $i32 $impure
	    set rt [linsert $rt1 0 FAIL IMPURE]
	    DBTY dummy <- $rt struct <$rt1>? $bool $impure


	}

	struct "" {
	    int
	    int16*
	}
	struct "" {







>
>







1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
	    DBTY impure <- $rt struct $rt1! $i32 $t
	    set rt [linsert $rt1 0 FAIL]
	    DBTY fail <- $rt struct $rt1? $bool $t
	    set rt [linsert $rt1 0 NEXIST IMPURE]
	    DBTY dummy <- $rt struct <$rt1>! $i32 $impure
	    set rt [linsert $rt1 0 FAIL IMPURE]
	    DBTY dummy <- $rt struct <$rt1>? $bool $impure
	    set rt [linsert $rt1 0 FAIL NEXIST]
	    DBTY dummy <- $rt struct $rt1!? $bool $impure
	}

	struct "" {
	    int
	    int16*
	}
	struct "" {

Changes to codegen/tycon.tcl.

215
216
217
218
219
220
221




222
223
224
225
226
227
228
		return [Type struct{[Type CALLFRAME],$packaged}]
	    }
	    {^VOID FAIL$} - {^VOID\?$} - {^FAIL$} - {^NEXIST$} -
	    {^NOTHING$} {
		# Just a Tcl result code
		return [Type int]
	    }




	    {^(.*) FAIL$} - {^FAIL (.*)} - {^(.*)\?$} {
		return [Type struct{int,[Type [lindex $m 1]]}]
	    }
	    {^NEXIST (.*)$} - {^(.*)\!$} {
		return [Type struct{bool,[Type [lindex $m 1]]}]
	    }
	    {^IMPURE (.*)$} - {^<(.*)>$} {







>
>
>
>







215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
		return [Type struct{[Type CALLFRAME],$packaged}]
	    }
	    {^VOID FAIL$} - {^VOID\?$} - {^FAIL$} - {^NEXIST$} -
	    {^NOTHING$} {
		# Just a Tcl result code
		return [Type int]
	    }
	    {^NEXIST FAIL (.*)} {
		# Flip the order of type stacking
		return [Type "FAIL NEXIST [lindex $m 1]"]
	    }
	    {^(.*) FAIL$} - {^FAIL (.*)} - {^(.*)\?$} {
		return [Type struct{int,[Type [lindex $m 1]]}]
	    }
	    {^NEXIST (.*)$} - {^(.*)\!$} {
		return [Type struct{bool,[Type [lindex $m 1]]}]
	    }
	    {^IMPURE (.*)$} - {^<(.*)>$} {

Changes to demos/perftest/tester.tcl.

480
481
482
483
484
485
486























487
488
489
490
491
492
493
....
1954
1955
1956
1957
1958
1959
1960



1961
1962
1963
1964
1965
1966
1967
....
2173
2174
2175
2176
2177
2178
2179

2180
2181
2182
2183
2184
2185
2186
}
proc dictest6 {} {
    for {set i 0} {$i < 10} {incr i} {
	dict set d $i x
    }
    return $d
}
























proc lrangetest {l} {
    return [lrange $l 0 3],[lrange $l end-1 end]
}

proc lsetest {l {ix { 2 }}} {
    for {set i 0} {$i < [llength $l]} {incr i} {
................................................................................
    {dictest {a b c d foo bar boo boo}}
    {dictest {a b c d}}
    {dictest2 {a b c d}}
    {dictest3 {a b c d}}
    {dictest4 p q r q}
    {dictest5}
    {dictest6}



    {dictfor {a b c d e f g h i j}}
    # Failure handling, [subst], [try]
    {cleanopt {switchfail xyz}}
    {jumptable a}
    {jumptable b}
    {jumptable c}
    {jumptable xyz}
................................................................................
    lsorttest
    lsortcmd
    # Dictionary operations (also see some [try] tests)
    dictest
    dictest2 dictest3
    dictest4 dictest5
    dictest6

    dictfor
    # Nonexistent variables
    nextest1
    nextest2
    nextest3
    nextest4
    # Array operations







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







 







>
>
>







 







>







480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
....
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
....
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
}
proc dictest6 {} {
    for {set i 0} {$i < 10} {incr i} {
	dict set d $i x
    }
    return $d
}
proc dictest7 {d} {
    dict update d a b e f {
	set f [info exists f]
	unset b
    }
    return $d
}
proc dictest8 {d} {
    dict update d a b e f {
	set f [info exists f]
	unset -nocomplain b
	set b(x) 123
    }
    return $d
}
proc dictest9 {d} {
    set b(x) 123
    dict update d a b e f {
	set f [info exists f]
	unset -nocomplain b
    }
    return $d
}

proc lrangetest {l} {
    return [lrange $l 0 3],[lrange $l end-1 end]
}

proc lsetest {l {ix { 2 }}} {
    for {set i 0} {$i < [llength $l]} {incr i} {
................................................................................
    {dictest {a b c d foo bar boo boo}}
    {dictest {a b c d}}
    {dictest2 {a b c d}}
    {dictest3 {a b c d}}
    {dictest4 p q r q}
    {dictest5}
    {dictest6}
    {dictest7 {a b c d}}
    {dictest8 {a b c d}}
    {cleanopt {dictest9 {a b c d}}}
    {dictfor {a b c d e f g h i j}}
    # Failure handling, [subst], [try]
    {cleanopt {switchfail xyz}}
    {jumptable a}
    {jumptable b}
    {jumptable c}
    {jumptable xyz}
................................................................................
    lsorttest
    lsortcmd
    # Dictionary operations (also see some [try] tests)
    dictest
    dictest2 dictest3
    dictest4 dictest5
    dictest6
    dictest7 dictest8 dictest9
    dictfor
    # Nonexistent variables
    nextest1
    nextest2
    nextest3
    nextest4
    # Array operations

Changes to quadcode/callframe.tcl.

311
312
313
314
315
316
317

318
319
320
321
322
323
324
		    lappend newbb $newq
		}
	    }
	}

	"dictAppend" - "dictGet" - "dictIncr" - "dictIterStart" -
	"dictLappend" - "dictSet" - "dictSize" - "dictUnset" -

	"div" - "expon" - "foreachStart" -
	"initException" -
	"listAppend" - "listConcat" -
	"listIn" - "listIndex" - "listLength" - "listRange" - "listSet" -
	"mod" - "not" - "originCmd" - "regexp" -
	"strindex" - "strrange" - "strreplace" {
	    # These operations all return FAIL, and a subsequent







>







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
		    lappend newbb $newq
		}
	    }
	}

	"dictAppend" - "dictGet" - "dictIncr" - "dictIterStart" -
	"dictLappend" - "dictSet" - "dictSize" - "dictUnset" -
	"dictSetOrUnset" -
	"div" - "expon" - "foreachStart" -
	"initException" -
	"listAppend" - "listConcat" -
	"listIn" - "listIndex" - "listLength" - "listRange" - "listSet" -
	"mod" - "not" - "originCmd" - "regexp" -
	"strindex" - "strrange" - "strreplace" {
	    # These operations all return FAIL, and a subsequent

Changes to quadcode/constfold.tcl.

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
			    puts "$b:$pc: $q"
			    puts "    replace [lindex $q 1] with $res"
			}
			my replaceUses [lindex $q 1] $res
			set changed 1
		    }

		    "dictGet" {
			set argl [lassign $argl d]
			set res [dict get $d {*}[lreverse $argl]]
			set res [list literal $res]
			my debug-constfold {
			    puts "$b:$pc: $q"
			    puts "    replace [lindex $q 1] with $res"
			}
................................................................................
			    puts "    replace [lindex $q 1] with $res"
			}
			my replaceUses [lindex $q 1] $res
			set changed 1
		    }


		    "dictSet" {
			set argl [lassign $argl d]
			dict set d {*}[lreverse $argl]
			set res [list literal $d]
			my debug-constfold {
			    puts "$b:$pc: $q"
			    puts "    replace [lindex $q 1] with $res"
			}







|







 







|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
			    puts "$b:$pc: $q"
			    puts "    replace [lindex $q 1] with $res"
			}
			my replaceUses [lindex $q 1] $res
			set changed 1
		    }

		    "dictGet" - "dictGetOrNexist" {
			set argl [lassign $argl d]
			set res [dict get $d {*}[lreverse $argl]]
			set res [list literal $res]
			my debug-constfold {
			    puts "$b:$pc: $q"
			    puts "    replace [lindex $q 1] with $res"
			}
................................................................................
			    puts "    replace [lindex $q 1] with $res"
			}
			my replaceUses [lindex $q 1] $res
			set changed 1
		    }


		    "dictSet" - "dictSetOrUnset" {
			set argl [lassign $argl d]
			dict set d {*}[lreverse $argl]
			set res [list literal $d]
			my debug-constfold {
			    puts "$b:$pc: $q"
			    puts "    replace [lindex $q 1] with $res"
			}

Changes to quadcode/narrow.tcl.

653
654
655
656
657
658
659

660
661
662
663
664
665
666
667
668
669
670
671
672

673
674
675
676
677
678
679
680
		    }
		}

		extractScalar {
		    set result [lindex $q 1]
		    set source [lindex $q 2]
		    set inputType [quadcode::typeOfOperand $types $source]

		    if {!($inputType & $ARRAY) && ($inputType & $NONARRAY)} {
			my removeUse $source $b
			my replaceUses $result $source
			dict unset udchain $result
			set changed 1
			continue; # delete the quad
		    }
		}

		extractArray {
		    set result [lindex $q 1]
		    set source [lindex $q 2]
		    set inputType [quadcode::typeOfOperand $types $source]

		    if {!($inputType & $NONARRAY) && ($inputType & $ARRAY)} {
			my removeUse $source $b
			my replaceUses $result $source
			dict unset udchain $result
			set changed 1
			continue; # delete the quad
		    }
		}







>
|












>
|







653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
		    }
		}

		extractScalar {
		    set result [lindex $q 1]
		    set source [lindex $q 2]
		    set inputType [quadcode::typeOfOperand $types $source]
		    set flag [quadcode::dataType::existence $types $source]
		    if {$flag eq "no" || (!($inputType & $ARRAY) && ($inputType & $NONARRAY))} {
			my removeUse $source $b
			my replaceUses $result $source
			dict unset udchain $result
			set changed 1
			continue; # delete the quad
		    }
		}

		extractArray {
		    set result [lindex $q 1]
		    set source [lindex $q 2]
		    set inputType [quadcode::typeOfOperand $types $source]
		    set flag [quadcode::dataType::existence $types $source]
		    if {$flag eq "no" || (!($inputType & $NONARRAY) && ($inputType & $ARRAY))} {
			my removeUse $source $b
			my replaceUses $result $source
			dict unset udchain $result
			set changed 1
			continue; # delete the quad
		    }
		}

Changes to quadcode/translate.tcl.

483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515


516
517
518
519
520
521
522
523
524







525
526

527
528
529
530
531
532
533
		    "can't set \"%s\": variable is array"
		my quads dictIterNext $var $var
		my quads dictIterKey $key $var
		my quads dictIterValue $value $var
		my quads dictIterDone $done $var
	    }
	    dictUpdateStart {
		# Consider doing a special opcode for this, but that's not
		# necessary until we get [unset] working right.
		set var [my index-to-var [lindex $insn 1]]
		my generate-scalar-check $pc $var {TCL READ VARNAME} \
		    "can't read \"%s\": variable is array"
		set auxNum [string range [lindex $insn 2] 1 end]
		set aux [lindex [dict get $bytecode auxiliary] $auxNum]
		set mid [list temp $depth]
		set val [list temp [incr depth -1]]
		set idx 0
		foreach v [dict get $aux variables] {
		    set r [my index-to-var $v]
		    my generate-scalar-check $pc $r {TCL WRITE VARNAME} \
			"can't set \"%s\": variable is array"
		    my error-quads $pc listIndex $mid $val [list literal $idx]
		    my error-quads $pc dictGet $r $var $mid
		    incr idx
		}
	    }
	    dictUpdateEnd {
		# FIXME: Need to handle NEXIST
		set var [my index-to-var [lindex $insn 1]]
		set auxNum [string range [lindex $insn 2] 1 end]
		set aux [lindex [dict get $bytecode auxiliary] $auxNum]
		set mid [list temp $depth]
		set mid2 [list temp [expr {$depth + 1}]]


		set val [list temp [incr depth -1]]
		set idx 0
		my generate-scalar-check $pc $var {TCL WRITE VARNAME} \
		    "can't write \"%s\": variable is array"
		my quads copy $mid2 $var
		foreach v [dict get $aux variables] {
		    set r [my index-to-var $v]
		    my generate-scalar-check $pc $r {TCL READ VARNAME} \
			"can't read \"%s\": variable is array"







		    my error-quads $pc listIndex $mid $val [list literal $idx]
		    my error-quads $pc dictSet $mid2 $mid2 $r $mid

		}
		my quads copy $var $mid2
	    }
	    unsetScalar {
		# TODO - This doesn't complain on unsetting a nonexistent
		#        variable, it ignores '-nocomplain'
		set var [my index-to-var [lindex $insn 2]]







<
<













|




<



|
|
>
>







|
|
>
>
>
>
>
>
>

|
>







483
484
485
486
487
488
489


490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
		    "can't set \"%s\": variable is array"
		my quads dictIterNext $var $var
		my quads dictIterKey $key $var
		my quads dictIterValue $value $var
		my quads dictIterDone $done $var
	    }
	    dictUpdateStart {


		set var [my index-to-var [lindex $insn 1]]
		my generate-scalar-check $pc $var {TCL READ VARNAME} \
		    "can't read \"%s\": variable is array"
		set auxNum [string range [lindex $insn 2] 1 end]
		set aux [lindex [dict get $bytecode auxiliary] $auxNum]
		set mid [list temp $depth]
		set val [list temp [incr depth -1]]
		set idx 0
		foreach v [dict get $aux variables] {
		    set r [my index-to-var $v]
		    my generate-scalar-check $pc $r {TCL WRITE VARNAME} \
			"can't set \"%s\": variable is array"
		    my error-quads $pc listIndex $mid $val [list literal $idx]
		    my error-quads $pc dictGetOrNexist $r $var $mid
		    incr idx
		}
	    }
	    dictUpdateEnd {

		set var [my index-to-var [lindex $insn 1]]
		set auxNum [string range [lindex $insn 2] 1 end]
		set aux [lindex [dict get $bytecode auxiliary] $auxNum]
		set mid [list temp opnd0]
		set mid2 [list temp opnd1]
		set mid3 [list temp opnd2]
		set mid4 [list temp opnd3]
		set val [list temp [incr depth -1]]
		set idx 0
		my generate-scalar-check $pc $var {TCL WRITE VARNAME} \
		    "can't write \"%s\": variable is array"
		my quads copy $mid2 $var
		foreach v [dict get $aux variables] {
		    set r [my index-to-var $v]
		    # Convert an ARRAY into a NEXIST here; ARRAY is unreadable
		    # so treat as NEXIST...
		    my quads arrayExists $mid3 $r
		    set n [llength $quads]
		    my quads jumpTrue [list pc [expr {$n + 3}]] $mid3
		    my quads copy $mid4 Nothing
		    my quads jump [list pc [expr {$n + 4}]]
		    my quads extractScalar $mid4 $r
		    # Write the value to the right key of the dict
		    my error-quads $pc listIndex $mid $val [list literal $idx]
		    my error-quads $pc dictSetOrUnset $mid2 $mid2 $mid $mid4
		    incr idx
		}
		my quads copy $var $mid2
	    }
	    unsetScalar {
		# TODO - This doesn't complain on unsetting a nonexistent
		#        variable, it ignores '-nocomplain'
		set var [my index-to-var [lindex $insn 2]]

Changes to quadcode/types.tcl.

697
698
699
700
701
702
703
704
705
706
707



708
709
710
711
712
713
714
	    return $FOREACH
	}
	foreachStart {
	    return [expr {$FOREACH | $FAIL}]
	}
	strindex - strrange - strreplace -
	listAppend - listConcat - listIndex - listSet -
	dictSet - dictGet - listRange - dictUnset -
	dictAppend - dictIncr - dictLappend {
	    return [expr {$STRING | $FAIL}]
	}



	arrayGet {
	    return [expr {$STRING | $NEXIST}]
	}
	arraySet - arrayUnset - initArray {
	    return $ARRAY
	}
	dictIterStart {







|



>
>
>







697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
	    return $FOREACH
	}
	foreachStart {
	    return [expr {$FOREACH | $FAIL}]
	}
	strindex - strrange - strreplace -
	listAppend - listConcat - listIndex - listSet -
	dictSet - dictSetOrUnset - dictGet - listRange - dictUnset -
	dictAppend - dictIncr - dictLappend {
	    return [expr {$STRING | $FAIL}]
	}
	dictGetOrNexist {
	    return [expr {$STRING | $FAIL | $NEXIST}]
	}
	arrayGet {
	    return [expr {$STRING | $NEXIST}]
	}
	arraySet - arrayUnset - initArray {
	    return $ARRAY
	}
	dictIterStart {