summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--liolib.c35
-rw-r--r--lparser.c1
-rw-r--r--lvm.c41
-rw-r--r--testes/files.lua8
-rw-r--r--testes/locals.lua50
5 files changed, 111 insertions, 24 deletions
diff --git a/liolib.c b/liolib.c
index 3dc509bd..5881b029 100644
--- a/liolib.c
+++ b/liolib.c
@@ -354,12 +354,22 @@ static int io_readline (lua_State *L);
354*/ 354*/
355#define MAXARGLINE 250 355#define MAXARGLINE 250
356 356
357/*
358** Auxiliar function to create the iteration function for 'lines'.
359** The iteration function is a closure over 'io_readline', with
360** the following upvalues:
361** 1) The file being read (first value in the stack)
362** 2) the number of arguments to read
363** 3) a boolean, true iff file has to be closed when finished ('toclose')
364** *) a variable number of format arguments (rest of the stack)
365*/
357static void aux_lines (lua_State *L, int toclose) { 366static void aux_lines (lua_State *L, int toclose) {
358 int n = lua_gettop(L) - 1; /* number of arguments to read */ 367 int n = lua_gettop(L) - 1; /* number of arguments to read */
359 luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); 368 luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
369 lua_pushvalue(L, 1); /* file */
360 lua_pushinteger(L, n); /* number of arguments to read */ 370 lua_pushinteger(L, n); /* number of arguments to read */
361 lua_pushboolean(L, toclose); /* close/not close file when finished */ 371 lua_pushboolean(L, toclose); /* close/not close file when finished */
362 lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ 372 lua_rotate(L, 2, 3); /* move the three values to their positions */
363 lua_pushcclosure(L, io_readline, 3 + n); 373 lua_pushcclosure(L, io_readline, 3 + n);
364} 374}
365 375
@@ -371,6 +381,11 @@ static int f_lines (lua_State *L) {
371} 381}
372 382
373 383
384/*
385** Return an iteration function for 'io.lines'. If file has to be
386** closed, also returns the file itself as a second result (to be
387** closed as the state at the exit of a generic for).
388*/
374static int io_lines (lua_State *L) { 389static int io_lines (lua_State *L) {
375 int toclose; 390 int toclose;
376 if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ 391 if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
@@ -386,8 +401,13 @@ static int io_lines (lua_State *L) {
386 lua_replace(L, 1); /* put file at index 1 */ 401 lua_replace(L, 1); /* put file at index 1 */
387 toclose = 1; /* close it after iteration */ 402 toclose = 1; /* close it after iteration */
388 } 403 }
389 aux_lines(L, toclose); 404 aux_lines(L, toclose); /* push iteration function */
390 return 1; 405 if (toclose) {
406 lua_pushvalue(L, 1); /* file will be second result */
407 return 2;
408 }
409 else
410 return 1;
391} 411}
392 412
393 413
@@ -453,7 +473,7 @@ static int readdigits (RN *rn, int hex) {
453/* 473/*
454** Read a number: first reads a valid prefix of a numeral into a buffer. 474** Read a number: first reads a valid prefix of a numeral into a buffer.
455** Then it calls 'lua_stringtonumber' to check whether the format is 475** Then it calls 'lua_stringtonumber' to check whether the format is
456** correct and to convert it to a Lua number 476** correct and to convert it to a Lua number.
457*/ 477*/
458static int read_number (lua_State *L, FILE *f) { 478static int read_number (lua_State *L, FILE *f) {
459 RN rn; 479 RN rn;
@@ -604,6 +624,9 @@ static int f_read (lua_State *L) {
604} 624}
605 625
606 626
627/*
628** Iteration function for 'lines'.
629*/
607static int io_readline (lua_State *L) { 630static int io_readline (lua_State *L) {
608 LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); 631 LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
609 int i; 632 int i;
@@ -624,8 +647,8 @@ static int io_readline (lua_State *L) {
624 return luaL_error(L, "%s", lua_tostring(L, -n + 1)); 647 return luaL_error(L, "%s", lua_tostring(L, -n + 1));
625 } 648 }
626 if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ 649 if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
627 lua_settop(L, 0); 650 lua_settop(L, 0); /* clear stack */
628 lua_pushvalue(L, lua_upvalueindex(1)); 651 lua_pushvalue(L, lua_upvalueindex(1)); /* push file at index 1 */
629 aux_close(L); /* close it */ 652 aux_close(L); /* close it */
630 } 653 }
631 return 0; 654 return 0;
diff --git a/lparser.c b/lparser.c
index 9419f880..a5b84aa1 100644
--- a/lparser.c
+++ b/lparser.c
@@ -1413,6 +1413,7 @@ static void forlist (LexState *ls, TString *indexname) {
1413 /* create control variables */ 1413 /* create control variables */
1414 new_localvarliteral(ls, "(for generator)"); 1414 new_localvarliteral(ls, "(for generator)");
1415 new_localvarliteral(ls, "(for state)"); 1415 new_localvarliteral(ls, "(for state)");
1416 markupval(fs, fs->nactvar); /* state may create an upvalue */
1416 new_localvarliteral(ls, "(for control)"); 1417 new_localvarliteral(ls, "(for control)");
1417 /* create declared variables */ 1418 /* create declared variables */
1418 new_localvar(ls, indexname); 1419 new_localvar(ls, indexname);
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) {
diff --git a/testes/files.lua b/testes/files.lua
index 9aae5913..a11c5e61 100644
--- a/testes/files.lua
+++ b/testes/files.lua
@@ -462,13 +462,13 @@ X
462- y; 462- y;
463]]:close() 463]]:close()
464_G.X = 1 464_G.X = 1
465assert(not load(io.lines(file))) 465assert(not load((io.lines(file))))
466collectgarbage() -- to close file in previous iteration 466collectgarbage() -- to close file in previous iteration
467load(io.lines(file, "L"))() 467load((io.lines(file, "L")))()
468assert(_G.X == 2) 468assert(_G.X == 2)
469load(io.lines(file, 1))() 469load((io.lines(file, 1)))()
470assert(_G.X == 4) 470assert(_G.X == 4)
471load(io.lines(file, 3))() 471load((io.lines(file, 3)))()
472assert(_G.X == 8) 472assert(_G.X == 8)
473 473
474print('+') 474print('+')
diff --git a/testes/locals.lua b/testes/locals.lua
index 65b145db..1e0f525b 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -108,7 +108,7 @@ print'+'
108if rawget(_G, "T") then 108if rawget(_G, "T") then
109 -- testing clearing of dead elements from tables 109 -- testing clearing of dead elements from tables
110 collectgarbage("stop") -- stop GC 110 collectgarbage("stop") -- stop GC
111 local a = {[{}] = 4, [3] = 0, alo = 1, 111 local a = {[{}] = 4, [3] = 0, alo = 1,
112 a1234567890123456789012345678901234567890 = 10} 112 a1234567890123456789012345678901234567890 = 10}
113 113
114 local t = T.querytab(a) 114 local t = T.querytab(a)
@@ -360,6 +360,54 @@ end)
360co() -- start coroutine 360co() -- start coroutine
361assert(co == nil) -- eventually it will be collected 361assert(co == nil) -- eventually it will be collected
362 362
363
364-- to-be-closed variables in generic for loops
365do
366 local numopen = 0
367 local function open (x)
368 numopen = numopen + 1
369 return
370 function () -- iteraction function
371 x = x - 1
372 if x > 0 then return x end
373 end,
374 function () -- closing function
375 numopen = numopen - 1
376 end
377 end
378
379 local s = 0
380 for i in open(10) do
381 s = s + i
382 end
383 assert(s == 45 and numopen == 0)
384
385 local s = 0
386 for i in open(10) do
387 if i < 5 then break end
388 s = s + i
389 end
390 assert(s == 35 and numopen == 0)
391
392 -- repeat test with '__open' metamethod instead of a function
393 local function open (x)
394 numopen = numopen + 1
395 return
396 function (t) -- iteraction function
397 t[1] = t[1] - 1
398 if t[1] > 0 then return t[1] end
399 end,
400 setmetatable({x}, {__close = function () numopen = numopen - 1 end})
401 end
402
403 local s = 0
404 for i in open(10) do
405 if (i < 5) then break end
406 s = s + i
407 end
408 assert(s == 35 and numopen == 0)
409end
410
363print('OK') 411print('OK')
364 412
365return 5,f 413return 5,f