• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 11028552819

25 Sep 2024 07:41AM UTC coverage: 92.894% (+0.05%) from 92.845%
11028552819

push

github

Buristan
Limit CSE for IR_CARG to fix loop optimizations.

Thanks to Peter Cawley.

(cherry picked from commit 3bdc6498c)

`IR_CALLXS` for the vararg function contains `IR_CARG(fptr, ctid)` as
the second operand. The `loop_emit_phi()` scans only the first operand
of the IR, so the second is not marked as PHI. In this case, when the IR
appears in both the invariant and variant parts of the loop, CSE may
remove it and thus lead to incorrect emitting results.

This patch tweaks the CSE rules to avoid CSE across the `IR_LOOP`.

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#10199

5688 of 6028 branches covered (94.36%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 1 file covered. (100.0%)

10 existing lines in 4 files now uncovered.

21685 of 23439 relevant lines covered (92.52%)

2939140.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.31
/src/lib_string.c
1
/*
2
** String library.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
**
5
** Major portions taken verbatim or adapted from the Lua interpreter.
6
** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
7
*/
8

9
#define lib_string_c
10
#define LUA_LIB
11

12
#include "lua.h"
13
#include "lauxlib.h"
14
#include "lualib.h"
15

16
#include "lj_obj.h"
17
#include "lj_gc.h"
18
#include "lj_err.h"
19
#include "lj_buf.h"
20
#include "lj_str.h"
21
#include "lj_tab.h"
22
#include "lj_meta.h"
23
#include "lj_state.h"
24
#include "lj_ff.h"
25
#include "lj_bcdump.h"
26
#include "lj_char.h"
27
#include "lj_strfmt.h"
28
#include "lj_lib.h"
29

30
/* ------------------------------------------------------------------------ */
31

32
#define LJLIB_MODULE_string
33

34
LJLIB_LUA(string_len) /*
35
  function(s)
36
    CHECK_str(s)
37
    return #s
38
  end
39
*/
40

41
LJLIB_ASM(string_byte)                LJLIB_REC(string_range 0)
1,941✔
42
{
43
  GCstr *s = lj_lib_checkstr(L, 1);
1,941✔
44
  int32_t len = (int32_t)s->len;
1,941✔
45
  int32_t start = lj_lib_optint(L, 2, 1);
1,941✔
46
  int32_t stop = lj_lib_optint(L, 3, start);
1,941✔
47
  int32_t n, i;
1,941✔
48
  const unsigned char *p;
1,941✔
49
  if (stop < 0) stop += len+1;
1,941✔
50
  if (start < 0) start += len+1;
1,941✔
51
  if (start <= 0) start = 1;
1,941✔
52
  if (stop > len) stop = len;
1,941✔
53
  if (start > stop) return FFH_RES(0);  /* Empty interval: return no results. */
1,941✔
54
  start--;
1,664✔
55
  n = stop - start;
1,664✔
56
  if ((uint32_t)n > LUAI_MAXCSTACK)
1,664✔
57
    lj_err_caller(L, LJ_ERR_STRSLC);
×
58
  lj_state_checkstack(L, (MSize)n);
1,664✔
59
  p = (const unsigned char *)strdata(s) + start;
1,664✔
60
  for (i = 0; i < n; i++)
84,302✔
61
    setintV(L->base + i-1-LJ_FR2, p[i]);
82,638✔
62
  return FFH_RES(n);
1,664✔
63
}
64

65
LJLIB_ASM(string_char)                LJLIB_REC(.)
646✔
66
{
67
  int i, nargs = (int)(L->top - L->base);
646✔
68
  char *buf = lj_buf_tmp(L, (MSize)nargs);
646✔
69
  for (i = 1; i <= nargs; i++) {
3,147✔
70
    int32_t k = lj_lib_checkint(L, i);
1,858✔
71
    if (!checku8(k))
1,857✔
72
      lj_err_arg(L, i, LJ_ERR_BADVAL);
2✔
73
    buf[i-1] = (char)k;
1,855✔
74
  }
75
  setstrV(L, L->base-1-LJ_FR2, lj_str_new(L, buf, (size_t)nargs));
643✔
76
  return FFH_RES(1);
643✔
77
}
78

79
LJLIB_ASM(string_sub)                LJLIB_REC(string_range 1)
2✔
80
{
81
  lj_lib_checkstr(L, 1);
2✔
82
  lj_lib_checkint(L, 2);
2✔
UNCOV
83
  setintV(L->base+2, lj_lib_optint(L, 3, -1));
×
UNCOV
84
  return FFH_RETRY;
×
85
}
86

87
LJLIB_CF(string_rep)                LJLIB_REC(.)
2,085✔
88
{
89
  GCstr *s = lj_lib_checkstr(L, 1);
2,085✔
90
  int32_t rep = lj_lib_checkint(L, 2);
2,085✔
91
  GCstr *sep = lj_lib_optstr(L, 3);
2,085✔
92
  SBuf *sb = lj_buf_tmp_(L);
2,085✔
93
  if (sep && rep > 1) {
2,085✔
94
    GCstr *s2 = lj_buf_cat2str(L, sep, s);
37✔
95
    lj_buf_reset(sb);
37✔
96
    lj_buf_putstr(sb, s);
37✔
97
    s = s2;
37✔
98
    rep--;
37✔
99
  }
100
  sb = lj_buf_putstr_rep(sb, s, rep);
2,085✔
101
  setstrV(L, L->top-1, lj_buf_str(L, sb));
2,084✔
102
  lj_gc_check(L);
2,084✔
103
  return 1;
2,084✔
104
}
105

106
LJLIB_ASM(string_reverse)  LJLIB_REC(string_op IRCALL_lj_buf_putstr_reverse)
174✔
107
{
108
  lj_lib_checkstr(L, 1);
174✔
109
  return FFH_RETRY;
174✔
110
}
111
LJLIB_ASM_(string_lower)  LJLIB_REC(string_op IRCALL_lj_buf_putstr_lower)
112
LJLIB_ASM_(string_upper)  LJLIB_REC(string_op IRCALL_lj_buf_putstr_upper)
113

114
/* ------------------------------------------------------------------------ */
115

116
static int writer_buf(lua_State *L, const void *p, size_t size, void *sb)
480✔
117
{
118
  lj_buf_putmem((SBuf *)sb, p, (MSize)size);
480✔
119
  UNUSED(L);
480✔
120
  return 0;
480✔
121
}
122

123
LJLIB_CF(string_dump)
52✔
124
{
125
  GCfunc *fn = lj_lib_checkfunc(L, 1);
52✔
126
  int strip = L->base+1 < L->top && tvistruecond(L->base+1);
52✔
127
  SBuf *sb = lj_buf_tmp_(L);  /* Assumes lj_bcwrite() doesn't use tmpbuf. */
52✔
128
  L->top = L->base+1;
52✔
129
  if (!isluafunc(fn) || lj_bcwrite(L, funcproto(fn), writer_buf, sb, strip))
52✔
130
    lj_err_caller(L, LJ_ERR_STRDUMP);
1✔
131
  setstrV(L, L->top-1, lj_buf_str(L, sb));
51✔
132
  lj_gc_check(L);
51✔
133
  return 1;
51✔
134
}
135

136
/* ------------------------------------------------------------------------ */
137

138
/* macro to `unsign' a character */
139
#define uchar(c)        ((unsigned char)(c))
140

141
#define CAP_UNFINISHED        (-1)
142
#define CAP_POSITION        (-2)
143

144
typedef struct MatchState {
145
  const char *src_init;  /* init of source string */
146
  const char *src_end;  /* end (`\0') of source string */
147
  lua_State *L;
148
  int level;  /* total number of captures (finished or unfinished) */
149
  int depth;
150
  struct {
151
    const char *init;
152
    ptrdiff_t len;
153
  } capture[LUA_MAXCAPTURES];
154
} MatchState;
155

156
#define L_ESC                '%'
157

158
static int check_capture(MatchState *ms, int l)
97✔
159
{
160
  l -= '1';
97✔
161
  if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED)
97✔
162
    lj_err_caller(ms->L, LJ_ERR_STRCAPI);
3✔
163
  return l;
94✔
164
}
165

