From b78fbe437888b18b389b39cacc70757ee472fdb3 Mon Sep 17 00:00:00 2001 From: Raimon Zamora Date: Mon, 30 Mar 2026 23:06:22 +0200 Subject: [PATCH] - [NEW] Lo mateix que he dit pa mini-debugger, pero la part del motor ^__^ --- lua.cpp | 353 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 348 insertions(+), 5 deletions(-) diff --git a/lua.cpp b/lua.cpp index ad48475..1c042f0 100644 --- a/lua.cpp +++ b/lua.cpp @@ -115,12 +115,10 @@ json getStackTrace(lua_State* L) { while (lua_getstack(L, depth, &ar)) { lua_getinfo(L, "nSl", &ar); - const char* src = ar.source; - if (src[0] == '@') - src++; + //const char* src = chunkToPath(ar.source).c_str(); json frame = { - { "file", src }, + { "file", chunkToPath(ar.source).c_str() }, { "line", ar.currentline }, { "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"] = ""; + } + + // 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) { json msg = { { "type", type }, { "payload", payload } }; - printf("STACKTRACE: %s", msg.dump().c_str()); + //printf("STACKTRACE: %s", msg.dump().c_str()); std::cout << "@@DEBUG@@" << msg.dump() << std::endl; } @@ -187,6 +500,36 @@ void processDebugCommand(const std::string& line) { json result = getStackTrace(L); 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) {