- [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:
211
lua.cpp
211
lua.cpp
@@ -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,34 +250,90 @@ std::string waitForDebugCommand() {
|
||||
}
|
||||
}*/
|
||||
|
||||
bool shouldPauseForStepping(lua_State* L, lua_Debug* ar) {
|
||||
int depth = getStackDepth(L);
|
||||
|
||||
switch (g_stepMode) {
|
||||
case STEP_INTO:
|
||||
return true; // siempre parar en la siguiente línea
|
||||
|
||||
case STEP_OVER:
|
||||
return depth <= g_stepDepth;
|
||||
|
||||
case STEP_OUT:
|
||||
return depth < g_stepDepth;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void pauseHere(const std::string& src, int line) {
|
||||
g_paused = true;
|
||||
g_pauseFile = src;
|
||||
g_pauseLine = line;
|
||||
g_stepMode = STEP_NONE;
|
||||
|
||||
sendBreakEvent(chunkToPath(src), line);
|
||||
|
||||
while (g_paused) {
|
||||
std::string cmd = waitForDebugCommand();
|
||||
processDebugCommand(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void luaHook(lua_State* L, lua_Debug* ar) {
|
||||
lua_getinfo(L, "Sl", ar);
|
||||
|
||||
if (ar->currentline <= 0)
|
||||
return;
|
||||
|
||||
|
||||
const char* src = ar->source;
|
||||
if (src[0]=='=') return;
|
||||
|
||||
// Lua usa "@filename" para archivos reales
|
||||
//if (src[0] == '@')
|
||||
// src++;
|
||||
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;
|
||||
|
||||
int line = ar->currentline;
|
||||
if (isBreakpoint(src, line)) {
|
||||
pauseHere(src, line);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isBreakpoint(src, line)) {
|
||||
g_paused = true;
|
||||
g_pauseFile = src;
|
||||
g_pauseLine = line;
|
||||
|
||||
std::string realPath = chunkToPath(src);
|
||||
sendBreakEvent(realPath, line);
|
||||
//sendBreakEvent(src, line);
|
||||
|
||||
// Esperar comandos del Debug Adapter
|
||||
while (g_paused) {
|
||||
std::string cmd = waitForDebugCommand();
|
||||
printf("PROCESANDO COMANDO: %s\n", cmd.c_str());
|
||||
processDebugCommand(cmd);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user