- [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)) {
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user