Compare commits

...
3 changed files with 219 additions and 2 deletions
+7 -2
View File
@@ -8462,7 +8462,12 @@ TclNRTailcallEval(
TclMarkTailcall(interp);
TclNRAddCallback(interp, TclNRReleaseValues, listPtr, NULL, NULL,NULL);
iPtr->lookupNsPtr = (Namespace *) nsPtr;
return TclNREvalObjv(interp, objc-1, objv+1, 0, NULL);
/* Error messages (because TCL_EVAL_NOERR - don't call TEOV_PushExceptionHandlers,
* to avoid exception on CONTINUE, BREAK or RETURN at level 0. */
objc--; objv++;
TclNRAddCallback(interp, TEOV_Error, INT2PTR(objc),
(ClientData)objv, NULL, NULL);
return TclNREvalObjv(interp, objc, objv, TCL_EVAL_NOERR, NULL);
}
int
@@ -9089,7 +9094,7 @@ TclNRCoroutineObjCmd(
/* ensure that the command is looked up in the correct namespace */
iPtr->lookupNsPtr = lookupNsPtr;
Tcl_NREvalObj(interp, Tcl_NewListObj(objc-2, objv+2), 0);
Tcl_NREvalObj(interp, Tcl_NewListObj(objc-2, objv+2), TCL_EVAL_NOERR);
iPtr->numLevels--;
SAVE_CONTEXT(corPtr->running);
+124
View File
@@ -19,6 +19,7 @@ catch [list package require -exact Tcltest [info patchlevel]]
testConstraint testnrelevels [llength [info commands testnrelevels]]
testConstraint memory [llength [info commands memory]]
testConstraint testevalobjv [llength [info commands testevalobjv]]
set lambda [list {{start 0} {stop 10}} {
# init
@@ -781,6 +782,129 @@ test coroutine-8.1.2 {coro inject with result, ticket 42202ba1e5ff566e} -body {
set result
} -result {inject-executed}
# following tests cover direct break/return from coroutine into proc,
# coro or top-level up-scope loop, in case of "infinite" loop the result is 10 or
# `invalid command name "c"`, in case of broken scope - `invoked "break" outside of a loop`
# (expected 1 for break and "" for return), test with "-nc" suffix are non-compiled.
test coroutine-9.1a {as direct return from proc: break into proc up-scope loop} -setup {
proc p {} {yield; return -code break}
} -body {
coroutine c p;
proc t {} {while {[incr i] < 10} {c}; set i}
t
} -cleanup {
rename p {}; rename t {}
} -result 1
test coroutine-9.1b {as direct return from proc: break into top-level up-scope loop} -setup {
proc p {} {yield; return -code break}
set i 0
} -body {
coroutine c p;
while {[incr i] < 10} {c}; set i
} -cleanup {
rename p {}
} -result 1
test coroutine-9.1b-nc {as direct return from proc: break into top-level up-scope loop (non-compiled)} \
-constraints {testevalobjv} -body {
exec [info nameofexecutable] << {
proc p {} {yield; return -code break}
set i 0
coroutine c p;
testevalobjv 1 while {[incr i] < 10} c; puts $i
}
} -result 1
test coroutine-9.1c {as direct return from coro: break into lambda up-scope loop} -setup {
proc p {} {yield; return -code break}
set i 0
} -body {
apply {{} {coroutine c p; while {[incr i] < 10} c; set i}}
} -cleanup {
rename p {}
} -result 1
test coroutine-9.1d {no yield, as direct return from proc: break into proc up-scope loop} -setup {
proc p {} {return -code break}
} -body {
proc t {} {while {[incr i] < 10} {coroutine c p}; set i}
t
} -cleanup {
rename p {}; rename t {}
} -result 1
test coroutine-9.1e {no yield, as direct return from proc: break into top-level up-scope loop} -setup {
proc p {} {return -code break}
set i 0
} -body {
while {[incr i] < 10} {coroutine c p}; set i
} -cleanup {
rename p {}
} -result 1
test coroutine-9.1e-nc {no yield, as direct return from proc: break into top-level up-scope loop (non-compiled)} \
-constraints {testevalobjv} -body {
exec [info nameofexecutable] << {
proc p {} {return -code break}
set i 0
testevalobjv 1 while {[incr i] < 10} {coroutine c p}; puts $i
}
} -result 1
test coroutine-9.2a {as direct return from proc: return into proc up-scope loop} -setup {
proc p {} {yield; return -code return}
} -body {
coroutine c p;
proc t {} {while {[incr i] < 10} {c}; set i}
t
} -cleanup {
rename p {}; rename t {}
} -result ""
test coroutine-9.2b {as direct return from proc: return into top-level up-scope loop} -setup {
proc p {} {yield; return -code return}
set i 0
} -body {
coroutine c p;
while {[incr i] < 10} {c}; set i
} -cleanup {
rename p {}
} -result ""
test coroutine-9.2b-nc {as direct return from proc: return into top-level up-scope loop (non-compiled)} \
-constraints {testevalobjv} -body {
exec [info nameofexecutable] << {
proc p {} {yield; return -code return}
set i 0
coroutine c p;
testevalobjv 1 while {[incr i] < 10} c; puts $i
}
} -result ""
test coroutine-9.2c {as direct return from coro: return into lambda up-scope loop} -setup {
proc p {} {yield; return -code return}
set i 0
} -body {
apply {{} {coroutine c p; while {[incr i] < 10} c; set i}}
} -cleanup {
rename p {}
} -result ""
test coroutine-9.2d {no yield, as direct return from proc: return into proc up-scope loop} -setup {
proc p {} {return -code return}
} -body {
proc t {} {while {[incr i] < 10} {coroutine c p}; set i}
t
} -cleanup {
rename p {}; rename t {}
} -result ""
test coroutine-9.2e {no yield, as direct return from proc: return into top-level up-scope loop} -setup {
proc p {} {return -code return}
set i 0
} -body {
while {[incr i] < 10} {coroutine c p}; set i
} -cleanup {
rename p {}
} -result ""
test coroutine-9.2e-nc {no yield, as direct return from proc: return into top-level up-scope loop (non-compiled)} \
-constraints {testevalobjv} -body {
exec [info nameofexecutable] << {
proc p {} {return -code return}
set i 0
testevalobjv 1 while {[incr i] < 10} {coroutine c p}; puts $i
}
} -result ""
# cleanup
+88
View File
@@ -18,6 +18,7 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
catch [list package require -exact Tcltest [info patchlevel]]
testConstraint testnrelevels [llength [info commands testnrelevels]]
testConstraint testevalobjv [llength [info commands testevalobjv]]
#
# The tests that risked blowing the C stack on failure have been removed: we
@@ -708,6 +709,93 @@ test tailcall-14.1-bc {{in a deleted namespace} {byte compiled}} -body {
}
} -returnCodes 1 -result {namespace "::ns" not found}
# following tests cover tailcall as direct break/return from proc into proc,
# coro or top-level up-scope loop, in case of "infinite" loop the result is 10
# (expected 1 for break and "" for return), test with "-nc" suffix are non-compiled.
test tailcall-15.1a {as direct return from proc: break into proc up-scope loop} -setup {
proc p {} {tailcall break}
} -body {
proc t {} {while {[incr i] < 10} p; set i}
t
} -cleanup {
rename p {}; rename t {}
} -result 1
test tailcall-15.1b {as direct return from proc: break into top-level up-scope loop} -setup {
proc p {} {tailcall break}
set i 0
} -body {
while {[incr i] < 10} p; set i
} -cleanup {
rename p {}
} -result 1
test tailcall-15.1b-nc {as direct return from proc: break into top-level up-scope loop (non-compiled)} \
-constraints {testevalobjv} -body {
exec [info nameofexecutable] << {
proc p {} {tailcall break}
set i 0
while {[incr i] < 10} p; puts $i
}
} -result 1
test tailcall-15.1c {as direct return from coro: break into lambda up-scope loop} -setup {
proc p {} {yield; tailcall break}
set i 0
} -body {
apply {{} {coroutine c p}}
while {[incr i] < 10} c; set i
} -cleanup {
rename p {}
} -result 1
test tailcall-15.1d {as direct return from proc: break into coro up-scope loop} -setup {
proc p {} {tailcall break}
set i 0
} -body {
apply {{} {while {[incr i] < 10} {coroutine c p}; set i}}
} -cleanup {
rename p {}
} -result 1
test tailcall-15.2a {as direct return from proc: return into proc up-scope loop} -setup {
proc p {} {tailcall return}
} -body {
proc t {} {while {[incr i] < 10} p; set i}
t
} -cleanup {
rename p {}; rename t {}
} -result ""
test tailcall-15.2b {as direct return from proc: return into top-level up-scope loop} -setup {
proc p {} {tailcall return}
set i 0
} -body {
while {[incr i] < 10} p; set i
} -cleanup {
rename p {}
} -result ""
test tailcall-15.2b-nc {as direct return from proc: return into top-level up-scope loop (non-compiled)} \
-constraints {testevalobjv} -body {
exec [info nameofexecutable] << {
proc p {} {tailcall return}
set i 0
while {[incr i] < 10} p; puts $i
}
} -result ""
test tailcall-15.2c {as direct return from coro: return into lambda up-scope loop} -setup {
proc p {} {yield; tailcall return}
set i 0
} -body {
apply {{} {coroutine c p}}
while {[incr i] < 10} c; set i
} -cleanup {
rename p {}
} -result ""
test tailcall-15.2d {as direct return from proc: return into coro up-scope loop} -setup {
proc p {} {tailcall return}
set i 0
} -body {
apply {{} {while {[incr i] < 10} {coroutine c p}; set i}}
} -cleanup {
rename p {}
} -result ""
# cleanup
::tcltest::cleanupTests