166
static int capture_to_close(MatchState *ms)
14,408✔
167
{
168
  int level = ms->level;
14,408✔
169
  for (level--; level>=0; level--)
14,429✔
170
    if (ms->capture[level].len == CAP_UNFINISHED) return level;
14,427✔
171
  lj_err_caller(ms->L, LJ_ERR_STRPATC);
2✔
172
  return 0;  /* unreachable */
173
}
174

175
static const char *classend(MatchState *ms, const char *p)
176
{
177
  switch (*p++) {
178
  case L_ESC:
179
    if (*p == '\0')
180
      lj_err_caller(ms->L, LJ_ERR_STRPATE);
181
    return p+1;
182
  case '[':
183
    if (*p == '^') p++;
184
    do {  /* look for a `]' */
185
      if (*p == '\0')
186
        lj_err_caller(ms->L, LJ_ERR_STRPATM);
187
      if (*(p++) == L_ESC && *p != '\0')
188
        p++;  /* skip escapes (e.g. `%]') */
189
    } while (*p != ']');
190
    return p+1;
191
  default:
192
    return p;
193
  }
194
}
195

196
static const unsigned char match_class_map[32] = {
197
  0,LJ_CHAR_ALPHA,0,LJ_CHAR_CNTRL,LJ_CHAR_DIGIT,0,0,LJ_CHAR_GRAPH,0,0,0,0,
198
  LJ_CHAR_LOWER,0,0,0,LJ_CHAR_PUNCT,0,0,LJ_CHAR_SPACE,0,
199
  LJ_CHAR_UPPER,0,LJ_CHAR_ALNUM,LJ_CHAR_XDIGIT,0,0,0,0,0,0,0
200
};
201

