- [NEW] (del debugger) Ja funciona: start, pause, stop, breakpoints, step into, step over, step out. Intentant que funcione el enviament del stackTrace

This commit is contained in:
2026-03-30 14:06:09 +02:00
parent 8a4110e821
commit 9f8533f62b
3 changed files with 187 additions and 28 deletions

197
lua.cpp
View File

@@ -6,6 +6,7 @@
#include <filesystem> #include <filesystem>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <stack>
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
@@ -16,6 +17,11 @@
#include <iostream> #include <iostream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
lua_State *L;
bool is_playing = false;
bool init_exists = false;
bool update_exists = false;
std::unordered_map<std::string, std::vector<int>> g_breakpoints; std::unordered_map<std::string, std::vector<int>> g_breakpoints;
std::mutex g_breakMutex; std::mutex g_breakMutex;
@@ -27,6 +33,19 @@ std::atomic<bool> g_paused = false;
std::string g_pauseFile; std::string g_pauseFile;
int g_pauseLine = 0; int g_pauseLine = 0;
bool function_has_breakpoints = false;
std::stack<bool> funBreakStack;
bool debug_enabled = false;
enum StepMode {
STEP_NONE,
STEP_INTO,
STEP_OVER,
STEP_OUT
};
StepMode g_stepMode = STEP_NONE;
int g_stepDepth = 0;
namespace fs = std::filesystem; namespace fs = std::filesystem;
using json = nlohmann::json; using json = nlohmann::json;
@@ -77,6 +96,53 @@ std::string chunkToPath(const std::string& chunk) {
return abs.lexically_normal().string(); return abs.lexically_normal().string();
} }
int getStackDepth(lua_State* L) {
lua_Debug ar;
int depth = 0;
while (lua_getstack(L, depth, &ar)) {
depth++;
}
return depth;
}
json getStackTrace(lua_State* L) {
json frames = json::array();
lua_Debug ar;
int depth = 0;
while (lua_getstack(L, depth, &ar)) {
lua_getinfo(L, "nSl", &ar);
const char* src = ar.source;
if (src[0] == '@')
src++;
json frame = {
{ "file", src },
{ "line", ar.currentline },
{ "name", ar.name ? ar.name : "?" }
};
frames.push_back(frame);
depth++;
}
return json{
{ "frames", frames }
};
}
void sendDebugResponse(const std::string& type, const json& payload) {
json msg = {
{ "type", type },
{ "payload", payload }
};
printf("STACKTRACE: %s", msg.dump().c_str());
std::cout << "@@DEBUG@@" << msg.dump() << std::endl;
}
void processDebugCommand(const std::string& line) { void processDebugCommand(const std::string& line) {
//printf("COMANDO PROCESADO: %s\n", line.c_str()); //printf("COMANDO PROCESADO: %s\n", line.c_str());
if (!line.starts_with("@@DEBUGCMD@@")) if (!line.starts_with("@@DEBUGCMD@@"))
@@ -96,8 +162,31 @@ void processDebugCommand(const std::string& line) {
} }
else if (cmd == "continue") { else if (cmd == "continue") {
printf("CONTINUA\n\n"); printf("CONTINUA\n\n");
g_stepMode = STEP_NONE;
g_paused = false; g_paused = false;
} }
else if (cmd == "pause") {
g_stepMode = STEP_INTO;
g_paused = false;
}
else if (cmd == "stepOver") {
g_stepMode = STEP_OVER;
g_stepDepth = getStackDepth(L);
g_paused = false;
}
else if (cmd == "stepInto") {
g_stepMode = STEP_INTO;
g_paused = false;
}
else if (cmd == "stepOut") {
g_stepMode = STEP_OUT;
g_stepDepth = getStackDepth(L);
g_paused = false;
}
else if (cmd == "stackTrace") {
json result = getStackTrace(L);
sendDebugResponse("stackTrace", result);
}
} }
bool isBreakpoint(const std::string& file, int line) { bool isBreakpoint(const std::string& file, int line) {
@@ -161,35 +250,91 @@ std::string waitForDebugCommand() {
} }
}*/ }*/
extern "C" void luaHook(lua_State* L, lua_Debug* ar) { bool shouldPauseForStepping(lua_State* L, lua_Debug* ar) {
lua_getinfo(L, "Sl", ar); int depth = getStackDepth(L);
if (ar->currentline <= 0) switch (g_stepMode) {
return; case STEP_INTO:
return true; // siempre parar en la siguiente línea
const char* src = ar->source; case STEP_OVER:
return depth <= g_stepDepth;
// Lua usa "@filename" para archivos reales case STEP_OUT:
//if (src[0] == '@') return depth < g_stepDepth;
// src++;
int line = ar->currentline; default:
return false;
}
}
if (isBreakpoint(src, line)) { void pauseHere(const std::string& src, int line) {
g_paused = true; g_paused = true;
g_pauseFile = src; g_pauseFile = src;
g_pauseLine = line; g_pauseLine = line;
g_stepMode = STEP_NONE;
std::string realPath = chunkToPath(src); sendBreakEvent(chunkToPath(src), line);
sendBreakEvent(realPath, line);
//sendBreakEvent(src, line);
// Esperar comandos del Debug Adapter
while (g_paused) { while (g_paused) {
std::string cmd = waitForDebugCommand(); std::string cmd = waitForDebugCommand();
printf("PROCESANDO COMANDO: %s\n", cmd.c_str());
processDebugCommand(cmd); processDebugCommand(cmd);
} }
}
extern "C" void luaHook(lua_State* L, lua_Debug* ar) {
lua_getinfo(L, "Sl", ar);
const char* src = ar->source;
if (src[0]=='=') return;
if (ar->event == LUA_HOOKCALL) {
funBreakStack.push(function_has_breakpoints);
bool new_function_has_breakpoints = false;
{
std::lock_guard<std::mutex> lock(g_breakMutex);
auto it = g_breakpoints.find(src);
new_function_has_breakpoints = (it != g_breakpoints.end() && !it->second.empty());
}
if (new_function_has_breakpoints || g_stepMode != STEP_NONE) {
if (!function_has_breakpoints)
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0);
} else {
//if (function_has_breakpoints)
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0);
}
function_has_breakpoints = new_function_has_breakpoints;
}
else if (ar->event == LUA_HOOKRET) {
// Siempre volver al hook base
bool new_function_has_breakpoints = funBreakStack.empty() ? false : funBreakStack.top();
funBreakStack.pop();
if (new_function_has_breakpoints || g_stepMode != STEP_NONE) {
if (!function_has_breakpoints)
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKLINE | LUA_MASKRET, 0);
} else {
//if (function_has_breakpoints)
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0);
}
function_has_breakpoints = new_function_has_breakpoints;
}
else if (ar->event == LUA_HOOKLINE) {
if (ar->currentline <= 0) return;
const char* src = ar->source;
int line = ar->currentline;
if (isBreakpoint(src, line)) {
pauseHere(src, line);
return;
}
// 2. Stepping
if (g_stepMode != STEP_NONE) {
if (shouldPauseForStepping(L, ar)) {
pauseHere(src, line);
return;
}
}
} }
} }
@@ -1287,10 +1432,6 @@ extern "C" {
} }
lua_State *L;
bool is_playing = false;
bool init_exists = false;
bool update_exists = false;
bool lua_is_playing() { bool lua_is_playing() {
return is_playing; return is_playing;
@@ -1643,6 +1784,7 @@ int MiniLoader(lua_State *L) {
// 1. Convertir puntos en barras // 1. Convertir puntos en barras
std::string path(name); std::string path(name);
std::string regpath(name);
std::replace(path.begin(), path.end(), '.', '/'); std::replace(path.begin(), path.end(), '.', '/');
// 2. Detectar comodín "/*" // 2. Detectar comodín "/*"
@@ -1650,6 +1792,7 @@ int MiniLoader(lua_State *L) {
if (path.size() >= 2 && path.substr(path.size()-2) == "/*") { if (path.size() >= 2 && path.substr(path.size()-2) == "/*") {
load_all = true; load_all = true;
path = path.substr(0, path.size()-2); // quitar "/*" path = path.substr(0, path.size()-2); // quitar "/*"
regpath = regpath.substr(0, regpath.size()-2); // quitar "/*"
} }
if (load_all) { if (load_all) {
@@ -1658,7 +1801,7 @@ int MiniLoader(lua_State *L) {
// Ejecutar todos los módulos // Ejecutar todos los módulos
for (auto &f : files) { for (auto &f : files) {
std::string fullpath = path + "/" + f; std::string fullpath = path + "/" + f;
std::string registerpath = std::string(path + "." + f.substr(0,f.size()-4)); std::string registerpath = std::string(regpath + "." + f.substr(0,f.size()-4));
int size; int size;
char* buffer = file_getfilebuffer(fullpath.c_str(), size); char* buffer = file_getfilebuffer(fullpath.c_str(), size);
@@ -1713,7 +1856,7 @@ int MiniLoader(lua_State *L) {
void lua_init(const char *main_lua_file) { void lua_init(const char *main_lua_file) {
L = luaL_newstate(); L = luaL_newstate();
luaL_openlibs(L); luaL_openlibs(L);
lua_sethook(L, luaHook, LUA_MASKLINE, 0);
push_lua_funcs(); push_lua_funcs();
lua_register(L, "mini_loader", MiniLoader); lua_register(L, "mini_loader", MiniLoader);
luaL_dostring(L, "table.insert(package.searchers,2,mini_loader)\n"); luaL_dostring(L, "table.insert(package.searchers,2,mini_loader)\n");
@@ -1765,6 +1908,8 @@ void lua_call_init() {
void lua_call_update() { void lua_call_update() {
if (!update_exists) return; if (!update_exists) return;
function_has_breakpoints = false;
while (!funBreakStack.empty()) funBreakStack.pop();
lua_process_debugger_commands(); lua_process_debugger_commands();
delta_time = float(SDL_GetTicks() - last_update)/1000.0f; delta_time = float(SDL_GetTicks() - last_update)/1000.0f;
last_update = SDL_GetTicks(); last_update = SDL_GetTicks();
@@ -1816,3 +1961,13 @@ void lua_kill_thread() {
g_running = false; g_running = false;
stdinThread.request_stop(); stdinThread.request_stop();
} }
void lua_toggle_debug() {
if (debug_enabled) {
debug_enabled = false;
lua_sethook(L, NULL,0, 0);
} else {
debug_enabled = true;
lua_sethook(L, luaHook, LUA_MASKCALL | LUA_MASKRET, 0);
}
}

2
lua.h
View File

@@ -7,3 +7,5 @@ void lua_call_init();
void lua_call_update(); void lua_call_update();
void lua_quit(); void lua_quit();
void lua_kill_thread(); void lua_kill_thread();
void lua_toggle_debug();
//void lua_disable_debug();

View File

@@ -740,6 +740,8 @@ int main(int argc,char*argv[]){
//} else { //} else {
// should_exit=true; // should_exit=true;
//} //}
} else if (mini_eve.key.scancode == SDL_SCANCODE_F11) {
lua_toggle_debug();
} else if (mini_eve.key.scancode == SDL_SCANCODE_F5) { } else if (mini_eve.key.scancode == SDL_SCANCODE_F5) {
should_exit=true; should_exit=true;
} else { } else {