- [NEW] [debugger] Soport per a expressions evaluables desde consola de vscode
This commit is contained in:
121
lua.cpp
121
lua.cpp
@@ -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) {
|
||||
json msg = {
|
||||
{ "type", type },
|
||||
@@ -529,7 +641,16 @@ void processDebugCommand(const std::string& line) {
|
||||
json result = expandTable(L, ref);
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user