202
static int match_class(int c, int cl)
670,912✔
203
{
204
  if ((cl & 0xc0) == 0x40) {
670,912✔
205
    int t = match_class_map[(cl&0x1f)];
664,262✔
206
    if (t) {
664,262✔
207
      t = lj_char_isa(c, t);
663,077✔
208
      return (cl & 0x20) ? t : !t;
663,077✔
209
    }
210
    if (cl == 'z') return c == 0;
1,185✔
211
    if (cl == 'Z') return c != 0;
1,181✔
212
  }
213
  return (cl == c);
7,567✔
214
}
215

216
static int matchbracketclass(int c, const char *p, const char *ec)
155,654✔
217
{
218
  int sig = 1;
155,654✔
219
  if (*(p+1) == '^') {
155,654✔
220
    sig = 0;
148,764✔
221
    p++;  /* skip the `^' */
148,764✔
222
  }
223
  while (++p < ec) {
331,366✔
224
    if (*p == L_ESC) {
194,053✔
225
      p++;
4,442✔
226
      if (match_class(c, uchar(*p)))
4,442✔
227
        return sig;
228
    }
229
    else if ((*(p+1) == '-') && (p+2 < ec)) {
189,611✔
230
      p+=2;
1,911✔
231
      if (uchar(*(p-2)) <= c && c <= uchar(*p))
1,911✔
232
        return sig;
233
    }
234
    else if (uchar(*p) == c) return sig;
187,700✔
235
  }
236
  return !sig;
137,313✔
237
}
238

239
static int singlematch(int c, const char *p, const char *ep)
4,223,642✔
240
{
241
  switch (*p) {
4,223,642✔
242
  case '.': return 1;  /* matches any char */
243
  case L_ESC: return match_class(c, uchar(*(p+1)));
666,470✔
244
  case '[': return matchbracketclass(c, p, ep-1);
155,448✔
245
  default:  return (uchar(*p) == c);
2,789,490✔
246
  }
247
}
248

249
static const char *match(MatchState *ms, const char *s, const char *p);
250

251
static const char *matchbalance(MatchState *ms, const char *s, const char *p)
252
{
253
  if (*p == 0 || *(p+1) == 0)
254
    lj_err_caller(ms->L, LJ_ERR_STRPATU);
255
  if (*s != *p) {
256
    return NULL;
257
  } else {
258
    int b = *p;
259
    int e = *(p+1);
260
    int cont = 1;
261
    while (++s < ms->src_end) {
262
      if (*s == e) {
263
        if (--cont == 0) return s+1;
264
      } else if (*s == b) {
265
        cont++;
266
      }
267
    }
268
  }
269
  return NULL;  /* string ends out of balance */
270
}
271

272
static const char *max_expand(MatchState *ms, const char *s,
116,471✔
273
                              const char *p, const char *ep)
274
{
275
  ptrdiff_t i = 0;  /* counts maximum expand for item */
116,471✔
276
  while ((s+i)<ms->src_end && singlematch(uchar(*(s+i)), p, ep))
860,527✔
277
    i++;
744,056✔
278
  /* keeps trying to match with the maximum repetitions */
279
  while (i>=0) {
593,162✔
280
    const char *res = match(ms, (s+i), ep+1);
486,649✔
281
    if (res) return res;
486,649✔
282
    i--;  /* else didn't match; reduce 1 repetition to try again */
476,691✔
283
  }
284
  return NULL;
285
}
286

