aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--liolib.c6
-rw-r--r--lopcodes.h6
-rw-r--r--lparser.c25
-rw-r--r--lvm.c23
-rw-r--r--testes/files.lua37
-rw-r--r--testes/locals.lua8
6 files changed, 76 insertions, 29 deletions
diff --git a/liolib.c b/liolib.c
index b2a2fec8..7d6d51e6 100644
--- a/liolib.c
+++ b/liolib.c
@@ -386,8 +386,10 @@ static int io_lines (lua_State *L) {
386 } 386 }
387 aux_lines(L, toclose); /* push iteration function */ 387 aux_lines(L, toclose); /* push iteration function */
388 if (toclose) { 388 if (toclose) {
389 lua_pushvalue(L, 1); /* file will be second result */ 389 lua_pushnil(L); /* state */
390 return 2; 390 lua_pushnil(L); /* control */
391 lua_pushvalue(L, 1); /* file is the to-be-closed variable (4th result) */
392 return 4;
391 } 393 }
392 else 394 else
393 return 1; 395 return 1;
diff --git a/lopcodes.h b/lopcodes.h
index 5a38f767..7bb83a1e 100644
--- a/lopcodes.h
+++ b/lopcodes.h
@@ -279,9 +279,9 @@ OP_FORLOOP,/* A Bx R(A)+=R(A+2);
279 if R(A) <?= R(A+1) then { pc-=Bx; R(A+3)=R(A) } */ 279 if R(A) <?= R(A+1) then { pc-=Bx; R(A+3)=R(A) } */
280OP_FORPREP,/* A Bx R(A)-=R(A+2); pc+=Bx */ 280OP_FORPREP,/* A Bx R(A)-=R(A+2); pc+=Bx */
281 281
282OP_TFORPREP,/* A Bx create upvalue A; pc+=Bx */ 282OP_TFORPREP,/* A Bx create upvalue for R(A + 3); pc+=Bx */
283OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ 283OP_TFORCALL,/* A C R(A+4), ... ,R(A+3+C) := R(A)(R(A+1), R(A+2)); */
284OP_TFORLOOP,/* A Bx if R(A+1) ~= nil then { R(A)=R(A+1); pc -= Bx } */ 284OP_TFORLOOP,/* A Bx if R(A+2) ~= nil then { R(A)=R(A+2); pc -= Bx } */
285 285
286OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ 286OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
287 287
diff --git a/lparser.c b/lparser.c
index e4f11cb6..afc5aeab 100644
--- a/lparser.c
+++ b/lparser.c
@@ -165,6 +165,9 @@ static int registerlocalvar (LexState *ls, TString *varname) {
165} 165}
166 166
167 167
168/*
169** Create a new local variable with the given 'name'.
170*/
168static void new_localvar (LexState *ls, TString *name) { 171static void new_localvar (LexState *ls, TString *name) {
169 FuncState *fs = ls->fs; 172 FuncState *fs = ls->fs;
170 Dyndata *dyd = ls->dyd; 173 Dyndata *dyd = ls->dyd;
@@ -176,13 +179,8 @@ static void new_localvar (LexState *ls, TString *name) {
176 dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); 179 dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg);
177} 180}
178 181
179
180static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) {
181 new_localvar(ls, luaX_newstring(ls, name, sz));
182}
183
184#define new_localvarliteral(ls,v) \ 182#define new_localvarliteral(ls,v) \
185 new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) 183 new_localvar(ls, luaX_newstring(ls, "" v, (sizeof(v)/sizeof(char)) - 1));
186 184
187 185
188static LocVar *getlocvar (FuncState *fs, int i) { 186static LocVar *getlocvar (FuncState *fs, int i) {
@@ -192,6 +190,9 @@ static LocVar *getlocvar (FuncState *fs, int i) {
192} 190}
193 191
194 192
193/*
194** Start the scope for the last 'nvars' created variables.
195*/
195static void adjustlocalvars (LexState *ls, int nvars) { 196static void adjustlocalvars (LexState *ls, int nvars) {
196 FuncState *fs = ls->fs; 197 FuncState *fs = ls->fs;
197 fs->nactvar = cast_byte(fs->nactvar + nvars); 198 fs->nactvar = cast_byte(fs->nactvar + nvars);
@@ -1357,7 +1358,6 @@ static void forbody (LexState *ls, int base, int line, int nvars, int kind) {
1357 BlockCnt bl; 1358 BlockCnt bl;
1358 FuncState *fs = ls->fs; 1359 FuncState *fs = ls->fs;
1359 int prep, endfor; 1360 int prep, endfor;
1360 adjustlocalvars(ls, 3); /* control variables */
1361 checknext(ls, TK_DO); 1361 checknext(ls, TK_DO);
1362 prep = luaK_codeABx(fs, forprep[kind], base, 0); 1362 prep = luaK_codeABx(fs, forprep[kind], base, 0);
1363 enterblock(fs, &bl, 0); /* scope for declared variables */ 1363 enterblock(fs, &bl, 0); /* scope for declared variables */
@@ -1399,6 +1399,7 @@ static void fornum (LexState *ls, TString *varname, int line) {
1399 luaK_int(fs, fs->freereg, 1); 1399 luaK_int(fs, fs->freereg, 1);
1400 luaK_reserveregs(fs, 1); 1400 luaK_reserveregs(fs, 1);
1401 } 1401 }
1402 adjustlocalvars(ls, 3); /* control variables */
1402 forbody(ls, base, line, 1, basicfor); 1403 forbody(ls, base, line, 1, basicfor);
1403} 1404}
1404 1405
@@ -1407,7 +1408,7 @@ static void forlist (LexState *ls, TString *indexname) {
1407 /* forlist -> NAME {,NAME} IN explist forbody */ 1408 /* forlist -> NAME {,NAME} IN explist forbody */
1408 FuncState *fs = ls->fs; 1409 FuncState *fs = ls->fs;
1409 expdesc e; 1410 expdesc e;
1410 int nvars = 4; /* gen, state, control, plus at least one declared var */ 1411 int nvars = 5; /* gen, state, control, toclose, 'indexname' */
1411 int line; 1412 int line;
1412 int base = fs->freereg; 1413 int base = fs->freereg;
1413 /* create control variables */ 1414 /* create control variables */
@@ -1415,6 +1416,7 @@ static void forlist (LexState *ls, TString *indexname) {
1415 new_localvarliteral(ls, "(for state)"); 1416 new_localvarliteral(ls, "(for state)");
1416 markupval(fs, fs->nactvar); /* state may create an upvalue */ 1417 markupval(fs, fs->nactvar); /* state may create an upvalue */
1417 new_localvarliteral(ls, "(for control)"); 1418 new_localvarliteral(ls, "(for control)");
1419 new_localvarliteral(ls, "(for toclose)");
1418 /* create declared variables */ 1420 /* create declared variables */
1419 new_localvar(ls, indexname); 1421 new_localvar(ls, indexname);
1420 while (testnext(ls, ',')) { 1422 while (testnext(ls, ',')) {
@@ -1423,9 +1425,10 @@ static void forlist (LexState *ls, TString *indexname) {
1423 } 1425 }
1424 checknext(ls, TK_IN); 1426 checknext(ls, TK_IN);
1425 line = ls->linenumber; 1427 line = ls->linenumber;
1426 adjust_assign(ls, 3, explist(ls, &e), &e); 1428 adjust_assign(ls, 4, explist(ls, &e), &e);
1429 adjustlocalvars(ls, 4); /* control variables */
1427 luaK_checkstack(fs, 3); /* extra space to call generator */ 1430 luaK_checkstack(fs, 3); /* extra space to call generator */
1428 forbody(ls, base, line, nvars - 3, 2); 1431 forbody(ls, base, line, nvars - 4, 2);
1429} 1432}
1430 1433
1431 1434
@@ -1575,9 +1578,9 @@ static void tocloselocalstat (LexState *ls) {
1575 new_localvar(ls, str_checkname(ls)); 1578 new_localvar(ls, str_checkname(ls));
1576 checknext(ls, '='); 1579 checknext(ls, '=');
1577 exp1(ls, 0); 1580 exp1(ls, 0);
1578 luaK_codeABC(fs, OP_TBC, fs->nactvar, 0, 0);
1579 markupval(fs, fs->nactvar); 1581 markupval(fs, fs->nactvar);
1580 adjustlocalvars(ls, 1); 1582 adjustlocalvars(ls, 1);
1583 luaK_codeABC(fs, OP_TBC, fs->nactvar - 1, 0, 0);
1581} 1584}
1582 1585
1583 1586
diff --git a/lvm.c b/lvm.c
index 9977bda4..7d5ab9db 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1654,11 +1654,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1654 vmbreak; 1654 vmbreak;
1655 } 1655 }
1656 vmcase(OP_TFORPREP) { 1656 vmcase(OP_TFORPREP) {
1657 /* is 'state' a function or has a '__close' metamethod? */ 1657 /* is 'toclose' a function or has a '__close' metamethod? */
1658 if (ttisfunction(s2v(ra + 1)) || 1658 if (ttisfunction(s2v(ra + 3)) ||
1659 !ttisnil(luaT_gettmbyobj(L, s2v(ra + 1), TM_CLOSE))) { 1659 !ttisnil(luaT_gettmbyobj(L, s2v(ra + 3), TM_CLOSE))) {
1660 /* create to-be-closed upvalue for it */ 1660 /* create to-be-closed upvalue for it */
1661 halfProtect(luaF_newtbcupval(L, ra + 1)); 1661 halfProtect(luaF_newtbcupval(L, ra + 3));
1662 } 1662 }
1663 pc += GETARG_Bx(i); 1663 pc += GETARG_Bx(i);
1664 i = *(pc++); /* go to next instruction */ 1664 i = *(pc++); /* go to next instruction */
@@ -1668,13 +1668,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1668 vmcase(OP_TFORCALL) { 1668 vmcase(OP_TFORCALL) {
1669 l_tforcall: 1669 l_tforcall:
1670 /* 'ra' has the iterator function, 'ra + 1' has the state, 1670 /* 'ra' has the iterator function, 'ra + 1' has the state,
1671 and 'ra + 2' has the control variable. The call will use 1671 'ra + 2' has the control variable, and 'ra + 3' has the
1672 the stack after these values (starting at 'ra + 3') 1672 to-be-closed variable. The call will use the stack after
1673 these values (starting at 'ra + 4')
1673 */ 1674 */
1674 /* push function, state, and control variable */ 1675 /* push function, state, and control variable */
1675 memcpy(ra + 3, ra, 3 * sizeof(*ra)); 1676 memcpy(ra + 4, ra, 3 * sizeof(*ra));
1676 L->top = ra + 6; 1677 L->top = ra + 4 + 3;
1677 Protect(luaD_call(L, ra + 3, GETARG_C(i))); /* do the call */ 1678 Protect(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
1678 if (trap) { /* stack may have changed? */ 1679 if (trap) { /* stack may have changed? */
1679 updatebase(ci); /* keep 'base' correct */ 1680 updatebase(ci); /* keep 'base' correct */
1680 ra = RA(i); /* keep 'ra' correct for next instruction */ 1681 ra = RA(i); /* keep 'ra' correct for next instruction */
@@ -1686,8 +1687,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1686 } 1687 }
1687 vmcase(OP_TFORLOOP) { 1688 vmcase(OP_TFORLOOP) {
1688 l_tforloop: 1689 l_tforloop:
1689 if (!ttisnil(s2v(ra + 1))) { /* continue loop? */ 1690 if (!ttisnil(s2v(ra + 2))) { /* continue loop? */
1690 setobjs2s(L, ra, ra + 1); /* save control variable */ 1691 setobjs2s(L, ra, ra + 2); /* save control variable */
1691 pc -= GETARG_Bx(i); /* jump back */ 1692 pc -= GETARG_Bx(i); /* jump back */
1692 } 1693 }
1693 vmbreak; 1694 vmbreak;
diff --git a/testes/files.lua b/testes/files.lua
index e68eb9b8..34fcf851 100644
--- a/testes/files.lua
+++ b/testes/files.lua
@@ -200,7 +200,7 @@ return x + y * z
200assert(f:close()) 200assert(f:close())
201f = coroutine.wrap(dofile) 201f = coroutine.wrap(dofile)
202assert(f(file) == 10) 202assert(f(file) == 10)
203print(f(100, 101) == 20) 203assert(f(100, 101) == 20)
204assert(f(200) == 100 + 200 * 101) 204assert(f(200) == 100 + 200 * 101)
205assert(os.remove(file)) 205assert(os.remove(file))
206 206
@@ -422,6 +422,41 @@ assert(load(io.lines(file, "L"), nil, nil, t))()
422assert(t.a == -((10 + 34) * 2)) 422assert(t.a == -((10 + 34) * 2))
423 423
424 424
425do -- testing closing file in line iteration
426
427 -- get the to-be-closed variable from a loop
428 local function gettoclose (lv)
429 lv = lv + 1
430 for i = 1, math.maxinteger do
431 local n, v = debug.getlocal(lv, i)
432 if n == "(for toclose)" then
433 return v
434 end
435 end
436 end
437
438 local f
439 for l in io.lines(file) do
440 f = gettoclose(1)
441 assert(io.type(f) == "file")
442 break
443 end
444 assert(io.type(f) == "closed file")
445
446 f = nil
447 local function foo (name)
448 for l in io.lines(name) do
449 f = gettoclose(1)
450 assert(io.type(f) == "file")
451 error(f) -- exit loop with an error
452 end
453 end
454 local st, msg = pcall(foo, file)
455 assert(st == false and io.type(msg) == "closed file")
456
457end
458
459
425-- test for multipe arguments in 'lines' 460-- test for multipe arguments in 'lines'
426io.output(file); io.write"0123456789\n":close() 461io.output(file); io.write"0123456789\n":close()
427for a,b in io.lines(file, 1, 1) do 462for a,b in io.lines(file, 1, 1) do
diff --git a/testes/locals.lua b/testes/locals.lua
index 869ac1ff..28f88e54 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -371,6 +371,8 @@ do
371 x = x - 1 371 x = x - 1
372 if x > 0 then return x end 372 if x > 0 then return x end
373 end, 373 end,
374 nil, -- state
375 nil, -- control variable
374 function () -- closing function 376 function () -- closing function
375 numopen = numopen - 1 377 numopen = numopen - 1
376 end 378 end
@@ -392,12 +394,16 @@ do
392 -- repeat test with '__open' metamethod instead of a function 394 -- repeat test with '__open' metamethod instead of a function
393 local function open (x) 395 local function open (x)
394 numopen = numopen + 1 396 numopen = numopen + 1
397 local state = setmetatable({x},
398 {__close = function () numopen = numopen - 1 end})
395 return 399 return
396 function (t) -- iteraction function 400 function (t) -- iteraction function
397 t[1] = t[1] - 1 401 t[1] = t[1] - 1
398 if t[1] > 0 then return t[1] end 402 if t[1] > 0 then return t[1] end
399 end, 403 end,
400 setmetatable({x}, {__close = function () numopen = numopen - 1 end}) 404 state,
405 nil,
406 state -- to-be-closed
401 end 407 end
402 408
403 local s = 0 409 local s = 0