手动设置“加载”LUA 块的值变量

问题描述 投票:0回答:1

我正在为 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

我在这里缺少什么?也许我正在以完全错误的方式处理这个问题?我的最终目标只是能够执行这些调试器监视,但仅限于某些类实例,因此我可以在每个实例的基础上启用我的监视并检查它们。是的,我绝对需要推出我自己的调试器。这是一个很长的故事。感谢任何和所有的帮助。

debugging lua upvalue
1个回答
0
投票

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
,这太过分了。

© www.soinside.com 2019 - 2024. All rights reserved.