287
static const char *min_expand(MatchState *ms, const char *s,
90✔
288
                              const char *p, const char *ep)
289
{
290
  for (;;) {
602,060✔
291
    const char *res = match(ms, s, ep+1);
301,075✔
292
    if (res != NULL)
301,075✔
293
      return res;
87✔
294
    else if (s<ms->src_end && singlematch(uchar(*s), p, ep))
300,988✔
295
      s++;  /* try with one more repetition */
300,985✔
296
    else
297
      return NULL;
298
  }
299
}
300

301
static const char *start_capture(MatchState *ms, const char *s,
562,017✔
302
                                 const char *p, int what)
303
{
304
  const char *res;
562,017✔
305
  int level = ms->level;
562,017✔
306
  if (level >= LUA_MAXCAPTURES) lj_err_caller(ms->L, LJ_ERR_STRCAPN);
562,017✔
307
  ms->capture[level].init = s;
562,017✔
308
  ms->capture[level].len = what;
562,017✔
309
  ms->level = level+1;
562,017✔
310
  if ((res=match(ms, s, p)) == NULL)  /* match failed? */
562,017✔
311
    ms->level--;  /* undo capture */
548,355✔
312
  return res;
562,015✔
313
}
314

315
static const char *end_capture(MatchState *ms, const char *s,
14,408✔
316
                               const char *p)
317
{
318
  int l = capture_to_close(ms);
14,408✔
319
  const char *res;
14,406✔
320
  ms->capture[l].len = s - ms->capture[l].init;  /* close capture */
14,406✔
321
  if ((res = match(ms, s, p)) == NULL)  /* match failed? */
14,406✔
322
    ms->capture[l].len = CAP_UNFINISHED;  /* undo capture */
1,638✔
323
  return res;
14,406✔
324
}
325

326
static const char *match_capture(MatchState *ms, const char *s, int l)
97✔
327
{
328
  size_t len;
97✔
329
  l = check_capture(ms, l);
97✔
330
  len = (size_t)ms->capture[l].len;
94✔
331
  if ((size_t)(ms->src_end-s) >= len &&
94✔
332
      memcmp(ms->capture[l].init, s, len) == 0)
65✔
333
    return s+len;
22✔
334
  else
335
    return NULL;
336
}
337

