Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/VM/src/laux.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
// This code is based on Lua 5.x implementation licensed under MIT License; see lua_LICENSE.txt for details
3
#include "lualib.h"
4
5
#include "lobject.h"
6
#include "lstate.h"
7
#include "lstring.h"
8
#include "lapi.h"
9
#include "lgc.h"
10
#include "lnumutils.h"
11
12
#include <string.h>
13
14
LUAU_FASTFLAG(LuauStacklessPcall)
15
LUAU_FASTFLAG(LuauIntegerType)
16
17
// convert a stack index to positive
18
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
19
20
/*
21
** {======================================================
22
** Error-report functions
23
** =======================================================
24
*/
25
26
static const char* currfuncname(lua_State* L)
27
{
28
Closure* cl = L->ci > L->base_ci ? curr_func(L) : NULL;
29
const char* debugname = cl && cl->isC ? cl->c.debugname + 0 : NULL;
30
31
if (debugname && strcmp(debugname, "__namecall") == 0)
32
return L->namecall ? getstr(L->namecall) : NULL;
33
else
34
return debugname;
35
}
36
37
l_noret luaL_argerrorL(lua_State* L, int narg, const char* extramsg)
38
{
39
const char* fname = currfuncname(L);
40
41
if (fname)
42
luaL_error(L, "invalid argument #%d to '%s' (%s)", narg, fname, extramsg);
43
else
44
luaL_error(L, "invalid argument #%d (%s)", narg, extramsg);
45
}
46
47
l_noret luaL_typeerrorL(lua_State* L, int narg, const char* tname)
48
{
49
const char* fname = currfuncname(L);
50
const TValue* obj = luaA_toobject(L, narg);
51
52
if (obj)
53
{
54
if (fname)
55
luaL_error(L, "invalid argument #%d to '%s' (%s expected, got %s)", narg, fname, tname, luaT_objtypename(L, obj));
56
else
57
luaL_error(L, "invalid argument #%d (%s expected, got %s)", narg, tname, luaT_objtypename(L, obj));
58
}
59
else
60
{
61
if (fname)
62
luaL_error(L, "missing argument #%d to '%s' (%s expected)", narg, fname, tname);
63
else
64
luaL_error(L, "missing argument #%d (%s expected)", narg, tname);
65
}
66
}
67
68
static l_noret tag_error(lua_State* L, int narg, int tag)
69
{
70
luaL_typeerrorL(L, narg, lua_typename(L, tag));
71
}
72
73
// Can be called without stack space reservation
74
void luaL_where(lua_State* L, int level)
75
{
76
lua_Debug ar;
77
if (lua_getinfo(L, level, "sl", &ar) && ar.currentline > 0)
78
{
79
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
80
return;
81
}
82
83
lua_rawcheckstack(L, 1);
84
lua_pushliteral(L, ""); // else, no information available...
85
}
86
87
// Can be called without stack space reservation
88
l_noret luaL_errorL(lua_State* L, const char* fmt, ...)
89
{
90
va_list argp;
91
va_start(argp, fmt);
92
luaL_where(L, 1);
93
lua_pushvfstring(L, fmt, argp);
94
va_end(argp);
95
lua_concat(L, 2);
96
lua_error(L);
97
}
98
99
// }======================================================
100
101
int luaL_checkoption(lua_State* L, int narg, const char* def, const char* const lst[])
102
{
103
const char* name = (def) ? luaL_optstring(L, narg, def) : luaL_checkstring(L, narg);
104
int i;
105
for (i = 0; lst[i]; i++)
106
if (strcmp(lst[i], name) == 0)
107
return i;
108
const char* msg = lua_pushfstring(L, "invalid option '%s'", name);
109
luaL_argerrorL(L, narg, msg);
110
}
111
112
int luaL_newmetatable(lua_State* L, const char* tname)
113
{
114
lua_getfield(L, LUA_REGISTRYINDEX, tname); // get registry.name
115
if (!lua_isnil(L, -1)) // name already in use?
116
return 0; // leave previous value on top, but return 0
117
lua_pop(L, 1);
118
lua_newtable(L); // create metatable
119
lua_pushvalue(L, -1);
120
lua_setfield(L, LUA_REGISTRYINDEX, tname); // registry.name = metatable
121
return 1;
122
}
123
124
void* luaL_checkudata(lua_State* L, int ud, const char* tname)
125
{
126
void* p = lua_touserdata(L, ud);
127
if (p != NULL)
128
{ // value is a userdata?
129
if (lua_getmetatable(L, ud))
130
{ // does it have a metatable?
131
lua_getfield(L, LUA_REGISTRYINDEX, tname); // get correct metatable
132
if (lua_rawequal(L, -1, -2))
133
{ // does it have the correct mt?
134
lua_pop(L, 2); // remove both metatables
135
return p;
136
}
137
}
138
}
139
luaL_typeerrorL(L, ud, tname); // else error
140
}
141
142
void* luaL_checkbuffer(lua_State* L, int narg, size_t* len)
143
{
144
void* b = lua_tobuffer(L, narg, len);
145
if (!b)
146
tag_error(L, narg, LUA_TBUFFER);
147
return b;
148
}
149
150
void luaL_checkstack(lua_State* L, int space, const char* mes)
151
{
152
if (!lua_checkstack(L, space))
153
luaL_error(L, "stack overflow (%s)", mes);
154
}
155
156
void luaL_checktype(lua_State* L, int narg, int t)
157
{
158
if (lua_type(L, narg) != t)
159
tag_error(L, narg, t);
160
}
161
162
void luaL_checkany(lua_State* L, int narg)
163
{
164
if (lua_type(L, narg) == LUA_TNONE)
165
luaL_error(L, "missing argument #%d", narg);
166
}
167
168
const char* luaL_checklstring(lua_State* L, int narg, size_t* len)
169
{
170
const char* s = lua_tolstring(L, narg, len);
171
if (!s)
172
tag_error(L, narg, LUA_TSTRING);
173
return s;
174
}
175
176
const char* luaL_optlstring(lua_State* L, int narg, const char* def, size_t* len)
177
{
178
if (lua_isnoneornil(L, narg))
179
{
180
if (len)
181
*len = (def ? strlen(def) : 0);
182
return def;
183
}
184
else
185
return luaL_checklstring(L, narg, len);
186
}
187
188
double luaL_checknumber(lua_State* L, int narg)
189
{
190
int isnum;
191
double d = lua_tonumberx(L, narg, &isnum);
192
if (!isnum)
193
tag_error(L, narg, LUA_TNUMBER);
194
return d;
195
}
196
197
double luaL_optnumber(lua_State* L, int narg, double def)
198
{
199
return luaL_opt(L, luaL_checknumber, narg, def);
200
}
201
202
int luaL_checkboolean(lua_State* L, int narg)
203
{
204
// This checks specifically for boolean values, ignoring
205
// all other truthy/falsy values. If the desired result
206
// is true if value is present then lua_toboolean should
207
// directly be used instead.
208
if (!lua_isboolean(L, narg))
209
tag_error(L, narg, LUA_TBOOLEAN);
210
return lua_toboolean(L, narg);
211
}
212
213
int luaL_optboolean(lua_State* L, int narg, int def)
214
{
215
return luaL_opt(L, luaL_checkboolean, narg, def);
216
}
217
218
int luaL_checkinteger(lua_State* L, int narg)
219
{
220
int isnum;
221
int d = lua_tointegerx(L, narg, &isnum);
222
if (!isnum)
223
tag_error(L, narg, LUA_TNUMBER);
224
return d;
225
}
226
227
int64_t luaL_checkinteger64(lua_State* L, int narg)
228
{
229
if (!lua_isinteger64(L, narg))
230
tag_error(L, narg, LUA_TINTEGER);
231
return lua_tointeger64(L, narg, nullptr);
232
}
233
234
int luaL_optinteger(lua_State* L, int narg, int def)
235
{
236
return luaL_opt(L, luaL_checkinteger, narg, def);
237
}
238
239
int64_t luaL_optinteger64(lua_State* L, int narg, int64_t def)
240
{
241
return luaL_opt(L, luaL_checkinteger64, narg, def);
242
}
243
244
unsigned luaL_checkunsigned(lua_State* L, int narg)
245
{
246
int isnum;
247
unsigned d = lua_tounsignedx(L, narg, &isnum);
248
if (!isnum)
249
tag_error(L, narg, LUA_TNUMBER);
250
return d;
251
}
252
253
unsigned luaL_optunsigned(lua_State* L, int narg, unsigned def)
254
{
255
return luaL_opt(L, luaL_checkunsigned, narg, def);
256
}
257
258
const float* luaL_checkvector(lua_State* L, int narg)
259
{
260
const float* v = lua_tovector(L, narg);
261
if (!v)
262
tag_error(L, narg, LUA_TVECTOR);
263
return v;
264
}
265
266
const float* luaL_optvector(lua_State* L, int narg, const float* def)
267
{
268
return luaL_opt(L, luaL_checkvector, narg, def);
269
}
270
271
int luaL_getmetafield(lua_State* L, int obj, const char* event)
272
{
273
if (!lua_getmetatable(L, obj)) // no metatable?
274
return 0;
275
lua_pushstring(L, event);
276
lua_rawget(L, -2);
277
if (lua_isnil(L, -1))
278
{
279
lua_pop(L, 2); // remove metatable and metafield
280
return 0;
281
}
282
else
283
{
284
lua_remove(L, -2); // remove only metatable
285
return 1;
286
}
287
}
288
289
int luaL_callmeta(lua_State* L, int obj, const char* event)
290
{
291
obj = abs_index(L, obj);
292
if (!luaL_getmetafield(L, obj, event)) // no metafield?
293
return 0;
294
lua_pushvalue(L, obj);
295
lua_call(L, 1, 1);
296
return 1;
297
}
298
299
static int libsize(const luaL_Reg* l)
300
{
301
int size = 0;
302
for (; l->name; l++)
303
size++;
304
return size;
305
}
306
307
void luaL_register(lua_State* L, const char* libname, const luaL_Reg* l)
308
{
309
if (libname)
310
{
311
int size = libsize(l);
312
// check whether lib already exists
313
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
314
lua_getfield(L, -1, libname); // get _LOADED[libname]
315
if (!lua_istable(L, -1))
316
{ // not found?
317
lua_pop(L, 1); // remove previous result
318
// try global variable (and create one if it does not exist)
319
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
320
luaL_error(L, "name conflict for module '%s'", libname);
321
lua_pushvalue(L, -1);
322
lua_setfield(L, -3, libname); // _LOADED[libname] = new table
323
}
324
lua_remove(L, -2); // remove _LOADED table
325
}
326
for (; l->name; l++)
327
{
328
lua_pushcfunction(L, l->func, l->name);
329
lua_setfield(L, -2, l->name);
330
}
331
}
332
333
const char* luaL_findtable(lua_State* L, int idx, const char* fname, int szhint)
334
{
335
const char* e;
336
lua_pushvalue(L, idx);
337
do
338
{
339
e = strchr(fname, '.');
340
if (e == NULL)
341
e = fname + strlen(fname);
342
lua_pushlstring(L, fname, e - fname);
343
lua_rawget(L, -2);
344
if (lua_isnil(L, -1))
345
{ // no such field?
346
lua_pop(L, 1); // remove this nil
347
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); // new table for field
348
lua_pushlstring(L, fname, e - fname);
349
lua_pushvalue(L, -2);
350
lua_settable(L, -4); // set new table into field
351
}
352
else if (!lua_istable(L, -1))
353
{ // field has a non-table value?
354
lua_pop(L, 2); // remove table and value
355
return fname; // return problematic part of the name
356
}
357
lua_remove(L, -2); // remove previous table
358
fname = e + 1;
359
} while (*e == '.');
360
return NULL;
361
}
362
363
const char* luaL_typename(lua_State* L, int idx)
364
{
365
const TValue* obj = luaA_toobject(L, idx);
366
return obj ? luaT_objtypename(L, obj) : "no value";
367
}
368
369
int luaL_callyieldable(lua_State* L, int nargs, int nresults)
370
{
371
api_check(L, iscfunction(L->ci->func));
372
Closure* cl = clvalue(L->ci->func);
373
api_check(L, cl->c.cont);
374
375
lua_call(L, nargs, nresults);
376
377
if (FFlag::LuauStacklessPcall)
378
{
379
// yielding means we need to propagate yield; resume will call continuation function later
380
if (isyielded(L))
381
return C_CALL_YIELD;
382
}
383
else
384
{
385
if (L->status == LUA_YIELD || L->status == LUA_BREAK)
386
return -1; // -1 is a marker for yielding from C
387
}
388
389
return cl->c.cont(L, LUA_OK);
390
}
391
392
void luaL_traceback(lua_State* L, lua_State* L1, const char* msg, int level)
393
{
394
api_check(L, level >= 0);
395
396
luaL_Strbuf buf;
397
luaL_buffinit(L, &buf);
398
399
if (msg)
400
{
401
luaL_addstring(&buf, msg);
402
luaL_addstring(&buf, "\n");
403
}
404
405
lua_Debug ar;
406
for (int i = level; lua_getinfo(L1, i, "sln", &ar); ++i)
407
{
408
if (strcmp(ar.what, "C") == 0)
409
continue;
410
411
if (ar.source)
412
luaL_addstring(&buf, ar.short_src);
413
414
if (ar.currentline > 0)
415
{
416
char line[32]; // manual conversion for performance
417
char* lineend = line + sizeof(line);
418
char* lineptr = lineend;
419
for (unsigned int r = ar.currentline; r > 0; r /= 10)
420
*--lineptr = '0' + (r % 10);
421
422
luaL_addchar(&buf, ':');
423
luaL_addlstring(&buf, lineptr, lineend - lineptr);
424
}
425
426
if (ar.name)
427
{
428
luaL_addstring(&buf, " function ");
429
luaL_addstring(&buf, ar.name);
430
}
431
432
luaL_addchar(&buf, '\n');
433
}
434
435
luaL_pushresult(&buf);
436
}
437
438
439
/*
440
** {======================================================
441
** Generic Buffer manipulation
442
** =======================================================
443
*/
444
445
static size_t getnextbuffersize(lua_State* L, size_t currentsize, size_t desiredsize)
446
{
447
size_t newsize = currentsize + currentsize / 2;
448
449
// check for size overflow
450
if (SIZE_MAX - desiredsize < currentsize)
451
luaL_error(L, "buffer too large");
452
453
// growth factor might not be enough to satisfy the desired size
454
if (newsize < desiredsize)
455
newsize = desiredsize;
456
457
return newsize;
458
}
459
460
static char* extendstrbuf(luaL_Strbuf* B, size_t additionalsize, int boxloc)
461
{
462
lua_State* L = B->L;
463
464
if (B->storage)
465
LUAU_ASSERT(B->storage == tsvalue(L->top + boxloc));
466
467
char* base = B->storage ? B->storage->data : B->buffer;
468
469
size_t capacity = B->end - base;
470
size_t nextsize = getnextbuffersize(B->L, capacity, capacity + additionalsize);
471
472
TString* newStorage = luaS_bufstart(L, nextsize);
473
474
memcpy(newStorage->data, base, B->p - base);
475
476
// place the string storage at the expected position in the stack
477
if (base == B->buffer)
478
{
479
lua_pushnil(L);
480
lua_insert(L, boxloc);
481
}
482
483
setsvalue(L, L->top + boxloc, newStorage);
484
B->p = newStorage->data + (B->p - base);
485
B->end = newStorage->data + nextsize;
486
B->storage = newStorage;
487
488
return B->p;
489
}
490
491
void luaL_buffinit(lua_State* L, luaL_Strbuf* B)
492
{
493
// start with an internal buffer
494
B->p = B->buffer;
495
B->end = B->p + LUA_BUFFERSIZE;
496
497
B->L = L;
498
B->storage = nullptr;
499
}
500
501
char* luaL_buffinitsize(lua_State* L, luaL_Strbuf* B, size_t size)
502
{
503
luaL_buffinit(L, B);
504
return luaL_prepbuffsize(B, size);
505
}
506
507
char* luaL_prepbuffsize(luaL_Strbuf* B, size_t size)
508
{
509
if (size_t(B->end - B->p) < size)
510
return extendstrbuf(B, size - (B->end - B->p), -1);
511
return B->p;
512
}
513
514
void luaL_addlstring(luaL_Strbuf* B, const char* s, size_t len)
515
{
516
if (size_t(B->end - B->p) < len)
517
extendstrbuf(B, len - (B->end - B->p), -1);
518
519
memcpy(B->p, s, len);
520
B->p += len;
521
}
522
523
void luaL_addvalue(luaL_Strbuf* B)
524
{
525
lua_State* L = B->L;
526
527
size_t vl;
528
if (const char* s = lua_tolstring(L, -1, &vl))
529
{
530
if (size_t(B->end - B->p) < vl)
531
extendstrbuf(B, vl - (B->end - B->p), -2);
532
533
memcpy(B->p, s, vl);
534
B->p += vl;
535
536
lua_pop(L, 1);
537
}
538
}
539
540
void luaL_addvalueany(luaL_Strbuf* B, int idx)
541
{
542
lua_State* L = B->L;
543
544
switch (lua_type(L, idx))
545
{
546
case LUA_TNONE:
547
{
548
LUAU_ASSERT(!"expected value");
549
break;
550
}
551
case LUA_TNIL:
552
luaL_addstring(B, "nil");
553
break;
554
case LUA_TBOOLEAN:
555
if (lua_toboolean(L, idx))
556
luaL_addstring(B, "true");
557
else
558
luaL_addstring(B, "false");
559
break;
560
case LUA_TNUMBER:
561
{
562
double n = lua_tonumber(L, idx);
563
char s[LUAI_MAXNUM2STR];
564
char* e = luai_num2str(s, n);
565
luaL_addlstring(B, s, e - s);
566
break;
567
}
568
case LUA_TSTRING:
569
{
570
size_t len;
571
const char* s = lua_tolstring(L, idx, &len);
572
luaL_addlstring(B, s, len);
573
break;
574
}
575
case LUA_TINTEGER:
576
if (FFlag::LuauIntegerType)
577
{
578
int64_t n = lua_tointeger64(L, idx, nullptr);
579
char s[LUAI_MAXINT2STR];
580
char* e = luai_int2str(s, n);
581
luaL_addlstring(B, s, e - s);
582
break;
583
}
584
[[fallthrough]];
585
default:
586
{
587
size_t len;
588
luaL_tolstring(L, idx, &len);
589
590
// note: luaL_addlstring assumes box is stored at top of stack, so we can't call it here
591
// instead we use luaL_addvalue which will take the string from the top of the stack and add that
592
luaL_addvalue(B);
593
}
594
}
595
}
596
597
void luaL_pushresult(luaL_Strbuf* B)
598
{
599
lua_State* L = B->L;
600
601
if (TString* storage = B->storage)
602
{
603
luaC_checkGC(L);
604
605
// if we finished just at the end of the string buffer, we can convert it to a mutable stirng without a copy
606
if (B->p == B->end)
607
{
608
setsvalue(L, L->top - 1, luaS_buffinish(L, storage));
609
}
610
else
611
{
612
setsvalue(L, L->top - 1, luaS_newlstr(L, storage->data, B->p - storage->data));
613
}
614
}
615
else
616
{
617
lua_pushlstring(L, B->buffer, B->p - B->buffer);
618
}
619
}
620
621
void luaL_pushresultsize(luaL_Strbuf* B, size_t size)
622
{
623
B->p += size;
624
luaL_pushresult(B);
625
}
626
627
// }======================================================
628
629
const char* luaL_tolstring(lua_State* L, int idx, size_t* len)
630
{
631
if (luaL_callmeta(L, idx, "__tostring")) // is there a metafield?
632
{
633
const char* s = lua_tolstring(L, -1, len);
634
if (!s)
635
luaL_error(L, "'__tostring' must return a string");
636
return s;
637
}
638
639
switch (lua_type(L, idx))
640
{
641
case LUA_TNIL:
642
lua_pushliteral(L, "nil");
643
break;
644
case LUA_TBOOLEAN:
645
lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
646
break;
647
case LUA_TNUMBER:
648
{
649
double n = lua_tonumber(L, idx);
650
char s[LUAI_MAXNUM2STR];
651
char* e = luai_num2str(s, n);
652
lua_pushlstring(L, s, e - s);
653
break;
654
}
655
case LUA_TVECTOR:
656
{
657
const float* v = lua_tovector(L, idx);
658
659
char s[LUAI_MAXNUM2STR * LUA_VECTOR_SIZE];
660
char* e = s;
661
for (int i = 0; i < LUA_VECTOR_SIZE; ++i)
662
{
663
if (i != 0)
664
{
665
*e++ = ',';
666
*e++ = ' ';
667
}
668
e = luai_num2str(e, v[i]);
669
}
670
lua_pushlstring(L, s, e - s);
671
break;
672
}
673
case LUA_TSTRING:
674
lua_pushvalue(L, idx);
675
break;
676
case LUA_TINTEGER:
677
if (FFlag::LuauIntegerType)
678
{
679
int64_t l = lua_tointeger64(L, idx, nullptr);
680
char s[LUAI_MAXINT2STR];
681
char* e = luai_int2str(s, l);
682
lua_pushlstring(L, s, e - s);
683
break;
684
}
685
[[fallthrough]];
686
default:
687
{
688
const void* ptr = lua_topointer(L, idx);
689
unsigned long long enc = lua_encodepointer(L, uintptr_t(ptr));
690
lua_pushfstring(L, "%s: 0x%016llx", luaL_typename(L, idx), enc);
691
break;
692
}
693
}
694
return lua_tolstring(L, -1, len);
695
}
696
697