diff options
Diffstat (limited to 'ltm.c')
-rw-r--r-- | ltm.c | 43 |
1 files changed, 24 insertions, 19 deletions
@@ -116,8 +116,8 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, | |||
116 | } | 116 | } |
117 | 117 | ||
118 | 118 | ||
119 | void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, | 119 | int luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, |
120 | const TValue *p2, StkId res) { | 120 | const TValue *p2, StkId res) { |
121 | ptrdiff_t result = savestack(L, res); | 121 | ptrdiff_t result = savestack(L, res); |
122 | StkId func = L->top.p; | 122 | StkId func = L->top.p; |
123 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ | 123 | setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ |
@@ -131,6 +131,7 @@ void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, | |||
131 | luaD_callnoyield(L, func, 1); | 131 | luaD_callnoyield(L, func, 1); |
132 | res = restorestack(L, result); | 132 | res = restorestack(L, result); |
133 | setobjs2s(L, res, --L->top.p); /* move result to its place */ | 133 | setobjs2s(L, res, --L->top.p); /* move result to its place */ |
134 | return ttypetag(s2v(res)); /* return tag of the result */ | ||
134 | } | 135 | } |
135 | 136 | ||
136 | 137 | ||
@@ -139,15 +140,16 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
139 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ | 140 | const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ |
140 | if (notm(tm)) | 141 | if (notm(tm)) |
141 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ | 142 | tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ |
142 | if (notm(tm)) return 0; | 143 | if (notm(tm)) |
143 | luaT_callTMres(L, tm, p1, p2, res); | 144 | return -1; /* tag method not found */ |
144 | return 1; | 145 | else /* call tag method and return the tag of the result */ |
146 | return luaT_callTMres(L, tm, p1, p2, res); | ||
145 | } | 147 | } |
146 | 148 | ||
147 | 149 | ||
148 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | 150 | void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, |
149 | StkId res, TMS event) { | 151 | StkId res, TMS event) { |
150 | if (l_unlikely(!callbinTM(L, p1, p2, res, event))) { | 152 | if (l_unlikely(callbinTM(L, p1, p2, res, event) < 0)) { |
151 | switch (event) { | 153 | switch (event) { |
152 | case TM_BAND: case TM_BOR: case TM_BXOR: | 154 | case TM_BAND: case TM_BOR: case TM_BXOR: |
153 | case TM_SHL: case TM_SHR: case TM_BNOT: { | 155 | case TM_SHL: case TM_SHR: case TM_BNOT: { |
@@ -164,11 +166,14 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, | |||
164 | } | 166 | } |
165 | 167 | ||
166 | 168 | ||
169 | /* | ||
170 | ** The use of 'p1' after 'callbinTM' is safe because, when a tag | ||
171 | ** method is not found, 'callbinTM' cannot change the stack. | ||
172 | */ | ||
167 | void luaT_tryconcatTM (lua_State *L) { | 173 | void luaT_tryconcatTM (lua_State *L) { |
168 | StkId top = L->top.p; | 174 | StkId p1 = L->top.p - 2; /* first argument */ |
169 | if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, | 175 | if (l_unlikely(callbinTM(L, s2v(p1), s2v(p1 + 1), p1, TM_CONCAT) < 0)) |
170 | TM_CONCAT))) | 176 | luaG_concaterror(L, s2v(p1), s2v(p1 + 1)); |
171 | luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); | ||
172 | } | 177 | } |
173 | 178 | ||
174 | 179 | ||
@@ -200,17 +205,17 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2, | |||
200 | */ | 205 | */ |
201 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, | 206 | int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, |
202 | TMS event) { | 207 | TMS event) { |
203 | if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */ | 208 | int tag = callbinTM(L, p1, p2, L->top.p, event); /* try original event */ |
204 | return !l_isfalse(s2v(L->top.p)); | 209 | if (tag >= 0) /* found tag method? */ |
210 | return !tagisfalse(tag); | ||
205 | #if defined(LUA_COMPAT_LT_LE) | 211 | #if defined(LUA_COMPAT_LT_LE) |
206 | else if (event == TM_LE) { | 212 | else if (event == TM_LE) { |
207 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ | 213 | /* try '!(p2 < p1)' for '(p1 <= p2)' */ |
208 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ | 214 | L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ |
209 | if (callbinTM(L, p2, p1, L->top.p, TM_LT)) { | 215 | tag = callbinTM(L, p2, p1, L->top.p, TM_LT); |
210 | L->ci->callstatus ^= CIST_LEQ; /* clear mark */ | 216 | L->ci->callstatus ^= CIST_LEQ; /* clear mark */ |
211 | return l_isfalse(s2v(L->top.p)); | 217 | if (tag >= 0) /* found tag method? */ |
212 | } | 218 | return tagisfalse(tag); |
213 | /* else error will remove this 'ci'; no need to clear mark */ | ||
214 | } | 219 | } |
215 | #endif | 220 | #endif |
216 | luaG_ordererror(L, p1, p2); /* no metamethod found */ | 221 | luaG_ordererror(L, p1, p2); /* no metamethod found */ |