diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.dep | 3 | ||||
-rw-r--r-- | src/lib_string.c | 85 | ||||
-rw-r--r-- | src/lj_strfmt.c | 117 | ||||
-rw-r--r-- | src/lj_strfmt.h | 5 |
4 files changed, 121 insertions, 89 deletions
diff --git a/src/Makefile.dep b/src/Makefile.dep index 315bf632..0bf63391 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep | |||
@@ -197,7 +197,8 @@ lj_state.o: lj_state.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | |||
197 | lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | 197 | lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ |
198 | lj_err.h lj_errmsg.h lj_str.h lj_char.h lj_prng.h | 198 | lj_err.h lj_errmsg.h lj_str.h lj_char.h lj_prng.h |
199 | lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 199 | lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
200 | lj_buf.h lj_gc.h lj_str.h lj_state.h lj_char.h lj_strfmt.h | 200 | lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_meta.h lj_state.h \ |
201 | lj_char.h lj_strfmt.h lj_lib.h | ||
201 | lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \ | 202 | lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \ |
202 | lj_arch.h lj_buf.h lj_gc.h lj_str.h lj_strfmt.h | 203 | lj_arch.h lj_buf.h lj_gc.h lj_str.h lj_strfmt.h |
203 | lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ | 204 | lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ |
diff --git a/src/lib_string.c b/src/lib_string.c index 4a3ff372..75d855d6 100644 --- a/src/lib_string.c +++ b/src/lib_string.c | |||
@@ -640,89 +640,14 @@ LJLIB_CF(string_gsub) | |||
640 | 640 | ||
641 | /* ------------------------------------------------------------------------ */ | 641 | /* ------------------------------------------------------------------------ */ |
642 | 642 | ||
643 | /* Emulate tostring() inline. */ | ||
644 | static GCstr *string_fmt_tostring(lua_State *L, int arg, int retry) | ||
645 | { | ||
646 | TValue *o = L->base+arg-1; | ||
647 | cTValue *mo; | ||
648 | lj_assertL(o < L->top, "bad usage"); /* Caller already checks for existence. */ | ||
649 | if (LJ_LIKELY(tvisstr(o))) | ||
650 | return strV(o); | ||
651 | if (retry != 2 && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { | ||
652 | copyTV(L, L->top++, mo); | ||
653 | copyTV(L, L->top++, o); | ||
654 | lua_call(L, 1, 1); | ||
655 | copyTV(L, L->base+arg-1, --L->top); | ||
656 | return NULL; /* Buffer may be overwritten, retry. */ | ||
657 | } | ||
658 | return lj_strfmt_obj(L, o); | ||
659 | } | ||
660 | |||
661 | LJLIB_CF(string_format) LJLIB_REC(.) | 643 | LJLIB_CF(string_format) LJLIB_REC(.) |
662 | { | 644 | { |
663 | int arg, top = (int)(L->top - L->base); | ||
664 | GCstr *fmt; | ||
665 | SBuf *sb; | ||
666 | FormatState fs; | ||
667 | SFormat sf; | ||
668 | int retry = 0; | 645 | int retry = 0; |
669 | again: | 646 | SBuf *sb; |
670 | arg = 1; | 647 | do { |
671 | sb = lj_buf_tmp_(L); | 648 | sb = lj_buf_tmp_(L); |
672 | fmt = lj_lib_checkstr(L, arg); | 649 | retry = lj_strfmt_putarg(L, sb, 1, -retry); |
673 | lj_strfmt_init(&fs, strdata(fmt), fmt->len); | 650 | } while (retry > 0); |
674 | while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { | ||
675 | if (sf == STRFMT_LIT) { | ||
676 | lj_buf_putmem(sb, fs.str, fs.len); | ||
677 | } else if (sf == STRFMT_ERR) { | ||
678 | lj_err_callerv(L, LJ_ERR_STRFMT, strdata(lj_str_new(L, fs.str, fs.len))); | ||
679 | } else { | ||
680 | if (++arg > top) | ||
681 | luaL_argerror(L, arg, lj_obj_typename[0]); | ||
682 | switch (STRFMT_TYPE(sf)) { | ||
683 | case STRFMT_INT: | ||
684 | if (tvisint(L->base+arg-1)) { | ||
685 | int32_t k = intV(L->base+arg-1); | ||
686 | if (sf == STRFMT_INT) | ||
687 | lj_strfmt_putint(sb, k); /* Shortcut for plain %d. */ | ||
688 | else | ||
689 | lj_strfmt_putfxint(sb, sf, k); | ||
690 | } else { | ||
691 | lj_strfmt_putfnum_int(sb, sf, lj_lib_checknum(L, arg)); | ||
692 | } | ||
693 | break; | ||
694 | case STRFMT_UINT: | ||
695 | if (tvisint(L->base+arg-1)) | ||
696 | lj_strfmt_putfxint(sb, sf, intV(L->base+arg-1)); | ||
697 | else | ||
698 | lj_strfmt_putfnum_uint(sb, sf, lj_lib_checknum(L, arg)); | ||
699 | break; | ||
700 | case STRFMT_NUM: | ||
701 | lj_strfmt_putfnum(sb, sf, lj_lib_checknum(L, arg)); | ||
702 | break; | ||
703 | case STRFMT_STR: { | ||
704 | GCstr *str = string_fmt_tostring(L, arg, retry); | ||
705 | if (str == NULL) | ||
706 | retry = 1; | ||
707 | else if ((sf & STRFMT_T_QUOTED)) | ||
708 | lj_strfmt_putquoted(sb, str); /* No formatting. */ | ||
709 | else | ||
710 | lj_strfmt_putfstr(sb, sf, str); | ||
711 | break; | ||
712 | } | ||
713 | case STRFMT_CHAR: | ||
714 | lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg)); | ||
715 | break; | ||
716 | case STRFMT_PTR: /* No formatting. */ | ||
717 | lj_strfmt_putptr(sb, lj_obj_ptr(G(L), L->base+arg-1)); | ||
718 | break; | ||
719 | default: | ||
720 | lj_assertL(0, "bad string format type"); | ||
721 | break; | ||
722 | } | ||
723 | } | ||
724 | } | ||
725 | if (retry++ == 1) goto again; | ||
726 | setstrV(L, L->top-1, lj_buf_str(L, sb)); | 651 | setstrV(L, L->top-1, lj_buf_str(L, sb)); |
727 | lj_gc_check(L); | 652 | lj_gc_check(L); |
728 | return 1; | 653 | return 1; |
diff --git a/src/lj_strfmt.c b/src/lj_strfmt.c index bde3ec0e..a9541d41 100644 --- a/src/lj_strfmt.c +++ b/src/lj_strfmt.c | |||
@@ -9,11 +9,14 @@ | |||
9 | #define LUA_CORE | 9 | #define LUA_CORE |
10 | 10 | ||
11 | #include "lj_obj.h" | 11 | #include "lj_obj.h" |
12 | #include "lj_err.h" | ||
12 | #include "lj_buf.h" | 13 | #include "lj_buf.h" |
13 | #include "lj_str.h" | 14 | #include "lj_str.h" |
15 | #include "lj_meta.h" | ||
14 | #include "lj_state.h" | 16 | #include "lj_state.h" |
15 | #include "lj_char.h" | 17 | #include "lj_char.h" |
16 | #include "lj_strfmt.h" | 18 | #include "lj_strfmt.h" |
19 | #include "lj_lib.h" | ||
17 | 20 | ||
18 | /* -- Format parser ------------------------------------------------------- */ | 21 | /* -- Format parser ------------------------------------------------------- */ |
19 | 22 | ||
@@ -196,10 +199,8 @@ SBuf * LJ_FASTCALL lj_strfmt_putptr(SBuf *sb, const void *v) | |||
196 | } | 199 | } |
197 | 200 | ||
198 | /* Add quoted string to buffer. */ | 201 | /* Add quoted string to buffer. */ |
199 | SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str) | 202 | static SBuf *strfmt_putquotedlen(SBuf *sb, const char *s, MSize len) |
200 | { | 203 | { |
201 | const char *s = strdata(str); | ||
202 | MSize len = str->len; | ||
203 | lj_buf_putb(sb, '"'); | 204 | lj_buf_putb(sb, '"'); |
204 | while (len--) { | 205 | while (len--) { |
205 | uint32_t c = (uint32_t)(uint8_t)*s++; | 206 | uint32_t c = (uint32_t)(uint8_t)*s++; |
@@ -225,6 +226,13 @@ SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str) | |||
225 | return sb; | 226 | return sb; |
226 | } | 227 | } |
227 | 228 | ||
229 | #if LJ_HASJIT | ||
230 | SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str) | ||
231 | { | ||
232 | return strfmt_putquotedlen(sb, strdata(str), str->len); | ||
233 | } | ||
234 | #endif | ||
235 | |||
228 | /* -- Formatted conversions to buffer ------------------------------------- */ | 236 | /* -- Formatted conversions to buffer ------------------------------------- */ |
229 | 237 | ||
230 | /* Add formatted char to buffer. */ | 238 | /* Add formatted char to buffer. */ |
@@ -240,18 +248,26 @@ SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat sf, int32_t c) | |||
240 | } | 248 | } |
241 | 249 | ||
242 | /* Add formatted string to buffer. */ | 250 | /* Add formatted string to buffer. */ |
243 | SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat sf, GCstr *str) | 251 | static SBuf *strfmt_putfstrlen(SBuf *sb, SFormat sf, const char *s, MSize len) |
244 | { | 252 | { |
245 | MSize len = str->len <= STRFMT_PREC(sf) ? str->len : STRFMT_PREC(sf); | ||
246 | MSize width = STRFMT_WIDTH(sf); | 253 | MSize width = STRFMT_WIDTH(sf); |
247 | char *w = lj_buf_more(sb, width > len ? width : len); | 254 | char *w; |
248 | if ((sf & STRFMT_F_LEFT)) w = lj_buf_wmem(w, strdata(str), len); | 255 | if (len > STRFMT_PREC(sf)) len = STRFMT_PREC(sf); |
256 | w = lj_buf_more(sb, width > len ? width : len); | ||
257 | if ((sf & STRFMT_F_LEFT)) w = lj_buf_wmem(w, s, len); | ||
249 | while (width-- > len) *w++ = ' '; | 258 | while (width-- > len) *w++ = ' '; |
250 | if (!(sf & STRFMT_F_LEFT)) w = lj_buf_wmem(w, strdata(str), len); | 259 | if (!(sf & STRFMT_F_LEFT)) w = lj_buf_wmem(w, s, len); |
251 | sb->w = w; | 260 | sb->w = w; |
252 | return sb; | 261 | return sb; |
253 | } | 262 | } |
254 | 263 | ||
264 | #if LJ_HASJIT | ||
265 | SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat sf, GCstr *str) | ||
266 | { | ||
267 | return strfmt_putfstrlen(sb, sf, strdata(str), str->len); | ||
268 | } | ||
269 | #endif | ||
270 | |||
255 | /* Add formatted signed/unsigned integer to buffer. */ | 271 | /* Add formatted signed/unsigned integer to buffer. */ |
256 | SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k) | 272 | SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k) |
257 | { | 273 | { |
@@ -346,6 +362,91 @@ SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n) | |||
346 | return lj_strfmt_putfxint(sb, sf, (uint64_t)k); | 362 | return lj_strfmt_putfxint(sb, sf, (uint64_t)k); |
347 | } | 363 | } |
348 | 364 | ||
365 | /* Format stack arguments to buffer. */ | ||
366 | int lj_strfmt_putarg(lua_State *L, SBuf *sb, int arg, int retry) | ||
367 | { | ||
368 | int narg = (int)(L->top - L->base); | ||
369 | GCstr *fmt = lj_lib_checkstr(L, arg); | ||
370 | FormatState fs; | ||
371 | SFormat sf; | ||
372 | lj_strfmt_init(&fs, strdata(fmt), fmt->len); | ||
373 | while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) { | ||
374 | if (sf == STRFMT_LIT) { | ||
375 | lj_buf_putmem(sb, fs.str, fs.len); | ||
376 | } else if (sf == STRFMT_ERR) { | ||
377 | lj_err_callerv(L, LJ_ERR_STRFMT, | ||
378 | strdata(lj_str_new(L, fs.str, fs.len))); | ||
379 | } else { | ||
380 | TValue *o = &L->base[arg++]; | ||
381 | if (arg > narg) | ||
382 | lj_err_arg(L, arg, LJ_ERR_NOVAL); | ||
383 | switch (STRFMT_TYPE(sf)) { | ||
384 | case STRFMT_INT: | ||
385 | if (tvisint(o)) { | ||
386 | int32_t k = intV(o); | ||
387 | if (sf == STRFMT_INT) | ||
388 | lj_strfmt_putint(sb, k); /* Shortcut for plain %d. */ | ||
389 | else | ||
390 | lj_strfmt_putfxint(sb, sf, k); | ||
391 | } else { | ||
392 | lj_strfmt_putfnum_int(sb, sf, lj_lib_checknum(L, arg)); | ||
393 | } | ||
394 | break; | ||
395 | case STRFMT_UINT: | ||
396 | if (tvisint(o)) | ||
397 | lj_strfmt_putfxint(sb, sf, intV(o)); | ||
398 | else | ||
399 | lj_strfmt_putfnum_uint(sb, sf, lj_lib_checknum(L, arg)); | ||
400 | break; | ||
401 | case STRFMT_NUM: | ||
402 | lj_strfmt_putfnum(sb, sf, lj_lib_checknum(L, arg)); | ||
403 | break; | ||
404 | case STRFMT_STR: { | ||
405 | MSize len; | ||
406 | const char *s; | ||
407 | cTValue *mo; | ||
408 | if (LJ_UNLIKELY(!tvisstr(o)) && retry >= 0 && | ||
409 | !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { | ||
410 | /* Call __tostring metamethod once. */ | ||
411 | copyTV(L, L->top++, mo); | ||
412 | copyTV(L, L->top++, o); | ||
413 | lua_call(L, 1, 1); | ||
414 | o = &L->base[arg-1]; /* Stack may have been reallocated. */ | ||
415 | copyTV(L, o, --L->top); /* Replace inline for retry. */ | ||
416 | if (retry < 2) { /* Global buffer may have been overwritten. */ | ||
417 | retry = 1; | ||
418 | break; | ||
419 | } | ||
420 | } | ||
421 | if (LJ_LIKELY(tvisstr(o))) { | ||
422 | len = strV(o)->len; | ||
423 | s = strVdata(o); | ||
424 | } else { | ||
425 | GCstr *str = lj_strfmt_obj(L, o); | ||
426 | len = str->len; | ||
427 | s = strdata(str); | ||
428 | } | ||
429 | if ((sf & STRFMT_T_QUOTED)) | ||
430 | strfmt_putquotedlen(sb, s, len); /* No formatting. */ | ||
431 | else | ||
432 | strfmt_putfstrlen(sb, sf, s, len); | ||
433 | break; | ||
434 | } | ||
435 | case STRFMT_CHAR: | ||
436 | lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg)); | ||
437 | break; | ||
438 | case STRFMT_PTR: /* No formatting. */ | ||
439 | lj_strfmt_putptr(sb, lj_obj_ptr(G(L), o)); | ||
440 | break; | ||
441 | default: | ||
442 | lj_assertL(0, "bad string format type"); | ||
443 | break; | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | return retry; | ||
448 | } | ||
449 | |||
349 | /* -- Conversions to strings ---------------------------------------------- */ | 450 | /* -- Conversions to strings ---------------------------------------------- */ |
350 | 451 | ||
351 | /* Convert integer to string. */ | 452 | /* Convert integer to string. */ |
diff --git a/src/lj_strfmt.h b/src/lj_strfmt.h index fa25dcd0..cb2c7360 100644 --- a/src/lj_strfmt.h +++ b/src/lj_strfmt.h | |||
@@ -95,7 +95,9 @@ LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putint(SBuf *sb, int32_t k); | |||
95 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o); | 95 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o); |
96 | #endif | 96 | #endif |
97 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putptr(SBuf *sb, const void *v); | 97 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putptr(SBuf *sb, const void *v); |
98 | #if LJ_HASJIT | ||
98 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str); | 99 | LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str); |
100 | #endif | ||
99 | 101 | ||
100 | /* Formatted conversions to buffer. */ | 102 | /* Formatted conversions to buffer. */ |
101 | LJ_FUNC SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k); | 103 | LJ_FUNC SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k); |
@@ -103,7 +105,10 @@ LJ_FUNC SBuf *lj_strfmt_putfnum_int(SBuf *sb, SFormat sf, lua_Number n); | |||
103 | LJ_FUNC SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n); | 105 | LJ_FUNC SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n); |
104 | LJ_FUNC SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat, lua_Number n); | 106 | LJ_FUNC SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat, lua_Number n); |
105 | LJ_FUNC SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat, int32_t c); | 107 | LJ_FUNC SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat, int32_t c); |
108 | #if LJ_HASJIT | ||
106 | LJ_FUNC SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat, GCstr *str); | 109 | LJ_FUNC SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat, GCstr *str); |
110 | #endif | ||
111 | LJ_FUNC int lj_strfmt_putarg(lua_State *L, SBuf *sb, int arg, int retry); | ||
107 | 112 | ||
108 | /* Conversions to strings. */ | 113 | /* Conversions to strings. */ |
109 | LJ_FUNC GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k); | 114 | LJ_FUNC GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k); |