diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-11-12 14:15:50 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-11-12 14:15:50 -0200 |
| commit | 5fda30b4f9f82b901113a6e666c797f835c708eb (patch) | |
| tree | a8011434f8c2ccee920d955db05ba4917a00e5f8 | |
| parent | 9eafe9c053ef17a0980ab32082bf229bd58e963b (diff) | |
| download | lua-5fda30b4f9f82b901113a6e666c797f835c708eb.tar.gz lua-5fda30b4f9f82b901113a6e666c797f835c708eb.tar.bz2 lua-5fda30b4f9f82b901113a6e666c797f835c708eb.zip | |
'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).
| -rw-r--r-- | lapi.c | 13 | ||||
| -rw-r--r-- | ltests.c | 2 | ||||
| -rw-r--r-- | lua.h | 2 | ||||
| -rw-r--r-- | testes/api.lua | 18 |
4 files changed, 22 insertions, 13 deletions
| @@ -1207,12 +1207,19 @@ LUA_API int lua_next (lua_State *L, int idx) { | |||
| 1207 | } | 1207 | } |
| 1208 | 1208 | ||
| 1209 | 1209 | ||
| 1210 | LUA_API void lua_toclose (lua_State *L) { | 1210 | LUA_API void lua_toclose (lua_State *L, int idx) { |
| 1211 | int nresults = L->ci->nresults; | 1211 | int nresults; |
| 1212 | luaF_newtbcupval(L, L->top - 1); /* create new to-be-closed upvalue */ | 1212 | StkId o; |
| 1213 | lua_lock(L); | ||
| 1214 | o = index2stack(L, idx); | ||
| 1215 | nresults = L->ci->nresults; | ||
| 1216 | api_check(L, L->openupval == NULL || uplevel(L->openupval) < o, | ||
| 1217 | "there is an already marked index below"); | ||
| 1218 | luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ | ||
| 1213 | if (!hastocloseCfunc(nresults)) /* function not marked yet? */ | 1219 | if (!hastocloseCfunc(nresults)) /* function not marked yet? */ |
| 1214 | L->ci->nresults = codeNresults(nresults); /* mark it */ | 1220 | L->ci->nresults = codeNresults(nresults); /* mark it */ |
| 1215 | lua_assert(hastocloseCfunc(L->ci->nresults)); | 1221 | lua_assert(hastocloseCfunc(L->ci->nresults)); |
| 1222 | lua_unlock(L); | ||
| 1216 | } | 1223 | } |
| 1217 | 1224 | ||
| 1218 | 1225 | ||
| @@ -1551,7 +1551,7 @@ static struct X { int x; } x; | |||
| 1551 | return lua_yieldk(L1, nres, i, Cfunck); | 1551 | return lua_yieldk(L1, nres, i, Cfunck); |
| 1552 | } | 1552 | } |
| 1553 | else if EQ("toclose") { | 1553 | else if EQ("toclose") { |
| 1554 | lua_toclose(L); | 1554 | lua_toclose(L, getnum); |
| 1555 | } | 1555 | } |
| 1556 | else luaL_error(L, "unknown instruction %s", buff); | 1556 | else luaL_error(L, "unknown instruction %s", buff); |
| 1557 | } | 1557 | } |
| @@ -333,7 +333,7 @@ LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); | |||
| 333 | LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); | 333 | LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); |
| 334 | LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); | 334 | LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); |
| 335 | 335 | ||
| 336 | LUA_API void (lua_toclose) (lua_State *L); | 336 | LUA_API void (lua_toclose) (lua_State *L, int idx); |
| 337 | 337 | ||
| 338 | 338 | ||
| 339 | /* | 339 | /* |
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 | |||
| 985 | return x | 985 | return x |
| 986 | end | 986 | end |
| 987 | 987 | ||
| 988 | local a = T.testC([[ | 988 | local a, b = T.testC([[ |
| 989 | call 0 1 # create resource | 989 | call 0 1 # create resource |
| 990 | toclose # mark it to be closed | 990 | pushint 34 |
| 991 | return 1 | 991 | toclose -2 # mark call result to be closed |
| 992 | toclose -1 # mark number to be closed (will be ignored) | ||
| 993 | return 2 | ||
| 992 | ]], newresource) | 994 | ]], newresource) |
| 993 | assert(a[1] == 11) | 995 | assert(a[1] == 11 and b == 34) |
| 994 | assert(#openresource == 0) -- was closed | 996 | assert(#openresource == 0) -- was closed |
| 995 | 997 | ||
| 996 | -- repeat the test, but calling function in a 'multret' context | 998 | -- repeat the test, but calling function in a 'multret' context |
| 997 | local a = {T.testC([[ | 999 | local a = {T.testC([[ |
| 998 | call 0 1 # create resource | 1000 | call 0 1 # create resource |
| 999 | toclose # mark it to be closed | 1001 | toclose 2 # mark it to be closed |
| 1000 | return 2 | 1002 | return 2 |
| 1001 | ]], newresource)} | 1003 | ]], newresource)} |
| 1002 | assert(type(a[1]) == "string" and a[2][1] == 11) | 1004 | assert(type(a[1]) == "string" and a[2][1] == 11) |
| @@ -1005,7 +1007,7 @@ do | |||
| 1005 | -- error | 1007 | -- error |
| 1006 | local a, b = pcall(T.testC, [[ | 1008 | local a, b = pcall(T.testC, [[ |
| 1007 | call 0 1 # create resource | 1009 | call 0 1 # create resource |
| 1008 | toclose # mark it to be closed | 1010 | toclose -1 # mark it to be closed |
| 1009 | error # resource is the error object | 1011 | error # resource is the error object |
| 1010 | ]], newresource) | 1012 | ]], newresource) |
| 1011 | assert(a == false and b[1] == 11) | 1013 | assert(a == false and b[1] == 11) |
| @@ -1019,10 +1021,10 @@ do | |||
| 1019 | local a = T.testC([[ | 1021 | local a = T.testC([[ |
| 1020 | pushvalue 2 | 1022 | pushvalue 2 |
| 1021 | call 0 1 # create resource | 1023 | call 0 1 # create resource |
| 1022 | toclose # mark it to be closed | 1024 | toclose -1 # mark it to be closed |
| 1023 | pushvalue 2 | 1025 | pushvalue 2 |
| 1024 | call 0 1 # create another resource | 1026 | call 0 1 # create another resource |
| 1025 | toclose # mark it to be closed | 1027 | toclose -1 # mark it to be closed |
| 1026 | pushvalue 3 | 1028 | pushvalue 3 |
| 1027 | pushint 2 # there should be two open resources | 1029 | pushint 2 # there should be two open resources |
| 1028 | call 1 0 | 1030 | call 1 0 |
