diff --git a/lua.cpp b/lua.cpp index 1c042f0..d0cee69 100644 --- a/lua.cpp +++ b/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) {