Как да изхвърля част от 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 отговор на проф. по археология (и малко разглобяване):

Отговорът на този древен въпрос се крие в първичния. А именно 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()

За по-стари версии ще трябва да обработвате upvalues, които може да имат препратки към глобални функции, които се опитвате да предефинирате. За по-новите версии ще трябва да се справите с upvalues, които биха били загубени по време на процеса на дъмп-зареждане.

3. Четене на файловете

И накрая, както казаха други, ако имате достъп до източника, можете да опитате да намерите дефиницията на функцията от него. Освен ако не е дефиниция на една функция или един файл за връщане, задачата може да се окаже еквивалентна на повторно внедряване на lua анализатора. Има повече от един от тях, но те не са направени с подобна функционалност в ума, така че може да отнеме малко работа, за да пренастроите техния код.

Ако всички функции са дефинирани сами и сте готови да се ограничите малко, можете да използвате отново lua metatables, решете проблема по време на етапа на кодиране:

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 ​​обаче ще бъде трудно.

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. Но не съм съгласен с теб по основния въпрос. Моля, обърнете внимание, че OP не попита дали самата Lua се справя с тези неща?. Въпросът беше Как да направя това?, което предполага известни усилия от програмиста. Вашият отговор изглежда твърде песимистичен за такъв мощен инструмент като Lua. - person Egor Skriptunoff; 12.02.2013
comment
@EgorSkriptunoff: Факт е, че вашето предложение не работи. Не като цяло. Може да работи в определени, специфични случаи, когато: а) случайно имате Lua анализатор. б) използват некомпилирани източници на Lua. в) не вграждат Lua в приложение. И дори тогава не обяснявате как всъщност да намерите въпросната функция, защото няма пряка връзка между функционален обект и наименувана функция в изходния код (което е, което OP поиска: как да вземете функция < i>обект и вземете неговия източник). Накратко, не можете като цяло да го направите. - 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 е много трудна работа за мен. Имате ли parse lua библиотека с кодове? - person Flash; 08.02.2013
comment
-1: Неправилно. Това зарежда изходния файл; не приема конкретна функция и не я преобразува в източник. - person Nicol Bolas; 12.02.2013