Простого ответа нет (после стольких лет все еще). Я подробно расскажу об альтернативах.
1 ответ профессора археологии (и немного разборки):
Ответ на этот древний вопрос лежит в изначальном. А именно луадек. Вероятно, тогда он был в простое, но, по крайней мере, на данный момент есть обновленная версия, который обрабатывает lua 5.1-.3.
Кроме того, string.dump
дает не полную тарабарщину, он дает программный код в необработанных байтах машинных инструкций, вы можете увидеть лучшее представление тех, что с luac -l -p <filename>
. Коды виртуальных машин плохо задокументированы, но люди что-то собирали здесь. У Luajit несколько лучшая документация по собственному набору инструкций.
Luadec делает пересборку кода из vm по инструкциям. Теоретически вы также можете вставить свои собственные инструкции прямо в выгруженную строку.
Однако какой бы трюк вы ни делали с байт-кодами, он будет сталкиваться с несовместимостью между разными интерпретаторами, включая разные версии самого lua.
<сильный>2. На самом деле делаю X
Преобразование функции в строку — весьма своеобразное желание (если только вы не занимаетесь генерацией кода, и в этом случае у вас уже есть строка).
Код «зарегистрировать и внедрить» действительно является довольно общим 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()
Для более старых версий вам придется обрабатывать повышающие значения, которые могут иметь ссылки на глобальные функции, которые вы пытаетесь переопределить. Для более новых версий вам придется обрабатывать повышающие значения, которые будут потеряны в процессе загрузки дампа.
<сильный>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))
Однако определить upvalue будет непросто.
person
Dimitry
schedule
16.05.2017