Как сбросить фрагмент функции 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 ===
Я хочу автоматически регистрировать и вводить код.


person Flash    schedule 06.02.2013    source источник


Ответы (5)


Простого ответа нет (после стольких лет все еще). Я подробно расскажу об альтернативах.

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
comment
Подробная компиляция. Спасибо, что собрали все в одном месте. - person Jesse Chisholm; 09.06.2017

Вы не говорите, почему хотите это сделать, что может быть важно. Вы можете вывести функцию в строку, просто это будет не очень читаемая строка; вы можете хранить и передавать свою функцию таким образом (между совместимыми движками Lua):

string.dump(function() print "Hello" end)
person Paul Kulchenko    schedule 06.02.2013

Вы не знаете. Lua нигде не хранит скомпилированный сценарий Lua в виде необработанного текста. И, поскольку он задуман как небольшой язык сценариев, он также не предоставляет механизма для декомпиляции собственного байт-кода.

person Nicol Bolas    schedule 06.02.2013
comment
-1. Неправильно. В Lua нет такой встроенной функции, но можно добиться той же функциональности, разбирая исходный файл (для функций, определенных явно в исходном коде программы) и перехватывая функции require, load и loadfile (для функций, динамически создаваемых во время выполнения программы). . Хотя реализация этой идеи может оказаться не такой простой. - person Egor Skriptunoff; 12.02.2013
comment
@EgorSkriptunoff: Мой ответ по-прежнему верен в том, что Lua не справляется с такими вещами. Да, очевидно, что вы могли бы это сделать, но это сложно. Даже для вас, так как вы пропустили dofile в своем списке функций. Кроме того, это не работает, если исходный код предварительно скомпилирован. Так что нет, этот метод вообще не работает. Короче говоря, вы не можете. - person Nicol Bolas; 12.02.2013
comment
@EgorSkriptunoff: Кроме того, голосование против мести - это мелочь. - person Nicol Bolas; 12.02.2013
comment
Спасибо за исправление о dofile. Но я не согласен с вами в главном вопросе. Обратите внимание, что ОП не спрашивал, справляется ли с этим сам Lua? Вопрос был в том, как это сделать?, что подразумевает некоторые усилия со стороны программиста. Ваш ответ кажется слишком пессимистичным для такого мощного инструмента, как Lua. - person Egor Skriptunoff; 12.02.2013
comment
@EgorSkriptunoff: Дело в том, что ваше предложение не работает. Не вообще. Это может работать в определенных случаях, когда у вас: а) случайно есть синтаксический анализатор Lua. б) используют непредварительно скомпилированные исходники Lua. c) не встраивают Lua в приложение. И даже тогда вы не объясняете, как на самом деле найти рассматриваемую функцию, потому что нет прямой связи между объектом функции и именованной функцией в исходном коде (это то, о чем просил ОП: как взять функцию < i>object и получить его источник). Короче говоря, вы не можете обычно это сделать. - person Nicol Bolas; 12.02.2013

ну, вы можете хранить несколько строк кода в одной строковой переменной. Просто используйте двойные квадратные скобки вместо кавычек.

chunk = [[
function test(a, b)
  local c = a + b
  return c
end
]]
person Rodrigo Piratee    schedule 12.02.2013

Вы можете получить исходный код вашей программы,

local source_code = io.open(arg[0]):read'*a'

и проанализируйте его, чтобы найти определение вашей функции.
Это работает только при запуске lua из командной строки и передаче исходного файла в качестве параметра, а не файла байт-кода.

person Egor Skriptunoff    schedule 06.02.2013
comment
parse source_code для меня очень тяжелая работа. У вас есть библиотека кода для разбора lua? - person Flash; 08.02.2013
comment
-1: Неверно. Это загружает исходный файл; он не берет конкретную функцию и не преобразует ее в исходный код. - person Nicol Bolas; 12.02.2013