aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2021-06-01 05:14:18 +0200
committerMike Pall <mike>2021-06-01 05:14:18 +0200
commitedd5cbadc5cdc7b5b66d5340ee97c5abe5a3892a (patch)
tree053c8bb18f0b9de559a4b712062fd99e96849be7 /src
parent50d6883e6027c4c2f9a5e495fee6b7fff1bd73c9 (diff)
downloadluajit-edd5cbadc5cdc7b5b66d5340ee97c5abe5a3892a.tar.gz
luajit-edd5cbadc5cdc7b5b66d5340ee97c5abe5a3892a.tar.bz2
luajit-edd5cbadc5cdc7b5b66d5340ee97c5abe5a3892a.zip
String buffers, part 2c: abstract out string.format.
Sponsored by fmad.io.
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.dep3
-rw-r--r--src/lib_string.c85
-rw-r--r--src/lj_strfmt.c117
-rw-r--r--src/lj_strfmt.h5
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 \
197lj_str.o: lj_str.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ 197lj_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
199lj_strfmt.o: lj_strfmt.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 199lj_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
201lj_strfmt_num.o: lj_strfmt_num.c lj_obj.h lua.h luaconf.h lj_def.h \ 202lj_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
203lj_strscan.o: lj_strscan.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \ 204lj_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. */
644static 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
661LJLIB_CF(string_format) LJLIB_REC(.) 643LJLIB_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;
669again: 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. */
199SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str) 202static 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
230SBuf * 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. */
243SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat sf, GCstr *str) 251static 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
265SBuf *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. */
256SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k) 272SBuf *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. */
366int 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);
95LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o); 95LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putnum(SBuf *sb, cTValue *o);
96#endif 96#endif
97LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putptr(SBuf *sb, const void *v); 97LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putptr(SBuf *sb, const void *v);
98#if LJ_HASJIT
98LJ_FUNC SBuf * LJ_FASTCALL lj_strfmt_putquoted(SBuf *sb, GCstr *str); 99LJ_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. */
101LJ_FUNC SBuf *lj_strfmt_putfxint(SBuf *sb, SFormat sf, uint64_t k); 103LJ_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);
103LJ_FUNC SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n); 105LJ_FUNC SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n);
104LJ_FUNC SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat, lua_Number n); 106LJ_FUNC SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat, lua_Number n);
105LJ_FUNC SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat, int32_t c); 107LJ_FUNC SBuf *lj_strfmt_putfchar(SBuf *sb, SFormat, int32_t c);
108#if LJ_HASJIT
106LJ_FUNC SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat, GCstr *str); 109LJ_FUNC SBuf *lj_strfmt_putfstr(SBuf *sb, SFormat, GCstr *str);
110#endif
111LJ_FUNC int lj_strfmt_putarg(lua_State *L, SBuf *sb, int arg, int retry);
107 112
108/* Conversions to strings. */ 113/* Conversions to strings. */
109LJ_FUNC GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k); 114LJ_FUNC GCstr * LJ_FASTCALL lj_strfmt_int(lua_State *L, int32_t k);