338
static const char *match(MatchState *ms, const char *s, const char *p)
3,760,438✔
339
{
340
  if (++ms->depth > LJ_MAX_XLEVEL)
3,760,438✔
341
    lj_err_caller(ms->L, LJ_ERR_STRPATX);
×
342
  init: /* using goto's to optimize tail recursion */
3,760,438✔
343
  switch (*p) {
4,483,923✔
344
  case '(':  /* start capture */
562,017✔
345
    if (*(p+1) == ')')  /* position capture? */
562,017✔
346
      s = start_capture(ms, s, p+2, CAP_POSITION);
269,475✔
347
    else
348
      s = start_capture(ms, s, p+1, CAP_UNFINISHED);
292,542✔
349
    break;
350
  case ')':  /* end capture */
14,408✔
351
    s = end_capture(ms, s, p+1);
14,408✔
352
    break;
14,408✔
353
  case L_ESC:
559,263✔
354
    switch (*(p+1)) {
559,263✔
355
    case 'b':  /* balanced string? */
53✔
356
      s = matchbalance(ms, s, p+2);
53✔
357
      if (s == NULL) break;
52✔
358
      p+=4;
12✔
359
      goto init;  /* else s = match(ms, s, p+4); */
12✔
360
    case 'f': {  /* frontier? */
144✔
361
      const char *ep; char previous;
144✔
362
      p += 2;
144✔
363
      if (*p != '[')
144✔
364
        lj_err_caller(ms->L, LJ_ERR_STRPATB);
1✔
365
      ep = classend(ms, p);  /* points to what is next */
143✔
366
      previous = (s == ms->src_init) ? '\0' : *(s-1);
143✔
367
      if (matchbracketclass(uchar(previous), p, ep-1) ||
206✔
368
         !matchbracketclass(uchar(*s), p, ep-1)) { s = NULL; break; }
63✔
369
      p=ep;
34✔
370
      goto init;  /* else s = match(ms, s, ep); */
34✔
371
      }
372
    default:
559,066✔
373
      if (lj_char_isdigit(uchar(*(p+1)))) {  /* capture results (%0-%9)? */
559,066✔
374
        s = match_capture(ms, s, uchar(*(p+1)));
97✔
375
        if (s == NULL) break;
94✔
376
        p+=2;
22✔
377
        goto init;  /* else s = match(ms, s, p+2) */
22✔
378
      }
379
      goto dflt;  /* case default */
558,969✔
380
    }
381
    break;
112✔
382
  case '\0':  /* end of pattern */
383
    break;  /* match succeeded */
384
  case '$':
772,690✔
385
    /* is the `$' the last char in pattern? */
386
    if (*(p+1) != '\0') goto dflt;
772,690✔
387
    if (s != ms->src_end) s = NULL;  /* check end of string */
772,538✔
388
    break;
389
  default: dflt: {  /* it is a pattern item */
3,087,705✔
390
    const char *ep = classend(ms, p);  /* points to what is next */
3,087,705✔
391
    int m = s<ms->src_end && singlematch(uchar(*s), p, ep);
3,087,701✔
392
    switch (*ep) {
3,087,701✔
393
    case '?': {  /* optional */
600,149✔
394
      const char *res;
600,149✔
395
      if (m && ((res=match(ms, s+1, ep+1)) != NULL)) {
600,149✔
396
        s = res;
397
        break;
398
      }
399
      p=ep+1;
600,068✔
400
      goto init;  /* else s = match(ms, s, ep+1); */
600,068✔
401
      }
402
    case '*':  /* 0 or more repetitions */
5,441✔
403
      s = max_expand(ms, s, p, ep);
5,441✔
404
      break;
5,441✔
405
    case '+':  /* 1 or more repetitions */
556,156✔
406
      s = (m ? max_expand(ms, s+1, p, ep) : NULL);
556,156✔
407
      break;
408
    case '-':  /* 0 or more repetitions (minimum) */
90✔
409
      s = min_expand(ms, s, p, ep);
90✔
410
      break;
90✔
411
    default:
1,925,865✔
412
      if (m) { s++; p=ep; goto init; }  /* else s = match(ms, s+1, ep); */
1,925,865✔
413
      s = NULL;
414
      break;
415
    }
416
    break;
417
    }
418
  }
419
  ms->depth--;
3,760,425✔
420
  return s;
3,760,425✔
421
}
422

423
static void push_onecapture(MatchState *ms, int i, const char *s, const char *e)
15,746✔
424
{
425
  if (i >= ms->level) {
15,746✔
426
    if (i == 0)  /* ms->level == 0, too */
2,097✔
427
      lua_pushlstring(ms->L, s, (size_t)(e - s));  /* add whole match */
2,095✔
428
    else
429
      lj_err_caller(ms->L, LJ_ERR_STRCAPI);
2✔
430
  } else {
431
    ptrdiff_t l = ms->capture[i].len;
13,649✔
432
    if (l == CAP_UNFINISHED) lj_err_caller(ms->L, LJ_ERR_STRCAPU);
13,649✔
433
    if (l == CAP_POSITION)
13,647✔
434
      lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
890✔
435
    else
436
      lua_pushlstring(ms->L, ms->capture[i].init, (size_t)l);
12,757✔
437
  }
438
}
15,742✔
439

440
static int push_captures(MatchState *ms, const char *s, const char *e)
13,696✔
441
{
442
  int i;
13,696✔
443
  int nlevels = (ms->level == 0 && s) ? 1 : ms->level;
13,696✔
444
  luaL_checkstack(ms->L, nlevels, "too many captures");
13,696✔
445
  for (i = 0; i < nlevels; i++)
42,958✔
446
    push_onecapture(ms, i, s, e);
15,567✔
447
  return nlevels;  /* number of strings pushed */
13,695✔
448
}
449

