- [NEW] [debugger] Soport per a expressions evaluables desde consola de vscode

This commit is contained in:
2026-03-31 09:20:47 +02:00
parent b78fbe4378
commit 6a24086556

121
lua.cpp
View File

@@ -447,6 +447,118 @@ json expandTable(lua_State* L, int ref) {
}; };
} }
json evalExpression(lua_State* L, const std::string& expr) {
lua_Debug ar;
if (!lua_getstack(L, 0, &ar)) {
return { {"error", "no stack"} };
}
lua_getinfo(L, "nSl", &ar);
// Creamos un entorno para la evaluación
lua_newtable(L); // env
int envIndex = lua_gettop(L);
// 1. Copiar locals al env
int i = 1;
const char* name;
while ((name = lua_getlocal(L, &ar, i)) != NULL) {
lua_setfield(L, envIndex, name);
i++;
}
// 2. Copiar upvalues al env
lua_getinfo(L, "f", &ar);
int funcIndex = lua_gettop(L);
i = 1;
while ((name = lua_getupvalue(L, funcIndex, i)) != NULL) {
lua_setfield(L, envIndex, name);
i++;
}
lua_pop(L, 1); // pop función
// 3. Copiar globals (_G)
lua_pushglobaltable(L);
lua_setfield(L, envIndex, "_G");
// mt = { __index = _G }
lua_newtable(L); // mt
lua_pushglobaltable(L); // _G
lua_setfield(L, -2, "__index"); // mt.__index = _G
// setmetatable(env, mt)
lua_setmetatable(L, envIndex);
// 4. Construir código: función que recibe _ENV
std::string code = "return function(_ENV) return " + expr + " end";
if (luaL_loadbuffer(L, code.c_str(), code.size(), "eval") != LUA_OK) {
std::string err = lua_tostring(L, -1);
lua_pop(L, 1);
return { {"error", err} };
}
// Ejecutar para obtener la función interna
if (lua_pcall(L, 0, 1, 0) != LUA_OK) {
std::string err = lua_tostring(L, -1);
lua_pop(L, 1);
return { {"error", err} };
}
// Ahora en la pila está la función interna
// Le pasamos env como argumento
lua_pushvalue(L, envIndex);
// Llamamos a la función(env)
if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
std::string err = lua_tostring(L, -1);
lua_pop(L, 1);
return { {"error", err} };
}
// Convertir el resultado
json result;
int type = lua_type(L, -1);
switch (type) {
case LUA_TNUMBER:
result["value"] = std::to_string(lua_tonumber(L, -1));
result["type"] = "number";
result["ref"] = 0;
break;
case LUA_TBOOLEAN:
result["value"] = lua_toboolean(L, -1) ? "true" : "false";
result["type"] = "boolean";
result["ref"] = 0;
break;
case LUA_TSTRING:
result["value"] = lua_tostring(L, -1);
result["type"] = "string";
result["ref"] = 0;
break;
case LUA_TTABLE:
result["value"] = "{table}";
result["type"] = "table";
result["ref"] = allocateRefForTable(L, -1);
break;
default:
result["value"] = lua_typename(L, type);
result["type"] = lua_typename(L, type);
result["ref"] = 0;
break;
}
lua_pop(L, 1); // pop result
lua_pop(L, 1); // pop env
return result;
}
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 },
@@ -529,7 +641,16 @@ void processDebugCommand(const std::string& line) {
json result = expandTable(L, ref); json result = expandTable(L, ref);
sendDebugResponse("variables", result); sendDebugResponse("variables", result);
} }
else if (cmd == "eval") {
std::string expr = j["expr"];
json result = evalExpression(L, expr);
json payload = {
{ "kind", "eval" },
{ "result", result }
};
sendDebugResponse("eval", payload);
}
} }
bool isBreakpoint(const std::string& file, int line) { bool isBreakpoint(const std::string& file, int line) {