Is there a way to determine the signature of a Lua function?
-
02-07-2019 - |
Question
Recently, Lee Baldwin showed how to write a generic, variable argument memoize function. I thought it would be better to return a simpler function where only one parameter is required. Here is my total bogus attempt:
local function memoize(f)
local cache = {}
if select('#', ...) == 1 then
return function (x)
if cache[x] then
return cache[x]
else
local y = f(x)
cache[x] = y
return y
end
end
else
return function (...)
local al = varg_tostring(...)
if cache[al] then
return cache[al]
else
local y = f(...)
cache[al] = y
return y
end
end
end
end
Obviously, select('#', ...)
fails in this context and wouldn't really do what I want anyway. Is there any way to tell inside memoize how many arguments f expects?
"No" is a fine answer if you know for sure. It's not a big deal to use two separate memoize functions.
Solution
I guess you could go into the debug info and determine this from the source-code, but basically it's a "no", sorry.
OTHER TIPS
Yes, for Lua functions but not C functions. It's a bit torturous and a little sketchy.
debug.getlocal
works on called functions so you have to call the function in question. It doesn't show any hint of ...
unless the call passes enough parameters. The code below tries 20 parameters.
debug.sethook
with the "call" event gives an opportunity to intercept the function before it runs any code.
This algorithm works with Lua 5.2. Older versions would be similar but not the same:
assert(_VERSION=="Lua 5.2", "Must be compatible with Lua 5.2")
A little helper iterator (could be inlined for efficiency):
local function getlocals(l)
local i = 0
local direction = 1
return function ()
i = i + direction
local k,v = debug.getlocal(l,i)
if (direction == 1 and (k == nil or k.sub(k,1,1) == '(')) then
i = -1
direction = -1
k,v = debug.getlocal(l,i)
end
return k,v
end
end
Returns the signature (but could return a parameter count and usesVarargs, instead):
local function dumpsig(f)
assert(type(f) == 'function',
"bad argument #1 to 'dumpsig' (function expected)")
local p = {}
pcall (function()
local oldhook
local hook = function(event, line)
for k,v in getlocals(3) do
if k == "(*vararg)" then
table.insert(p,"...")
break
end
table.insert(p,k) end
debug.sethook(oldhook)
error('aborting the call')
end
oldhook = debug.sethook(hook, "c")
-- To test for vararg must pass a least one vararg parameter
f(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
end)
return "function("..table.concat(p,",")..")"
end
I'm pretty sure you can't do that in Lua.