I think the problem is string formatting. Nicole Bolas may be right about the [[]] quotes associated with the bytecode dump, but this indicates a big problem; The bytecode can really be anything, but you see it as a regular line that can be written to and read from a text file. This problem is demonstrated by your last demo, where you load a discarded string without writing it to a file.
This is a serializer implementation for tables that include functions like what you want, I think, but I also think it broke (well, I couldn’t let this work anyway ...). In any case, this is on the right track. You need to format the bytecode and then write it to a file.
I am sure there is a better way to do this, but this works:
1. binary = string.dump(some_function) 2. formatted_binary = "" 3. for i = 1, string.len(binary) do 4. dec, _ = ("\\%3d"):format(binary:sub(i, i):byte()):gsub(' ', '0') 5. formatted_binary = formatted_binary .. dec 6. end
This loop goes through each character in the bytecode, formats them as escaped bytes (each line contains a code like "\ 097", which after interpolation will escape to "a").
Line 4 of this pattern is tight, so I will break it. At first,
binary:sub(i, i)
pulls the i-th character from the string. Then
binary:sub(i, i):byte()
returns the integer representation of the ascii of the i-th character. Then we format it using
("\\%3d"):format(binary:sub(i, i):byte())
which gives us a string like "\ 97", for example, if the character is "a". But this will not disappear properly, because we need “\ 097”, so we will replace gsub “with“ 0. "Gsub returns the result string and the number of substitutions performed, so we just take the first return value and put it in" dec ". I'm not sure why the format "% 3d" does not replace the spaces "0" by default ... oh well.
Then, to execute the formatted binary string, we need to avoid it and pass the result to "load". The quotation marks from [[]] in Lua do not escape flows, like "... I'm actually not sure that they have no escape at all. So, to create an Lua executable string that will return a function that will do what is in "some_function", we do the following:
executable_string = 'load("' .. formatted_binary .. '")'
Good - therefore, putting all this together, I think that we can make your test script work like this:
1 function love.load() 2 draw_before_serialize = function() 3 love.graphics.print('hello, world', 10, 10) 4 end 5 6 binary = string.dump(draw_before_serialize) 7 formatted_binary = "" 8 for i = 1, string.len(binary) do 9 dec, _ = ("\\%3d"):format(binary:sub(i, i):byte()):gsub(' ', '0') 10 formatted_binary = formatted_binary .. dec 11 end 12 13 out = io.open("serialized.lua", "wb") 14 out:write('draw = load("' .. formatted_binary .. '")') 15 out:close() 16 17 require "serialized" 18 end 19 function love.draw() 20 draw() 21 end
When I run this with Love, I get an OpenGL screen with a "hello world" printed in the corner. The resulting file "serialized.lua" contains the following:
draw = load("\027\076\074\001\000\009\064\109\097\105\110\046\108\117\097\084\000\000\004\000\004\000\008\009\002\002\052\000\000\000\055\000\001\000\055\000\002\000\037\001\003\000\039\002\010\000\039\003\010\000\062\000\004\001\071\000\001\000\017\104\101\108\108\111\044\032\119\111\114\108\100\010\112\114\105\110\116\013\103\114\097\112\104\105\099\115\009\108\111\118\101\001\001\001\001\001\001\001\002\000\000")