To-be-closed variable in 'for' loop separated from the state

The variable to be closed in a generic 'for' loop now is the
4th value produced in the loop initialization, instead of being
the loop state (the 2nd value produced). That allows a loop to
use a state with a '__toclose' metamethod but do not close it.
(As an example, 'f:lines()' might use the file 'f' as a state
for the loop, but it should not close the file when the loop ends.)
This commit is contained in:
Roberto Ierusalimschy
2018-11-07 14:42:05 -02:00
parent b8fed93215
commit 7f6f70853c
6 changed files with 76 additions and 29 deletions

23
lvm.c
View File

@@ -1654,11 +1654,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak;
}
vmcase(OP_TFORPREP) {
/* is 'state' a function or has a '__close' metamethod? */
if (ttisfunction(s2v(ra + 1)) ||
!ttisnil(luaT_gettmbyobj(L, s2v(ra + 1), TM_CLOSE))) {
/* is 'toclose' a function or has a '__close' metamethod? */
if (ttisfunction(s2v(ra + 3)) ||
!ttisnil(luaT_gettmbyobj(L, s2v(ra + 3), TM_CLOSE))) {
/* create to-be-closed upvalue for it */
halfProtect(luaF_newtbcupval(L, ra + 1));
halfProtect(luaF_newtbcupval(L, ra + 3));
}
pc += GETARG_Bx(i);
i = *(pc++); /* go to next instruction */
@@ -1668,13 +1668,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmcase(OP_TFORCALL) {
l_tforcall:
/* 'ra' has the iterator function, 'ra + 1' has the state,
and 'ra + 2' has the control variable. The call will use
the stack after these values (starting at 'ra + 3')
'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after
these values (starting at 'ra + 4')
*/
/* push function, state, and control variable */
memcpy(ra + 3, ra, 3 * sizeof(*ra));
L->top = ra + 6;
Protect(luaD_call(L, ra + 3, GETARG_C(i))); /* do the call */
memcpy(ra + 4, ra, 3 * sizeof(*ra));
L->top = ra + 4 + 3;
Protect(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
if (trap) { /* stack may have changed? */
updatebase(ci); /* keep 'base' correct */
ra = RA(i); /* keep 'ra' correct for next instruction */
@@ -1686,8 +1687,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
}
vmcase(OP_TFORLOOP) {
l_tforloop:
if (!ttisnil(s2v(ra + 1))) { /* continue loop? */
setobjs2s(L, ra, ra + 1); /* save control variable */
if (!ttisnil(s2v(ra + 2))) { /* continue loop? */
setobjs2s(L, ra, ra + 2); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */
}
vmbreak;