我正在为 C++ 和 LUA 项目推出我自己的 LUA 调试器,但我遇到了一些障碍。我正在尝试遵循 MobDebug 的实现来设置表达式监视,在删除所有花哨的功能之后,它基本上可以归结为在
return(...)
语句中字符串连接要监视的表达式并运行它。确切的行是:
local func, res = mobdebug.loadstring("return(" .. exp .. ")")
只要您只是调试单个脚本并且大多数变量都位于全局环境中,这就可以完美工作,但出于我自己的目的,我试图将这些
return(...)
表达式的评估限制/范围缩小到某些表及其字段。
更具体地说,我正在使用
setmetatable / __index
模式处理一些 LUA“类”,并且,如果可以访问表(我们称之为 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
函数的文档提到:
加载:当您加载主块时,生成的函数将始终只有一个上值,即 _ENV 变量(请参阅第 2.2 节)。
lua_load:加载主块时,此upvalue将是_ENV变量(参见§2.2)。
综上所述,加载的 chunk 只有一个 upvalue,即
_ENV
。
从 Lua 5.2 开始,
SomeClass = {}
相当于 _ENV.SomeClass = {}
,print(self)
相当于 print(_ENV.self)
。因为 SomeClass
是在全局范围内设置的,加载的 chunk 也可以在 _ENV
表中看到这个条目,但是没有地方会自动设置 _ENV.self
。
您可能期望该函数像这样工作:
function expect(self)
return (function()
return print(self)
end)()
end
事实上它会这样工作:
function fact(self)
return (function()
return print(_ENV.self)
end)()
end
对于
expect
函数,lua编译器会自动为你设置_ENV.self
,但是对于fact
函数,它不会做任何事情。
并且你的 C++ 代码完全用
_ENV
覆盖了 SomeClass
,这太过分了。