'lua_toclose' gets the index to be closed as an argument

Sometimes it is useful to mark to-be-closed an index that is not
at the top of the stack (e.g., if the value to be closed came from
a function call returning multiple values).
This commit is contained in:
Roberto Ierusalimschy 2018-11-12 14:15:50 -02:00
parent 9eafe9c053
commit 5fda30b4f9
4 changed files with 22 additions and 13 deletions

13
lapi.c
View File

@ -1207,12 +1207,19 @@ LUA_API int lua_next (lua_State *L, int idx) {
} }
LUA_API void lua_toclose (lua_State *L) { LUA_API void lua_toclose (lua_State *L, int idx) {
int nresults = L->ci->nresults; int nresults;
luaF_newtbcupval(L, L->top - 1); /* create new to-be-closed upvalue */ StkId o;
lua_lock(L);
o = index2stack(L, idx);
nresults = L->ci->nresults;
api_check(L, L->openupval == NULL || uplevel(L->openupval) < o,
"there is an already marked index below");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */ if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */ L->ci->nresults = codeNresults(nresults); /* mark it */
lua_assert(hastocloseCfunc(L->ci->nresults)); lua_assert(hastocloseCfunc(L->ci->nresults));
lua_unlock(L);
} }

View File

@ -1551,7 +1551,7 @@ static struct X { int x; } x;
return lua_yieldk(L1, nres, i, Cfunck); return lua_yieldk(L1, nres, i, Cfunck);
} }
else if EQ("toclose") { else if EQ("toclose") {
lua_toclose(L); lua_toclose(L, getnum);
} }
else luaL_error(L, "unknown instruction %s", buff); else luaL_error(L, "unknown instruction %s", buff);
} }

2
lua.h
View File

@ -333,7 +333,7 @@ LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
LUA_API void (lua_toclose) (lua_State *L); LUA_API void (lua_toclose) (lua_State *L, int idx);
/* /*

View File

@ -985,18 +985,20 @@ do
return x return x
end end
local a = T.testC([[ local a, b = T.testC([[
call 0 1 # create resource call 0 1 # create resource
toclose # mark it to be closed pushint 34
return 1 toclose -2 # mark call result to be closed
toclose -1 # mark number to be closed (will be ignored)
return 2
]], newresource) ]], newresource)
assert(a[1] == 11) assert(a[1] == 11 and b == 34)
assert(#openresource == 0) -- was closed assert(#openresource == 0) -- was closed
-- repeat the test, but calling function in a 'multret' context -- repeat the test, but calling function in a 'multret' context
local a = {T.testC([[ local a = {T.testC([[
call 0 1 # create resource call 0 1 # create resource
toclose # mark it to be closed toclose 2 # mark it to be closed
return 2 return 2
]], newresource)} ]], newresource)}
assert(type(a[1]) == "string" and a[2][1] == 11) assert(type(a[1]) == "string" and a[2][1] == 11)
@ -1005,7 +1007,7 @@ do
-- error -- error
local a, b = pcall(T.testC, [[ local a, b = pcall(T.testC, [[
call 0 1 # create resource call 0 1 # create resource
toclose # mark it to be closed toclose -1 # mark it to be closed
error # resource is the error object error # resource is the error object
]], newresource) ]], newresource)
assert(a == false and b[1] == 11) assert(a == false and b[1] == 11)
@ -1019,10 +1021,10 @@ do
local a = T.testC([[ local a = T.testC([[
pushvalue 2 pushvalue 2
call 0 1 # create resource call 0 1 # create resource
toclose # mark it to be closed toclose -1 # mark it to be closed
pushvalue 2 pushvalue 2
call 0 1 # create another resource call 0 1 # create another resource
toclose # mark it to be closed toclose -1 # mark it to be closed
pushvalue 3 pushvalue 3
pushint 2 # there should be two open resources pushint 2 # there should be two open resources
call 1 0 call 1 0