- [NEW] [debugger] Soport per a expressions d'assignació en vscode
- [NEW] [debugger] Soport per a Logpoints en vscode - [NEW] Al tornar del debugger, torna a pillar el foco la finestra de mini
This commit is contained in:
317
lua.cpp
317
lua.cpp
@@ -474,6 +474,112 @@ json expandTable(lua_State* L, int ref) {
|
||||
};
|
||||
}
|
||||
|
||||
json setVariable(lua_State* L, int frame, const std::string& scope,
|
||||
const std::string& name, const std::string& valueStr)
|
||||
{
|
||||
lua_Debug ar;
|
||||
|
||||
if (!lua_getstack(L, frame, &ar)) {
|
||||
return { {"error", "invalid frame"} };
|
||||
}
|
||||
|
||||
lua_getinfo(L, "nSl", &ar);
|
||||
|
||||
// Convertir valueStr a valor Lua
|
||||
auto pushValue = [&](const std::string& s) {
|
||||
// número
|
||||
char* end;
|
||||
double num = strtod(s.c_str(), &end);
|
||||
if (*end == '\0') {
|
||||
lua_pushnumber(L, num);
|
||||
return;
|
||||
}
|
||||
|
||||
// boolean
|
||||
if (s == "true") { lua_pushboolean(L, 1); return; }
|
||||
if (s == "false") { lua_pushboolean(L, 0); return; }
|
||||
|
||||
// nil
|
||||
if (s == "nil") { lua_pushnil(L); return; }
|
||||
|
||||
// string
|
||||
lua_pushstring(L, s.c_str());
|
||||
};
|
||||
|
||||
if (scope == "locals") {
|
||||
int i = 1;
|
||||
const char* localName;
|
||||
while ((localName = lua_getlocal(L, &ar, i)) != NULL) {
|
||||
lua_pop(L, 1); // pop old value
|
||||
|
||||
if (name == localName) {
|
||||
pushValue(valueStr);
|
||||
lua_setlocal(L, &ar, i);
|
||||
return { {"value", valueStr} };
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (scope == "upvalues") {
|
||||
lua_getinfo(L, "f", &ar); // push function
|
||||
|
||||
int i = 1;
|
||||
const char* upName;
|
||||
while ((upName = lua_getupvalue(L, -1, i)) != NULL) {
|
||||
lua_pop(L, 1); // pop old value
|
||||
|
||||
if (name == upName) {
|
||||
pushValue(valueStr);
|
||||
lua_setupvalue(L, -1, i);
|
||||
lua_pop(L, 1); // pop function
|
||||
return { {"value", valueStr} };
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
lua_pop(L, 1); // pop function
|
||||
}
|
||||
|
||||
if (scope == "globals") {
|
||||
pushValue(valueStr);
|
||||
lua_setglobal(L, name.c_str());
|
||||
return { {"value", valueStr} };
|
||||
}
|
||||
|
||||
return { {"error", "variable not found"} };
|
||||
}
|
||||
|
||||
json setTableField(lua_State* L, int ref, const std::string& key, const std::string& valueStr)
|
||||
{
|
||||
// Recuperar la tabla desde tu sistema de referencias
|
||||
if (!pushTableFromRef(L, ref)) {
|
||||
return { {"error", "invalid table ref"} };
|
||||
}
|
||||
|
||||
// Convertir el valor
|
||||
auto pushValue = [&](const std::string& s) {
|
||||
char* end;
|
||||
double num = strtod(s.c_str(), &end);
|
||||
if (*end == '\0') { lua_pushnumber(L, num); return; }
|
||||
if (s == "true") { lua_pushboolean(L, 1); return; }
|
||||
if (s == "false") { lua_pushboolean(L, 0); return; }
|
||||
if (s == "nil") { lua_pushnil(L); return; }
|
||||
lua_pushstring(L, s.c_str());
|
||||
};
|
||||
|
||||
pushValue(valueStr);
|
||||
|
||||
// tabla[key] = valor
|
||||
lua_setfield(L, -2, key.c_str());
|
||||
|
||||
lua_pop(L, 1); // pop tabla
|
||||
|
||||
return { {"value", valueStr} };
|
||||
}
|
||||
|
||||
json evalExpression(lua_State* L, const std::string& expr) {
|
||||
lua_Debug ar;
|
||||
if (!lua_getstack(L, 0, &ar)) {
|
||||
@@ -586,110 +692,95 @@ json evalExpression(lua_State* L, const std::string& expr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
json setVariable(lua_State* L, int frame, const std::string& scope,
|
||||
const std::string& name, const std::string& valueStr)
|
||||
{
|
||||
lua_Debug ar;
|
||||
|
||||
if (!lua_getstack(L, frame, &ar)) {
|
||||
return { {"error", "invalid frame"} };
|
||||
json evalAssign(lua_State* L, int frame, const std::string& expr) {
|
||||
// 1. Separar LHS y RHS
|
||||
size_t eq = expr.find('=');
|
||||
if (eq == std::string::npos) {
|
||||
return { {"error", "not an assignment"} };
|
||||
}
|
||||
|
||||
lua_getinfo(L, "nSl", &ar);
|
||||
std::string lhs = expr.substr(0, eq);
|
||||
std::string rhs = expr.substr(eq + 1);
|
||||
|
||||
// Convertir valueStr a valor Lua
|
||||
auto pushValue = [&](const std::string& s) {
|
||||
// número
|
||||
char* end;
|
||||
double num = strtod(s.c_str(), &end);
|
||||
if (*end == '\0') {
|
||||
lua_pushnumber(L, num);
|
||||
return;
|
||||
}
|
||||
|
||||
// boolean
|
||||
if (s == "true") { lua_pushboolean(L, 1); return; }
|
||||
if (s == "false") { lua_pushboolean(L, 0); return; }
|
||||
|
||||
// nil
|
||||
if (s == "nil") { lua_pushnil(L); return; }
|
||||
|
||||
// string
|
||||
lua_pushstring(L, s.c_str());
|
||||
// limpiar espacios
|
||||
auto trim = [](std::string& s) {
|
||||
size_t a = s.find_first_not_of(" \t");
|
||||
size_t b = s.find_last_not_of(" \t");
|
||||
if (a == std::string::npos) { s = ""; return; }
|
||||
s = s.substr(a, b - a + 1);
|
||||
};
|
||||
|
||||
if (scope == "locals") {
|
||||
int i = 1;
|
||||
const char* localName;
|
||||
while ((localName = lua_getlocal(L, &ar, i)) != NULL) {
|
||||
lua_pop(L, 1); // pop old value
|
||||
trim(lhs);
|
||||
trim(rhs);
|
||||
|
||||
if (name == localName) {
|
||||
pushValue(valueStr);
|
||||
lua_setlocal(L, &ar, i);
|
||||
return { {"value", valueStr} };
|
||||
// 2. Evaluar RHS usando tu evalExpression
|
||||
json rhsValue = evalExpression(L, rhs);
|
||||
if (rhsValue.contains("error")) {
|
||||
return rhsValue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
std::string rhsStr = rhsValue["value"];
|
||||
|
||||
// 3. Determinar si LHS es:
|
||||
// - variable simple: x
|
||||
// - acceso tabla: player.health
|
||||
// - acceso profundo: a.b.c
|
||||
if (lhs.find('.') == std::string::npos) {
|
||||
// variable simple → locals, upvalues o globals
|
||||
// Intentar locals
|
||||
json r = setVariable(L, frame, "locals", lhs, rhsStr);
|
||||
if (!r.contains("error")) return r;
|
||||
|
||||
// Intentar upvalues
|
||||
r = setVariable(L, frame, "upvalues", lhs, rhsStr);
|
||||
if (!r.contains("error")) return r;
|
||||
|
||||
// Intentar globals
|
||||
r = setVariable(L, frame, "globals", lhs, rhsStr);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (scope == "upvalues") {
|
||||
lua_getinfo(L, "f", &ar); // push function
|
||||
|
||||
int i = 1;
|
||||
const char* upName;
|
||||
while ((upName = lua_getupvalue(L, -1, i)) != NULL) {
|
||||
lua_pop(L, 1); // pop old value
|
||||
|
||||
if (name == upName) {
|
||||
pushValue(valueStr);
|
||||
lua_setupvalue(L, -1, i);
|
||||
lua_pop(L, 1); // pop function
|
||||
return { {"value", valueStr} };
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
lua_pop(L, 1); // pop function
|
||||
}
|
||||
|
||||
if (scope == "globals") {
|
||||
pushValue(valueStr);
|
||||
lua_setglobal(L, name.c_str());
|
||||
return { {"value", valueStr} };
|
||||
}
|
||||
|
||||
return { {"error", "variable not found"} };
|
||||
}
|
||||
|
||||
json setTableField(lua_State* L, int ref, const std::string& key, const std::string& valueStr)
|
||||
// 4. Acceso tabla: a.b.c
|
||||
// separar en partes
|
||||
std::vector<std::string> parts;
|
||||
{
|
||||
// Recuperar la tabla desde tu sistema de referencias
|
||||
if (!pushTableFromRef(L, ref)) {
|
||||
return { {"error", "invalid table ref"} };
|
||||
std::stringstream ss(lhs);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, '.')) {
|
||||
trim(item);
|
||||
parts.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Convertir el valor
|
||||
auto pushValue = [&](const std::string& s) {
|
||||
char* end;
|
||||
double num = strtod(s.c_str(), &end);
|
||||
if (*end == '\0') { lua_pushnumber(L, num); return; }
|
||||
if (s == "true") { lua_pushboolean(L, 1); return; }
|
||||
if (s == "false") { lua_pushboolean(L, 0); return; }
|
||||
if (s == "nil") { lua_pushnil(L); return; }
|
||||
lua_pushstring(L, s.c_str());
|
||||
};
|
||||
if (parts.size() < 2) {
|
||||
return { {"error", "invalid table assignment"} };
|
||||
}
|
||||
|
||||
pushValue(valueStr);
|
||||
// La clave final
|
||||
std::string finalKey = parts.back();
|
||||
parts.pop_back();
|
||||
|
||||
// tabla[key] = valor
|
||||
lua_setfield(L, -2, key.c_str());
|
||||
// 5. Evaluar la ruta de tabla (a.b.c → obtener tabla c)
|
||||
// usando tu evalExpression
|
||||
std::string tableExpr;
|
||||
for (size_t i = 0; i < parts.size(); i++) {
|
||||
if (i > 0) tableExpr += ".";
|
||||
tableExpr += parts[i];
|
||||
}
|
||||
|
||||
lua_pop(L, 1); // pop tabla
|
||||
json tableValue = evalExpression(L, tableExpr);
|
||||
if (tableValue.contains("error")) {
|
||||
return tableValue;
|
||||
}
|
||||
|
||||
return { {"value", valueStr} };
|
||||
if (tableValue["type"] != "table") {
|
||||
return { {"error", "LHS is not a table"} };
|
||||
}
|
||||
|
||||
int ref = tableValue["ref"];
|
||||
|
||||
// 6. Asignar dentro de la tabla
|
||||
return setTableField(L, ref, finalKey, rhsStr);
|
||||
}
|
||||
|
||||
void sendDebugResponse(const std::string& type, const json& payload) {
|
||||
@@ -743,6 +834,7 @@ void processDebugCommand(const std::string& line) {
|
||||
printf("CONTINUA\n\n");
|
||||
g_stepMode = STEP_NONE;
|
||||
g_paused = false;
|
||||
raisewindow();
|
||||
}
|
||||
else if (cmd == "pause") {
|
||||
g_stepMode = STEP_INTO;
|
||||
@@ -807,6 +899,19 @@ void processDebugCommand(const std::string& line) {
|
||||
};
|
||||
sendDebugResponse("eval", payload);
|
||||
}
|
||||
else if (cmd == "evalAssign") {
|
||||
int frame = j.value("frame", 0);
|
||||
std::string expr = j["expr"];
|
||||
|
||||
json result = evalAssign(L, frame, expr);
|
||||
|
||||
json payload = {
|
||||
{ "kind", "eval" },
|
||||
{ "result", result }
|
||||
};
|
||||
|
||||
sendDebugResponse("eval", payload);
|
||||
}
|
||||
else if (cmd == "setVariable") {
|
||||
int frame = j.value("frame", 0);
|
||||
std::string scope = j["scope"];
|
||||
@@ -840,6 +945,37 @@ bool checkBreakpointCondition(lua_State* L, const Breakpoint& bp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string expandLogMessage(lua_State* L, const std::string& msg) {
|
||||
std::string out;
|
||||
size_t i = 0;
|
||||
|
||||
while (i < msg.size()) {
|
||||
if (msg[i] == '{') {
|
||||
size_t j = msg.find('}', i + 1);
|
||||
if (j == std::string::npos) break;
|
||||
|
||||
std::string expr = msg.substr(i + 1, j - i - 1);
|
||||
|
||||
json r = evalExpression(L, expr);
|
||||
out += r.value("value", "nil");
|
||||
|
||||
i = j + 1;
|
||||
} else {
|
||||
out += msg[i++];
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void sendLogOutput(const std::string& text) {
|
||||
json payload = {
|
||||
{ "kind", "log" },
|
||||
{ "text", text }
|
||||
};
|
||||
sendDebugResponse("log", payload);
|
||||
}
|
||||
|
||||
bool isBreakpoint(const std::string& file, int line) {
|
||||
std::lock_guard<std::mutex> lock(g_breakMutex);
|
||||
|
||||
@@ -849,9 +985,14 @@ bool isBreakpoint(const std::string& file, int line) {
|
||||
|
||||
for (auto& bp : it->second) {
|
||||
if (bp.line == line) {
|
||||
if (checkBreakpointCondition(L, bp)) {
|
||||
if (!bp.logMessage.empty()) {
|
||||
std::string msg = expandLogMessage(L, bp.logMessage);
|
||||
sendLogOutput(msg);
|
||||
return false; // NO parar
|
||||
} else if (checkBreakpointCondition(L, bp)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
5
mini.cpp
5
mini.cpp
@@ -146,6 +146,11 @@ int16_t beats, num_beats = 0;
|
||||
|
||||
void createNewProject();
|
||||
|
||||
void raisewindow() {
|
||||
SDL_RaiseWindow(mini_win);
|
||||
//SDL_SetWindowInputFocus(mini_win);
|
||||
}
|
||||
|
||||
char* get_value_from_line(char* line) {
|
||||
char* equal_character = strchr(line, '=');
|
||||
if (equal_character == NULL) return NULL;
|
||||
|
||||
Reference in New Issue
Block a user