diff options
Diffstat (limited to 'lfunc.c')
-rw-r--r-- | lfunc.c | 47 |
1 files changed, 44 insertions, 3 deletions
@@ -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 | ||
87 | static void callclose (lua_State *L, void *ud) { | ||
88 | luaD_callnoyield(L, cast(StkId, ud), 0); | ||
89 | } | ||
90 | |||
91 | |||
92 | static 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 | |||
86 | void luaF_unlinkupval (UpVal *uv) { | 121 | void 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 | ||
94 | void luaF_close (lua_State *L, StkId level) { | 129 | int 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 | ||