我正在为 C++ 和 LUA 项目推出自己的 LUA 调试器,但遇到了一点障碍。我尝试遵循 MobDebug 的实现来设置表达式监视,在删除所有花哨的东西之后,它本质上归结为将要监视的表达式字符串连接到语句中return(...)
并运行它。确切的行是:
local func, res = mobdebug.loadstring("return(" .. exp .. ")")
只要您只是调试一个脚本并且大多数变量都位于全局环境中,这就可以完美地工作,但出于我自己的目的,我试图将这些return(...)
表达式的评估限制/范围缩小到某些表及其字段。
更具体地说,我正在使用该模式处理一些 LUA“类” setmetatable / __index
,并且,如果可以访问该表(我们称之为SomeClass
),我希望能够评估如下表达式
self.mSomeVariable + self.mSomeOtherVariable - self:someOperation(...)
其中self
指的是SomeClass
(即存在SomeClass:someOperation
,等等)。
我真的不知道该如何解决这个问题。起初我尝试了以下方法,但显然没有效果。
> SomeClass = {}
> SomeClass.DebugEval = function(self, chunk_str) return load("return(" .. chunk_str .. ")")() end
> SomeClass.DebugEval(SomeClass, "print(1)") // 1 nil
> SomeClass.DebugEval(SomeClass, "print(SomeClass)") // table: 0000000000CBB5C0 nil
> SomeClass.DebugEval(SomeClass, "print(self)") // nil nil
self
我甚至无法通过将其直接传递给包装函数的参数来引用“类”,这让我怀疑这可能是一个upvalue
问题。也就是说,load(...)
是否为这个块的执行创建了一个闭包,而这个闭包无法到达参数self
……但为什么呢?它确实在那里???
无论如何,我的调试器后端已经在 C++ 上了,所以我想“没问题,我只需手动设置upvalue
。再次,我尝试使用执行以下操作lua_setupvalue
,但这也不起作用。我收到了运行时错误pcall
。
luaL_dostring(L, "SomeClass = {}"); // just for convenience; I could've done this manually
luaL_loadstring(L, "print(1)"); // [ ... , loadstring_closure ]
lua_getglobal(L, "SomeClass"); // [ ... , loadstring_closure, reference table]
lua_setupvalue(L, -2, 1); // [ ... , loadstring_closure] this returns '_ENV'
lua_pcall(L, 0, 0, 0); // getting LUA_ERRRUN
我在这里遗漏了什么?也许我完全用错误的方式处理这个问题?我的最终目标只是能够执行这些调试器监视,但仅限于某些类实例,这样我就可以根据每个实例启用监视并检查它们。是的,我绝对需要推出自己的调试器。这是一个很长的故事。任何帮助都值得感激。
Lua 手册中的文档
load
和函数提到:lua_load
总结一下,加载的chunk只有一个upvalue,就是
_ENV
。从Lua 5.2开始,
SomeClass = {}
相当于_ENV.SomeClass = {}
,print(self)
相当于print(_ENV.self)
。 因为SomeClass
是在全局范围内设置的,所以加载的chunk也能在_ENV
表中看到这个条目,但是没有地方会自动设置_ENV.self
。您可能期望该函数像这样工作:
事实上它的工作原理如下:
对于“expect”函数,lua编译器会
self
为你添加一个上值,但是对于“fact”函数,它不会做任何事情。并且你的 C++ 代码完全被覆盖
_ENV
,SomeClass
这太过分了。