diff options
Diffstat (limited to 'ldo.c')
-rw-r--r-- | ldo.c | 66 |
1 files changed, 46 insertions, 20 deletions
@@ -103,7 +103,7 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { | |||
103 | break; | 103 | break; |
104 | } | 104 | } |
105 | default: { | 105 | default: { |
106 | lua_assert(errcode >= LUA_ERRRUN); /* real error */ | 106 | lua_assert(errorstatus(errcode)); /* real error */ |
107 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ | 107 | setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ |
108 | break; | 108 | break; |
109 | } | 109 | } |
@@ -593,15 +593,11 @@ static void finishCcall (lua_State *L, int status) { | |||
593 | /* | 593 | /* |
594 | ** Executes "full continuation" (everything in the stack) of a | 594 | ** Executes "full continuation" (everything in the stack) of a |
595 | ** previously interrupted coroutine until the stack is empty (or another | 595 | ** previously interrupted coroutine until the stack is empty (or another |
596 | ** interruption long-jumps out of the loop). If the coroutine is | 596 | ** interruption long-jumps out of the loop). |
597 | ** recovering from an error, 'ud' points to the error status, which must | ||
598 | ** be passed to the first continuation function (otherwise the default | ||
599 | ** status is LUA_YIELD). | ||
600 | */ | 597 | */ |
601 | static void unroll (lua_State *L, void *ud) { | 598 | static void unroll (lua_State *L, void *ud) { |
602 | CallInfo *ci; | 599 | CallInfo *ci; |
603 | if (ud != NULL) /* error status? */ | 600 | UNUSED(ud); |
604 | finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ | ||
605 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ | 601 | while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ |
606 | if (!isLua(ci)) /* C function? */ | 602 | if (!isLua(ci)) /* C function? */ |
607 | finishCcall(L, LUA_YIELD); /* complete its execution */ | 603 | finishCcall(L, LUA_YIELD); /* complete its execution */ |
@@ -628,21 +624,36 @@ static CallInfo *findpcall (lua_State *L) { | |||
628 | 624 | ||
629 | 625 | ||
630 | /* | 626 | /* |
631 | ** Recovers from an error in a coroutine. Finds a recover point (if | 627 | ** Auxiliary structure to call 'recover' in protected mode. |
632 | ** there is one) and completes the execution of the interrupted | ||
633 | ** 'luaD_pcall'. If there is no recover point, returns zero. | ||
634 | */ | 628 | */ |
635 | static int recover (lua_State *L, int status) { | 629 | struct RecoverS { |
636 | CallInfo *ci = findpcall(L); | 630 | int status; |
637 | if (ci == NULL) return 0; /* no recovery point */ | 631 | CallInfo *ci; |
632 | }; | ||
633 | |||
634 | |||
635 | /* | ||
636 | ** Recovers from an error in a coroutine: completes the execution of the | ||
637 | ** interrupted 'luaD_pcall', completes the interrupted C function which | ||
638 | ** called 'lua_pcallk', and continues running the coroutine. If there is | ||
639 | ** an error in 'luaF_close', this function will be called again and the | ||
640 | ** coroutine will continue from where it left. | ||
641 | */ | ||
642 | static void recover (lua_State *L, void *ud) { | ||
643 | struct RecoverS *r = cast(struct RecoverS *, ud); | ||
644 | int status = r->status; | ||
645 | CallInfo *ci = r->ci; /* recover point */ | ||
646 | StkId func = restorestack(L, ci->u2.funcidx); | ||
638 | /* "finish" luaD_pcall */ | 647 | /* "finish" luaD_pcall */ |
639 | L->ci = ci; | 648 | L->ci = ci; |
640 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ | 649 | L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ |
641 | status = luaD_closeprotected(L, ci->u2.funcidx, status); | 650 | luaF_close(L, func, status); /* may change the stack */ |
642 | luaD_seterrorobj(L, status, restorestack(L, ci->u2.funcidx)); | 651 | func = restorestack(L, ci->u2.funcidx); |
652 | luaD_seterrorobj(L, status, func); | ||
643 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ | 653 | luaD_shrinkstack(L); /* restore stack size in case of overflow */ |
644 | L->errfunc = ci->u.c.old_errfunc; | 654 | L->errfunc = ci->u.c.old_errfunc; |
645 | return 1; /* continue running the coroutine */ | 655 | finishCcall(L, status); /* finish 'lua_pcallk' callee */ |
656 | unroll(L, NULL); /* continue running the coroutine */ | ||
646 | } | 657 | } |
647 | 658 | ||
648 | 659 | ||
@@ -692,6 +703,24 @@ static void resume (lua_State *L, void *ud) { | |||
692 | } | 703 | } |
693 | } | 704 | } |
694 | 705 | ||
706 | |||
707 | /* | ||
708 | ** Calls 'recover' in protected mode, repeating while there are | ||
709 | ** recoverable errors, that is, errors inside a protected call. (Any | ||
710 | ** error interrupts 'recover', and this loop protects it again so it | ||
711 | ** can continue.) Stops with a normal end (status == LUA_OK), an yield | ||
712 | ** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't | ||
713 | ** find a recover point). | ||
714 | */ | ||
715 | static int p_recover (lua_State *L, int status) { | ||
716 | struct RecoverS r; | ||
717 | r.status = status; | ||
718 | while (errorstatus(status) && (r.ci = findpcall(L)) != NULL) | ||
719 | r.status = luaD_rawrunprotected(L, recover, &r); | ||
720 | return r.status; | ||
721 | } | ||
722 | |||
723 | |||
695 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | 724 | LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, |
696 | int *nresults) { | 725 | int *nresults) { |
697 | int status; | 726 | int status; |
@@ -709,10 +738,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, | |||
709 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); | 738 | api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); |
710 | status = luaD_rawrunprotected(L, resume, &nargs); | 739 | status = luaD_rawrunprotected(L, resume, &nargs); |
711 | /* continue running after recoverable errors */ | 740 | /* continue running after recoverable errors */ |
712 | while (errorstatus(status) && recover(L, status)) { | 741 | status = p_recover(L, status); |
713 | /* unroll continuation */ | ||
714 | status = luaD_rawrunprotected(L, unroll, &status); | ||
715 | } | ||
716 | if (likely(!errorstatus(status))) | 742 | if (likely(!errorstatus(status))) |
717 | lua_assert(status == L->status); /* normal end or yield */ | 743 | lua_assert(status == L->status); /* normal end or yield */ |
718 | else { /* unrecoverable error */ | 744 | else { /* unrecoverable error */ |