Skip to content

Commit

Permalink
feat: support watch hover and eval with current break env
Browse files Browse the repository at this point in the history
  • Loading branch information
sssooonnnggg committed Nov 21, 2024
1 parent 7a604ff commit 3c9c68c
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 26 deletions.
99 changes: 86 additions & 13 deletions debugger/src/internal/debug_bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,31 +394,104 @@ ResponseOrError<EvaluateResponse> DebugBridge::evaluate(
}
}

EvaluateResponse DebugBridge::evaluateRepl(const EvaluateRequest& request) {
int ret = lua_utils::doString(break_vm_, request.expression);
ResponseOrError<EvaluateResponse> DebugBridge::evaluateRepl(
const EvaluateRequest& request) {
return evalWithEnv(request);
}

ResponseOrError<EvaluateResponse> DebugBridge::evaluateWatch(
const EvaluateRequest& request) {
return evalWithEnv(request);
}

ResponseOrError<EvaluateResponse> DebugBridge::evaluateHover(
const EvaluateRequest& request) {
return evalWithEnv(request);
}

ResponseOrError<EvaluateResponse> DebugBridge::evalWithEnv(
const EvaluateRequest& request) {
int level = 0;
if (request.frameId.has_value())
level = request.frameId.value();

if (!pushBreakEnv(level))
return Error{"Failed to push break environment"};

int ret = lua_utils::doString(break_vm_, request.expression, -1);
std::string result;
for (int i = 1; i <= ret; ++i) {
result += lua_utils::getDisplayValue(break_vm_, -i);
if (i != ret)
result += "\n";
lua_pop(break_vm_, 1);
}

// Pop the environment
lua_pop(break_vm_, 1);

EvaluateResponse response{.result = result};
return response;
}

EvaluateResponse DebugBridge::evaluateWatch(const EvaluateRequest& request) {
// TODO:
EvaluateResponse response;
response.result = "Not implemented";
return response;
}
bool DebugBridge::pushBreakEnv(int level) {
lua_Debug ar;
lua_checkstack(break_vm_, 5);

EvaluateResponse DebugBridge::evaluateHover(const EvaluateRequest& request) {
// TODO:
EvaluateResponse response;
response.result = "Not implemented";
return response;
// Create new table for break environment
lua_newtable(break_vm_);

// Push function at level
if (!lua_getinfo(break_vm_, level, "f", &ar)) {
DEBUGGER_LOG_ERROR("[pushBreakEnv] Failed to get function info at level {}",
level);
lua_pop(break_vm_, 1);
return false;
}

// Get function env
lua_getfenv(break_vm_, -1);

// Copy function env to break env
// -1: function env table
// -2: function
// -3: break env table
int break_env = lua_absindex(break_vm_, -3);
lua_pushnil(break_vm_);
while (lua_next(break_vm_, -2)) {
lua_pushvalue(break_vm_, -2);
lua_pushvalue(break_vm_, -2);
lua_settable(break_vm_, break_env);
lua_pop(break_vm_, 1);
}
lua_pop(break_vm_, 1);

// -1: function
// -2: table

int index = 1;
while (auto* name = lua_getlocal(break_vm_, level, index++)) {
lua_pushstring(break_vm_, name);
lua_insert(break_vm_, -2);

// -1: value
// -2: key
// -3: function
// -4: table
lua_rawset(break_vm_, -4);
}

index = 1;
while (auto* name = lua_getupvalue(break_vm_, -1, index++)) {
lua_pushstring(break_vm_, name);
lua_insert(break_vm_, -2);
lua_rawset(break_vm_, -4);
}

// Pop function
lua_pop(break_vm_, 1);

return true;
}

} // namespace luau::debugger
12 changes: 9 additions & 3 deletions debugger/src/internal/debug_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,15 @@ class DebugBridge {

void resumeInternal();

EvaluateResponse evaluateRepl(const EvaluateRequest& request);
EvaluateResponse evaluateWatch(const EvaluateRequest& request);
EvaluateResponse evaluateHover(const EvaluateRequest& request);
ResponseOrError<EvaluateResponse> evaluateRepl(
const EvaluateRequest& request);
ResponseOrError<EvaluateResponse> evaluateWatch(
const EvaluateRequest& request);
ResponseOrError<EvaluateResponse> evaluateHover(
const EvaluateRequest& request);

ResponseOrError<EvaluateResponse> evalWithEnv(const EvaluateRequest& request);
bool pushBreakEnv(int level);

private:
bool stop_on_entry_ = false;
Expand Down
31 changes: 24 additions & 7 deletions debugger/src/internal/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include <dap/typeof.h>
#include <nlohmann_json_serializer.h>
#include <concepts>
#include <exception>

#include <Luau/Common.h>
#include <Luau/Compiler.h>
#include <lua.h>

#include "Luau/BytecodeBuilder.h"
#include "internal/log.h"
#include "log.h"

Expand All @@ -30,17 +32,32 @@ inline std::string toString(const T& t) {

namespace luau::debugger::lua_utils {

inline int doString(lua_State* L, const std::string& code) {
inline int doString(lua_State* L, const std::string& code, int env) {
lua_setsafeenv(L, LUA_ENVIRONINDEX, false);

auto env_idx = lua_absindex(L, env);
int top = lua_gettop(L);
std::string bytecode = Luau::compile(std::string("return ") + code);
int result = luau_load(L, "repl", bytecode.data(), bytecode.size(), 0);
if (result != 0) {
DEBUGGER_LOG_ERROR("Error loading code: {}", lua_tostring(L, -1));
return result;

Luau::BytecodeBuilder bcb;
try {
Luau::compileOrThrow(bcb, std::string("return ") + code);
} catch (const std::exception&) {
try {
Luau::compileOrThrow(bcb, code);
} catch (const std::exception& e) {
DEBUGGER_LOG_ERROR("Error compiling code: {}", e.what());
lua_pushstring(L, e.what());
return 1;
}
}

auto bytecode = bcb.getBytecode();
int result = luau_load(L, "repl", bytecode.data(), bytecode.size(), 0);
if (result != 0)
lua_pop(L, 1);

lua_pushvalue(L, env_idx);
lua_setfenv(L, -2);

int call_result = lua_pcall(L, 0, LUA_MULTRET, 0);
if (call_result == LUA_OK)
return lua_gettop(L) - top;
Expand Down
6 changes: 3 additions & 3 deletions tests/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,6 @@ end

test_loadstring()

-- while true do
-- main()
-- end
while true do
main()
end

0 comments on commit 3c9c68c

Please sign in to comment.