450
static int str_find_aux(lua_State *L, int find)
4,649✔
451
{
452
  GCstr *s = lj_lib_checkstr(L, 1);
4,649✔
453
  GCstr *p = lj_lib_checkstr(L, 2);
4,649✔
454
  int32_t start = lj_lib_optint(L, 3, 1);
4,649✔
455
  MSize st;
4,649✔
456
  if (start < 0) start += (int32_t)s->len; else start--;
4,649✔
457
  if (start < 0) start = 0;
4,649✔
458
  st = (MSize)start;
4,649✔
459
  if (st > s->len) {
4,649✔
460
#if LJ_52
461
    setnilV(L->top-1);
462
    return 1;
463
#else
464
    st = s->len;
465
#endif
466
  }
467
  if (find && ((L->base+3 < L->top && tvistruecond(L->base+3)) ||
7,292✔
468
               !lj_str_haspattern(p))) {  /* Search for fixed string. */
2,643✔
469
    const char *q = lj_str_find(strdata(s)+st, strdata(p), s->len-st, p->len);
1,425✔
470
    if (q) {
1,425✔
471
      setintV(L->top-2, (int32_t)(q-strdata(s)) + 1);
236✔
472
      setintV(L->top-1, (int32_t)(q-strdata(s)) + (int32_t)p->len);
236✔
473
      return 2;
236✔
474
    }
475
  } else {  /* Search for pattern. */
476
    MatchState ms;
3,224✔
477
    const char *pstr = strdata(p);
3,224✔
478
    const char *sstr = strdata(s) + st;
3,224✔
479
    int anchor = 0;
3,224✔
480
    if (*pstr == '^') { pstr++; anchor = 1; }
3,224✔
481
    ms.L = L;
3,224✔
482
    ms.src_init = strdata(s);
3,224✔
483
    ms.src_end = strdata(s) + s->len;
3,224✔
484
    do {  /* Loop through string and try to match the pattern. */
68,973✔
485
      const char *q;
68,973✔
486
      ms.level = ms.depth = 0;
68,973✔
487
      q = match(&ms, sstr, pstr);
68,973✔
488
      if (q) {
68,966✔
489
        if (find) {
1,148✔
490
          setintV(L->top++, (int32_t)(sstr-(strdata(s)-1)));
253✔
491
          setintV(L->top++, (int32_t)(q-strdata(s)));
253✔
492
          return push_captures(&ms, NULL, NULL) + 2;
1,148✔
493
        } else {
494
          return push_captures(&ms, sstr, q);
895✔
495
        }
496
      }
497
    } while (sstr++ < ms.src_end && !anchor);
67,818✔
498
  }
499
  setnilV(L->top-1);  /* Not found. */
3,258✔
500
  return 1;
3,258✔
501
}
502

503
LJLIB_CF(string_find)                LJLIB_REC(.)
2,755✔
504
{
505
  return str_find_aux(L, 1);
2,755✔
506
}
507

508
LJLIB_CF(string_match)
1,894✔
509
{
510
  return str_find_aux(L, 0);
1,894✔
511
}
512

513
LJLIB_NOREG LJLIB_CF(string_gmatch_aux)
373✔
514
{
515
  const char *p = strVdata(lj_lib_upvalue(L, 2));
373✔
516
  GCstr *str = strV(lj_lib_upvalue(L, 1));
373✔
517
  const char *s = strdata(str);
373✔
518
  TValue *tvpos = lj_lib_upvalue(L, 3);
373✔
519
  const char *src = s + tvpos->u32.lo;
373✔
520
  MatchState ms;
373✔
521
  ms.L = L;
373✔
522
  ms.src_init = s;
373✔
523
  ms.src_end = s + str->len;
373✔
524
  for (; src <= ms.src_end; src++) {
6,841✔
525
    const char *e;
6,748✔
526
    ms.level = ms.depth = 0;
6,748✔
527
    if ((e = match(&ms, src, p)) != NULL) {
6,748✔
528
      int32_t pos = (int32_t)(e - s);
280✔
529
      if (e == src) pos++;  /* Ensure progress for empty match. */
280✔
530
      tvpos->u32.lo = (uint32_t)pos;
280✔
531
      return push_captures(&ms, src, e);
280✔
532
    }
533
  }
534
  return 0;  /* not found */
535
}
536

537
LJLIB_CF(string_gmatch)
101✔
538
{
539
  lj_lib_checkstr(L, 1);
101✔
540
  lj_lib_checkstr(L, 2);
101✔
541
  L->top = L->base+3;
101✔
542
  (L->top-1)->u64 = 0;
101✔
543
  lj_lib_pushcc(L, lj_cf_string_gmatch_aux, FF_string_gmatch_aux, 3);
101✔
544
  return 1;
101✔
545
}
546

