aboutsummaryrefslogtreecommitdiff
path: root/src/lj_meta.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_meta.c')
-rw-r--r--src/lj_meta.c73
1 files changed, 37 insertions, 36 deletions
diff --git a/src/lj_meta.c b/src/lj_meta.c
index 0a526671..dea456f2 100644
--- a/src/lj_meta.c
+++ b/src/lj_meta.c
@@ -12,6 +12,7 @@
12#include "lj_obj.h" 12#include "lj_obj.h"
13#include "lj_gc.h" 13#include "lj_gc.h"
14#include "lj_err.h" 14#include "lj_err.h"
15#include "lj_buf.h"
15#include "lj_str.h" 16#include "lj_str.h"
16#include "lj_tab.h" 17#include "lj_tab.h"
17#include "lj_meta.h" 18#include "lj_meta.h"
@@ -19,6 +20,8 @@
19#include "lj_bc.h" 20#include "lj_bc.h"
20#include "lj_vm.h" 21#include "lj_vm.h"
21#include "lj_strscan.h" 22#include "lj_strscan.h"
23#include "lj_strfmt.h"
24#include "lj_lib.h"
22 25
23/* -- Metamethod handling ------------------------------------------------- */ 26/* -- Metamethod handling ------------------------------------------------- */
24 27
@@ -225,27 +228,14 @@ TValue *lj_meta_arith(lua_State *L, TValue *ra, cTValue *rb, cTValue *rc,
225 } 228 }
226} 229}
227 230
228/* In-place coercion of a number to a string. */
229static LJ_AINLINE int tostring(lua_State *L, TValue *o)
230{
231 if (tvisstr(o)) {
232 return 1;
233 } else if (tvisnumber(o)) {
234 setstrV(L, o, lj_str_fromnumber(L, o));
235 return 1;
236 } else {
237 return 0;
238 }
239}
240
241/* Helper for CAT. Coercion, iterative concat, __concat metamethod. */ 231/* Helper for CAT. Coercion, iterative concat, __concat metamethod. */
242TValue *lj_meta_cat(lua_State *L, TValue *top, int left) 232TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
243{ 233{
244 int fromc = 0; 234 int fromc = 0;
245 if (left < 0) { left = -left; fromc = 1; } 235 if (left < 0) { left = -left; fromc = 1; }
246 do { 236 do {
247 int n = 1; 237 if (!(tvisstr(top) || tvisnumber(top)) ||
248 if (!(tvisstr(top-1) || tvisnumber(top-1)) || !tostring(L, top)) { 238 !(tvisstr(top-1) || tvisnumber(top-1))) {
249 cTValue *mo = lj_meta_lookup(L, top-1, MM_concat); 239 cTValue *mo = lj_meta_lookup(L, top-1, MM_concat);
250 if (tvisnil(mo)) { 240 if (tvisnil(mo)) {
251 mo = lj_meta_lookup(L, top, MM_concat); 241 mo = lj_meta_lookup(L, top, MM_concat);
@@ -271,8 +261,6 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
271 copyTV(L, top, mo); 261 copyTV(L, top, mo);
272 setcont(top-1, lj_cont_cat); 262 setcont(top-1, lj_cont_cat);
273 return top+1; /* Trigger metamethod call. */ 263 return top+1; /* Trigger metamethod call. */
274 } else if (strV(top)->len == 0) { /* Shortcut. */
275 (void)tostring(L, top-1);
276 } else { 264 } else {
277 /* Pick as many strings as possible from the top and concatenate them: 265 /* Pick as many strings as possible from the top and concatenate them:
278 ** 266 **
@@ -281,27 +269,28 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
281 ** concat: [...][CAT stack ...] [result] 269 ** concat: [...][CAT stack ...] [result]
282 ** next step: [...][CAT stack ............] 270 ** next step: [...][CAT stack ............]
283 */ 271 */
284 MSize tlen = strV(top)->len; 272 TValue *e, *o = top;
285 char *buffer; 273 uint64_t tlen = tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM;
286 int i; 274 char *p, *buf;
287 for (n = 1; n <= left && tostring(L, top-n); n++) { 275 do {
288 MSize len = strV(top-n)->len; 276 o--; tlen += tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM;
289 if (len >= LJ_MAX_STR - tlen) 277 } while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1)));
290 lj_err_msg(L, LJ_ERR_STROV); 278 if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV);
291 tlen += len; 279 p = buf = lj_buf_tmp(L, (MSize)tlen);
292 } 280 for (e = top, top = o; o <= e; o++) {
293 buffer = lj_str_needbuf(L, &G(L)->tmpbuf, tlen); 281 if (tvisstr(o)) {
294 n--; 282 GCstr *s = strV(o);
295 tlen = 0; 283 MSize len = s->len;
296 for (i = n; i >= 0; i--) { 284 p = lj_buf_wmem(p, strdata(s), len);
297 MSize len = strV(top-i)->len; 285 } else if (tvisint(o)) {
298 memcpy(buffer + tlen, strVdata(top-i), len); 286 p = lj_strfmt_wint(p, intV(o));
299 tlen += len; 287 } else {
288 lua_assert(tvisnum(o));
289 p = lj_strfmt_wnum(p, o);
290 }
300 } 291 }
301 setstrV(L, top-n, lj_str_new(L, buffer, tlen)); 292 setstrV(L, top, lj_str_new(L, buf, (size_t)(p-buf)));
302 } 293 }
303 left -= n;
304 top -= n;
305 } while (left >= 1); 294 } while (left >= 1);
306 if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) { 295 if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) {
307 if (!fromc) L->top = curr_topL(L); 296 if (!fromc) L->top = curr_topL(L);
@@ -423,6 +412,18 @@ TValue *lj_meta_comp(lua_State *L, cTValue *o1, cTValue *o2, int op)
423 } 412 }
424} 413}
425 414
415/* Helper for ISTYPE and ISNUM. Implicit coercion or error. */
416void lj_meta_istype(lua_State *L, BCReg ra, BCReg tp)
417{
418 L->top = curr_topL(L);
419 ra++; tp--;
420 lua_assert(LJ_DUALNUM || tp != ~LJ_TNUMX); /* ISTYPE -> ISNUM broken. */
421 if (LJ_DUALNUM && tp == ~LJ_TNUMX) lj_lib_checkint(L, ra);
422 else if (tp == ~LJ_TNUMX+1) lj_lib_checknum(L, ra);
423 else if (tp == ~LJ_TSTR) lj_lib_checkstr(L, ra);
424 else lj_err_argtype(L, ra, lj_obj_itypename[tp]);
425}
426
426/* Helper for calls. __call metamethod. */ 427/* Helper for calls. __call metamethod. */
427void lj_meta_call(lua_State *L, TValue *func, TValue *top) 428void lj_meta_call(lua_State *L, TValue *func, TValue *top)
428{ 429{