aboutsummaryrefslogtreecommitdiff
path: root/lvm.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-10-31 14:54:45 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-10-31 14:54:45 -0300
commit947a372f5860a76fcafb4a2845abc322e440d6fc (patch)
treee35840847207c850af5262f93f863f583d2af76d /lvm.c
parente073cbc2e538369e0611abfc9948f301aea6aef3 (diff)
downloadlua-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.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/lvm.c b/lvm.c
index aad965d6..1535700f 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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) {