'__pairs' can also return a to-be-closed object

This commit is contained in:
Roberto I
2025-11-11 15:11:06 -03:00
parent 5b7d998764
commit 4cf498210e
3 changed files with 15 additions and 9 deletions

View File

@@ -279,21 +279,22 @@ static int luaB_next (lua_State *L) {
static int pairscont (lua_State *L, int status, lua_KContext k) { static int pairscont (lua_State *L, int status, lua_KContext k) {
(void)L; (void)status; (void)k; /* unused */ (void)L; (void)status; (void)k; /* unused */
return 3; return 4; /* __pairs did all the work, just return its results */
} }
static int luaB_pairs (lua_State *L) { static int luaB_pairs (lua_State *L) {
luaL_checkany(L, 1); luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */ if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
lua_pushcfunction(L, luaB_next); /* will return generator, */ lua_pushcfunction(L, luaB_next); /* will return generator and */
lua_pushvalue(L, 1); /* state, */ lua_pushvalue(L, 1); /* state */
lua_pushnil(L); /* and initial value */ lua_pushnil(L); /* initial value */
lua_pushnil(L); /* to-be-closed object */
} }
else { else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */ lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */ lua_callk(L, 1, 4, 0, pairscont); /* get 4 values from metamethod */
} }
return 3; return 4;
} }

View File

@@ -6799,11 +6799,11 @@ In particular, you may set existing fields to nil.
@LibEntry{pairs (t)| @LibEntry{pairs (t)|
If @id{t} has a metamethod @idx{__pairs}, If @id{t} has a metamethod @idx{__pairs},
calls it with @id{t} as argument and returns the first three calls it with @id{t} as argument and returns the first four
results from the call. results from the call.
Otherwise, Otherwise,
returns three values: the @Lid{next} function, the table @id{t}, and @nil, returns the @Lid{next} function, the table @id{t}, plus two @nil values,
so that the construction so that the construction
@verbatim{ @verbatim{
for k,v in pairs(t) do @rep{body} end for k,v in pairs(t) do @rep{body} end

View File

@@ -905,13 +905,18 @@ local function foo1 (e,i)
if i <= e.n then return i,a[i] end if i <= e.n then return i,a[i] end
end end
setmetatable(a, {__pairs = function (x) return foo, x, 0 end}) local closed = false
setmetatable(a, {__pairs = function (x)
local tbc = setmetatable({}, {__close = function () closed = true end})
return foo, x, 0, tbc
end})
local i = 0 local i = 0
for k,v in pairs(a) do for k,v in pairs(a) do
i = i + 1 i = i + 1
assert(k == i and v == k+1) assert(k == i and v == k+1)
end end
assert(closed) -- 'tbc' has been closed
a.n = 5 a.n = 5
a[3] = 30 a[3] = 30