aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c44
1 files changed, 19 insertions, 25 deletions
diff --git a/lfunc.c b/lfunc.c
index ae68487c..a8030afa 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -101,31 +101,32 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
101 101
102 102
103/* 103/*
104** Prepare closing method plus its arguments for object 'obj' with 104** Call closing method for object 'obj' with error message 'err'.
105** error message 'err'. (This function assumes EXTRA_STACK.) 105** (This function assumes EXTRA_STACK.)
106*/ 106*/
107static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { 107static void callclosemethod (lua_State *L, TValue *obj, TValue *err) {
108 StkId top = L->top; 108 StkId top = L->top;
109 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); 109 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
110 if (ttisnil(tm)) /* no metamethod? */
111 return 0; /* nothing to call */
112 setobj2s(L, top, tm); /* will call metamethod... */ 110 setobj2s(L, top, tm); /* will call metamethod... */
113 setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ 111 setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
114 setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ 112 setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
115 L->top = top + 3; /* add function and arguments */ 113 L->top = top + 3; /* add function and arguments */
116 return 1; 114 luaD_callnoyield(L, top, 0); /* call method */
117} 115}
118 116
119 117
120/* 118/*
121** Raise an error with message 'msg', inserting the name of the 119** Check whether 'obj' has a close metamethod and raise an error
122** local variable at position 'level' in the stack. 120** if not.
123*/ 121*/
124static void varerror (lua_State *L, StkId level, const char *msg) { 122static void checkclosemth (lua_State *L, StkId level, const TValue *obj) {
125 int idx = cast_int(level - L->ci->func); 123 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
126 const char *vname = luaG_findlocal(L, L->ci, idx, NULL); 124 if (ttisnil(tm)) { /* no metamethod? */
127 if (vname == NULL) vname = "?"; 125 int idx = cast_int(level - L->ci->func); /* variable index */
128 luaG_runerror(L, msg, vname); 126 const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
127 if (vname == NULL) vname = "?";
128 luaG_runerror(L, "variable '%s' got a non-closable value", vname);
129 }
129} 130}
130 131
131 132
@@ -136,7 +137,7 @@ static void varerror (lua_State *L, StkId level, const char *msg) {
136** the 'level' of the upvalue being closed, as everything after that 137** the 'level' of the upvalue being closed, as everything after that
137** won't be used again. 138** won't be used again.
138*/ 139*/
139static void callclosemth (lua_State *L, StkId level, int status) { 140static void prepcallclosemth (lua_State *L, StkId level, int status) {
140 TValue *uv = s2v(level); /* value being closed */ 141 TValue *uv = s2v(level); /* value being closed */
141 TValue *errobj; 142 TValue *errobj;
142 if (status == CLOSEKTOP) 143 if (status == CLOSEKTOP)
@@ -145,10 +146,7 @@ static void callclosemth (lua_State *L, StkId level, int status) {
145 errobj = s2v(level + 1); /* error object goes after 'uv' */ 146 errobj = s2v(level + 1); /* error object goes after 'uv' */
146 luaD_seterrorobj(L, status, level + 1); /* set error object */ 147 luaD_seterrorobj(L, status, level + 1); /* set error object */
147 } 148 }
148 if (prepclosingmethod(L, uv, errobj)) /* something to call? */ 149 callclosemethod(L, uv, errobj);
149 luaD_callnoyield(L, L->top - 3, 0); /* call method */
150 else if (!l_isfalse(uv)) /* non-closable non-false value? */
151 varerror(L, level, "attempt to close non-closable variable '%s'");
152} 150}
153 151
154 152
@@ -171,16 +169,12 @@ void luaF_newtbcupval (lua_State *L, StkId level) {
171 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); 169 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
172 if (!l_isfalse(obj)) { /* false doesn't need to be closed */ 170 if (!l_isfalse(obj)) { /* false doesn't need to be closed */
173 int status; 171 int status;
174 const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); 172 checkclosemth(L, level, obj);
175 if (ttisnil(tm)) /* no metamethod? */
176 varerror(L, level, "variable '%s' got a non-closable value");
177 status = luaD_rawrunprotected(L, trynewtbcupval, level); 173 status = luaD_rawrunprotected(L, trynewtbcupval, level);
178 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ 174 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */
179 lua_assert(status == LUA_ERRMEM); 175 lua_assert(status == LUA_ERRMEM);
180 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ 176 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
181 /* next call must succeed, as object is closable */ 177 callclosemethod(L, s2v(level), s2v(level + 1));
182 prepclosingmethod(L, s2v(level), s2v(level + 1));
183 luaD_callnoyield(L, L->top - 3, 0); /* call method */
184 luaD_throw(L, LUA_ERRMEM); /* throw memory error */ 178 luaD_throw(L, LUA_ERRMEM); /* throw memory error */
185 } 179 }
186 } 180 }
@@ -215,7 +209,7 @@ void luaF_close (lua_State *L, StkId level, int status) {
215 } 209 }
216 if (uv->tbc && status != NOCLOSINGMETH) { 210 if (uv->tbc && status != NOCLOSINGMETH) {
217 ptrdiff_t levelrel = savestack(L, level); 211 ptrdiff_t levelrel = savestack(L, level);
218 callclosemth(L, upl, status); /* may change the stack */ 212 prepcallclosemth(L, upl, status); /* may change the stack */
219 level = restorestack(L, levelrel); 213 level = restorestack(L, levelrel);
220 } 214 }
221 } 215 }