547
static void add_s(MatchState *ms, luaL_Buffer *b, const char *s, const char *e)
33,709✔
548
{
549
  size_t l, i;
33,709✔
550
  const char *news = lua_tolstring(ms->L, 3, &l);
33,709✔
551
  for (i = 0; i < l; i++) {
69,477✔
552
    if (news[i] != L_ESC) {
2,061✔
553
      luaL_addchar(b, news[i]);
1,941✔
554
    } else {
555
      i++;  /* skip ESC */
120✔
556
      if (!lj_char_isdigit(uchar(news[i]))) {
120✔
557
        luaL_addchar(b, news[i]);
19✔
558
      } else if (news[i] == '0') {
101✔
559
        luaL_addlstring(b, s, (size_t)(e - s));
25✔
560
      } else {
561
        push_onecapture(ms, news[i] - '1', s, e);
76✔
562
        luaL_addvalue(b);  /* add capture to accumulated result */
74✔
563
      }
564
    }
565
  }
566
}
33,707✔
567

568
static void add_value(MatchState *ms, luaL_Buffer *b,
46,080✔
569
                      const char *s, const char *e)
570
{
571
  lua_State *L = ms->L;
46,080✔
572
  switch (lua_type(L, 3)) {
46,080✔
573
    case LUA_TNUMBER:
33,709✔
574
    case LUA_TSTRING: {
575
      add_s(ms, b, s, e);
33,709✔
576
      return;
33,709✔
577
    }
578
    case LUA_TFUNCTION: {
12,268✔
579
      int n;
12,268✔
580
      lua_pushvalue(L, 3);
12,268✔
581
      n = push_captures(ms, s, e);
12,268✔
582
      lua_call(L, n, 1);
12,267✔
583
      break;
12,267✔
584
    }
585
    case LUA_TTABLE: {
103✔
586
      push_onecapture(ms, 0, s, e);
103✔
587
      lua_gettable(L, 3);
102✔
588
      break;
102✔
589
    }
590
  }
591
  if (!lua_toboolean(L, -1)) {  /* nil or false? */
12,369✔
592
    lua_pop(L, 1);
1,297✔
593
    lua_pushlstring(L, s, (size_t)(e - s));  /* keep original text */
1,297✔
594
  } else if (!lua_isstring(L, -1)) {
11,072✔
595
    lj_err_callerv(L, LJ_ERR_STRGSRV, luaL_typename(L, -1));
1✔
596
  }
597
  luaL_addvalue(b);  /* add result to accumulator */
12,368✔
598
}
599

600
LJLIB_CF(string_gsub)
22,479✔
601
{
602
  size_t srcl;
22,479✔
603
  const char *src = luaL_checklstring(L, 1, &srcl);
22,479✔
604
  const char *p = luaL_checkstring(L, 2);
22,479✔
605
  int  tr = lua_type(L, 3);
22,479✔
606
  int max_s = luaL_optint(L, 4, (int)(srcl+1));
22,479✔
607
  int anchor = (*p == '^') ? (p++, 1) : 0;
22,479✔
608
  int n = 0;
22,479✔
609
  MatchState ms;
22,479✔
610
  luaL_Buffer b;
22,479✔
611
  if (!(tr == LUA_TNUMBER || tr == LUA_TSTRING ||
28✔
612
        tr == LUA_TFUNCTION || tr == LUA_TTABLE))
22,479✔
613
    lj_err_arg(L, 3, LJ_ERR_NOSFT);
1✔
614
  luaL_buffinit(L, &b);
22,478✔
615
  ms.L = L;
22,478✔
616
  ms.src_init = src;
22,478✔
617
  ms.src_end = src+srcl;
22,478✔
618
  while (n < max_s) {
1,720,511✔
619
    const char *e;
1,720,488✔
620
    ms.level = ms.depth = 0;
1,720,488✔
621
    e = match(&ms, src, p);
1,720,488✔
622
    if (e) {
1,720,484✔
623
      n++;
46,080✔
624
      add_value(&ms, &b, src, e);
46,080✔
625
    }
626
    if (e && e>src) /* non empty match? */
1,720,479✔
627
      src = e;  /* skip it */
628
    else if (src < ms.src_end)
1,674,425✔
629
      luaL_addchar(&b, *src++);
1,652,014✔
630
    else
631
      break;
632
    if (anchor)
1,698,068✔
633
      break;
634
  }
635
  luaL_addlstring(&b, src, (size_t)(ms.src_end-src));
22,469✔
636
  luaL_pushresult(&b);
22,469✔
637
  lua_pushinteger(L, n);  /* number of substitutions */
22,469✔
638
  return 2;
22,469✔
639
}
640

641
/* ------------------------------------------------------------------------ */
642

