diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-13 13:54:10 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-01-13 13:54:10 -0300 |
commit | b07fc10e91a5954254b47280aba287220c734a4b (patch) | |
tree | e50d4e5ef9aab68487caf0944e72a7de04bb8bb5 /testes | |
parent | cc1692515e2a6aabc6d07159e7926656e38eda53 (diff) | |
download | lua-b07fc10e91a5954254b47280aba287220c734a4b.tar.gz lua-b07fc10e91a5954254b47280aba287220c734a4b.tar.bz2 lua-b07fc10e91a5954254b47280aba287220c734a4b.zip |
Allow yields inside '__close' metamethods
Initial implementation to allow yields inside '__close' metamethods.
This current version still does not allow a '__close' metamethod
to yield when called due to an error. '__close' metamethods from
C functions also are not allowed to yield.
Diffstat (limited to 'testes')
-rw-r--r-- | testes/locals.lua | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/testes/locals.lua b/testes/locals.lua index add023ca..c9c93ccf 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
@@ -641,6 +641,94 @@ end | |||
641 | print "to-be-closed variables in coroutines" | 641 | print "to-be-closed variables in coroutines" |
642 | 642 | ||
643 | do | 643 | do |
644 | -- yielding inside closing metamethods | ||
645 | |||
646 | local function checktable (t1, t2) | ||
647 | assert(#t1 == #t2) | ||
648 | for i = 1, #t1 do | ||
649 | assert(t1[i] == t2[i]) | ||
650 | end | ||
651 | end | ||
652 | |||
653 | local trace = {} | ||
654 | local co = coroutine.wrap(function () | ||
655 | |||
656 | trace[#trace + 1] = "nowX" | ||
657 | |||
658 | -- will be closed after 'y' | ||
659 | local x <close> = func2close(function (_, msg) | ||
660 | assert(msg == nil) | ||
661 | trace[#trace + 1] = "x1" | ||
662 | coroutine.yield("x") | ||
663 | trace[#trace + 1] = "x2" | ||
664 | end) | ||
665 | |||
666 | return pcall(function () | ||
667 | do -- 'z' will be closed first | ||
668 | local z <close> = func2close(function (_, msg) | ||
669 | assert(msg == nil) | ||
670 | trace[#trace + 1] = "z1" | ||
671 | coroutine.yield("z") | ||
672 | trace[#trace + 1] = "z2" | ||
673 | end) | ||
674 | end | ||
675 | |||
676 | trace[#trace + 1] = "nowY" | ||
677 | |||
678 | -- will be closed after 'z' | ||
679 | local y <close> = func2close(function(_, msg) | ||
680 | assert(msg == nil) | ||
681 | trace[#trace + 1] = "y1" | ||
682 | coroutine.yield("y") | ||
683 | trace[#trace + 1] = "y2" | ||
684 | end) | ||
685 | |||
686 | return 10, 20, 30 | ||
687 | end) | ||
688 | end) | ||
689 | |||
690 | assert(co() == "z") | ||
691 | assert(co() == "y") | ||
692 | assert(co() == "x") | ||
693 | checktable({co()}, {true, 10, 20, 30}) | ||
694 | checktable(trace, {"nowX", "z1", "z2", "nowY", "y1", "y2", "x1", "x2"}) | ||
695 | |||
696 | end | ||
697 | |||
698 | |||
699 | do | ||
700 | -- yielding inside closing metamethods after an error: | ||
701 | -- not yet implemented; raises an error | ||
702 | |||
703 | local co = coroutine.wrap(function () | ||
704 | |||
705 | local function foo (err) | ||
706 | |||
707 | local x <close> = func2close(function(_, msg) | ||
708 | assert(msg == err) | ||
709 | coroutine.yield("x") | ||
710 | return 100, 200 | ||
711 | end) | ||
712 | |||
713 | if err then error(err) else return 10, 20 end | ||
714 | end | ||
715 | |||
716 | coroutine.yield(pcall(foo, nil)) -- no error | ||
717 | return pcall(foo, 10) -- 'foo' will raise an error | ||
718 | end) | ||
719 | |||
720 | local a, b = co() | ||
721 | assert(a == "x" and b == nil) -- yields inside 'x'; Ok | ||
722 | |||
723 | local a, b, c = co() | ||
724 | assert(a and b == 10 and c == 20) -- returns from 'pcall(foo, nil)' | ||
725 | |||
726 | local st, msg = co() -- error yielding after an error | ||
727 | assert(not st and string.find(msg, "attempt to yield")) | ||
728 | end | ||
729 | |||
730 | |||
731 | do | ||
644 | -- an error in a wrapped coroutine closes variables | 732 | -- an error in a wrapped coroutine closes variables |
645 | local x = false | 733 | local x = false |
646 | local y = false | 734 | local y = false |