diff options
| -rw-r--r-- | ldo.c | 1 | ||||
| -rw-r--r-- | lfunc.c | 24 | ||||
| -rw-r--r-- | ltests.c | 18 | ||||
| -rw-r--r-- | manual/manual.of | 34 | ||||
| -rw-r--r-- | testes/api.lua | 19 | ||||
| -rw-r--r-- | testes/coroutine.lua | 13 | ||||
| -rw-r--r-- | testes/goto.lua | 2 | ||||
| -rw-r--r-- | testes/locals.lua | 54 |
8 files changed, 97 insertions, 68 deletions
| @@ -118,6 +118,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { | |||
| 118 | } | 118 | } |
| 119 | else { /* thread has no error handler */ | 119 | else { /* thread has no error handler */ |
| 120 | global_State *g = G(L); | 120 | global_State *g = G(L); |
| 121 | errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */ | ||
| 121 | L->status = cast_byte(errcode); /* mark it as dead */ | 122 | L->status = cast_byte(errcode); /* mark it as dead */ |
| 122 | if (g->mainthread->errorJmp) { /* main thread has a handler? */ | 123 | if (g->mainthread->errorJmp) { /* main thread has a handler? */ |
| 123 | setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ | 124 | setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ |
| @@ -100,28 +100,23 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { | |||
| 100 | 100 | ||
| 101 | static void callclose (lua_State *L, void *ud) { | 101 | static void callclose (lua_State *L, void *ud) { |
| 102 | UNUSED(ud); | 102 | UNUSED(ud); |
| 103 | luaD_callnoyield(L, L->top - 2, 0); | 103 | luaD_callnoyield(L, L->top - 3, 0); |
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | 106 | ||
| 107 | /* | 107 | /* |
| 108 | ** Prepare closing method plus its argument for object 'obj' with | 108 | ** Prepare closing method plus its arguments for object 'obj' with |
| 109 | ** error message 'err'. (This function assumes EXTRA_STACK.) | 109 | ** error message 'err'. (This function assumes EXTRA_STACK.) |
| 110 | */ | 110 | */ |
| 111 | static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { | 111 | static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { |
| 112 | StkId top = L->top; | 112 | StkId top = L->top; |
| 113 | if (ttisfunction(obj)) { /* object to-be-closed is a function? */ | 113 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); |
| 114 | setobj2s(L, top, obj); /* push function */ | 114 | if (ttisnil(tm)) /* no metamethod? */ |
| 115 | setobj2s(L, top + 1, err); /* push error msg. as argument */ | 115 | return 0; /* nothing to call */ |
| 116 | } | 116 | setobj2s(L, top, tm); /* will call metamethod... */ |
| 117 | else { /* try '__close' metamethod */ | 117 | setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ |
| 118 | const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); | 118 | setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ |
| 119 | if (ttisnil(tm)) /* no metamethod? */ | 119 | L->top = top + 3; /* add function and arguments */ |
| 120 | return 0; /* nothing to call */ | ||
| 121 | setobj2s(L, top, tm); /* will call metamethod... */ | ||
| 122 | setobj2s(L, top + 1, obj); /* with 'self' as the argument */ | ||
| 123 | } | ||
| 124 | L->top = top + 2; /* add function and argument */ | ||
| 125 | return 1; | 120 | return 1; |
| 126 | } | 121 | } |
| 127 | 122 | ||
| @@ -156,6 +151,7 @@ static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) { | |||
| 156 | if (newstatus != LUA_OK) /* another error when closing? */ | 151 | if (newstatus != LUA_OK) /* another error when closing? */ |
| 157 | status = newstatus; /* this will be the new error */ | 152 | status = newstatus; /* this will be the new error */ |
| 158 | } | 153 | } |
| 154 | /* else no metamethod; ignore this case and keep original error */ | ||
| 159 | } | 155 | } |
| 160 | return status; | 156 | return status; |
| 161 | } | 157 | } |
| @@ -1201,8 +1201,8 @@ static const char *const delimits = " \t\n,;"; | |||
| 1201 | static void skip (const char **pc) { | 1201 | static void skip (const char **pc) { |
| 1202 | for (;;) { | 1202 | for (;;) { |
| 1203 | if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; | 1203 | if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; |
| 1204 | else if (**pc == '#') { | 1204 | else if (**pc == '#') { /* comment? */ |
| 1205 | while (**pc != '\n' && **pc != '\0') (*pc)++; | 1205 | while (**pc != '\n' && **pc != '\0') (*pc)++; /* until end-of-line */ |
| 1206 | } | 1206 | } |
| 1207 | else break; | 1207 | else break; |
| 1208 | } | 1208 | } |
| @@ -1544,18 +1544,22 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { | |||
| 1544 | } | 1544 | } |
| 1545 | else if EQ("setfield") { | 1545 | else if EQ("setfield") { |
| 1546 | int t = getindex; | 1546 | int t = getindex; |
| 1547 | lua_setfield(L1, t, getstring); | 1547 | const char *s = getstring; |
| 1548 | lua_setfield(L1, t, s); | ||
| 1548 | } | 1549 | } |
| 1549 | else if EQ("setglobal") { | 1550 | else if EQ("setglobal") { |
| 1550 | lua_setglobal(L1, getstring); | 1551 | const char *s = getstring; |
| 1552 | lua_setglobal(L1, s); | ||
| 1551 | } | 1553 | } |
| 1552 | else if EQ("sethook") { | 1554 | else if EQ("sethook") { |
| 1553 | int mask = getnum; | 1555 | int mask = getnum; |
| 1554 | int count = getnum; | 1556 | int count = getnum; |
| 1555 | sethookaux(L1, mask, count, getstring); | 1557 | const char *s = getstring; |
| 1558 | sethookaux(L1, mask, count, s); | ||
| 1556 | } | 1559 | } |
| 1557 | else if EQ("setmetatable") { | 1560 | else if EQ("setmetatable") { |
| 1558 | lua_setmetatable(L1, getindex); | 1561 | int idx = getindex; |
| 1562 | lua_setmetatable(L1, idx); | ||
| 1559 | } | 1563 | } |
| 1560 | else if EQ("settable") { | 1564 | else if EQ("settable") { |
| 1561 | lua_settable(L1, getindex); | 1565 | lua_settable(L1, getindex); |
| @@ -1620,7 +1624,7 @@ static struct X { int x; } x; | |||
| 1620 | return lua_yieldk(L1, nres, i, Cfunck); | 1624 | return lua_yieldk(L1, nres, i, Cfunck); |
| 1621 | } | 1625 | } |
| 1622 | else if EQ("toclose") { | 1626 | else if EQ("toclose") { |
| 1623 | lua_toclose(L, getnum); | 1627 | lua_toclose(L1, getnum); |
| 1624 | } | 1628 | } |
| 1625 | else luaL_error(L, "unknown instruction %s", buff); | 1629 | else luaL_error(L, "unknown instruction %s", buff); |
| 1626 | } | 1630 | } |
diff --git a/manual/manual.of b/manual/manual.of index d64f0f1a..b9ab1ebe 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
| @@ -1536,33 +1536,29 @@ goes out of scope, including normal block termination, | |||
| 1536 | exiting its block by @Rw{break}/@Rw{goto}/@Rw{return}, | 1536 | exiting its block by @Rw{break}/@Rw{goto}/@Rw{return}, |
| 1537 | or exiting by an error. | 1537 | or exiting by an error. |
| 1538 | 1538 | ||
| 1539 | To \emph{close} a value has the following meaning here: | 1539 | Here, to \emph{close} a value means |
| 1540 | If the value of the variable when it goes out of scope is a function, | 1540 | to call its @idx{__close} metamethod. |
| 1541 | that function is called; | 1541 | If the value is @nil, it is ignored; |
| 1542 | otherwise, if the value has a @idx{__close} metamethod, | 1542 | otherwise, |
| 1543 | that metamethod is called; | 1543 | if it does not have a @idx{__close} metamethod, |
| 1544 | otherwise, if the value is @nil, nothing is done; | 1544 | an error is raised. |
| 1545 | otherwise, an error is raised. | 1545 | When calling the metamethod, |
| 1546 | In the function case, | 1546 | the value itself is passed as the first argument |
| 1547 | if the scope is being closed by an error, | 1547 | and the error object (if any) is passed as a second argument; |
| 1548 | the error object is passed as an argument to the function; | 1548 | if there was no error, the second argument is @nil. |
| 1549 | if there is no error, the function gets @nil. | ||
| 1550 | In the metamethod case, | ||
| 1551 | the value itself always is passed as an argument to the metamethod. | ||
| 1552 | 1549 | ||
| 1553 | If several to-be-closed variables go out of scope at the same event, | 1550 | If several to-be-closed variables go out of scope at the same event, |
| 1554 | they are closed in the reverse order that they were declared. | 1551 | they are closed in the reverse order that they were declared. |
| 1555 | If there is any error while running a closing function, | 1552 | If there is any error while running a closing method, |
| 1556 | that error is handled like an error in the regular code | 1553 | that error is handled like an error in the regular code |
| 1557 | where the variable was defined; | 1554 | where the variable was defined; |
| 1558 | in particular, | 1555 | in particular, |
| 1559 | the other pending closing functions will still be called. | 1556 | the other pending closing methods will still be called. |
| 1560 | 1557 | ||
| 1561 | If a coroutine yields inside a block and is never resumed again, | 1558 | If a coroutine yields inside a block and is never resumed again, |
| 1562 | the variables visible at that block will never go out of scope, | 1559 | the variables visible at that block will never go out of scope, |
| 1563 | and therefore they will not be closed. | 1560 | and therefore they will not be closed. |
| 1564 | Similarly, if a script is interrupted by an unprotected error, | 1561 | (You should use finalizers to handle this case.) |
| 1565 | its to-be-closed variables will not be closed. | ||
| 1566 | 1562 | ||
| 1567 | } | 1563 | } |
| 1568 | 1564 | ||
| @@ -3002,7 +2998,7 @@ and therefore never returns | |||
| 3002 | } | 2998 | } |
| 3003 | 2999 | ||
| 3004 | @APIEntry{int lua_gc (lua_State *L, int what, int data);| | 3000 | @APIEntry{int lua_gc (lua_State *L, int what, int data);| |
| 3005 | @apii{0,0,v} | 3001 | @apii{0,0,-} |
| 3006 | 3002 | ||
| 3007 | Controls the garbage collector. | 3003 | Controls the garbage collector. |
| 3008 | 3004 | ||
| @@ -3056,8 +3052,6 @@ returns a boolean that tells whether the collector is running | |||
| 3056 | For more details about these options, | 3052 | For more details about these options, |
| 3057 | see @Lid{collectgarbage}. | 3053 | see @Lid{collectgarbage}. |
| 3058 | 3054 | ||
| 3059 | This function may raise errors when calling finalizers. | ||
| 3060 | |||
| 3061 | } | 3055 | } |
| 3062 | 3056 | ||
| 3063 | @APIEntry{lua_Alloc lua_getallocf (lua_State *L, void **ud);| | 3057 | @APIEntry{lua_Alloc lua_getallocf (lua_State *L, void **ud);| |
diff --git a/testes/api.lua b/testes/api.lua index 893a36cb..9904dadf 100644 --- a/testes/api.lua +++ b/testes/api.lua | |||
| @@ -396,6 +396,23 @@ do | |||
| 396 | assert(string.find(msg, "stack overflow")) | 396 | assert(string.find(msg, "stack overflow")) |
| 397 | end | 397 | end |
| 398 | 398 | ||
| 399 | -- exit in panic still close to-be-closed variables | ||
| 400 | assert(T.checkpanic([[ | ||
| 401 | pushstring "return {__close = function () Y = 'ho'; end}" | ||
| 402 | newtable | ||
| 403 | loadstring -2 | ||
| 404 | call 0 1 | ||
| 405 | setmetatable -2 | ||
| 406 | toclose -1 | ||
| 407 | pushstring "hi" | ||
| 408 | error | ||
| 409 | ]], | ||
| 410 | [[ | ||
| 411 | getglobal Y | ||
| 412 | concat 2 # concat original error with global Y | ||
| 413 | ]]) == "hiho") | ||
| 414 | |||
| 415 | |||
| 399 | end | 416 | end |
| 400 | 417 | ||
| 401 | -- testing deep C stack | 418 | -- testing deep C stack |
| @@ -1115,7 +1132,7 @@ end) | |||
| 1115 | testamem("to-be-closed variables", function() | 1132 | testamem("to-be-closed variables", function() |
| 1116 | local flag | 1133 | local flag |
| 1117 | do | 1134 | do |
| 1118 | local *toclose x = function () flag = true end | 1135 | local *toclose x = setmetatable({}, {__close = function () flag = true end}) |
| 1119 | flag = false | 1136 | flag = false |
| 1120 | local x = {} | 1137 | local x = {} |
| 1121 | end | 1138 | end |
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index ca30011f..a4321bed 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
| @@ -142,8 +142,15 @@ do | |||
| 142 | 142 | ||
| 143 | -- to-be-closed variables in coroutines | 143 | -- to-be-closed variables in coroutines |
| 144 | local X | 144 | local X |
| 145 | |||
| 146 | local function func2close (f) | ||
| 147 | return setmetatable({}, {__close = f}) | ||
| 148 | end | ||
| 149 | |||
| 145 | co = coroutine.create(function () | 150 | co = coroutine.create(function () |
| 146 | local *toclose x = function (err) assert(err == nil); X = false end | 151 | local *toclose x = func2close(function (self, err) |
| 152 | assert(err == nil); X = false | ||
| 153 | end) | ||
| 147 | X = true | 154 | X = true |
| 148 | coroutine.yield() | 155 | coroutine.yield() |
| 149 | end) | 156 | end) |
| @@ -154,7 +161,9 @@ do | |||
| 154 | 161 | ||
| 155 | -- error killing a coroutine | 162 | -- error killing a coroutine |
| 156 | co = coroutine.create(function() | 163 | co = coroutine.create(function() |
| 157 | local *toclose x = function (err) assert(err == nil); error(111) end | 164 | local *toclose x = func2close(function (self, err) |
| 165 | assert(err == nil); error(111) | ||
| 166 | end) | ||
| 158 | coroutine.yield() | 167 | coroutine.yield() |
| 159 | end) | 168 | end) |
| 160 | coroutine.resume(co) | 169 | coroutine.resume(co) |
diff --git a/testes/goto.lua b/testes/goto.lua index 5d863a42..f3dcfd4a 100644 --- a/testes/goto.lua +++ b/testes/goto.lua | |||
| @@ -258,7 +258,7 @@ do | |||
| 258 | ::L2:: goto L3 | 258 | ::L2:: goto L3 |
| 259 | 259 | ||
| 260 | ::L1:: do | 260 | ::L1:: do |
| 261 | local *toclose a = function () X = true end | 261 | local *toclose a = setmetatable({}, {__close = function () X = true end}) |
| 262 | assert(X == nil) | 262 | assert(X == nil) |
| 263 | if a then goto L2 end -- jumping back out of scope of 'a' | 263 | if a then goto L2 end -- jumping back out of scope of 'a' |
| 264 | end | 264 | end |
diff --git a/testes/locals.lua b/testes/locals.lua index 340af61c..de47ae31 100644 --- a/testes/locals.lua +++ b/testes/locals.lua | |||
| @@ -177,13 +177,19 @@ print"testing to-be-closed variables" | |||
| 177 | 177 | ||
| 178 | local function stack(n) n = ((n == 0) or stack(n - 1)) end | 178 | local function stack(n) n = ((n == 0) or stack(n - 1)) end |
| 179 | 179 | ||
| 180 | local function func2close (f) | ||
| 181 | return setmetatable({}, {__close = f}) | ||
| 182 | end | ||
| 183 | |||
| 180 | 184 | ||
| 181 | do | 185 | do |
| 182 | local a = {} | 186 | local a = {} |
| 183 | do | 187 | do |
| 184 | local *toclose x = setmetatable({"x"}, {__close = function (self) | 188 | local *toclose x = setmetatable({"x"}, {__close = function (self) |
| 185 | a[#a + 1] = self[1] end}) | 189 | a[#a + 1] = self[1] end}) |
| 186 | local *toclose y = function (x) assert(x == nil); a[#a + 1] = "y" end | 190 | local *toclose y = func2close(function (self, err) |
| 191 | assert(err == nil); a[#a + 1] = "y" | ||
| 192 | end) | ||
| 187 | a[#a + 1] = "in" | 193 | a[#a + 1] = "in" |
| 188 | end | 194 | end |
| 189 | a[#a + 1] = "out" | 195 | a[#a + 1] = "out" |
| @@ -193,7 +199,7 @@ end | |||
| 193 | do | 199 | do |
| 194 | local X = false | 200 | local X = false |
| 195 | 201 | ||
| 196 | local function closescope () stack(10); X = true end | 202 | local closescope = func2close(function () stack(10); X = true end) |
| 197 | 203 | ||
| 198 | -- closing functions do not corrupt returning values | 204 | -- closing functions do not corrupt returning values |
| 199 | local function foo (x) | 205 | local function foo (x) |
| @@ -228,13 +234,13 @@ do | |||
| 228 | -- calls cannot be tail in the scope of to-be-closed variables | 234 | -- calls cannot be tail in the scope of to-be-closed variables |
| 229 | local X, Y | 235 | local X, Y |
| 230 | local function foo () | 236 | local function foo () |
| 231 | local *toclose _ = function () Y = 10 end | 237 | local *toclose _ = func2close(function () Y = 10 end) |
| 232 | assert(X == true and Y == nil) -- 'X' not closed yet | 238 | assert(X == true and Y == nil) -- 'X' not closed yet |
| 233 | return 1,2,3 | 239 | return 1,2,3 |
| 234 | end | 240 | end |
| 235 | 241 | ||
| 236 | local function bar () | 242 | local function bar () |
| 237 | local *toclose _ = function () X = false end | 243 | local *toclose _ = func2close(function () X = false end) |
| 238 | X = true | 244 | X = true |
| 239 | do | 245 | do |
| 240 | return foo() -- not a tail call! | 246 | return foo() -- not a tail call! |
| @@ -249,11 +255,15 @@ end | |||
| 249 | do -- errors in __close | 255 | do -- errors in __close |
| 250 | local log = {} | 256 | local log = {} |
| 251 | local function foo (err) | 257 | local function foo (err) |
| 252 | local *toclose x = function (msg) log[#log + 1] = msg; error(1) end | 258 | local *toclose x = |
| 253 | local *toclose x1 = function (msg) log[#log + 1] = msg; end | 259 | func2close(function (self, msg) log[#log + 1] = msg; error(1) end) |
| 254 | local *toclose gc = function () collectgarbage() end | 260 | local *toclose x1 = |
| 255 | local *toclose y = function (msg) log[#log + 1] = msg; error(2) end | 261 | func2close(function (self, msg) log[#log + 1] = msg; end) |
| 256 | local *toclose z = function (msg) log[#log + 1] = msg or 10; error(3) end | 262 | local *toclose gc = func2close(function () collectgarbage() end) |
| 263 | local *toclose y = | ||
| 264 | func2close(function (self, msg) log[#log + 1] = msg; error(2) end) | ||
| 265 | local *toclose z = | ||
| 266 | func2close(function (self, msg) log[#log + 1] = msg or 10; error(3) end) | ||
| 257 | if err then error(4) end | 267 | if err then error(4) end |
| 258 | end | 268 | end |
| 259 | local stat, msg = pcall(foo, false) | 269 | local stat, msg = pcall(foo, false) |
| @@ -282,7 +292,7 @@ do | |||
| 282 | -- with other errors, non-closable values are ignored | 292 | -- with other errors, non-closable values are ignored |
| 283 | local function foo () | 293 | local function foo () |
| 284 | local *toclose x = 34 | 294 | local *toclose x = 34 |
| 285 | local *toclose y = function () error(32) end | 295 | local *toclose y = func2close(function () error(32) end) |
| 286 | end | 296 | end |
| 287 | local stat, msg = pcall(foo) | 297 | local stat, msg = pcall(foo) |
| 288 | assert(not stat and msg == 32) | 298 | assert(not stat and msg == 32) |
| @@ -294,7 +304,7 @@ if rawget(_G, "T") then | |||
| 294 | 304 | ||
| 295 | -- memory error inside closing function | 305 | -- memory error inside closing function |
| 296 | local function foo () | 306 | local function foo () |
| 297 | local *toclose y = function () T.alloccount() end | 307 | local *toclose y = func2close(function () T.alloccount() end) |
| 298 | local *toclose x = setmetatable({}, {__close = function () | 308 | local *toclose x = setmetatable({}, {__close = function () |
| 299 | T.alloccount(0); local x = {} -- force a memory error | 309 | T.alloccount(0); local x = {} -- force a memory error |
| 300 | end}) | 310 | end}) |
| @@ -308,12 +318,12 @@ if rawget(_G, "T") then | |||
| 308 | local _, msg = pcall(foo) | 318 | local _, msg = pcall(foo) |
| 309 | assert(msg == "not enough memory") | 319 | assert(msg == "not enough memory") |
| 310 | 320 | ||
| 311 | local function close (msg) | 321 | local close = func2close(function (self, msg) |
| 312 | T.alloccount() | 322 | T.alloccount() |
| 313 | assert(msg == "not enough memory") | 323 | assert(msg == "not enough memory") |
| 314 | end | 324 | end) |
| 315 | 325 | ||
| 316 | -- set a memory limit and return a closing function to remove the limit | 326 | -- set a memory limit and return a closing object to remove the limit |
| 317 | local function enter (count) | 327 | local function enter (count) |
| 318 | stack(10) -- reserve some stack space | 328 | stack(10) -- reserve some stack space |
| 319 | T.alloccount(count) | 329 | T.alloccount(count) |
| @@ -336,13 +346,13 @@ if rawget(_G, "T") then | |||
| 336 | 346 | ||
| 337 | -- repeat test with extra closing upvalues | 347 | -- repeat test with extra closing upvalues |
| 338 | local function test () | 348 | local function test () |
| 339 | local *toclose xxx = function (msg) | 349 | local *toclose xxx = func2close(function (self, msg) |
| 340 | assert(msg == "not enough memory"); | 350 | assert(msg == "not enough memory"); |
| 341 | error(1000) -- raise another error | 351 | error(1000) -- raise another error |
| 342 | end | 352 | end) |
| 343 | local *toclose xx = function (msg) | 353 | local *toclose xx = func2close(function (self, msg) |
| 344 | assert(msg == "not enough memory"); | 354 | assert(msg == "not enough memory"); |
| 345 | end | 355 | end) |
| 346 | local *toclose x = enter(0) -- set a memory limit | 356 | local *toclose x = enter(0) -- set a memory limit |
| 347 | -- creation of previous upvalue will raise a memory error | 357 | -- creation of previous upvalue will raise a memory error |
| 348 | os.exit(false) -- should not run | 358 | os.exit(false) -- should not run |
| @@ -413,9 +423,9 @@ do | |||
| 413 | local x = false | 423 | local x = false |
| 414 | local y = false | 424 | local y = false |
| 415 | local co = coroutine.create(function () | 425 | local co = coroutine.create(function () |
| 416 | local *toclose xv = function () x = true end | 426 | local *toclose xv = func2close(function () x = true end) |
| 417 | do | 427 | do |
| 418 | local *toclose yv = function () y = true end | 428 | local *toclose yv = func2close(function () y = true end) |
| 419 | coroutine.yield(100) -- yield doesn't close variable | 429 | coroutine.yield(100) -- yield doesn't close variable |
| 420 | end | 430 | end |
| 421 | coroutine.yield(200) -- yield doesn't close variable | 431 | coroutine.yield(200) -- yield doesn't close variable |
| @@ -453,9 +463,7 @@ do | |||
| 453 | end, | 463 | end, |
| 454 | nil, -- state | 464 | nil, -- state |
| 455 | nil, -- control variable | 465 | nil, -- control variable |
| 456 | function () -- closing function | 466 | func2close(function () numopen = numopen - 1 end) -- closing function |
| 457 | numopen = numopen - 1 | ||
| 458 | end | ||
| 459 | end | 467 | end |
| 460 | 468 | ||
| 461 | local s = 0 | 469 | local s = 0 |