643
/* Emulate tostring() inline. */
644
static GCstr *string_fmt_tostring(lua_State *L, int arg, int retry)
138,171✔
645
{
646
  TValue *o = L->base+arg-1;
138,171✔
647
  cTValue *mo;
138,171✔
648
  lj_assertL(o < L->top, "bad usage");  /* Caller already checks for existence. */
138,171✔
649
  if (LJ_LIKELY(tvisstr(o)))
138,171✔
650
    return strV(o);
135,404✔
651
  if (retry != 2 && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
2,767✔
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);
2,767✔
659
}
660

661
LJLIB_CF(string_format)                LJLIB_REC(.)
29,074✔
662
{
663
  int arg, top = (int)(L->top - L->base);
29,074✔
664
  GCstr *fmt;
29,074✔
665
  SBuf *sb;
29,074✔
666
  FormatState fs;
29,074✔
667
  SFormat sf;
29,074✔
668
  int retry = 0;
29,074✔
669
again:
29,074✔
670
  arg = 1;
29,074✔
671
  sb = lj_buf_tmp_(L);
29,074✔
672
  fmt = lj_lib_checkstr(L, arg);
29,074✔
673
  lj_strfmt_init(&fs, strdata(fmt), fmt->len);
29,074✔
674
  while ((sf = lj_strfmt_parse(&fs)) != STRFMT_EOF) {
443,070✔
675
    if (sf == STRFMT_LIT) {
414,002✔
676
      lj_buf_putmem(sb, fs.str, fs.len);
265,871✔
677
    } else if (sf == STRFMT_ERR) {
148,131✔
678
      lj_err_callerv(L, LJ_ERR_STRFMT, strdata(lj_str_new(L, fs.str, fs.len)));
4✔
679
    } else {
680
      if (++arg > top)
148,127✔
681
        luaL_argerror(L, arg, lj_obj_typename[0]);
1✔
682
      switch (STRFMT_TYPE(sf)) {
148,126✔
683
      case STRFMT_INT:
684
        if (tvisint(L->base+arg-1)) {
8,655✔
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));
8,655✔
692
        }
693
        break;
8,654✔
694
      case STRFMT_UINT:
695
        if (tvisint(L->base+arg-1))
208✔
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));
208✔
699
        break;
208✔
700
      case STRFMT_NUM:
1,078✔
701
        lj_strfmt_putfnum(sb, sf, lj_lib_checknum(L, arg));
1,078✔
702
        break;
1,078✔
703
      case STRFMT_STR: {
138,171✔
704
        GCstr *str = string_fmt_tostring(L, arg, retry);
138,171✔
705
        if (str == NULL)
138,171✔
706
          retry = 1;
707
        else if ((sf & STRFMT_T_QUOTED))
138,171✔
708
          lj_strfmt_putquoted(sb, str);  /* No formatting. */
118✔
709
        else
710
          lj_strfmt_putfstr(sb, sf, str);
138,053✔
711
        break;
712
        }
713
      case STRFMT_CHAR:
12✔
714
        lj_strfmt_putfchar(sb, sf, lj_lib_checkint(L, arg));
12✔
715
        break;
12✔
716
      case STRFMT_PTR:  /* No formatting. */
2✔
717
        lj_strfmt_putptr(sb, lj_obj_ptr(G(L), L->base+arg-1));
2✔
718
        break;
2✔
719
      default:
720
        lj_assertL(0, "bad string format type");
721
        break;
722
      }
723
    }
724
  }
725
  if (retry++ == 1) goto again;
29,068✔
726
  setstrV(L, L->top-1, lj_buf_str(L, sb));
29,068✔
727
  lj_gc_check(L);
29,068✔
728
  return 1;
29,068✔
729
}
730

731
/* ------------------------------------------------------------------------ */
732

733
#include "lj_libdef.h"
734

735
LUALIB_API int luaopen_string(lua_State *L)
338✔
736
{
737
  GCtab *mt;
338✔
738
  global_State *g;
338✔
739
  LJ_LIB_REG(L, LUA_STRLIBNAME, string);
338✔
740
  mt = lj_tab_new(L, 0, 1);
338✔
741
  /* NOBARRIER: basemt is a GC root. */
742
  g = G(L);
338✔
743
  setgcref(basemt_it(g, LJ_TSTR), obj2gco(mt));
338✔
744
  settabV(L, lj_tab_setstr(L, mt, mmname_str(g, MM_index)), tabV(L->top-1));
338✔
745
  mt->nomm = (uint8_t)(~(1u<<MM_index));
338✔
746
  return 1;
338✔
747
}
748

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc