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 |
