Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/VM/src/ldblib.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 "lvm.h"
6
7
#include <string.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10
11
static lua_State* getthread(lua_State* L, int* arg)
12
{
13
if (lua_isthread(L, 1))
14
{
15
*arg = 1;
16
return lua_tothread(L, 1);
17
}
18
else
19
{
20
*arg = 0;
21
return L;
22
}
23
}
24
25
static int db_info(lua_State* L)
26
{
27
int arg;
28
lua_State* L1 = getthread(L, &arg);
29
int l1top = 0;
30
31
// if L1 != L, L1 can be in any state, and therefore there are no guarantees about its stack space
32
if (L != L1)
33
{
34
// for 'f' option, we reserve one slot and we also record the stack top
35
lua_rawcheckstack(L1, 1);
36
37
l1top = lua_gettop(L1);
38
}
39
40
int level;
41
if (lua_isnumber(L, arg + 1))
42
{
43
level = (int)lua_tointeger(L, arg + 1);
44
luaL_argcheck(L, level >= 0, arg + 1, "level can't be negative");
45
}
46
else if (arg == 0 && lua_isfunction(L, 1))
47
{
48
// convert absolute index to relative index
49
level = -lua_gettop(L);
50
}
51
else
52
luaL_argerror(L, arg + 1, "function or level expected");
53
54
const char* options = luaL_checkstring(L, arg + 2);
55
56
lua_Debug ar;
57
if (!lua_getinfo(L1, level, options, &ar))
58
return 0;
59
60
int results = 0;
61
bool occurs[26] = {};
62
63
for (const char* it = options; *it; ++it)
64
{
65
if (unsigned(*it - 'a') < 26)
66
{
67
if (occurs[*it - 'a'])
68
{
69
// restore stack state of another thread as 'f' option might not have been visited yet
70
if (L != L1)
71
lua_settop(L1, l1top);
72
73
luaL_argerror(L, arg + 2, "duplicate option");
74
}
75
occurs[*it - 'a'] = true;
76
}
77
78
switch (*it)
79
{
80
case 's':
81
lua_pushstring(L, ar.short_src);
82
results++;
83
break;
84
85
case 'l':
86
lua_pushinteger(L, ar.currentline);
87
results++;
88
break;
89
90
case 'n':
91
lua_pushstring(L, ar.name ? ar.name : "");
92
results++;
93
break;
94
95
case 'f':
96
if (L1 == L)
97
lua_pushvalue(L, -1 - results); // function is right before results
98
else
99
lua_xmove(L1, L, 1); // function is at top of L1
100
results++;
101
break;
102
103
case 'a':
104
lua_pushinteger(L, ar.nparams);
105
lua_pushboolean(L, ar.isvararg);
106
results += 2;
107
break;
108
109
default:
110
// restore stack state of another thread as 'f' option might not have been visited yet
111
if (L != L1)
112
lua_settop(L1, l1top);
113
114
luaL_argerror(L, arg + 2, "invalid option");
115
}
116
}
117
118
return results;
119
}
120
121
static int db_traceback(lua_State* L)
122
{
123
int arg;
124
lua_State* L1 = getthread(L, &arg);
125
const char* msg = luaL_optstring(L, arg + 1, NULL);
126
int level = luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
127
luaL_argcheck(L, level >= 0, arg + 2, "level can't be negative");
128
129
luaL_traceback(L, L1, msg, level);
130
131
return 1;
132
}
133
134
static const luaL_Reg dblib[] = {
135
{"info", db_info},
136
{"traceback", db_traceback},
137
{NULL, NULL},
138
};
139
140
int luaopen_debug(lua_State* L)
141
{
142
luaL_register(L, LUA_DBLIBNAME, dblib);
143
return 1;
144
}
145
146