Accessing the Body of a Function with Lua
Asked Answered
B

4

11

I'm going back to the basics here but in Lua, you can define a table like so:

myTable = {}
myTable [1] = 12

Printing the table reference itself brings back a pointer to it. To access its elements you need to specify an index (i.e. exactly like you would an array)

print(myTable )    --prints pointer
print(myTable[1])  --prints 12

Now functions are a different story. You can define and print a function like so:

myFunc = function() local x = 14 end     --Defined function
print(myFunc)                            --Printed pointer to function

Is there a way to access the body of a defined function. I am trying to put together a small code visualizer and would like to 'seed' a given function with special functions/variables to allow a visualizer to 'hook' itself into the code, I would need to be able to redefine the function either from a variable or a string.

Bobolink answered 2/2, 2009 at 18:36 Comment(1)
keep in mind a function in lua does not really need to be defined with a name because they are first class and can be passed around. They can also be anonymous functions which are returned by another function (see closures - lua.org/pil/6.1.html )Interscholastic
M
11

There is no way to get access to body source code of given function in plain Lua. Source code is thrown away after compilation to byte-code.

Note BTW that function may be defined in run-time with loadstring-like facility.

Partial solutions are possible — depending on what you actually want to achieve.

You may get source code position from the debug library — if debug library is enabled and debug symbols are not stripped from the bytecode. After that you may load actual source file and extract code from there.

You may decorate functions you're interested in manually with required metadata. Note that functions in Lua are valid table keys, so you may create a function-to-metadata table. You would want to make this table weak-keyed, so it would not prevent functions from being collected by GC.

If you would need a solution for analyzing Lua code, take a look at Metalua.

Mauramauralia answered 2/2, 2009 at 21:35 Comment(0)
I
5

Check out Lua Introspective Facilities in the debugging library.

The main introspective function in the debug library is the debug.getinfo function. Its first parameter may be a function or a stack level. When you call debug.getinfo(foo) for some function foo, you get a table with some data about that function. The table may have the following fields:

The field you would want is func I think.

Interscholastic answered 2/2, 2009 at 19:52 Comment(3)
While a step in the right direction as debug.getinfo() returns the name of the function, the line where it was defined, etc, the 'func' field still only returns the pointer to the function. I have also taken a look at the Debug library and none of it seems to be able to accomplish what I need.Bobolink
try short_src or source in the same table otherwise you may be SOL.Interscholastic
'source' and 'short_src' appear to return the same thing. 'source' returns @<filename> and 'short_src' returns <filename>. It seems to me that I'm SOL as well.Bobolink
S
5

Using the debug library is your only bet. Using that, you can get either the string (if the function is defined in a chunk that was loaded with 'loadstring') or the name of the file in which the function was defined; together with the line-numbers at which the function definition starts and ends. See the documentation.

Here at my current job we have patched Lua so that it even gives you the column numbers for the start and end of the function, so you can get the function source using that. The patch is not very difficult to reproduce, but I don't think I'll be allowed to post it here :-(

Sneed answered 4/2, 2009 at 10:4 Comment(1)
I unfortunately don't have access to recompile Lua (I'm in a Lua Sandbox environment). I could set up someway to automatically create a table for the functions that hold the columns. The problem is mainly that I don't have access to the file system. Thanks for the suggestion.Bobolink
S
0

You could accomplish this by creating an environment for each function (see setfenv) and using global (versus local) variables. Variables created in the function would then appear in the environment table after the function is executed.

env = {}
myFunc = function() x = 14 end
setfenv(myFunc, env)
myFunc()
print(myFunc)    -- prints pointer
print(env.x)     -- prints 14

Alternatively, you could make use of the Debug Library:

> myFunc = function() local x = 14 ; debug.debug() end
> myFunc()
> lua_debug> _, x = debug.getlocal(3, 1)
> lua_debug> print(x) -- prints 14

It would probably be more useful to you to retrieve the local variables with a hook function instead of explicitly entering debug mode (i.e. adding the debug.debug() call)

There is also a Debug Interface in the Lua C API.

Susumu answered 2/2, 2009 at 19:9 Comment(1)
While this might be useful for something, I need to be able to parse the body of the function and look at everything that is executed, not just variable declarations. I would also need to allow local variables. I can't currently view the pages you linked to, but I'll take a close look later.Bobolink

© 2022 - 2024 — McMap. All rights reserved.