Как сбросить функцию lua с чанка на строку?
Как сбросить функцию 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
Как это сделать?
=== update1 ===
Я хочу автоматически войти и ввести код.
5 ответов
Вы не говорите, почему вы хотите это сделать, что может быть важно. Вы можете записать функцию в строку, она просто не будет очень читаемой строкой; Вы можете хранить и передавать свою функцию следующим образом (между совместимыми двигателями Lua):
string.dump(function() print "Hello" end)
Простого ответа не существует (после всех этих лет все еще). Я подробно остановлюсь на альтернативах.
1 Ответ профессора археологии (и немного разборки):
Ответ на этот древний вопрос лежит в первозданном. А именно, luadec. Вероятно, тогда это было во время простоя, но, по крайней мере, на данный момент, существует обновленная версия, которая обрабатывает lua 5.1-.3.
Кроме того, string.dump
обеспечивает не полный бред, он дает программный код в необработанных байтах машинных инструкций, вы можете увидеть лучшее представление тех, у кого luac -l -p <filename>
, Коды Vm плохо документированы, но люди кое-что здесь собрали. Luajit имеет несколько лучшую документацию по собственному набору инструкций.
Восстановление кода из vm по инструкции - это то, что делает luadec. Теоретически, вы также можете объединить свои собственные инструкции прямо в выгруженную строку.
Однако, какой бы трюк вы ни делали с байт-кодами, он будет испытывать несовместимость между разными интерпретаторами, включая разные версии самого 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))
Однако определить повышательные значения будет непросто.
Вы не Lua нигде не хранит скомпилированный скрипт Lua как необработанный текст. И, поскольку он предназначен для небольшого языка сценариев, он также не предоставляет механизм декомпиляции своего собственного байт-кода.
Ну, вы можете хранить несколько строк кода в одной строковой переменной. Просто используйте двойные квадратные скобки вместо кавычек.
chunk = [[
function test(a, b)
local c = a + b
return c
end
]]
Вы можете получить исходный код вашей программы
local source_code = io.open(arg[0]):read'*a'
и разобрать его, чтобы найти определение вашей функции.
Он работает только при запуске lua из командной строки и передаче его исходного файла в качестве параметра, а не файла байт-кода.