From 5fda30b4f9f82b901113a6e666c797f835c708eb Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 12 Nov 2018 14:15:50 -0200 Subject: [PATCH] '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). --- lapi.c | 13 ++++++++++--- ltests.c | 2 +- lua.h | 2 +- testes/api.lua | 18 ++++++++++-------- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lapi.c b/lapi.c index 91a6e389..da866a66 100644 --- a/lapi.c +++ b/lapi.c @@ -1207,12 +1207,19 @@ LUA_API int lua_next (lua_State *L, int idx) { } -LUA_API void lua_toclose (lua_State *L) { - int nresults = L->ci->nresults; - luaF_newtbcupval(L, L->top - 1); /* create new to-be-closed upvalue */ +LUA_API void lua_toclose (lua_State *L, int idx) { + int nresults; + 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? */ L->ci->nresults = codeNresults(nresults); /* mark it */ lua_assert(hastocloseCfunc(L->ci->nresults)); + lua_unlock(L); } diff --git a/ltests.c b/ltests.c index 192ae861..c5c1040a 100644 --- a/ltests.c +++ b/ltests.c @@ -1551,7 +1551,7 @@ static struct X { int x; } x; return lua_yieldk(L1, nres, i, Cfunck); } else if EQ("toclose") { - lua_toclose(L); + lua_toclose(L, getnum); } else luaL_error(L, "unknown instruction %s", buff); } diff --git a/lua.h b/lua.h index fe468c8e..6aa184d1 100644 --- a/lua.h +++ b/lua.h @@ -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 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); /* diff --git a/testes/api.lua b/testes/api.lua index a6ddca8e..ed857fd0 100644 --- a/testes/api.lua +++ b/testes/api.lua @@ -985,18 +985,20 @@ do return x end - local a = T.testC([[ + local a, b = T.testC([[ call 0 1 # create resource - toclose # mark it to be closed - return 1 + pushint 34 + toclose -2 # mark call result to be closed + toclose -1 # mark number to be closed (will be ignored) + return 2 ]], newresource) - assert(a[1] == 11) + assert(a[1] == 11 and b == 34) assert(#openresource == 0) -- was closed -- repeat the test, but calling function in a 'multret' context local a = {T.testC([[ call 0 1 # create resource - toclose # mark it to be closed + toclose 2 # mark it to be closed return 2 ]], newresource)} assert(type(a[1]) == "string" and a[2][1] == 11) @@ -1005,7 +1007,7 @@ do -- error local a, b = pcall(T.testC, [[ call 0 1 # create resource - toclose # mark it to be closed + toclose -1 # mark it to be closed error # resource is the error object ]], newresource) assert(a == false and b[1] == 11) @@ -1019,10 +1021,10 @@ do local a = T.testC([[ pushvalue 2 call 0 1 # create resource - toclose # mark it to be closed + toclose -1 # mark it to be closed pushvalue 2 call 0 1 # create another resource - toclose # mark it to be closed + toclose -1 # mark it to be closed pushvalue 3 pushint 2 # there should be two open resources call 1 0