- [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 <algorithm>
#include <vector>
#include <stack>
#include <unordered_map>
#include <string>
@@ -16,6 +17,11 @@
#include <iostream>
#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::mutex g_breakMutex;
@@ -27,6 +33,19 @@ std::atomic<bool> g_paused = false;
std::string g_pauseFile;
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;
using json = nlohmann::json;
@@ -77,6 +96,53 @@ std::string chunkToPath(const std::string& chunk) {
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) {
//printf("COMANDO PROCESADO: %s\n", line.c_str());
if (!line.starts_with("@@DEBUGCMD@@"))
@@ -96,8 +162,31 @@ void processDebugCommand(const std::string& line) {
}
else if (cmd == "continue") {
printf("CONTINUA\n\n");
g_stepMode = STEP_NONE;
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) {
@@ -161,35 +250,91 @@ std::string waitForDebugCommand() {
}
}*/
extern "C" void luaHook(lua_State* L, lua_Debug* ar) {
lua_getinfo(L, "Sl", ar);
bool shouldPauseForStepping(lua_State* L, lua_Debug* ar) {
int depth = getStackDepth(L);
if (ar->currentline <= 0)
return;
switch (g_stepMode) {
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
//if (src[0] == '@')
// src++;
case STEP_OUT:
return depth < g_stepDepth;
int line = ar->currentline;
default:
return false;
}
}
if (isBreakpoint(src, line)) {
void pauseHere(const std::string& src, int line) {
g_paused = true;
g_pauseFile = src;
g_pauseLine = line;
g_stepMode = STEP_NONE;
std::string realPath = chunkToPath(src);
sendBreakEvent(realPath, line);
//sendBreakEvent(src, line);
sendBreakEvent(chunkToPath(src), line);
// Esperar comandos del Debug Adapter
while (g_paused) {
std::string cmd = waitForDebugCommand();
printf("PROCESANDO COMANDO: %s\n", cmd.c_str());
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() {
return is_playing;
@@ -1643,6 +1784,7 @@ int MiniLoader(lua_State *L) {
// 1. Convertir puntos en barras
std::string path(name);
std::string regpath(name);
std::replace(path.begin(), path.end(), '.', '/');
// 2. Detectar comodín "/*"
@@ -1650,6 +1792,7 @@ int MiniLoader(lua_State *L) {
if (path.size() >= 2 && path.substr(path.size()-2) == "/*") {
load_all = true;
path = path.substr(0, path.size()-2); // quitar "/*"
regpath = regpath.substr(0, regpath.size()-2); // quitar "/*"
}
if (load_all) {
@@ -1658,7 +1801,7 @@ int MiniLoader(lua_State *L) {
// Ejecutar todos los módulos
for (auto &f : files) {
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;
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) {
L = luaL_newstate();
luaL_openlibs(L);
lua_sethook(L, luaHook, LUA_MASKLINE, 0);
push_lua_funcs();
lua_register(L, "mini_loader", MiniLoader);
luaL_dostring(L, "table.insert(package.searchers,2,mini_loader)\n");
@@ -1765,6 +1908,8 @@ void lua_call_init() {
void lua_call_update() {
if (!update_exists) return;
function_has_breakpoints = false;
while (!funBreakStack.empty()) funBreakStack.pop();
lua_process_debugger_commands();
delta_time = float(SDL_GetTicks() - last_update)/1000.0f;
last_update = SDL_GetTicks();
@@ -1816,3 +1961,13 @@ void lua_kill_thread() {
g_running = false;
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_quit();
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 {
// should_exit=true;
//}
} else if (mini_eve.key.scancode == SDL_SCANCODE_F11) {
lua_toggle_debug();
} else if (mini_eve.key.scancode == SDL_SCANCODE_F5) {
should_exit=true;
} else {