- [NEW] Lo mateix que he dit pa mini-debugger, pero la part del motor ^__^

This commit is contained in:
2026-03-30 23:06:22 +02:00
parent 9f8533f62b
commit b78fbe4378

353
lua.cpp
View File

@@ -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"] = "<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) {
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) {