- [NEW] Lo mateix que he dit pa mini-debugger, pero la part del motor ^__^
This commit is contained in:
353
lua.cpp
353
lua.cpp
@@ -115,12 +115,10 @@ json getStackTrace(lua_State* L) {
|
|||||||
while (lua_getstack(L, depth, &ar)) {
|
while (lua_getstack(L, depth, &ar)) {
|
||||||
lua_getinfo(L, "nSl", &ar);
|
lua_getinfo(L, "nSl", &ar);
|
||||||
|
|
||||||
const char* src = ar.source;
|
//const char* src = chunkToPath(ar.source).c_str();
|
||||||
if (src[0] == '@')
|
|
||||||
src++;
|
|
||||||
|
|
||||||
json frame = {
|
json frame = {
|
||||||
{ "file", src },
|
{ "file", chunkToPath(ar.source).c_str() },
|
||||||
{ "line", ar.currentline },
|
{ "line", ar.currentline },
|
||||||
{ "name", ar.name ? ar.name : "?" }
|
{ "name", ar.name ? ar.name : "?" }
|
||||||
};
|
};
|
||||||
@@ -134,12 +132,327 @@ json getStackTrace(lua_State* L) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int allocateRefForTable(lua_State* L, int index) {
|
||||||
|
lua_pushvalue(L, index); // copia la tabla
|
||||||
|
int ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
json getLocals(lua_State* L) {
|
||||||
|
json vars = json::array();
|
||||||
|
|
||||||
|
lua_Debug ar;
|
||||||
|
// Obtenemos el frame 0 (el actual)
|
||||||
|
if (!lua_getstack(L, 0, &ar)) {
|
||||||
|
return json{ {"variables", vars} };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pedimos info del frame
|
||||||
|
lua_getinfo(L, "nSl", &ar);
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
const char* name;
|
||||||
|
|
||||||
|
while ((name = lua_getlocal(L, &ar, i)) != NULL) {
|
||||||
|
|
||||||
|
if (strcmp(name, "(temporary)") == 0) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// El valor está ahora en la pila
|
||||||
|
json v;
|
||||||
|
|
||||||
|
v["name"] = name;
|
||||||
|
|
||||||
|
// Convertimos el valor Lua a string y tipo
|
||||||
|
int type = lua_type(L, -1);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
||||||
|
v["type"] = "number";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
||||||
|
v["type"] = "boolean";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TSTRING:
|
||||||
|
v["value"] = lua_tostring(L, -1);
|
||||||
|
v["type"] = "string";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TTABLE:
|
||||||
|
v["value"] = "{table}";
|
||||||
|
v["type"] = "table";
|
||||||
|
v["ref"] = allocateRefForTable(L, -1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TFUNCTION:
|
||||||
|
v["value"] = "function";
|
||||||
|
v["type"] = "function";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TNIL:
|
||||||
|
v["value"] = "nil";
|
||||||
|
v["type"] = "nil";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
v["value"] = lua_typename(L, type);
|
||||||
|
v["type"] = lua_typename(L, type);
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.push_back(v);
|
||||||
|
|
||||||
|
// Quitamos el valor de la pila
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json{
|
||||||
|
{ "variables", vars }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
json getUpvalues(lua_State* L) {
|
||||||
|
json vars = json::array();
|
||||||
|
|
||||||
|
lua_Debug ar;
|
||||||
|
if (!lua_getstack(L, 0, &ar)) {
|
||||||
|
return json{ {"variables", vars} };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pedimos info del frame, incluyendo la función ("f")
|
||||||
|
lua_getinfo(L, "nSlf", &ar);
|
||||||
|
|
||||||
|
// La función está ahora en la pila
|
||||||
|
int funcIndex = lua_gettop(L);
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
const char* name;
|
||||||
|
|
||||||
|
while ((name = lua_getupvalue(L, funcIndex, i)) != NULL) {
|
||||||
|
json v;
|
||||||
|
v["name"] = name;
|
||||||
|
|
||||||
|
int type = lua_type(L, -1);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
||||||
|
v["type"] = "number";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
||||||
|
v["type"] = "boolean";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TSTRING:
|
||||||
|
v["value"] = lua_tostring(L, -1);
|
||||||
|
v["type"] = "string";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TTABLE:
|
||||||
|
v["value"] = "{table}";
|
||||||
|
v["type"] = "table";
|
||||||
|
v["ref"] = allocateRefForTable(L, -1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TNIL:
|
||||||
|
v["value"] = "nil";
|
||||||
|
v["type"] = "nil";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
v["value"] = lua_typename(L, type);
|
||||||
|
v["type"] = lua_typename(L, type);
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.push_back(v);
|
||||||
|
|
||||||
|
lua_pop(L, 1); // quitamos el valor del upvalue
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quitamos la función del stack
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
return json{
|
||||||
|
{ "variables", vars }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
json getGlobals(lua_State* L) {
|
||||||
|
json vars = json::array();
|
||||||
|
|
||||||
|
// Empujamos _G a la pila
|
||||||
|
lua_pushglobaltable(L); // equivalente a lua_getglobal(L, "_G")
|
||||||
|
|
||||||
|
lua_pushnil(L); // primera clave
|
||||||
|
while (lua_next(L, -2) != 0) {
|
||||||
|
// Ahora en la pila:
|
||||||
|
// -1 → valor
|
||||||
|
// -2 → clave
|
||||||
|
// -3 → _G
|
||||||
|
|
||||||
|
// Solo aceptamos claves string
|
||||||
|
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||||
|
const char* name = lua_tostring(L, -2);
|
||||||
|
|
||||||
|
json v;
|
||||||
|
v["name"] = name;
|
||||||
|
|
||||||
|
int type = lua_type(L, -1);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
||||||
|
v["type"] = "number";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
||||||
|
v["type"] = "boolean";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TSTRING:
|
||||||
|
v["value"] = lua_tostring(L, -1);
|
||||||
|
v["type"] = "string";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TTABLE:
|
||||||
|
v["value"] = "{table}";
|
||||||
|
v["type"] = "table";
|
||||||
|
v["ref"] = allocateRefForTable(L, -1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TFUNCTION:
|
||||||
|
v["value"] = "function";
|
||||||
|
v["type"] = "function";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TNIL:
|
||||||
|
v["value"] = "nil";
|
||||||
|
v["type"] = "nil";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
v["value"] = lua_typename(L, type);
|
||||||
|
v["type"] = lua_typename(L, type);
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.push_back(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1); // pop valor, deja clave para lua_next
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1); // pop _G
|
||||||
|
|
||||||
|
return json{
|
||||||
|
{ "variables", vars }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
json expandTable(lua_State* L, int ref) {
|
||||||
|
json vars = json::array();
|
||||||
|
|
||||||
|
// Recuperamos la tabla del registry
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||||
|
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, -2) != 0) {
|
||||||
|
json v;
|
||||||
|
|
||||||
|
// clave
|
||||||
|
if (lua_type(L, -2) == LUA_TSTRING) {
|
||||||
|
v["name"] = lua_tostring(L, -2);
|
||||||
|
} else if (lua_type(L, -2) == LUA_TNUMBER) {
|
||||||
|
v["name"] = std::to_string(lua_tonumber(L, -2));
|
||||||
|
} else {
|
||||||
|
v["name"] = "<non-string-key>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// valor
|
||||||
|
int type = lua_type(L, -1);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
v["value"] = std::to_string(lua_tonumber(L, -1));
|
||||||
|
v["type"] = "number";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TBOOLEAN:
|
||||||
|
v["value"] = lua_toboolean(L, -1) ? "true" : "false";
|
||||||
|
v["type"] = "boolean";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TSTRING:
|
||||||
|
v["value"] = lua_tostring(L, -1);
|
||||||
|
v["type"] = "string";
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LUA_TTABLE:
|
||||||
|
v["value"] = "{table}";
|
||||||
|
v["type"] = "table";
|
||||||
|
v["ref"] = allocateRefForTable(L, -1);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
v["value"] = lua_typename(L, type);
|
||||||
|
v["type"] = lua_typename(L, type);
|
||||||
|
v["ref"] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
vars.push_back(v);
|
||||||
|
|
||||||
|
lua_pop(L, 1); // pop valor
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1); // pop tabla
|
||||||
|
|
||||||
|
return json{
|
||||||
|
{ "kind", "expand" },
|
||||||
|
{ "variables", vars }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void sendDebugResponse(const std::string& type, const json& payload) {
|
void sendDebugResponse(const std::string& type, const json& payload) {
|
||||||
json msg = {
|
json msg = {
|
||||||
{ "type", type },
|
{ "type", type },
|
||||||
{ "payload", payload }
|
{ "payload", payload }
|
||||||
};
|
};
|
||||||
printf("STACKTRACE: %s", msg.dump().c_str());
|
//printf("STACKTRACE: %s", msg.dump().c_str());
|
||||||
std::cout << "@@DEBUG@@" << msg.dump() << std::endl;
|
std::cout << "@@DEBUG@@" << msg.dump() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +500,36 @@ void processDebugCommand(const std::string& line) {
|
|||||||
json result = getStackTrace(L);
|
json result = getStackTrace(L);
|
||||||
sendDebugResponse("stackTrace", result);
|
sendDebugResponse("stackTrace", result);
|
||||||
}
|
}
|
||||||
|
else if (cmd == "locals") {
|
||||||
|
json result = getLocals(L);
|
||||||
|
json payload = {
|
||||||
|
{ "kind", "locals" },
|
||||||
|
{ "variables", result["variables"] }
|
||||||
|
};
|
||||||
|
sendDebugResponse("variables", payload);
|
||||||
|
}
|
||||||
|
else if (cmd == "upvalues") {
|
||||||
|
json result = getUpvalues(L);
|
||||||
|
json payload = {
|
||||||
|
{ "kind", "upvalues" },
|
||||||
|
{ "variables", result["variables"] }
|
||||||
|
};
|
||||||
|
sendDebugResponse("variables", payload);
|
||||||
|
}
|
||||||
|
else if (cmd == "globals") {
|
||||||
|
json result = getGlobals(L);
|
||||||
|
json payload = {
|
||||||
|
{ "kind", "globals" },
|
||||||
|
{ "variables", result["variables"] }
|
||||||
|
};
|
||||||
|
sendDebugResponse("variables", payload);
|
||||||
|
}
|
||||||
|
else if (cmd == "expand") {
|
||||||
|
int ref = j["ref"];
|
||||||
|
json result = expandTable(L, ref);
|
||||||
|
sendDebugResponse("variables", result);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isBreakpoint(const std::string& file, int line) {
|
bool isBreakpoint(const std::string& file, int line) {
|
||||||
|
|||||||
Reference in New Issue
Block a user