如何从 Lua 脚本中获取有关函数调用的信息?

How do I get information about function calls from a Lua script?

我有一个用 Lua 5.1 编写的脚本,它导入第三方模块并从中调用一些函数。我想从一个模块中获取函数调用列表及其参数(当它们在执行前已知时)。

因此,我需要编写另一个脚本来获取我的第一个脚本的源代码、对其进行解析并从其代码中提取信息。

考虑最小的例子。

我有以下模块:

local mod = {}

function mod.foo(a, ...)
    print(a, ...)
end

return mod

以及以下驱动程序代码:

local M = require "mod"
M.foo('a', 1)
M.foo('b')

使用 M.foo 函数的“使用”事件检索数据的更好方法是什么?

理想情况下,我想获取有关被调用函数的名称及其参数值的信息。从上面的示例代码中,获得这样的映射就足够了:{'foo': [('a', 1), ('b')]}.

我不确定 Lua 是否具有反射函数来检索此信息。因此,我可能需要使用 Lua 的现有解析器之一来获取完整的 AST 并找到我感兴趣的函数调用。

还有其他建议吗?

如果你不能mod化文件,你可以将文件读入字符串然后解析mod文件并找到其中的所有函数,然后使用该信息解析目标文件mod 库的所有用途

functions = {}

for func in modFile:gmatch("function mod%.(%w+)") do
    functions[func] = {}
end

for func, call in targetFile:gmatch("M%.(%w+)%(([^%)]+)%)") do
    args = {}
    for arg in string.gmatch(call, "([^,]+)") do
        table.insert(args, arg)
    end

    table.insert(functions[func], args)
end

结果table然后可以序列化

    ['foo'] = {{"'a'", " 1"}, {"'b'"}}

3 个可能的陷阱:

  1. M 不是一个非常独特的名称,可能会有所不同,可能匹配对另一个库的意外函数调用。
  2. 如果在 arg 列表中进行了函数调用,则此示例不处理。例如myfunc(getStuff(), true)
  3. 生成的 table 不知道 args 的类型,所以它们都保存为字符串表示形式。

如果可以选择 mod 化目标文件,您可以围绕 required module

创建一个包装器
function log(mod)
    local calls = {}
    local wrapper = {
        __index = function(_, k)
            if mod[k] then
                return function(...)
                    calls[k] = calls[k] or {}
                    table.insert(calls[k], {...})

                    return mod[k](...)
                end
            end
        end,
    }

    return setmetatable({},wrapper), calls
end

那么你就这样使用这个函数。

local M, calls = log(require("mod"))
M.foo('a', 1)
M.foo('b')

如果您的 module 不仅仅是 functions,您需要在包装器中处理它,该包装器假定所有索引都是一个函数。

在所有调用之后,您可以序列化 calls table 以获取所有调用的历史记录。对于示例代码,table 看起来像

{
    ['foo'] = {{'a', 1}, {'b'}}
}