diff options
| -rw-r--r-- | liolib.c | 6 | ||||
| -rw-r--r-- | lopcodes.h | 6 | ||||
| -rw-r--r-- | lparser.c | 25 | ||||
| -rw-r--r-- | lvm.c | 23 | ||||
| -rw-r--r-- | testes/files.lua | 37 | ||||
| -rw-r--r-- | testes/locals.lua | 8 |
6 files changed, 76 insertions, 29 deletions
| @@ -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; |
| @@ -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) } */ |
| 280 | OP_FORPREP,/* A Bx R(A)-=R(A+2); pc+=Bx */ | 280 | OP_FORPREP,/* A Bx R(A)-=R(A+2); pc+=Bx */ |
| 281 | 281 | ||
| 282 | OP_TFORPREP,/* A Bx create upvalue A; pc+=Bx */ | 282 | OP_TFORPREP,/* A Bx create upvalue for R(A + 3); pc+=Bx */ |
| 283 | OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ | 283 | OP_TFORCALL,/* A C R(A+4), ... ,R(A+3+C) := R(A)(R(A+1), R(A+2)); */ |
| 284 | OP_TFORLOOP,/* A Bx if R(A+1) ~= nil then { R(A)=R(A+1); pc -= Bx } */ | 284 | OP_TFORLOOP,/* A Bx if R(A+2) ~= nil then { R(A)=R(A+2); pc -= Bx } */ |
| 285 | 285 | ||
| 286 | OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ | 286 | OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ |
| 287 | 287 | ||
| @@ -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 | */ | ||
| 168 | static void new_localvar (LexState *ls, TString *name) { | 171 | static 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 | |||
| 180 | static 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 | ||
| 188 | static LocVar *getlocvar (FuncState *fs, int i) { | 186 | static 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 | */ | ||
| 195 | static void adjustlocalvars (LexState *ls, int nvars) { | 196 | static 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 | ||
| @@ -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 | |||
| 200 | assert(f:close()) | 200 | assert(f:close()) |
| 201 | f = coroutine.wrap(dofile) | 201 | f = coroutine.wrap(dofile) |
| 202 | assert(f(file) == 10) | 202 | assert(f(file) == 10) |
| 203 | print(f(100, 101) == 20) | 203 | assert(f(100, 101) == 20) |
| 204 | assert(f(200) == 100 + 200 * 101) | 204 | assert(f(200) == 100 + 200 * 101) |
| 205 | assert(os.remove(file)) | 205 | assert(os.remove(file)) |
| 206 | 206 | ||
| @@ -422,6 +422,41 @@ assert(load(io.lines(file, "L"), nil, nil, t))() | |||
| 422 | assert(t.a == -((10 + 34) * 2)) | 422 | assert(t.a == -((10 + 34) * 2)) |
| 423 | 423 | ||
| 424 | 424 | ||
| 425 | do -- 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 | |||
| 457 | end | ||
| 458 | |||
| 459 | |||
| 425 | -- test for multipe arguments in 'lines' | 460 | -- test for multipe arguments in 'lines' |
| 426 | io.output(file); io.write"0123456789\n":close() | 461 | io.output(file); io.write"0123456789\n":close() |
| 427 | for a,b in io.lines(file, 1, 1) do | 462 | for 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 |
