OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tcl8.6.12 / tests / compile.test
1 # This file contains tests for the files tclCompile.c, tclCompCmds.c and
2 # tclLiteral.c
3 #
4 # This file contains a collection of tests for one or more of the Tcl built-in
5 # commands. Sourcing this file into Tcl runs the tests and generates output
6 # for errors. No output means no errors were found.
7 #
8 # Copyright (c) 1997 by Sun Microsystems, Inc.
9 # Copyright (c) 1998-1999 by Scriptics Corporation.
10 #
11 # See the file "license.terms" for information on usage and redistribution of
12 # this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
14 if {"::tcltest" ni [namespace children]} {
15     package require tcltest 2.5
16     namespace import -force ::tcltest::*
17 }
18
19 ::tcltest::loadTestedCommands
20 catch [list package require -exact Tcltest [info patchlevel]]
21
22 testConstraint exec       [llength [info commands exec]]
23 testConstraint memory     [llength [info commands memory]]
24 testConstraint testevalex [llength [info commands testevalex]]
25
26 # The following tests are very incomplete, although the rest of the
27 # test suite covers this file fairly well.
28
29 catch {rename p ""}
30 catch {namespace delete test_ns_compile}
31 catch {unset x}
32 catch {unset y}
33 catch {unset a}
34 \f
35 test compile-1.1 {TclCompileString: look up cmds in proc ns, not current ns} -setup {
36     catch {namespace delete test_ns_compile}
37     catch {unset x}
38 } -body {
39     set x 123
40     namespace eval test_ns_compile {
41         proc set {args} {
42             global x
43             lappend x test_ns_compile::set
44         }
45         proc p {} {
46             set 0
47         }
48     }
49     list [test_ns_compile::p] [set x]
50 } -result {{123 test_ns_compile::set} {123 test_ns_compile::set}}
51 test compile-1.2 {TclCompileString, error result is reset if TclGetLong determines word isn't an integer} {
52     proc p {x} {info commands 3m}
53     list [catch {p} msg] $msg
54 } {1 {wrong # args: should be "p x"}}
55
56 test compile-2.1 {TclCompileDollarVar: global scalar name with ::s} -setup {
57     catch {unset x}
58 } -body {
59     set x 123
60     list $::x [expr {"x" in [info globals]}]
61 } -result {123 1}
62 test compile-2.2 {TclCompileDollarVar: global scalar name with ::s} -setup {
63     catch {unset y}
64 } -body {
65     proc p {} {
66         set ::y 789
67         return $::y
68     }
69     list [p] $::y [expr {"y" in [info globals]}]
70 } -result {789 789 1}
71 test compile-2.3 {TclCompileDollarVar: global array name with ::s} -setup {
72     catch {unset a}
73 } -body {
74     set ::a(1) 2
75     list $::a(1) [set ::a($::a(1)) 3] $::a(2) [expr {"a" in [info globals]}]
76 } -result {2 3 3 1}
77 test compile-2.4 {TclCompileDollarVar: global scalar name with ::s} -setup {
78     catch {unset a}
79 } -body {
80     proc p {} {
81         set ::a(1) 1
82         return $::a($::a(1))
83     }
84     list [p] $::a(1) [expr {"a" in [info globals]}]
85 } -result {1 1 1}
86 test compile-2.5 {TclCompileDollarVar: global array, called as ${arrName(0)}} -setup {
87     catch {unset a}
88 } -body {
89     proc p {} {
90         global a
91         set a(1) 1
92         return ${a(1)}$::a(1)$a(1)
93     }
94     list [p] $::a(1) [expr {"a" in [info globals]}]
95 } -result {111 1 1}
96
97 test compile-3.1 {TclCompileCatchCmd: only catch cmds with scalar vars are compiled inline} -setup {
98     catch {unset a}
99 } -body {
100     set a(1) xyzzyx
101     proc p {} {
102         global a
103         catch {set x 123} a(1)
104     }
105     list [p] $a(1)
106 } -result {0 123}
107 test compile-3.2 {TclCompileCatchCmd: non-local variables} {
108     set ::foo 1
109     proc catch-test {} {
110         catch {set x 3} ::foo
111     }
112     catch-test
113     return $::foo
114 } 3
115 test compile-3.3 {TclCompileCatchCmd: overagressive compiling [bug 219184]} {
116     proc catch-test {str} {
117         catch [eval $str GOOD]
118         error BAD
119     }
120     catch {catch-test error} ::foo
121     return $::foo
122 } {GOOD}
123 test compile-3.4 {TclCompileCatchCmd: bcc'ed [return] is caught} {
124     proc foo {} {
125         set fail [catch {
126             return 1
127         }] ; # {}
128         return 2
129     }
130     foo
131 } {2}
132 test compile-3.5 {TclCompileCatchCmd: recover from error, [Bug 705406]} {
133     proc foo {} {
134         catch {
135             if {[a]} {
136                 if b {}
137             }
138         }
139     }
140     list [catch foo msg] $msg
141 } {0 1}
142 test compile-3.6 {TclCompileCatchCmd: error in storing result [Bug 3098302]} {*}{
143      -setup {
144          namespace eval catchtest {
145              variable result1 {}
146          }
147          trace add variable catchtest::result1 write catchtest::failtrace
148          proc catchtest::failtrace {n1 n2 op} {
149              return -code error "trace on $n1 fails by request"
150          }
151      }
152     -body {
153         proc catchtest::x {} {
154             variable result1
155             set count 0
156             for {set i 0} {$i < 10} {incr i} {
157                 set status2 [catch {
158                     set status1 [catch {
159                         return -code error -level 0 "original failure"
160                     } result1 options1]
161                 } result2 options2]
162                 incr count
163             }
164             list $count $result2
165         }
166         catchtest::x
167     }
168     -result {10 {can't set "result1": trace on result1 fails by request}}
169     -cleanup {namespace delete catchtest}
170 }
171
172 test compile-3.7 {TclCompileCatchCmd: error in storing options [Bug 3098302]} {*}{
173      -setup {
174          namespace eval catchtest {
175              variable options1 {}
176          }
177          trace add variable catchtest::options1 write catchtest::failtrace
178          proc catchtest::failtrace {n1 n2 op} {
179              return -code error "trace on $n1 fails by request"
180          }
181      }
182     -body {
183         proc catchtest::x {} {
184             variable options1
185             set count 0
186             for {set i 0} {$i < 10} {incr i} {
187                 set status2 [catch {
188                     set status1 [catch {
189                         return -code error -level 0 "original failure"
190                     } result1 options1]
191                 } result2 options2]
192                 incr count
193             }
194             list $count $result2
195         }
196         catchtest::x
197     }
198     -result {10 {can't set "options1": trace on options1 fails by request}}
199     -cleanup {namespace delete catchtest}
200 }
201
202 test compile-4.1 {TclCompileForCmd: command substituted test expression} {
203     set i 0
204     set j 0
205     # Should be "forever"
206     for {} [expr {$i < 3}] {} {
207         set j [incr i]
208         if {$j > 3} break
209     }
210     set j
211 } {4}
212
213 test compile-5.1 {TclCompileForeachCmd: exception stack} {
214     proc foreach-exception-test {} {
215         foreach array(index) [list 1 2 3] break
216         foreach array(index) [list 1 2 3] break
217         foreach scalar [list 1 2 3] break
218     }
219     list [catch foreach-exception-test result] $result
220 } {0 {}}
221 test compile-5.2 {TclCompileForeachCmd: non-local variables} {
222     set ::foo 1
223     proc foreach-test {} {
224         foreach ::foo {1 2 3} {}
225     }
226     foreach-test
227     set ::foo
228 } 3
229 test compile-5.3 {TclCompileForeachCmd: [Bug b9b2079e6d]} -setup {
230     proc demo {} {
231         foreach x y {
232             if 1 break else
233         }
234     }
235 } -body {
236     demo
237 } -cleanup {
238     rename demo {}
239 } -returnCodes error -result {wrong # args: no script following "else" argument}
240
241 test compile-6.1 {TclCompileSetCmd: global scalar names with ::s} -setup {
242     catch {unset x}
243     catch {unset y}
244 } -body {
245     set x 123
246     proc p {} {
247         set ::y 789
248         return $::y
249     }
250     list $::x [expr {"x" in [info globals]}] \
251          [p] $::y [expr {"y" in [info globals]}]
252 } -result {123 1 789 789 1}
253 test compile-6.2 {TclCompileSetCmd: global array names with ::s} -setup {
254     catch {unset a}
255 } -body {
256     set ::a(1) 2
257     proc p {} {
258         set ::a(1) 1
259         return $::a($::a(1))
260     }
261     list $::a(1) [p] [set ::a($::a(1)) 3] $::a(1) [expr {"a" in [info globals]}]
262 } -result {2 1 3 3 1}
263 test compile-6.3 {TclCompileSetCmd: namespace var names with ::s} -setup {
264     catch {namespace delete test_ns_compile}
265     catch {unset x}
266 } -body {
267     namespace eval test_ns_compile {
268         variable v hello
269         variable arr
270         set ::x $::test_ns_compile::v
271         set ::test_ns_compile::arr(1) 123
272     }
273     list $::x $::test_ns_compile::arr(1)
274 } -result {hello 123}
275
276 test compile-7.1 {TclCompileWhileCmd: command substituted test expression} {
277     set i 0
278     set j 0
279     # Should be "forever"
280     while [expr {$i < 3}] {
281         set j [incr i]
282         if {$j > 3} break
283     }
284     set j
285 } {4}
286
287 test compile-8.1 {CollectArgInfo: binary data} {
288     list [catch "string length \000foo" msg] $msg
289 } {0 4}
290 test compile-8.2 {CollectArgInfo: binary data} {
291     list [catch "string length foo\000" msg] $msg
292 } {0 4}
293 test compile-8.3 {CollectArgInfo: handle "]" at end of command properly} {
294     set x ]
295 } {]}
296
297 test compile-9.1 {UpdateStringOfByteCode: called for duplicate of compiled empty object} {
298     proc p {} {
299         set x {}
300         eval $x
301         append x { }
302         eval $x
303     }
304     p
305 } {}
306
307 test compile-10.1 {BLACKBOX: exception stack overflow} {
308     set x {{0}}
309     set y 0
310     while {$y < 100} {
311         if !$x {incr y}
312     }
313 } {}
314
315 test compile-11.1 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
316     apply {{} {
317         # shared object - Interp result && Var 'r'
318         set r [list foobar]
319         # command that will add error to result
320         lindex a bogus
321     }}
322 } -returnCodes error -result {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}
323 test compile-11.2 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
324     apply {{} { set r [list foobar] ; string index a bogus }}
325 } -returnCodes error -result {bad index "bogus": must be integer?[+-]integer? or end?[+-]integer?}
326 test compile-11.3 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
327     apply {{} { set r [list foobar] ; string index a 0o9 }}
328 } -returnCodes error -match glob -result {*invalid octal number*}
329 test compile-11.4 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
330     apply {{} { set r [list foobar] ; array set var {one two many} }}
331 } -returnCodes error -result {list must have an even number of elements}
332 test compile-11.5 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
333     apply {{} { set r [list foobar] ; incr foo bar baz}}
334 } -returnCodes error -result {wrong # args: should be "incr varName ?increment?"}
335 test compile-11.6 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
336     apply {{} { set r [list foobar] ; incr}}
337 } -returnCodes error -result {wrong # args: should be "incr varName ?increment?"}
338 test compile-11.7 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
339     apply {{} { set r [list foobar] ; expr [concat !a] }}
340 } -returnCodes error -match glob -result *
341 test compile-11.8 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
342     apply {{} { set r [list foobar] ; expr {!a} }}
343 } -returnCodes error -match glob -result *
344 test compile-11.9 {Tcl_Append*: ensure Tcl_ResetResult is used properly} -body {
345     apply {{} { set r [list foobar] ; llength "\{" }}
346     list [catch {p} msg] $msg
347 } -returnCodes error -result {unmatched open brace in list}
348
349 #
350 # Special section for tests of tclLiteral.c
351 # The following tests check for incorrect memory handling in
352 # TclReleaseLiteral. They are only effective when tcl is compiled with
353 # TCL_MEM_DEBUG
354 #
355 # Special test for leak on interp delete [Bug 467523].
356 test compile-12.1 {testing literal leak on interp delete} -setup {
357     proc getbytes {} {
358         set lines [split [memory info] "\n"]
359         lindex $lines 3 3
360     }
361 } -constraints memory -body {
362     set end [getbytes]
363     for {set i 0} {$i < 5} {incr i} {
364         interp create foo
365         foo eval {
366             namespace eval bar {}
367         }
368         interp delete foo
369         set tmp $end
370         set end [getbytes]
371     }
372     set leakedBytes [expr {$end - $tmp}]
373 } -cleanup {
374     rename getbytes {}
375     unset -nocomplain end i tmp leakedBytes
376 } -result 0
377 # Special test for a memory error in a preliminary fix of [Bug 467523].  It
378 # requires executing a helpfile.  Presumably the child process is used because
379 # when this test fails, it crashes.
380 test compile-12.2 {testing error on literal deletion} -constraints {memory exec} -body {
381     set sourceFile [makeFile {
382         for {set i 0} {$i < 5} {incr i} {
383             namespace eval bar {}
384             namespace delete bar
385         }
386         puts 0
387     } source.file]
388     exec [interpreter] $sourceFile
389 } -cleanup {
390     catch {removeFile $sourceFile}
391 } -result 0
392 # Test to catch buffer overrun in TclCompileTokens from buf 530320
393 test compile-12.3 {check for a buffer overrun} -body {
394     proc crash {} {
395         puts $array([expr {a+2}])
396     }
397     crash
398 } -returnCodes error -cleanup {
399     rename crash {}
400 } -match glob -result *
401 test compile-12.4 {TclCleanupLiteralTable segfault} -body {
402     # Tcl Bug 1001997
403     # Here, we're trying to test a case that causes a crash in
404     # TclCleanupLiteralTable.  The conditions that we're trying to establish
405     # are:
406     # - TclCleanupLiteralTable is attempting to clean up a bytecode object in
407     #   the literal table.
408     # - The bytecode object in question contains the only reference to another
409     #   literal.
410     # - The literal in question is in the same hash bucket as the bytecode
411     #   object, and immediately follows it in the chain.
412     # Since newly registered literals are added at the FRONT of the bucket
413     # chains, and since the bytecode object is registered before its literals,
414     # this is difficult to achieve.  What we do is:
415     #  (a) do a [namespace eval] of a string that's calculated to hash into
416     #      the same bucket as a literal that it contains.  In this case, the
417     #      script and the variable 'bugbug' land in the same bucket.
418     #  (b) do a [namespace eval] of a string that contains enough literals to
419     #      force TclRegisterLiteral to rebuild the global literal table.  The
420     #      newly created hash buckets will contain the literals, IN REVERSE
421     #      ORDER, thus putting the bytecode immediately ahead of 'bugbug' and
422     #      'bug4345bug'.  The bytecode object will contain the only references
423     #      to those two literals.
424     #  (c) Delete the interpreter to invoke TclCleanupLiteralTable and tickle
425     #      the bug.
426     proc foo {} {
427         set i [interp create]
428         $i eval {
429             namespace eval ::w {concat 4649; variable bugbug}
430             namespace eval ::w {
431                 concat x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 \
432                     x11 x12 x13 x14 x15 x16 x17 x18 x19 x20 \
433                     x21 x22 x23 x24 x25 x26 x27 x28 x29 x30 \
434                     x31 x32 X33 X34 X35 X36 X37 X38 X39 X40 \
435                     x41 x42 x43 x44 x45 x46 x47 x48 x49 x50 \
436                     x51 x52 x53 x54 x55 x56 x57 x58 x59 x60 \
437                     x61 x62 x63 x64
438                 concat y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 \
439                     y11 y12 y13 y14 y15 y16 y17 y18 y19 y20 \
440                     y21 y22 y23 y24 y25 y26 y27 y28 y29 y30 \
441                     y31 y32 Y33 Y34 Y35 Y36 Y37 Y38 Y39 Y40 \
442                     y41 y42 y43 y44 y45 y46 y47 y48 y49 y50 \
443                     y51 y52 y53 y54 y55 y56 y57 y58 y59 y60 \
444                     y61 y62 y63 y64
445                 concat z1 z2 z3 z4 z5 z6 z7 z8 z9 z10 \
446                     z11 z12 z13 z14 z15 z16 z17 z18 z19 z20 \
447                     z21 z22 z23 z24 z25 z26 z27 z28 z29 z30 \
448                     z31 z32
449             }
450         }
451         interp delete $i; # must not crash
452         return ok
453     }
454     foo
455 } -cleanup {
456     rename foo {}
457 } -result ok
458
459 # Special test for underestimating the maxStackSize required for a compiled
460 # command. A failure will cause a segfault in the child process.
461 test compile-13.1 {testing underestimate of maxStackSize in list cmd} {exec} {
462     set body {set x [list}
463     for {set i 0} {$i < 3000} {incr i} {
464         append body " $i"
465     }
466     append body {]; puts OK}
467     regsub BODY {proc crash {} {BODY}; crash} $body script
468     list [catch {exec [interpreter] << $script} msg] $msg
469 } {0 OK}
470
471 # Tests of nested compile (body in body compilation), should not generate stack overflow
472 # (with abnormal program termination), bug [fec0c17d39]:
473 proc _ti_gencode {} {
474     # creates test interpreter on demand with [gencode] generator:
475     if {[interp exists ti]} {
476         return
477     }
478     interp create ti
479     ti eval {proc gencode {nr {cmd eval} {nl 0}} {
480         set code ""
481         set e ""; if {$nl} {set e "\n"}
482         for {set i 0} {$i < $nr} {incr i} {
483             append code "$cmd \{$e"
484         }
485         append code "lappend result 1$e"
486         for {set i 0} {$i < $nr} {incr i} {
487             append code "\}$e"
488         }
489         #puts [format "%% %.40s ... %d bytes" $code [string length $code]]
490         return $code
491     }}
492 }
493 test compile-13.2 {TclCompileScript: testing expected nested scripts compilation} -setup {
494     _ti_gencode
495     interp recursionlimit ti [expr {10000+50}]
496     ti eval {set result {}}
497 } -body {
498     # Test different compilation variants (instructions evalStk, invokeStk, etc),
499     # with 1500 (1000 in debug) nested scripts (bodies). If you get SO/SF exceptions on some low-stack
500     # boxes or systems, please don't decrease it (either provide a constraint)
501     ti eval {foreach cmd {eval "if 1" try catch} {
502         set c [gencode [expr {![::tcl::pkgconfig get debug] ? 1500 : 1000}] $cmd]
503         if 1 $c
504     }}
505     ti eval {set result}
506 } -result {1 1 1 1}
507 test compile-13.3 {TclCompileScript: testing check of max depth by nested scripts compilation} -setup {
508     _ti_gencode
509     interp recursionlimit ti 100
510     ti eval {set result {}}
511 } -body {
512     # Test different compilation variants (instructions evalStk, invokeStk, etc),
513     # with 500 nested scripts (bodies). It must generate "too many nested compilations"
514     # error for any variant we're testing here:
515     ti eval {foreach cmd {eval "if 1" try catch} {
516         set c [gencode 500 $cmd]
517         lappend errors [catch $c e] $e
518     }}
519     #puts $errors
520     # all of nested calls exceed the limit, so must end with "too many nested compilations"
521     # (or evaluations, depending on compile method/instruction and "mixed" compile within
522     # evaliation), so no one succeeds, the result must be empty:
523     ti eval {set result}
524 } -result {}
525 #
526 # clean up:
527 if {[interp exists ti]} {
528     interp delete ti
529 }
530 rename _ti_gencode {}
531
532 # Tests compile-14.* for [Bug 599788] [Bug 0c043a175a47da8c2342]
533 test compile-14.1 {testing errors in element name; segfault?} {} {
534      catch {set a([error])} msg1
535      catch {set bubba([join $abba $jubba]) $vol} msg2
536      list $msg1 $msg2
537 } {{wrong # args: should be "error message ?errorInfo? ?errorCode?"} {can't read "abba": no such variable}}
538
539 test compile-14.2 {testing element name "$"} -body {
540     unset -nocomplain a
541     set a() 1
542     set a(1) 2
543     set a($) 3
544     list [set a()] [set a(1)] [set a($)] [unset a() a(1); lindex [array names a] 0]
545 } -cleanup {unset a} -result [list 1 2 3 {$}]
546
547
548 # Tests compile-15.* cover Tcl Bug 633204
549 test compile-15.1 {proper TCL_RETURN code from [return]} {
550     apply {{} {catch return}}
551 } 2
552 test compile-15.2 {proper TCL_RETURN code from [return]} {
553     apply {{} {catch {return foo}}}
554 } 2
555 test compile-15.3 {proper TCL_RETURN code from [return]} {
556     apply {{} {catch {return $::tcl_library}}}
557 } 2
558 test compile-15.4 {proper TCL_RETURN code from [return]} {
559     apply {{} {catch {return [info library]}}}
560 } 2
561 test compile-15.5 {proper TCL_RETURN code from [return]} {
562     apply {{} {catch {set a 1}; return}}
563 } ""
564
565 for {set noComp 0} {$noComp <= 1} {incr noComp} {
566
567 if {$noComp} {
568     interp alias {} run {} testevalex
569     set constraints testevalex
570 } else {
571     interp alias {} run {} if 1
572     set constraints {}
573 }
574
575 test compile-16.1.$noComp {TclCompileScript: word expansion} $constraints {
576     run "list [string repeat {{*}a } 255]"
577 } [lrepeat 255 a]
578 test compile-16.2.$noComp {TclCompileScript: word expansion} $constraints {
579     run "list [string repeat {{*}a } 256]"
580 } [lrepeat 256 a]
581 test compile-16.3.$noComp {TclCompileScript: word expansion} $constraints {
582     run "list [string repeat {{*}a } 257]"
583 } [lrepeat 257 a]
584 test compile-16.4.$noComp {TclCompileScript: word expansion} $constraints {
585     run {{*}list}
586 } {}
587 test compile-16.5.$noComp {TclCompileScript: word expansion} $constraints {
588     run {{*}list {*}{x y z}}
589 } {x y z}
590 test compile-16.6.$noComp {TclCompileScript: word expansion} $constraints {
591     run {{*}list {*}[list x y z]}
592 } {x y z}
593 test compile-16.7.$noComp {TclCompileScript: word expansion} $constraints {
594     run {{*}list {*}[list x y z][list x y z]}
595 } {x y zx y z}
596 test compile-16.8.$noComp {TclCompileScript: word expansion} -body {
597     set l {x y z}
598     run {{*}list {*}$l}
599 } -constraints $constraints -cleanup {
600     unset l
601 } -result {x y z}
602 test compile-16.9.$noComp {TclCompileScript: word expansion} -body {
603     set l {x y z}
604     run {{*}list {*}$l$l}
605 } -constraints $constraints -cleanup {
606     unset l
607 } -result {x y zx y z}
608 test compile-16.10.$noComp {TclCompileScript: word expansion} -body {
609     run {{*}\{}
610 } -constraints $constraints -returnCodes error \
611 -result {unmatched open brace in list}
612 test compile-16.11.$noComp {TclCompileScript: word expansion} -body {
613     proc badList {} {return \{}
614     run {{*}[badList]}
615 } -constraints $constraints -cleanup {
616     rename badList {}
617 } -returnCodes error  -result {unmatched open brace in list}
618 test compile-16.12.$noComp {TclCompileScript: word expansion} $constraints {
619     run {{*}list x y z}
620 } {x y z}
621 test compile-16.13.$noComp {TclCompileScript: word expansion} $constraints {
622     run {{*}list x y {*}z}
623 } {x y z}
624 test compile-16.14.$noComp {TclCompileScript: word expansion} $constraints {
625     run {{*}list x {*}y z}
626 } {x y z}
627 test compile-16.15.$noComp {TclCompileScript: word expansion} $constraints {
628     run {list x y {*}z}
629 } {x y z}
630 test compile-16.16.$noComp {TclCompileScript: word expansion} $constraints {
631     run {list x {*}y z}
632 } {x y z}
633 test compile-16.17.$noComp {TclCompileScript: word expansion} $constraints {
634     run {list {*}x y z}
635 } {x y z}
636
637 # These tests note that expansion can in theory cause the number of arguments
638 # to a command to exceed INT_MAX, which is as big as objc is allowed to get.
639 #
640 # In practice, it seems we will run out of memory before we confront this
641 # issue. Note that compiled operations run out of memory at smaller objc
642 # values than direct string evaluation.
643 #
644 # These tests are constrained as knownBug because they are likely to cause
645 # memory allocation panics somewhere, and we don't want panics in the test
646 # suite.
647 #
648 test compile-16.18.$noComp {TclCompileScript: word expansion} -body {
649     proc LongList {} {return [lrepeat [expr {1<<10}] x]}
650     llength [run "list [string repeat {{*}[LongList] } [expr {1<<10}]]"]
651 } -constraints [linsert $constraints 0 knownBug] -cleanup {
652     rename LongList {}
653 } -returnCodes ok  -result [expr {1<<20}]
654 test compile-16.19.$noComp {TclCompileScript: word expansion} -body {
655     proc LongList {} {return [lrepeat [expr {1<<11}] x]}
656     llength [run "list [string repeat {{*}[LongList] } [expr {1<<11}]]"]
657 } -constraints [linsert $constraints 0 knownBug] -cleanup {
658     rename LongList {}
659 } -returnCodes ok  -result [expr {1<<22}]
660 test compile-16.20.$noComp {TclCompileScript: word expansion} -body {
661     proc LongList {} {return [lrepeat [expr {1<<12}] x]}
662     llength [run "list [string repeat {{*}[LongList] } [expr {1<<12}]]"]
663 } -constraints [linsert $constraints 0 knownBug] -cleanup {
664     rename LongList {}
665 } -returnCodes ok  -result [expr {1<<24}]
666 # This is the one that should cause overflow
667 test compile-16.21.$noComp {TclCompileScript: word expansion} -body {
668     proc LongList {} {return [lrepeat [expr {1<<16}] x]}
669     llength [run "list [string repeat {{*}[LongList] } [expr {1<<16}]]"]
670 } -constraints [linsert $constraints 0 knownBug] -cleanup {
671     rename LongList {}
672 } -returnCodes ok  -result [expr {wide(1)<<32}]
673 test compile-16.22.$noComp {
674     Bug 845412: TclCompileScript: word expansion not mandatory
675 } -body {
676     # This test may crash and will fail unless Bug 845412 is fixed.
677     proc ReturnResults args {return $args}
678     run "ReturnResults [string repeat {x } 260]"
679 } -constraints $constraints -cleanup {
680     rename ReturnResults {}
681 } -returnCodes ok -result [string trim [string repeat {x } 260]]
682 test compile-16.23.$noComp {
683     Bug 1032805: defer parse error until run time
684 } -constraints $constraints -body {
685     namespace eval x {
686         run {
687             proc if {a b} {uplevel 1 [list set $a $b]}
688             if 1 {syntax {}{}}
689         }
690     }
691 } -cleanup {
692     namespace delete x
693 } -returnCodes ok -result {syntax {}{}}
694 test compile-16.24.$noComp {
695     Bug 1638414: bad list constant as first expanded term
696 } -constraints $constraints -body {
697     run "{*}\"\{foo bar\""
698 } -returnCodes error -result {unmatched open brace in list}
699 test compile-16.25.$noComp {TclCompileScript: word expansion, naked backslashes} $constraints {
700     run {list {*}{a \n b}}
701 } {a {
702 } b}
703 test compile-16.26.$noComp {TclCompileScript: word expansion, protected backslashes} $constraints {
704     run {list {*}{a {\n} b}}
705 } {a {\n} b}
706 }       ;# End of noComp loop
707
708 # These tests are messy because it wrecks the interpreter it runs in!  They
709 # demonstrate issues arising from [FRQ 1101710]
710 test compile-17.1 {Command interpretation binding for compiled code} -constraints knownBug -setup {
711     set i [interp create]
712 } -body {
713     $i eval {
714         if 1 {
715             expr [
716                 proc expr args {return substituted}
717                 format {[subst compiled]}
718             ]
719         }
720     }
721 } -cleanup {
722     interp delete $i
723 } -result substituted
724 test compile-17.2 {Command interpretation binding for non-compiled code} -setup {
725     set i [interp create]
726 } -body {
727     $i eval {
728         if 1 {
729             [subst expr] [
730                 proc expr args {return substituted}
731                 format {[subst compiled]}
732             ]
733         }
734     }
735 } -cleanup {
736     interp delete $i
737 } -result substituted
738
739 # This tests the supported parts of the unsupported [disassemble] command. It
740 # does not check the format of disassembled bytecode though; that's liable to
741 # change without warning.
742
743 set disassemblables [linsert [join {
744     constructor destructor lambda method objmethod proc script
745 } ", "] end-1 or]
746 test compile-18.1 {disassembler - basics} -returnCodes error -body {
747     tcl::unsupported::disassemble
748 } -match glob -result {wrong # args: should be "*"}
749 test compile-18.2 {disassembler - basics} -returnCodes error -body {
750     tcl::unsupported::disassemble ?
751 } -result "bad type \"?\": must be $disassemblables"
752 test compile-18.3 {disassembler - basics} -returnCodes error -body {
753     tcl::unsupported::disassemble lambda
754 } -match glob -result {wrong # args: should be "* lambda lambdaTerm"}
755 test compile-18.4 {disassembler - basics} -returnCodes error -body {
756     tcl::unsupported::disassemble lambda \{
757 } -result "can't interpret \"\{\" as a lambda expression"
758 test compile-18.5 {disassembler - basics} -body {
759     # Allow any string: the result format is not defined anywhere!
760     tcl::unsupported::disassemble lambda {{} {}}
761 } -match glob -result *
762 test compile-18.6 {disassembler - basics} -returnCodes error -body {
763     tcl::unsupported::disassemble proc
764 } -match glob -result {wrong # args: should be "* proc procName"}
765 test compile-18.7 {disassembler - basics} -returnCodes error -body {
766     tcl::unsupported::disassemble proc nosuchproc
767 } -result {"nosuchproc" isn't a procedure}
768 test compile-18.8 {disassembler - basics} -setup {
769     proc chewonthis {} {}
770 } -body {
771     # Allow any string: the result format is not defined anywhere!
772     tcl::unsupported::disassemble proc chewonthis
773 } -cleanup {
774     rename chewonthis {}
775 } -match glob -result *
776 test compile-18.9 {disassembler - basics} -returnCodes error -body {
777     tcl::unsupported::disassemble script
778 } -match glob -result {wrong # args: should be "* script script"}
779 test compile-18.10 {disassembler - basics} -body {
780     # Allow any string: the result format is not defined anywhere!
781     tcl::unsupported::disassemble script {}
782 } -match glob -result *
783 test compile-18.11 {disassembler - basics} -returnCodes error -body {
784     tcl::unsupported::disassemble method
785 } -match glob -result {wrong # args: should be "* method className methodName"}
786 test compile-18.12 {disassembler - basics} -returnCodes error -body {
787     tcl::unsupported::disassemble method nosuchclass foo
788 } -result {nosuchclass does not refer to an object}
789 test compile-18.13 {disassembler - basics} -returnCodes error -setup {
790     oo::object create justanobject
791 } -body {
792     tcl::unsupported::disassemble method justanobject foo
793 } -cleanup {
794     justanobject destroy
795 } -result {"justanobject" is not a class}
796 test compile-18.14 {disassembler - basics} -returnCodes error -body {
797     tcl::unsupported::disassemble method oo::object nosuchmethod
798 } -result {unknown method "nosuchmethod"}
799 test compile-18.15 {disassembler - basics} -setup {
800     oo::class create foo {method bar {} {}}
801 } -body {
802     # Allow any string: the result format is not defined anywhere!
803     tcl::unsupported::disassemble method foo bar
804 } -cleanup {
805     foo destroy
806 } -match glob -result *
807 test compile-18.16 {disassembler - basics} -returnCodes error -body {
808     tcl::unsupported::disassemble objmethod
809 } -match glob -result {wrong # args: should be "* objmethod objectName methodName"}
810 test compile-18.17 {disassembler - basics} -returnCodes error -body {
811     tcl::unsupported::disassemble objmethod nosuchobject foo
812 } -result {nosuchobject does not refer to an object}
813 test compile-18.18 {disassembler - basics} -returnCodes error -body {
814     tcl::unsupported::disassemble objmethod oo::object nosuchmethod
815 } -result {unknown method "nosuchmethod"}
816 test compile-18.19 {disassembler - basics} -setup {
817     oo::object create foo
818     oo::objdefine foo {method bar {} {}}
819 } -body {
820     # Allow any string: the result format is not defined anywhere!
821     tcl::unsupported::disassemble objmethod foo bar
822 } -cleanup {
823     foo destroy
824 } -match glob -result *
825 # There never was a compile-18.20.
826 # The keys of the dictionary produced by [getbytecode] are defined.
827 set bytecodekeys {literals variables exception instructions auxiliary commands script namespace stackdepth exceptdepth}
828 test compile-18.21 {disassembler - basics} -returnCodes error -body {
829     tcl::unsupported::getbytecode
830 } -match glob -result {wrong # args: should be "*"}
831 test compile-18.22 {disassembler - basics} -returnCodes error -body {
832     tcl::unsupported::getbytecode ?
833 } -result "bad type \"?\": must be $disassemblables"
834 test compile-18.23 {disassembler - basics} -returnCodes error -body {
835     tcl::unsupported::getbytecode lambda
836 } -match glob -result {wrong # args: should be "* lambda lambdaTerm"}
837 test compile-18.24 {disassembler - basics} -returnCodes error -body {
838     tcl::unsupported::getbytecode lambda \{
839 } -result "can't interpret \"\{\" as a lambda expression"
840 test compile-18.25 {disassembler - basics} -body {
841     dict keys [tcl::unsupported::getbytecode lambda {{} {}}]
842 } -result "$bytecodekeys initiallinenumber sourcefile"
843 test compile-18.26 {disassembler - basics} -returnCodes error -body {
844     tcl::unsupported::getbytecode proc
845 } -match glob -result {wrong # args: should be "* proc procName"}
846 test compile-18.27 {disassembler - basics} -returnCodes error -body {
847     tcl::unsupported::getbytecode proc nosuchproc
848 } -result {"nosuchproc" isn't a procedure}
849 test compile-18.28 {disassembler - basics} -setup {
850     proc chewonthis {} {}
851 } -body {
852     dict keys [tcl::unsupported::getbytecode proc chewonthis]
853 } -cleanup {
854     rename chewonthis {}
855 } -result "$bytecodekeys initiallinenumber sourcefile"
856 test compile-18.28.1 {disassembler - tricky bit} -setup {
857     eval [list proc chewonthis {} {}]
858 } -body {
859     dict keys [tcl::unsupported::getbytecode proc chewonthis]
860 } -cleanup {
861     rename chewonthis {}
862 } -result $bytecodekeys
863 test compile-18.28.2 {disassembler - tricky bit} -setup {
864     eval {proc chewonthis {} {}}
865 } -body {
866     dict keys [tcl::unsupported::getbytecode proc chewonthis]
867 } -cleanup {
868     rename chewonthis {}
869 } -result "$bytecodekeys initiallinenumber sourcefile"
870 test compile-18.28.3 {disassembler - tricky bit} -setup {
871     proc Proc {n a b} {
872         proc $n $a $b
873     }
874     Proc chewonthis {} {}
875 } -body {
876     dict keys [tcl::unsupported::getbytecode proc chewonthis]
877 } -cleanup {
878     rename Proc {}
879     rename chewonthis {}
880 } -result $bytecodekeys
881 test compile-18.28.4 {disassembler - tricky bit} -setup {
882     proc Proc {n a b} {
883         tailcall proc $n $a $b
884     }
885     Proc chewonthis {} {}
886 } -body {
887     dict keys [tcl::unsupported::getbytecode proc chewonthis]
888 } -cleanup {
889     rename Proc {}
890     rename chewonthis {}
891 } -result "$bytecodekeys initiallinenumber sourcefile"
892 test compile-18.29 {disassembler - basics} -returnCodes error -body {
893     tcl::unsupported::getbytecode script
894 } -match glob -result {wrong # args: should be "* script script"}
895 test compile-18.30 {disassembler - basics} -body {
896     dict keys [tcl::unsupported::getbytecode script {}]
897 } -result $bytecodekeys
898 test compile-18.31 {disassembler - basics} -returnCodes error -body {
899     tcl::unsupported::getbytecode method
900 } -match glob -result {wrong # args: should be "* method className methodName"}
901 test compile-18.32 {disassembler - basics} -returnCodes error -body {
902     tcl::unsupported::getbytecode method nosuchclass foo
903 } -result {nosuchclass does not refer to an object}
904 test compile-18.33 {disassembler - basics} -returnCodes error -setup {
905     oo::object create justanobject
906 } -body {
907     tcl::unsupported::getbytecode method justanobject foo
908 } -cleanup {
909     justanobject destroy
910 } -result {"justanobject" is not a class}
911 test compile-18.34 {disassembler - basics} -returnCodes error -body {
912     tcl::unsupported::getbytecode method oo::object nosuchmethod
913 } -result {unknown method "nosuchmethod"}
914 test compile-18.35 {disassembler - basics} -setup {
915     oo::class create foo {method bar {} {}}
916 } -body {
917     dict keys [tcl::unsupported::getbytecode method foo bar]
918 } -cleanup {
919     foo destroy
920 } -result "$bytecodekeys initiallinenumber sourcefile"
921 test compile-18.36 {disassembler - basics} -returnCodes error -body {
922     tcl::unsupported::getbytecode objmethod
923 } -match glob -result {wrong # args: should be "* objmethod objectName methodName"}
924 test compile-18.37 {disassembler - basics} -returnCodes error -body {
925     tcl::unsupported::getbytecode objmethod nosuchobject foo
926 } -result {nosuchobject does not refer to an object}
927 test compile-18.38 {disassembler - basics} -returnCodes error -body {
928     tcl::unsupported::getbytecode objmethod oo::object nosuchmethod
929 } -result {unknown method "nosuchmethod"}
930 test compile-18.39 {disassembler - basics} -setup {
931     oo::object create foo
932     oo::objdefine foo {method bar {} {}}
933 } -body {
934     dict keys [tcl::unsupported::getbytecode objmethod foo bar]
935 } -cleanup {
936     foo destroy
937 } -result "$bytecodekeys initiallinenumber sourcefile"
938 test compile-18.40 {disassembler - basics} -returnCodes error -body {
939     tcl::unsupported::disassemble constructor
940 } -match glob -result {wrong # args: should be "* constructor className"}
941 test compile-18.41 {disassembler - basics} -returnCodes error -body {
942     tcl::unsupported::disassemble constructor nosuchclass
943 } -result {nosuchclass does not refer to an object}
944 test compile-18.42 {disassembler - basics} -returnCodes error -setup {
945     oo::object create justanobject
946 } -body {
947     tcl::unsupported::disassemble constructor justanobject
948 } -cleanup {
949     justanobject destroy
950 } -result {"justanobject" is not a class}
951 test compile-18.43 {disassembler - basics} -returnCodes error -setup {
952     oo::class create constructorless
953 } -body {
954     tcl::unsupported::disassemble constructor constructorless
955 } -cleanup {
956     constructorless destroy
957 } -result {"constructorless" has no defined constructor}
958 test compile-18.44 {disassembler - basics} -setup {
959     oo::class create foo {constructor {} {set x 1}}
960 } -body {
961     # Allow any string: the result format is not defined anywhere!
962     tcl::unsupported::disassemble constructor foo
963 } -cleanup {
964     foo destroy
965 } -match glob -result *
966 test compile-18.45 {disassembler - basics} -returnCodes error -body {
967     tcl::unsupported::getbytecode constructor
968 } -match glob -result {wrong # args: should be "* constructor className"}
969 test compile-18.46 {disassembler - basics} -returnCodes error -body {
970     tcl::unsupported::getbytecode constructor nosuchobject
971 } -result {nosuchobject does not refer to an object}
972 test compile-18.47 {disassembler - basics} -returnCodes error -setup {
973     oo::class create constructorless
974 } -body {
975     tcl::unsupported::getbytecode constructor constructorless
976 } -cleanup {
977     constructorless destroy
978 } -result {"constructorless" has no defined constructor}
979 test compile-18.48 {disassembler - basics} -setup {
980     oo::class create foo {constructor {} {set x 1}}
981 } -body {
982     dict keys [tcl::unsupported::getbytecode constructor foo]
983 } -cleanup {
984     foo destroy
985 } -result "$bytecodekeys"
986 # There is no compile-18.49
987 test compile-18.50 {disassembler - basics} -returnCodes error -body {
988     tcl::unsupported::disassemble destructor
989 } -match glob -result {wrong # args: should be "* destructor className"}
990 test compile-18.51 {disassembler - basics} -returnCodes error -body {
991     tcl::unsupported::disassemble destructor nosuchclass
992 } -result {nosuchclass does not refer to an object}
993 test compile-18.52 {disassembler - basics} -returnCodes error -setup {
994     oo::object create justanobject
995 } -body {
996     tcl::unsupported::disassemble destructor justanobject
997 } -cleanup {
998     justanobject destroy
999 } -result {"justanobject" is not a class}
1000 test compile-18.53 {disassembler - basics} -returnCodes error -setup {
1001     oo::class create constructorless
1002 } -body {
1003     tcl::unsupported::disassemble destructor constructorless
1004 } -cleanup {
1005     constructorless destroy
1006 } -result {"constructorless" has no defined destructor}
1007 test compile-18.54 {disassembler - basics} -setup {
1008     oo::class create foo {destructor {set x 1}}
1009 } -body {
1010     # Allow any string: the result format is not defined anywhere!
1011     tcl::unsupported::disassemble destructor foo
1012 } -cleanup {
1013     foo destroy
1014 } -match glob -result *
1015 test compile-18.55 {disassembler - basics} -returnCodes error -body {
1016     tcl::unsupported::getbytecode destructor
1017 } -match glob -result {wrong # args: should be "* destructor className"}
1018 test compile-18.56 {disassembler - basics} -returnCodes error -body {
1019     tcl::unsupported::getbytecode destructor nosuchobject
1020 } -result {nosuchobject does not refer to an object}
1021 test compile-18.57 {disassembler - basics} -returnCodes error -setup {
1022     oo::class create constructorless
1023 } -body {
1024     tcl::unsupported::getbytecode destructor constructorless
1025 } -cleanup {
1026     constructorless destroy
1027 } -result {"constructorless" has no defined destructor}
1028 test compile-18.58 {disassembler - basics} -setup {
1029     oo::class create foo {destructor {set x 1}}
1030 } -body {
1031     dict keys [tcl::unsupported::getbytecode destructor foo]
1032 } -cleanup {
1033     foo destroy
1034 } -result "$bytecodekeys"
1035
1036 test compile-19.0 {Bug 3614102: reset stack housekeeping} -body {
1037     # This will panic in a --enable-symbols=compile build, unless bug is fixed.
1038     apply {{} {list [if 1]}}
1039 } -returnCodes error -match glob -result *
1040
1041 test compile-20.1 {ensure there are no infinite loops in optimizing} {
1042     tcl::unsupported::disassemble script {
1043         while 1 {
1044             return -code continue -level 0
1045         }
1046     }
1047     return
1048 } {}
1049 test compile-20.2 {ensure there are no infinite loops in optimizing} {
1050     tcl::unsupported::disassemble script {
1051         while 1 {
1052             while 1 {
1053                 return -code break -level 0
1054             }
1055         }
1056     }
1057     return
1058 } {}
1059
1060 test compile-21.1 {stack balance management} {
1061     apply {{} {
1062         set result {}
1063         while 1 {
1064             lappend result a
1065             lappend result [list b [break]]
1066             lappend result c
1067         }
1068         return $result
1069     }}
1070 } a
1071 test compile-21.2 {stack balance management} {
1072     apply {{} {
1073         set result {}
1074         while {[incr i] <= 10} {
1075             lappend result $i
1076             lappend result [list b [continue] c]
1077             lappend result c
1078         }
1079         return $result
1080     }}
1081 } {1 2 3 4 5 6 7 8 9 10}
1082 test compile-21.3 {stack balance management} {
1083     apply {args {
1084         set result {}
1085         while 1 {
1086             lappend result a
1087             lappend result [concat {*}$args [break]]
1088             lappend result c
1089         }
1090         return $result
1091     }} P Q R S T
1092 } a
1093 test compile-21.4 {stack balance management} {
1094     apply {args {
1095         set result {}
1096         while {[incr i] <= 10} {
1097             lappend result $i
1098             lappend result [concat {*}$args [continue] c]
1099             lappend result c
1100         }
1101         return $result
1102     }} P Q R S T
1103 } {1 2 3 4 5 6 7 8 9 10}
1104
1105 # TODO sometime - check that bytecode from tbcload is *not* disassembled.
1106 \f
1107 # cleanup
1108 catch {rename p ""}
1109 catch {namespace delete test_ns_compile}
1110 catch {unset x}
1111 catch {unset y}
1112 catch {unset a}
1113 ::tcltest::cleanupTests
1114 return
1115
1116 # Local Variables:
1117 # mode: tcl
1118 # fill-column: 78
1119 # End: