aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/lfunc.c b/lfunc.c
index 16e00731..fde72b8c 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -14,6 +14,7 @@
14 14
15#include "lua.h" 15#include "lua.h"
16 16
17#include "ldo.h"
17#include "lfunc.h" 18#include "lfunc.h"
18#include "lgc.h" 19#include "lgc.h"
19#include "lmem.h" 20#include "lmem.h"
@@ -83,6 +84,40 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
83} 84}
84 85
85 86
87static void callclose (lua_State *L, void *ud) {
88 luaD_callnoyield(L, cast(StkId, ud), 0);
89}
90
91
92static int closeupval (lua_State *L, UpVal *uv, StkId level, int status) {
93 StkId func = level + 1; /* save slot for old error message */
94 if (status != LUA_OK) /* was there an error? */
95 luaD_seterrorobj(L, status, level); /* save error message */
96 else
97 setnilvalue(s2v(level));
98 if (ttisfunction(uv->v)) { /* object to-be-closed is a function? */
99 setobj2s(L, func, uv->v); /* will call it */
100 setobjs2s(L, func + 1, level); /* error msg. as argument */
101 }
102 else { /* try '__close' metamethod */
103 const TValue *tm = luaT_gettmbyobj(L, uv->v, TM_CLOSE);
104 if (ttisnil(tm))
105 return status; /* no metamethod */
106 setobj2s(L, func, tm); /* will call metamethod */
107 setobj2s(L, func + 1, uv->v); /* with 'self' as argument */
108 }
109 L->top = func + 2; /* add function and argument */
110 if (status == LUA_OK) /* not in "error mode"? */
111 callclose(L, func); /* call closing method */
112 else { /* already inside error handler; cannot raise another error */
113 int newstatus = luaD_pcall(L, callclose, func, savestack(L, level), 0);
114 if (newstatus != LUA_OK) /* error when closing? */
115 status = newstatus; /* this will be the new error */
116 }
117 return status;
118}
119
120
86void luaF_unlinkupval (UpVal *uv) { 121void luaF_unlinkupval (UpVal *uv) {
87 lua_assert(upisopen(uv)); 122 lua_assert(upisopen(uv));
88 *uv->u.open.previous = uv->u.open.next; 123 *uv->u.open.previous = uv->u.open.next;
@@ -91,10 +126,10 @@ void luaF_unlinkupval (UpVal *uv) {
91} 126}
92 127
93 128
94void luaF_close (lua_State *L, StkId level) { 129int luaF_close (lua_State *L, StkId level, int status) {
95 UpVal *uv; 130 UpVal *uv;
96 while (L->openupval != NULL && 131 while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
97 (uv = L->openupval, uplevel(uv) >= level)) { 132 StkId upl = uplevel(uv);
98 TValue *slot = &uv->u.value; /* new position for value */ 133 TValue *slot = &uv->u.value; /* new position for value */
99 luaF_unlinkupval(uv); 134 luaF_unlinkupval(uv);
100 setobj(L, slot, uv->v); /* move value to upvalue slot */ 135 setobj(L, slot, uv->v); /* move value to upvalue slot */
@@ -102,7 +137,13 @@ void luaF_close (lua_State *L, StkId level) {
102 if (!iswhite(uv)) 137 if (!iswhite(uv))
103 gray2black(uv); /* closed upvalues cannot be gray */ 138 gray2black(uv); /* closed upvalues cannot be gray */
104 luaC_barrier(L, uv, slot); 139 luaC_barrier(L, uv, slot);
140 if (status >= 0 && uv->tt == LUA_TUPVALTBC) { /* must be closed? */
141 ptrdiff_t levelrel = savestack(L, level);
142 status = closeupval(L, uv, upl, status); /* may reallocate the stack */
143 level = restorestack(L, levelrel);
144 }
105 } 145 }
146 return status;
106} 147}
107 148
108 149