- [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:
311
lua.cpp
311
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) {
|
json evalExpression(lua_State* L, const std::string& expr) {
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
if (!lua_getstack(L, 0, &ar)) {
|
if (!lua_getstack(L, 0, &ar)) {
|
||||||
@@ -586,110 +692,95 @@ json evalExpression(lua_State* L, const std::string& expr) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
json setVariable(lua_State* L, int frame, const std::string& scope,
|
json evalAssign(lua_State* L, int frame, const std::string& expr) {
|
||||||
const std::string& name, const std::string& valueStr)
|
// 1. Separar LHS y RHS
|
||||||
{
|
size_t eq = expr.find('=');
|
||||||
lua_Debug ar;
|
if (eq == std::string::npos) {
|
||||||
|
return { {"error", "not an assignment"} };
|
||||||
if (!lua_getstack(L, frame, &ar)) {
|
|
||||||
return { {"error", "invalid frame"} };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_getinfo(L, "nSl", &ar);
|
std::string lhs = expr.substr(0, eq);
|
||||||
|
std::string rhs = expr.substr(eq + 1);
|
||||||
|
|
||||||
// Convertir valueStr a valor Lua
|
// limpiar espacios
|
||||||
auto pushValue = [&](const std::string& s) {
|
auto trim = [](std::string& s) {
|
||||||
// número
|
size_t a = s.find_first_not_of(" \t");
|
||||||
char* end;
|
size_t b = s.find_last_not_of(" \t");
|
||||||
double num = strtod(s.c_str(), &end);
|
if (a == std::string::npos) { s = ""; return; }
|
||||||
if (*end == '\0') {
|
s = s.substr(a, b - a + 1);
|
||||||
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") {
|
trim(lhs);
|
||||||
int i = 1;
|
trim(rhs);
|
||||||
const char* localName;
|
|
||||||
while ((localName = lua_getlocal(L, &ar, i)) != NULL) {
|
|
||||||
lua_pop(L, 1); // pop old value
|
|
||||||
|
|
||||||
if (name == localName) {
|
// 2. Evaluar RHS usando tu evalExpression
|
||||||
pushValue(valueStr);
|
json rhsValue = evalExpression(L, rhs);
|
||||||
lua_setlocal(L, &ar, i);
|
if (rhsValue.contains("error")) {
|
||||||
return { {"value", valueStr} };
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Acceso tabla: a.b.c
|
||||||
|
// separar en partes
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
{
|
||||||
|
std::stringstream ss(lhs);
|
||||||
|
std::string item;
|
||||||
|
while (std::getline(ss, item, '.')) {
|
||||||
|
trim(item);
|
||||||
|
parts.push_back(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope == "upvalues") {
|
if (parts.size() < 2) {
|
||||||
lua_getinfo(L, "f", &ar); // push function
|
return { {"error", "invalid table assignment"} };
|
||||||
|
|
||||||
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++;
|
// La clave final
|
||||||
|
std::string finalKey = parts.back();
|
||||||
|
parts.pop_back();
|
||||||
|
|
||||||
|
// 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 function
|
json tableValue = evalExpression(L, tableExpr);
|
||||||
|
if (tableValue.contains("error")) {
|
||||||
|
return tableValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scope == "globals") {
|
if (tableValue["type"] != "table") {
|
||||||
pushValue(valueStr);
|
return { {"error", "LHS is not a table"} };
|
||||||
lua_setglobal(L, name.c_str());
|
|
||||||
return { {"value", valueStr} };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { {"error", "variable not found"} };
|
int ref = tableValue["ref"];
|
||||||
}
|
|
||||||
|
|
||||||
json setTableField(lua_State* L, int ref, const std::string& key, const std::string& valueStr)
|
// 6. Asignar dentro de la tabla
|
||||||
{
|
return setTableField(L, ref, finalKey, rhsStr);
|
||||||
// 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} };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendDebugResponse(const std::string& type, const json& payload) {
|
void sendDebugResponse(const std::string& type, const json& payload) {
|
||||||
@@ -743,6 +834,7 @@ void processDebugCommand(const std::string& line) {
|
|||||||
printf("CONTINUA\n\n");
|
printf("CONTINUA\n\n");
|
||||||
g_stepMode = STEP_NONE;
|
g_stepMode = STEP_NONE;
|
||||||
g_paused = false;
|
g_paused = false;
|
||||||
|
raisewindow();
|
||||||
}
|
}
|
||||||
else if (cmd == "pause") {
|
else if (cmd == "pause") {
|
||||||
g_stepMode = STEP_INTO;
|
g_stepMode = STEP_INTO;
|
||||||
@@ -807,6 +899,19 @@ void processDebugCommand(const std::string& line) {
|
|||||||
};
|
};
|
||||||
sendDebugResponse("eval", payload);
|
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") {
|
else if (cmd == "setVariable") {
|
||||||
int frame = j.value("frame", 0);
|
int frame = j.value("frame", 0);
|
||||||
std::string scope = j["scope"];
|
std::string scope = j["scope"];
|
||||||
@@ -840,6 +945,37 @@ bool checkBreakpointCondition(lua_State* L, const Breakpoint& bp) {
|
|||||||
return false;
|
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) {
|
bool isBreakpoint(const std::string& file, int line) {
|
||||||
std::lock_guard<std::mutex> lock(g_breakMutex);
|
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) {
|
for (auto& bp : it->second) {
|
||||||
if (bp.line == line) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
mini.cpp
5
mini.cpp
@@ -146,6 +146,11 @@ int16_t beats, num_beats = 0;
|
|||||||
|
|
||||||
void createNewProject();
|
void createNewProject();
|
||||||
|
|
||||||
|
void raisewindow() {
|
||||||
|
SDL_RaiseWindow(mini_win);
|
||||||
|
//SDL_SetWindowInputFocus(mini_win);
|
||||||
|
}
|
||||||
|
|
||||||
char* get_value_from_line(char* line) {
|
char* get_value_from_line(char* line) {
|
||||||
char* equal_character = strchr(line, '=');
|
char* equal_character = strchr(line, '=');
|
||||||
if (equal_character == NULL) return NULL;
|
if (equal_character == NULL) return NULL;
|
||||||
|
|||||||
2
mini.h
2
mini.h
@@ -124,6 +124,8 @@ void loop();
|
|||||||
int scrw();
|
int scrw();
|
||||||
int scrh();
|
int scrh();
|
||||||
|
|
||||||
|
void raisewindow();
|
||||||
|
|
||||||
uint8_t newsurf(int w, int h);
|
uint8_t newsurf(int w, int h);
|
||||||
uint8_t loadsurf(const char* filename, const bool external = false);
|
uint8_t loadsurf(const char* filename, const bool external = false);
|
||||||
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors=0);
|
void savesurf(uint8_t surface, const char* filename, uint8_t *pal, uint8_t colors=0);
|
||||||
|
|||||||
Reference in New Issue
Block a user