OpenFPGA/libs/EXTERNAL/tcl8.6.12/tests/nre.test

454 lines
9.9 KiB
Plaintext
Raw Normal View History

2022-06-07 11:15:20 -05:00
# Commands covered: proc, apply, [interp alias], [namespce import]
#
# This file contains a collection of tests for the non-recursive executor that
# avoids recursive calls to TEBC. Only the NRE behaviour is tested here, the
# actual command functionality is tested in the specific test file.
#
# Copyright (c) 2008 by Miguel Sofer.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
::tcltest::loadTestedCommands
catch [list package require -exact Tcltest [info patchlevel]]
testConstraint testnrelevels [llength [info commands testnrelevels]]
#
# The tests that risked blowing the C stack on failure have been removed: we
# can now actually measure using testnrelevels.
#
if {[testConstraint testnrelevels]} {
namespace eval testnre {
namespace path ::tcl::mathop
#
# [testnrelevels] returns a 6-list with: C-stack depth, iPtr->numlevels,
# cmdFrame level, callFrame level, tosPtr and callback depth
#
variable last [testnrelevels]
proc depthDiff {} {
variable last
set depth [testnrelevels]
set res {}
foreach t $depth l $last {
lappend res [expr {$t-$l}]
}
set last $depth
return $res
}
proc setabs {} {
variable abs [- [lindex [testnrelevels] 0]]
}
variable body0 {
set x [depthDiff]
if {[incr i] > 10} {
namespace upvar [namespace qualifiers \
[namespace origin depthDiff]] abs abs
incr abs [lindex [testnrelevels] 0]
return [list [lrange $x 0 3] $abs]
}
}
proc makebody txt {
variable body0
return "$body0; $txt"
}
namespace export *
}
namespace import testnre::*
}
test nre-0.1 {levels while unwinding} -body {
testnreunwind
} -constraints {
testnrelevels
} -result {0 0 0}
test nre-1.1 {self-recursive procs} -setup {
proc a i [makebody {a $i}]
} -body {
setabs
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 1 1 1} 0}
test nre-1.2 {self-recursive lambdas} -setup {
set a [list i [makebody {apply $::a $i}]]
} -body {
setabs
apply $a 0
} -cleanup {
unset a
} -constraints {
testnrelevels
} -result {{0 1 1 1} 0}
test nre-1.3 {mutually recursive procs and lambdas} -setup {
proc a i {
apply $::b [incr i]
}
set b [list i [makebody {a $i}]]
} -body {
setabs
a 0
} -cleanup {
rename a {}
unset b
} -constraints {
testnrelevels
} -result {{0 2 2 2} 0}
#
# Test that aliases are non-recursive
#
test nre-2.1 {alias is not recursive} -setup {
proc a i [makebody {b $i}]
interp alias {} b {} a
} -body {
setabs
a 0
} -cleanup {
rename a {}
rename b {}
} -constraints {
testnrelevels
} -result {{0 2 1 1} 0}
#
# Test that imports are non-recursive
#
test nre-3.1 {imports are not recursive} -setup {
namespace eval foo {
setabs
namespace export a
}
proc foo::a i [makebody {::a $i}]
namespace import foo::a
} -body {
a 0
} -cleanup {
rename a {}
namespace delete ::foo
} -constraints {
testnrelevels
} -result {{0 2 1 1} 0}
test nre-4.1 {ensembles are not recursive} -setup {
proc a i [makebody {b foo $i}]
namespace ensemble create \
-command b \
-map [list foo a]
} -body {
setabs
a 0
} -cleanup {
rename a {}
rename b {}
} -constraints {
testnrelevels
} -result {{0 2 1 1} 0}
test nre-4.2 {(compiled) ensembles do not break tailcall} -setup {
# Fix Bug d87cb18205
proc b {} {
tailcall append result first
}
set map [namespace ensemble configure ::dict -map]
dict set map a b
namespace ensemble configure ::dict -map $map
proc demo {} {
dict a
append result second
}
} -body {
demo
} -cleanup {
rename demo {}
namespace ensemble configure ::dict -map [dict remove $map a]
unset map
rename b {}
} -result firstsecond
test nre-5.1 {[namespace eval] is not recursive} -setup {
namespace eval ::foo {
setabs
}
proc foo::a i [makebody {namespace eval ::foo [list a $i]}]
} -body {
::foo::a 0
} -cleanup {
namespace delete ::foo
} -constraints {
testnrelevels
} -result {{0 2 2 2} 0}
test nre-5.2 {[namespace eval] is not recursive} -setup {
namespace eval ::foo {
setabs
}
proc foo::a i [makebody {namespace eval ::foo "set x $i; a $i"}]
} -body {
foo::a 0
} -cleanup {
namespace delete ::foo
} -constraints {
testnrelevels
} -result {{0 2 2 2} 0}
test nre-6.1 {[uplevel] is not recursive} -setup {
proc a i [makebody {uplevel 1 [list a $i]}]
} -body {
setabs
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 0} 0}
test nre-6.2 {[uplevel] is not recursive} -setup {
setabs
proc a i [makebody {uplevel 1 "set x $i; a $i"}]
} -body {
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 0} 0}
test nre-7.1 {[catch] is not recursive} -setup {
setabs
proc a i [makebody {uplevel 1 "catch {a $i} msg; set msg"}]
} -body {
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 3 3 0} 0}
test nre-7.2 {[if] is not recursive} -setup {
setabs
proc a i [makebody {uplevel 1 "if 1 {a $i}"}]
} -body {
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 0} 0}
test nre-7.3 {[while] is not recursive} -setup {
setabs
proc a i [makebody {uplevel 1 "while 1 {set res \[a $i\]; break}; set res"}]
} -body {
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 0} 0}
test nre-7.4 {[for] is not recursive} -setup {
setabs
proc a i [makebody {uplevel 1 "for {set j 0} {\$j < 10} {incr j} {set res \[a $i\]; break}; set res"}]
} -body {
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 0} 0}
test nre-7.5 {[foreach] is not recursive} -setup {
#
# Enable once [foreach] is NR-enabled
#
setabs
proc a i [makebody {uplevel 1 "foreach j {1 2 3 4 5 6} {set res \[a $i\]; break}; set res"}]
} -body {
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 3 3 0} 0}
test nre-7.6 {[eval] is not recursive} -setup {
proc a i [makebody {eval [list a $i]}]
} -body {
setabs
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 1} 0}
test nre-7.7 {[eval] is not recursive} -setup {
proc a i [makebody {eval "a $i"}]
} -body {
setabs
a 0
} -cleanup {
rename a {}
} -constraints {
testnrelevels
} -result {{0 2 2 1} 0}
test nre-7.8 {bug #2910748: switch out of stale BC is not nre-aware} -setup {
proc foo args {}
foo
coroutine bar apply {{} {
yield
proc foo args {return ok}
while 1 {
yield [incr i]
foo
}
}}
} -body {
# if switching to plain eval is not nre aware, this will cause a "cannot
# yield" error
list [bar] [bar] [bar]
} -cleanup {
rename bar {}
rename foo {}
} -result {1 2 3}
test nre-8.1 {nre and {*}} -body {
# force an expansion that grows the evaluation stack, check that nre
# adapts the TEBCdataPtr. This crashes on failure.
proc inner {} {
set long [lrepeat 1000000 1]
list {*}$long
}
proc outer {} inner
lrange [outer] 0 2
} -cleanup {
rename inner {}
rename outer {}
} -result {1 1 1}
test nre-8.2 {nre and {*}, [Bug 2415422]} -body {
# force an expansion that grows the evaluation stack, check that nre
# adapts the bcFramePtr. This causes an NRE assertion to fail if it is not
# done properly.
proc nop {} {}
proc crash {} {
foreach val [list {*}[lrepeat 100000 x]] {
nop
}
}
crash
} -cleanup {
rename nop {}
rename crash {}
}
#
# Basic TclOO tests
#
test nre-oo.1 {really deep calls in oo - direct} -setup {
oo::object create foo
oo::objdefine foo method bar i [makebody {foo bar $i}]
} -body {
setabs
foo bar 0
} -cleanup {
foo destroy
} -constraints {
testnrelevels
} -result {{0 1 1 1} 0}
test nre-oo.2 {really deep calls in oo - call via [self]} -setup {
oo::object create foo
oo::objdefine foo method bar i [makebody {[self] bar $i}]
} -body {
setabs
foo bar 0
} -cleanup {
foo destroy
} -constraints {
testnrelevels
} -result {{0 1 1 1} 0}
test nre-oo.3 {really deep calls in oo - private calls} -setup {
oo::object create foo
oo::objdefine foo method bar i [makebody {my bar $i}]
} -body {
setabs
foo bar 0
} -cleanup {
foo destroy
} -constraints {
testnrelevels
} -result {{0 1 1 1} 0}
test nre-oo.4 {really deep calls in oo - overriding} -setup {
oo::class create foo {
method bar i [makebody {my bar $i}]
}
oo::class create boo {
superclass foo
method bar i [makebody {next $i}]
}
} -body {
setabs
[boo new] bar 0
} -cleanup {
foo destroy
} -constraints {
testnrelevels
} -result {{0 1 1 1} 0}
test nre-oo.5 {really deep calls in oo - forwards} -setup {
oo::object create foo
set body [makebody {my boo $i}]
oo::objdefine foo "
method bar i {$body}
forward boo ::foo bar
"
} -body {
setabs
foo bar 0
} -cleanup {
foo destroy
} -constraints {
testnrelevels
} -result {{0 2 1 1} 0}
#
# NASTY BUG found by tcllib's interp package
#
test nre-X.1 {eval in wrong interp} -setup {
set i [interp create]
$i eval {proc filter lst {lsearch -all -inline -not $lst "::tcl"}}
} -body {
$i eval {
set x {namespace children ::}
set y [list namespace children ::]
namespace delete {*}[filter [{*}$y]]
set j [interp create]
$j alias filter filter
$j eval {namespace delete {*}[filter [namespace children ::]]}
namespace eval foo {}
list [filter [eval $x]] [filter [eval $y]] [filter [$j eval $x]] [filter [$j eval $y]]
}
} -cleanup {
interp delete $i
} -result {::foo ::foo {} {}}
# cleanup
::tcltest::cleanupTests
if {[testConstraint testnrelevels]} {
namespace forget testnre::*
namespace delete testnre
}
return
# Local Variables:
# mode: tcl
# fill-column: 78
# End: