diff options
-rw-r--r-- | liolib.c | 35 | ||||
-rw-r--r-- | lparser.c | 1 | ||||
-rw-r--r-- | lvm.c | 41 | ||||
-rw-r--r-- | testes/files.lua | 8 | ||||
-rw-r--r-- | testes/locals.lua | 50 |
5 files changed, 111 insertions, 24 deletions
@@ -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 | */ | ||
357 | static void aux_lines (lua_State *L, int toclose) { | 366 | static 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 | */ | ||
374 | static int io_lines (lua_State *L) { | 389 | static 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 | */ |
458 | static int read_number (lua_State *L, FILE *f) { | 478 | static 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 | */ | ||
607 | static int io_readline (lua_State *L) { | 630 | static 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; |
@@ -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); |
@@ -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 |
465 | assert(not load(io.lines(file))) | 465 | assert(not load((io.lines(file)))) |
466 | collectgarbage() -- to close file in previous iteration | 466 | collectgarbage() -- to close file in previous iteration |
467 | load(io.lines(file, "L"))() | 467 | load((io.lines(file, "L")))() |
468 | assert(_G.X == 2) | 468 | assert(_G.X == 2) |
469 | load(io.lines(file, 1))() | 469 | load((io.lines(file, 1)))() |
470 | assert(_G.X == 4) | 470 | assert(_G.X == 4) |
471 | load(io.lines(file, 3))() | 471 | load((io.lines(file, 3)))() |
472 | assert(_G.X == 8) | 472 | assert(_G.X == 8) |
473 | 473 | ||
474 | print('+') | 474 | print('+') |
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'+' | |||
108 | if rawget(_G, "T") then | 108 | if 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) | |||
360 | co() -- start coroutine | 360 | co() -- start coroutine |
361 | assert(co == nil) -- eventually it will be collected | 361 | assert(co == nil) -- eventually it will be collected |
362 | 362 | ||
363 | |||
364 | -- to-be-closed variables in generic for loops | ||
365 | do | ||
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) | ||
409 | end | ||
410 | |||
363 | print('OK') | 411 | print('OK') |
364 | 412 | ||
365 | return 5,f | 413 | return 5,f |