From 7f6f70853c8a2730fca2e95d5968ad52cf470bda Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 7 Nov 2018 14:42:05 -0200 Subject: To-be-closed variable in 'for' loop separated from the state The variable to be closed in a generic 'for' loop now is the 4th value produced in the loop initialization, instead of being the loop state (the 2nd value produced). That allows a loop to use a state with a '__toclose' metamethod but do not close it. (As an example, 'f:lines()' might use the file 'f' as a state for the loop, but it should not close the file when the loop ends.) --- testes/files.lua | 37 ++++++++++++++++++++++++++++++++++++- testes/locals.lua | 8 +++++++- 2 files changed, 43 insertions(+), 2 deletions(-) (limited to 'testes') 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 assert(f:close()) f = coroutine.wrap(dofile) assert(f(file) == 10) -print(f(100, 101) == 20) +assert(f(100, 101) == 20) assert(f(200) == 100 + 200 * 101) assert(os.remove(file)) @@ -422,6 +422,41 @@ assert(load(io.lines(file, "L"), nil, nil, t))() assert(t.a == -((10 + 34) * 2)) +do -- testing closing file in line iteration + + -- get the to-be-closed variable from a loop + local function gettoclose (lv) + lv = lv + 1 + for i = 1, math.maxinteger do + local n, v = debug.getlocal(lv, i) + if n == "(for toclose)" then + return v + end + end + end + + local f + for l in io.lines(file) do + f = gettoclose(1) + assert(io.type(f) == "file") + break + end + assert(io.type(f) == "closed file") + + f = nil + local function foo (name) + for l in io.lines(name) do + f = gettoclose(1) + assert(io.type(f) == "file") + error(f) -- exit loop with an error + end + end + local st, msg = pcall(foo, file) + assert(st == false and io.type(msg) == "closed file") + +end + + -- test for multipe arguments in 'lines' io.output(file); io.write"0123456789\n":close() 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 x = x - 1 if x > 0 then return x end end, + nil, -- state + nil, -- control variable function () -- closing function numopen = numopen - 1 end @@ -392,12 +394,16 @@ do -- repeat test with '__open' metamethod instead of a function local function open (x) numopen = numopen + 1 + local state = setmetatable({x}, + {__close = function () numopen = numopen - 1 end}) return function (t) -- iteraction function t[1] = t[1] - 1 if t[1] > 0 then return t[1] end end, - setmetatable({x}, {__close = function () numopen = numopen - 1 end}) + state, + nil, + state -- to-be-closed end local s = 0 -- cgit v1.2.3-55-g6feb