diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-31 14:54:45 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-10-31 14:54:45 -0300 |
commit | 947a372f5860a76fcafb4a2845abc322e440d6fc (patch) | |
tree | e35840847207c850af5262f93f863f583d2af76d /lvm.c | |
parent | e073cbc2e538369e0611abfc9948f301aea6aef3 (diff) | |
download | lua-947a372f5860a76fcafb4a2845abc322e440d6fc.tar.gz lua-947a372f5860a76fcafb4a2845abc322e440d6fc.tar.bz2 lua-947a372f5860a76fcafb4a2845abc322e440d6fc.zip |
State in generic 'for' acts as a to-be-closed variable
The implicit variable 'state' in a generic 'for' is marked as a
to-be-closed variable, so that the state will be closed as soon
as the loop ends, no matter how.
Taking advantage of this new facility, the call 'io.lines(filename)'
now returns the open file as a second result. Therefore,
an iteraction like 'for l in io.lines(name)...' will close the
file even when the loop ends with a break or an error.
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 41 |
1 files changed, 28 insertions, 13 deletions
@@ -866,7 +866,8 @@ void luaV_finishOp (lua_State *L) { | |||
866 | #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) | 866 | #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) |
867 | 867 | ||
868 | /* | 868 | /* |
869 | ** Protect code that will finish the loop (returns). | 869 | ** Protect code that will finish the loop (returns) or can only raise |
870 | ** errors. | ||
870 | */ | 871 | */ |
871 | #define halfProtect(exp) (savepc(L), (exp)) | 872 | #define halfProtect(exp) (savepc(L), (exp)) |
872 | 873 | ||
@@ -1457,7 +1458,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1457 | vmbreak; | 1458 | vmbreak; |
1458 | } | 1459 | } |
1459 | vmcase(OP_TBC) { | 1460 | vmcase(OP_TBC) { |
1460 | luaF_newtbcupval(L, ra); /* create new to-be-closed upvalue */ | 1461 | /* create new to-be-closed upvalue */ |
1462 | halfProtect(luaF_newtbcupval(L, ra)); | ||
1461 | vmbreak; | 1463 | vmbreak; |
1462 | } | 1464 | } |
1463 | vmcase(OP_JMP) { | 1465 | vmcase(OP_JMP) { |
@@ -1745,21 +1747,34 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1745 | vmbreak; | 1747 | vmbreak; |
1746 | } | 1748 | } |
1747 | vmcase(OP_TFORPREP) { | 1749 | vmcase(OP_TFORPREP) { |
1750 | /* is 'state' a function or has a '__close' metamethod? */ | ||
1751 | if (ttisfunction(s2v(ra + 1)) || | ||
1752 | !ttisnil(luaT_gettmbyobj(L, s2v(ra + 1), TM_CLOSE))) { | ||
1753 | /* create to-be-closed upvalue for it */ | ||
1754 | halfProtect(luaF_newtbcupval(L, ra + 1)); | ||
1755 | } | ||
1748 | pc += GETARG_Bx(i); | 1756 | pc += GETARG_Bx(i); |
1749 | vmbreak; | 1757 | i = *(pc++); /* go to next instruction */ |
1758 | lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i)); | ||
1759 | goto l_tforcall; | ||
1750 | } | 1760 | } |
1751 | vmcase(OP_TFORCALL) { | 1761 | vmcase(OP_TFORCALL) { |
1752 | StkId cb = ra + 3; /* call base */ | 1762 | l_tforcall: |
1753 | setobjs2s(L, cb+2, ra+2); | 1763 | /* 'ra' has the iterator function, 'ra + 1' has the state, |
1754 | setobjs2s(L, cb+1, ra+1); | 1764 | and 'ra + 2' has the control variable. The call will use |
1755 | setobjs2s(L, cb, ra); | 1765 | the stack after these values (starting at 'ra + 3') |
1756 | L->top = cb + 3; /* func. + 2 args (state and index) */ | 1766 | */ |
1757 | Protect(luaD_call(L, cb, GETARG_C(i))); | 1767 | /* push function, state, and control variable */ |
1758 | if (trap) /* keep 'base' correct for next instruction */ | 1768 | memcpy(ra + 3, ra, 3 * sizeof(*ra)); |
1759 | updatebase(ci); | 1769 | L->top = ra + 6; |
1770 | Protect(luaD_call(L, ra + 3, GETARG_C(i))); /* do the call */ | ||
1771 | if (trap) { /* stack may have changed? */ | ||
1772 | updatebase(ci); /* keep 'base' correct */ | ||
1773 | ra = RA(i); /* keep 'ra' correct for next instruction */ | ||
1774 | } | ||
1760 | i = *(pc++); /* go to next instruction */ | 1775 | i = *(pc++); /* go to next instruction */ |
1761 | ra = RA(i); /* get its 'ra' */ | 1776 | ra += 2; /* adjust for next instruction */ |
1762 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP); | 1777 | lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); |
1763 | goto l_tforloop; | 1778 | goto l_tforloop; |
1764 | } | 1779 | } |
1765 | vmcase(OP_TFORLOOP) { | 1780 | vmcase(OP_TFORLOOP) { |