diff options
| -rw-r--r-- | lcorolib.c | 58 | ||||
| -rw-r--r-- | ldo.c | 4 | ||||
| -rw-r--r-- | lfunc.c | 18 | ||||
| -rw-r--r-- | lfunc.h | 11 | ||||
| -rw-r--r-- | lstate.c | 27 | ||||
| -rw-r--r-- | ltests.c | 3 | ||||
| -rw-r--r-- | lua.h | 1 | ||||
| -rw-r--r-- | lvm.c | 2 | ||||
| -rw-r--r-- | manual/manual.of | 34 | ||||
| -rw-r--r-- | testes/coroutine.lua | 45 | ||||
| -rw-r--r-- | testes/main.lua | 24 |
11 files changed, 195 insertions, 32 deletions
| @@ -107,29 +107,40 @@ static int luaB_yield (lua_State *L) { | |||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | 109 | ||
| 110 | static int luaB_costatus (lua_State *L) { | 110 | #define COS_RUN 0 |
| 111 | lua_State *co = getco(L); | 111 | #define COS_DEAD 1 |
| 112 | if (L == co) lua_pushliteral(L, "running"); | 112 | #define COS_YIELD 2 |
| 113 | #define COS_NORM 3 | ||
| 114 | |||
| 115 | |||
| 116 | static const char *statname[] = {"running", "dead", "suspended", "normal"}; | ||
| 117 | |||
| 118 | |||
| 119 | static int auxstatus (lua_State *L, lua_State *co) { | ||
| 120 | if (L == co) return COS_RUN; | ||
| 113 | else { | 121 | else { |
| 114 | switch (lua_status(co)) { | 122 | switch (lua_status(co)) { |
| 115 | case LUA_YIELD: | 123 | case LUA_YIELD: |
| 116 | lua_pushliteral(L, "suspended"); | 124 | return COS_YIELD; |
| 117 | break; | ||
| 118 | case LUA_OK: { | 125 | case LUA_OK: { |
| 119 | lua_Debug ar; | 126 | lua_Debug ar; |
| 120 | if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ | 127 | if (lua_getstack(co, 0, &ar)) /* does it have frames? */ |
| 121 | lua_pushliteral(L, "normal"); /* it is running */ | 128 | return COS_NORM; /* it is running */ |
| 122 | else if (lua_gettop(co) == 0) | 129 | else if (lua_gettop(co) == 0) |
| 123 | lua_pushliteral(L, "dead"); | 130 | return COS_DEAD; |
| 124 | else | 131 | else |
| 125 | lua_pushliteral(L, "suspended"); /* initial state */ | 132 | return COS_YIELD; /* initial state */ |
| 126 | break; | ||
| 127 | } | 133 | } |
| 128 | default: /* some error occurred */ | 134 | default: /* some error occurred */ |
| 129 | lua_pushliteral(L, "dead"); | 135 | return COS_DEAD; |
| 130 | break; | ||
| 131 | } | 136 | } |
| 132 | } | 137 | } |
| 138 | } | ||
| 139 | |||
| 140 | |||
| 141 | static int luaB_costatus (lua_State *L) { | ||
| 142 | lua_State *co = getco(L); | ||
| 143 | lua_pushstring(L, statname[auxstatus(L, co)]); | ||
| 133 | return 1; | 144 | return 1; |
| 134 | } | 145 | } |
| 135 | 146 | ||
| @@ -147,6 +158,28 @@ static int luaB_corunning (lua_State *L) { | |||
| 147 | } | 158 | } |
| 148 | 159 | ||
| 149 | 160 | ||
| 161 | static int luaB_kill (lua_State *L) { | ||
| 162 | lua_State *co = getco(L); | ||
| 163 | int status = auxstatus(L, co); | ||
| 164 | switch (status) { | ||
| 165 | case COS_DEAD: case COS_YIELD: { | ||
| 166 | status = lua_resetthread(co); | ||
| 167 | if (status == LUA_OK) { | ||
| 168 | lua_pushboolean(L, 1); | ||
| 169 | return 1; | ||
| 170 | } | ||
| 171 | else { | ||
| 172 | lua_pushboolean(L, 0); | ||
| 173 | lua_xmove(co, L, 1); /* copy error message */ | ||
| 174 | return 2; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | default: /* normal or running coroutine */ | ||
| 178 | return luaL_error(L, "cannot kill a %s coroutine", statname[status]); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | |||
| 182 | |||
| 150 | static const luaL_Reg co_funcs[] = { | 183 | static const luaL_Reg co_funcs[] = { |
| 151 | {"create", luaB_cocreate}, | 184 | {"create", luaB_cocreate}, |
| 152 | {"resume", luaB_coresume}, | 185 | {"resume", luaB_coresume}, |
| @@ -155,6 +188,7 @@ static const luaL_Reg co_funcs[] = { | |||
| 155 | {"wrap", luaB_cowrap}, | 188 | {"wrap", luaB_cowrap}, |
| 156 | {"yield", luaB_yield}, | 189 | {"yield", luaB_yield}, |
| 157 | {"isyieldable", luaB_yieldable}, | 190 | {"isyieldable", luaB_yieldable}, |
| 191 | {"kill", luaB_kill}, | ||
| 158 | {NULL, NULL} | 192 | {NULL, NULL} |
| 159 | }; | 193 | }; |
| 160 | 194 | ||
| @@ -98,6 +98,10 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { | |||
| 98 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); | 98 | setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); |
| 99 | break; | 99 | break; |
| 100 | } | 100 | } |
| 101 | case CLOSEPROTECT: { | ||
| 102 | setnilvalue(s2v(oldtop)); /* no error message */ | ||
| 103 | break; | ||
| 104 | } | ||
| 101 | default: { | 105 | default: { |
| 102 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ | 106 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ |
| 103 | break; | 107 | break; |
| @@ -127,17 +127,18 @@ static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { | |||
| 127 | 127 | ||
| 128 | 128 | ||
| 129 | /* | 129 | /* |
| 130 | ** Prepare and call a closing method. If status is OK, code is | 130 | ** Prepare and call a closing method. If status is OK, code is still |
| 131 | ** still inside the original protected call, and so any error | 131 | ** inside the original protected call, and so any error will be handled |
| 132 | ** will be handled there. Otherwise, a previous error already | 132 | ** there. Otherwise, a previous error already activated original |
| 133 | ** activated original protected call, and so the call to the | 133 | ** protected call, and so the call to the closing method must be |
| 134 | ** closing method must be protected here. | 134 | ** protected here. (A status = CLOSEPROTECT behaves like a previous |
| 135 | ** error, to also run the closing method in protected mode). | ||
| 135 | ** If status is OK, the call to the closing method will be pushed | 136 | ** If status is OK, the call to the closing method will be pushed |
| 136 | ** at the top of the stack. Otherwise, values are pushed after | 137 | ** at the top of the stack. Otherwise, values are pushed after |
| 137 | ** the 'level' of the upvalue being closed, as everything after | 138 | ** the 'level' of the upvalue being closed, as everything after |
| 138 | ** that won't be used again. | 139 | ** that won't be used again. |
| 139 | */ | 140 | */ |
| 140 | static int closeupval (lua_State *L, TValue *uv, StkId level, int status) { | 141 | static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) { |
| 141 | if (likely(status == LUA_OK)) { | 142 | if (likely(status == LUA_OK)) { |
| 142 | if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ | 143 | if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ |
| 143 | callclose(L, NULL); /* call closing method */ | 144 | callclose(L, NULL); /* call closing method */ |
| @@ -207,9 +208,10 @@ int luaF_close (lua_State *L, StkId level, int status) { | |||
| 207 | if (!iswhite(uv)) | 208 | if (!iswhite(uv)) |
| 208 | gray2black(uv); /* closed upvalues cannot be gray */ | 209 | gray2black(uv); /* closed upvalues cannot be gray */ |
| 209 | luaC_barrier(L, uv, slot); | 210 | luaC_barrier(L, uv, slot); |
| 210 | if (status >= 0 && uv->tt == LUA_TUPVALTBC) { /* must be closed? */ | 211 | if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) { |
| 212 | /* must run closing method */ | ||
| 211 | ptrdiff_t levelrel = savestack(L, level); | 213 | ptrdiff_t levelrel = savestack(L, level); |
| 212 | status = closeupval(L, uv->v, upl, status); /* may realloc. the stack */ | 214 | status = callclosemth(L, uv->v, upl, status); /* may change the stack */ |
| 213 | level = restorestack(L, levelrel); | 215 | level = restorestack(L, levelrel); |
| 214 | } | 216 | } |
| 215 | } | 217 | } |
| @@ -42,6 +42,17 @@ | |||
| 42 | #define MAXMISS 10 | 42 | #define MAXMISS 10 |
| 43 | 43 | ||
| 44 | 44 | ||
| 45 | /* | ||
| 46 | ** Special "status" for 'luaF_close' | ||
| 47 | */ | ||
| 48 | |||
| 49 | /* close upvalues without running their closing methods */ | ||
| 50 | #define NOCLOSINGMETH (-1) | ||
| 51 | |||
| 52 | /* close upvalues running all closing methods in protected mode */ | ||
| 53 | #define CLOSEPROTECT (-2) | ||
| 54 | |||
| 55 | |||
| 45 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); | 56 | LUAI_FUNC Proto *luaF_newproto (lua_State *L); |
| 46 | LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); | 57 | LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); |
| 47 | LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); | 58 | LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); |
| @@ -258,7 +258,7 @@ static void preinit_thread (lua_State *L, global_State *g) { | |||
| 258 | 258 | ||
| 259 | static void close_state (lua_State *L) { | 259 | static void close_state (lua_State *L) { |
| 260 | global_State *g = G(L); | 260 | global_State *g = G(L); |
| 261 | luaF_close(L, L->stack, -1); /* close all upvalues for this thread */ | 261 | luaF_close(L, L->stack, CLOSEPROTECT); /* close all upvalues */ |
| 262 | luaC_freeallobjects(L); /* collect all objects */ | 262 | luaC_freeallobjects(L); /* collect all objects */ |
| 263 | if (ttisnil(&g->nilvalue)) /* closing a fully built state? */ | 263 | if (ttisnil(&g->nilvalue)) /* closing a fully built state? */ |
| 264 | luai_userstateclose(L); | 264 | luai_userstateclose(L); |
| @@ -301,7 +301,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { | |||
| 301 | 301 | ||
| 302 | void luaE_freethread (lua_State *L, lua_State *L1) { | 302 | void luaE_freethread (lua_State *L, lua_State *L1) { |
| 303 | LX *l = fromstate(L1); | 303 | LX *l = fromstate(L1); |
| 304 | luaF_close(L1, L1->stack, -1); /* close all upvalues for this thread */ | 304 | luaF_close(L1, L1->stack, NOCLOSINGMETH); /* close all upvalues */ |
| 305 | lua_assert(L1->openupval == NULL); | 305 | lua_assert(L1->openupval == NULL); |
| 306 | luai_userstatefree(L, L1); | 306 | luai_userstatefree(L, L1); |
| 307 | freestack(L1); | 307 | freestack(L1); |
| @@ -309,6 +309,29 @@ void luaE_freethread (lua_State *L, lua_State *L1) { | |||
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | 311 | ||
| 312 | int lua_resetthread (lua_State *L) { | ||
| 313 | CallInfo *ci; | ||
| 314 | int status; | ||
| 315 | lua_lock(L); | ||
| 316 | ci = &L->base_ci; | ||
| 317 | status = luaF_close(L, L->stack, CLOSEPROTECT); | ||
| 318 | setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ | ||
| 319 | if (status != CLOSEPROTECT) /* real errors? */ | ||
| 320 | luaD_seterrorobj(L, status, L->stack + 1); | ||
| 321 | else { | ||
| 322 | status = LUA_OK; | ||
| 323 | L->top = L->stack + 1; | ||
| 324 | } | ||
| 325 | ci->callstatus = CIST_C; | ||
| 326 | ci->func = L->stack; | ||
| 327 | ci->top = L->top + LUA_MINSTACK; | ||
| 328 | L->ci = ci; | ||
| 329 | L->status = status; | ||
| 330 | lua_unlock(L); | ||
| 331 | return status; | ||
| 332 | } | ||
| 333 | |||
| 334 | |||
| 312 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | 335 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { |
| 313 | int i; | 336 | int i; |
| 314 | lua_State *L; | 337 | lua_State *L; |
| @@ -1366,6 +1366,9 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { | |||
| 1366 | else if EQ("newthread") { | 1366 | else if EQ("newthread") { |
| 1367 | lua_newthread(L1); | 1367 | lua_newthread(L1); |
| 1368 | } | 1368 | } |
| 1369 | else if EQ("resetthread") { | ||
| 1370 | lua_pushinteger(L1, lua_resetthread(L1)); | ||
| 1371 | } | ||
| 1369 | else if EQ("newuserdata") { | 1372 | else if EQ("newuserdata") { |
| 1370 | lua_newuserdata(L1, getnum); | 1373 | lua_newuserdata(L1, getnum); |
| 1371 | } | 1374 | } |
| @@ -147,6 +147,7 @@ extern const char lua_ident[]; | |||
| 147 | LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); | 147 | LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); |
| 148 | LUA_API void (lua_close) (lua_State *L); | 148 | LUA_API void (lua_close) (lua_State *L); |
| 149 | LUA_API lua_State *(lua_newthread) (lua_State *L); | 149 | LUA_API lua_State *(lua_newthread) (lua_State *L); |
| 150 | LUA_API int (lua_resetthread) (lua_State *L); | ||
| 150 | 151 | ||
| 151 | LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); | 152 | LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); |
| 152 | 153 | ||
| @@ -1565,7 +1565,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
| 1565 | if (nparams1) /* vararg function? */ | 1565 | if (nparams1) /* vararg function? */ |
| 1566 | delta = ci->u.l.nextraargs + nparams1; | 1566 | delta = ci->u.l.nextraargs + nparams1; |
| 1567 | /* close upvalues from current call */ | 1567 | /* close upvalues from current call */ |
| 1568 | luaF_close(L, base, -1); /* (no to-be-closed vars. here) */ | 1568 | luaF_close(L, base, LUA_OK); |
| 1569 | updatestack(ci); | 1569 | updatestack(ci); |
| 1570 | } | 1570 | } |
| 1571 | if (!ttisfunction(s2v(ra))) { /* not a function? */ | 1571 | if (!ttisfunction(s2v(ra))) { /* not a function? */ |
diff --git a/manual/manual.of b/manual/manual.of index 0e8e3d72..862d032b 100644 --- a/manual/manual.of +++ b/manual/manual.of | |||
| @@ -3927,6 +3927,19 @@ and then pops the top element. | |||
| 3927 | 3927 | ||
| 3928 | } | 3928 | } |
| 3929 | 3929 | ||
| 3930 | @APIEntry{int lua_resetthread (lua_State *L);| | ||
| 3931 | @apii{0,?,-} | ||
| 3932 | |||
| 3933 | Resets a thread, cleaning its call stack and closing all pending | ||
| 3934 | to-be-closed variables. | ||
| 3935 | Returns a status code: | ||
| 3936 | @Lid{LUA_OK} for no errors in closing methods, | ||
| 3937 | or an error status otherwise. | ||
| 3938 | In case of error, | ||
| 3939 | leave the error object on the stack, | ||
| 3940 | |||
| 3941 | } | ||
| 3942 | |||
| 3930 | @APIEntry{int lua_resume (lua_State *L, lua_State *from, int nargs, | 3943 | @APIEntry{int lua_resume (lua_State *L, lua_State *from, int nargs, |
| 3931 | int *nresults);| | 3944 | int *nresults);| |
| 3932 | @apii{?,?,-} | 3945 | @apii{?,?,-} |
| @@ -3948,11 +3961,8 @@ or returned by the body function. | |||
| 3948 | @Lid{LUA_OK} if the coroutine finishes its execution | 3961 | @Lid{LUA_OK} if the coroutine finishes its execution |
| 3949 | without errors, | 3962 | without errors, |
| 3950 | or an error code in case of errors @seeC{lua_pcall}. | 3963 | or an error code in case of errors @seeC{lua_pcall}. |
| 3951 | |||
| 3952 | In case of errors, | 3964 | In case of errors, |
| 3953 | the stack is not unwound, | 3965 | the error object is on the top of the stack. |
| 3954 | so you can use the debug API over it. | ||
| 3955 | The error object is on the top of the stack. | ||
| 3956 | 3966 | ||
| 3957 | To resume a coroutine, | 3967 | To resume a coroutine, |
| 3958 | you remove all results from the last @Lid{lua_yield}, | 3968 | you remove all results from the last @Lid{lua_yield}, |
| @@ -6285,6 +6295,17 @@ it is not inside a non-yieldable @N{C function}. | |||
| 6285 | 6295 | ||
| 6286 | } | 6296 | } |
| 6287 | 6297 | ||
| 6298 | @LibEntry{coroutine.kill(co)| | ||
| 6299 | |||
| 6300 | Kills coroutine @id{co}, | ||
| 6301 | closing all its pending to-be-closed variables | ||
| 6302 | and putting the coroutine in a dead state. | ||
| 6303 | In case of error closing some variable, | ||
| 6304 | returns @false plus the error object; | ||
| 6305 | otherwise returns @true. | ||
| 6306 | |||
| 6307 | } | ||
| 6308 | |||
| 6288 | @LibEntry{coroutine.resume (co [, val1, @Cdots])| | 6309 | @LibEntry{coroutine.resume (co [, val1, @Cdots])| |
| 6289 | 6310 | ||
| 6290 | Starts or continues the execution of coroutine @id{co}. | 6311 | Starts or continues the execution of coroutine @id{co}. |
| @@ -8648,6 +8669,11 @@ has been removed. | |||
| 8648 | When needed, this metamethod must be explicitly defined. | 8669 | When needed, this metamethod must be explicitly defined. |
| 8649 | } | 8670 | } |
| 8650 | 8671 | ||
| 8672 | @item{ | ||
| 8673 | When a coroutine finishes with an error, | ||
| 8674 | its stack is unwound (to run any pending closing methods). | ||
| 8675 | } | ||
| 8676 | |||
| 8651 | } | 8677 | } |
| 8652 | 8678 | ||
| 8653 | } | 8679 | } |
diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 7d42eadd..5674a4dd 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua | |||
| @@ -119,6 +119,51 @@ end | |||
| 119 | assert(#a == 25 and a[#a] == 97) | 119 | assert(#a == 25 and a[#a] == 97) |
| 120 | x, a = nil | 120 | x, a = nil |
| 121 | 121 | ||
| 122 | |||
| 123 | -- coroutine kill | ||
| 124 | do | ||
| 125 | -- ok to kill a dead coroutine | ||
| 126 | local co = coroutine.create(print) | ||
| 127 | assert(coroutine.resume(co, "testing 'coroutine.kill'")) | ||
| 128 | assert(coroutine.status(co) == "dead") | ||
| 129 | assert(coroutine.kill(co)) | ||
| 130 | |||
| 131 | -- cannot kill the running coroutine | ||
| 132 | local st, msg = pcall(coroutine.kill, coroutine.running()) | ||
| 133 | assert(not st and string.find(msg, "running")) | ||
| 134 | |||
| 135 | local main = coroutine.running() | ||
| 136 | |||
| 137 | -- cannot kill a "normal" coroutine | ||
| 138 | ;(coroutine.wrap(function () | ||
| 139 | local st, msg = pcall(coroutine.kill, main) | ||
| 140 | assert(not st and string.find(msg, "normal")) | ||
| 141 | end))() | ||
| 142 | |||
| 143 | -- to-be-closed variables in coroutines | ||
| 144 | local X | ||
| 145 | co = coroutine.create(function () | ||
| 146 | local *toclose x = function (err) assert(err == nil); X = false end | ||
| 147 | X = true | ||
| 148 | coroutine.yield() | ||
| 149 | end) | ||
| 150 | coroutine.resume(co) | ||
| 151 | assert(X) | ||
| 152 | assert(coroutine.kill(co)) | ||
| 153 | assert(not X and coroutine.status(co) == "dead") | ||
| 154 | |||
| 155 | -- error killing a coroutine | ||
| 156 | co = coroutine.create(function() | ||
| 157 | local *toclose x = function (err) assert(err == nil); error(111) end | ||
| 158 | coroutine.yield() | ||
| 159 | end) | ||
| 160 | coroutine.resume(co) | ||
| 161 | local st, msg = coroutine.kill(co) | ||
| 162 | assert(not st and coroutine.status(co) == "dead" and msg == 111) | ||
| 163 | |||
| 164 | end | ||
| 165 | |||
| 166 | |||
| 122 | -- yielding across C boundaries | 167 | -- yielding across C boundaries |
| 123 | 168 | ||
| 124 | co = coroutine.wrap(function() | 169 | co = coroutine.wrap(function() |
diff --git a/testes/main.lua b/testes/main.lua index c7bde0d9..b9dcab1c 100644 --- a/testes/main.lua +++ b/testes/main.lua | |||
| @@ -254,15 +254,15 @@ NoRun("error object is a table value", [[lua %s]], prog) | |||
| 254 | 254 | ||
| 255 | 255 | ||
| 256 | -- chunk broken in many lines | 256 | -- chunk broken in many lines |
| 257 | s = [=[ -- | 257 | s = [=[ -- |
| 258 | function f ( x ) | 258 | function f ( x ) |
| 259 | local a = [[ | 259 | local a = [[ |
| 260 | xuxu | 260 | xuxu |
| 261 | ]] | 261 | ]] |
| 262 | local b = "\ | 262 | local b = "\ |
| 263 | xuxu\n" | 263 | xuxu\n" |
| 264 | if x == 11 then return 1 + 12 , 2 + 20 end --[[ test multiple returns ]] | 264 | if x == 11 then return 1 + 12 , 2 + 20 end --[[ test multiple returns ]] |
| 265 | return x + 1 | 265 | return x + 1 |
| 266 | --\\ | 266 | --\\ |
| 267 | end | 267 | end |
| 268 | return( f( 100 ) ) | 268 | return( f( 100 ) ) |
| @@ -272,10 +272,10 @@ s = string.gsub(s, ' ', '\n\n') -- change all spaces for newlines | |||
| 272 | prepfile(s) | 272 | prepfile(s) |
| 273 | RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) | 273 | RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) |
| 274 | checkprogout("101\n13\t22\n\n") | 274 | checkprogout("101\n13\t22\n\n") |
| 275 | 275 | ||
| 276 | prepfile[[#comment in 1st line without \n at the end]] | 276 | prepfile[[#comment in 1st line without \n at the end]] |
| 277 | RUN('lua %s', prog) | 277 | RUN('lua %s', prog) |
| 278 | 278 | ||
| 279 | prepfile[[#test line number when file starts with comment line | 279 | prepfile[[#test line number when file starts with comment line |
| 280 | debug = require"debug" | 280 | debug = require"debug" |
| 281 | print(debug.getinfo(1).currentline) | 281 | print(debug.getinfo(1).currentline) |
| @@ -306,6 +306,20 @@ NoRun("", "lua %s", prog) -- no message | |||
| 306 | prepfile("os.exit(false, true)") | 306 | prepfile("os.exit(false, true)") |
| 307 | NoRun("", "lua %s", prog) -- no message | 307 | NoRun("", "lua %s", prog) -- no message |
| 308 | 308 | ||
| 309 | |||
| 310 | -- to-be-closed variables in main chunk | ||
| 311 | prepfile[[ | ||
| 312 | local *toclose x = function (err) | ||
| 313 | assert(err == 120) | ||
| 314 | print("Ok") | ||
| 315 | end | ||
| 316 | local *toclose e1 = function () error(120) end | ||
| 317 | os.exit(true, true) | ||
| 318 | ]] | ||
| 319 | RUN('lua %s > %s', prog, out) | ||
| 320 | checkprogout("Ok") | ||
| 321 | |||
| 322 | |||
| 309 | -- remove temporary files | 323 | -- remove temporary files |
| 310 | assert(os.remove(prog)) | 324 | assert(os.remove(prog)) |
| 311 | assert(os.remove(otherprog)) | 325 | assert(os.remove(otherprog)) |
