如何将lua函数块转储为字符串?

如何将lua函数块转储为字符串?,lua,lua-5.2,Lua,Lua 5.2,如何将lua函数块转储为字符串 function test(a, b) local c = a + b return c end print( type(test) ) --> function print( test ) --> function: 0053B108 print( dumpToString(test) ) 我希望dumpToString的结果如下: function test(a, b) local c = a + b retu

如何将lua函数块转储为字符串

function test(a, b)
  local c = a + b
  return c
end

print( type(test) )  --> function
print( test )         --> function: 0053B108
print( dumpToString(test) )
我希望dumpToString的结果如下:

function test(a, b)
  local c = a + b
  return c
end
如何做到这一点

===更新1===

我想自动记录并注入代码。

您不需要。Lua不会将编译后的Lua脚本作为原始文本存储在任何地方。而且,由于它是一种小型脚本语言,它也没有提供一种机制来反编译自己的字节码。

您可以通过

local source_code = io.open(arg[0]):read'*a'
并对其进行分析以找到您的函数定义。
它只在从命令行运行lua并将其作为参数传递给源文件(而不是字节码文件)时起作用。

您没有说明为什么要这样做,这可能很重要。你可以把一个函数转储到一个字符串中,它只是不是一个可读性很强的字符串;您可以通过这种方式存储和传输功能(在兼容的Lua引擎之间):


您可以将多行代码全部存储在一个字符串变量中。只需使用双方括号而不是引号

chunk = [[
function test(a, b)
  local c = a + b
  return c
end
]]
没有简单的答案(经过这么多年,仍然如此)。我将详细说明替代方案

1考古学教授的答案(还有一点拆解):

这个古老问题的答案就在你的内心深处。也就是卢阿德克。很可能当时它处于停机状态,但至少到目前为止,有一个可以处理Lua5.1-.3的

此外,
string.dump
提供的不是完全的胡言乱语,它以机器指令的原始字节给出程序代码,您可以看到使用
luac-l-p
的程序代码的更好表示形式。 虚拟机代码没有很好的文档记录,但人们确实把一些东西放在了一起。Luajit在自己的指令集上有更好的文档

从vm指令中重建代码是luadec的工作。理论上,您也可以将自己的指令直接拼接到转储字符串中

然而,无论您对字节码做什么处理,都会遇到不同解释器之间的不兼容,包括lua本身的不同版本

2。实际执行

将函数转换为字符串是一个非常特殊的愿望(除非您正在进行代码生成,在这种情况下,您首先已经拥有了字符串)

“日志和注入代码”实际上是相当通用的X,这可能保证解决Y。但是,单一的措施可以涵盖单一的情况。 Lua是一种非常灵活的语言,例如,您可以通过将其设置为对象来跟踪示例中值
x
的流动:

local to2number = tonumber
tonumber= function(o)
    local r= to2number(o) 
    if not r then
        local m= getmetatable(o)
        if m and m.__tonumber then
            r=m.__tonumber(o)
        end
    end
    return r
end
local number
number={
    new=function(n)
        return setmetatable({n},number)
    end,
    __add=function(me,other)
        print("I'm "..tostring(me).." and I'm being added to "..tostring(other))
        local o=tonumber(other) 
        return number.new(me[1]+o)
    end,
    __tonumber=function(me) return me[1] end,
    __tostring=function(me) return tostring(me[1]) end,
}
test(number.new(4), number.new(10))
如上面的示例所示,您可以通过改变函数的环境来注入行为。也就是说,我重新定义了全局函数
tonumber
。您可能希望在不同的环境中完全打包函数:

local test = function() print"hello" end
local newenv={print=function(s) print(s..'world')  end}
setfenv(test,newenv)--this is lua 5.1, luajit, good luck with upvalues
local test = load(string.dump(test),nil,nil,newenv)--this is lua 5.2-5.3, good luck with upvalues
test()
对于旧版本,您必须处理可能引用了您试图重新定义的全局函数的值。对于较新的版本,您必须处理在转储加载过程中丢失的UPValue

3。正在读取文件

最后,正如其他人所说,如果您可以访问源代码,您可以尝试从中查找函数定义。除非是单个函数定义或单个返回文件,否则该任务可能最终等同于重新实现lua解析器。这些功能不止一个,但它们并没有考虑到这些功能,因此可能需要一些工作来重新调整代码的用途

如果所有函数都是您自己定义的,并且您愿意稍微约束自己,那么您可以再次使用lua元表,在编码阶段解决问题:

local def=function(code,env)
    env=env or _ENV
    local compiled,q=load("return "..code,nil,nil,env)
    if not compiled then error(q) end
    local f=compiled()
    return setmetatable({code=code},{__call=function(me,...) return  f(...)  end})
end

local test=def[[function(a,b)
    return a+b
end]]

print(test(2,3))

然而,定义upvalues将是一件棘手的事情。

解析源代码对我来说非常困难。你有代码库吗?-1:不正确。这将加载源文件;它不接受特定的函数并将其转换为源代码。不对。Lua中不存在这样的内置函数,但是可以通过解析源文件(对于程序源代码中明确定义的函数)和拦截
require
load
loadfile
函数(对于在程序执行期间动态创建的函数)来实现相同的功能。尽管如此,这个想法的实现可能并不那么简单。@EgorSkriptunoff:我的答案仍然正确,因为Lua不能处理这些事情。是的,显然你能做到,但这很棘手。即使对于您,因为您在函数列表中遗漏了
dofile
。此外,如果源代码是预编译的,那么它也不起作用。所以不,这种方法通常也不起作用。简言之,你不能。@EgorSkriptunoff:另外,报复性的向下投票很小。谢谢你对
dofile
的更正。但在主要问题上我不同意你的看法。请注意OP并没有问“Lua自己处理这些事情吗?”。问题是“如何做到这一点?”,这意味着程序员做出了一些努力。对于Lua这样一个强大的工具来说,你的答案似乎太悲观了。@EgorSkriptunoff:事实是你的建议不起作用。不一般。它可能在某些特定的情况下工作,您:a)碰巧有一个Lua解析器。b) 正在使用非预编译的Lua源。c) 没有在应用程序中嵌入Lua。即使这样,您也没有解释如何实际找到所讨论的函数,因为在源代码中函数对象和命名函数之间没有直接关联(这就是OP要求的:如何获取函数对象并获取其源代码)。简言之,你一般不能这样做。详细编译。谢谢你在一个地方总结了这一切。
local def=function(code,env)
    env=env or _ENV
    local compiled,q=load("return "..code,nil,nil,env)
    if not compiled then error(q) end
    local f=compiled()
    return setmetatable({code=code},{__call=function(me,...) return  f(...)  end})
end

local test=def[[function(a,b)
    return a+b
end]]

print(test(2,3))