tags:

views:

265

answers:

5

Supposed I register many different function names in Lua to the same function in C. Now, everytime my C function is called, is there a way to determine which function name was invoked?

for example:

int runCommand(lua_State *lua)
{
  const char *name = // getFunctionName(lua) ? how would I do this part
  for(int i = 0; i < functions.size; i++)
    if(functions[i].name == name)
      functions[i].Call()
}

int main()
{
  ...

  lua_register(lua, "delay", runCommand);
  lua_register(lua, "execute", runCommand);
  lua_register(lua, "loadPlugin", runCommand);
  lua_register(lua, "loadModule", runCommand);
  lua_register(lua, "delay", runCommand);
}

So, how do I get the name of what ever function called it?

A: 

Unfortunately, that's not possible - among other things, because functions in Lua don't actually have to have a name at all. (Consider: (loadstring("a=1"))() is executing a nameless function returned from loadstring.)

Amber
+2  A: 

You can use lua_getinfo : http://pgl.yoyo.org/luai/i/lua_getinfo

This might work:

const char* lua_getcurrentfunction(lua_State* L) {
    lua_Debug ar;
    lua_getstack(L, 1, &ar);
    lua_getinfo(L, "f", &ar);
    return ar.name;
}

There is one caveat:

name: a reasonable name for the given function. Because functions in Lua are first-class values, they do not have a fixed name: some functions may be the value of multiple global variables, while others may be stored only in a table field. The lua_getinfo function checks how the function was called to find a suitable name. If it cannot find a name, then name is set to NULL.

Nick
+1  A: 

An alternative solution would be to register a metatable for the Lua environment table that implements the __index metamethod for dispatching these functions calls.

Judge Maygarden
A: 

If you're willing to slurp up all unknown function executions, you may be able to play games with setmetatable and currying:

    -- This function would not be in lua in your example,
    -- you'd be doing lua_register( lua, "runCommandNamed", runCommandNamed )
    -- and writing a runCommandNamed in C.
    function runCommandNamed( cmd, ... )
        print( "running command", cmd, "with arguments", ... )
    end

    -- The rest would be somewhere in lua-land:
    local utilMetaTable = {
        __index = function ( t, key ) 
            return function( ... ) -- mmm, curry
                runCommandNamed( key, ... )
            end
        end
    }

    _util = {}
    setmetatable( _util, utilMetaTable )

    -- prints "running command CommandOne      with arguments  arg1    arg2    arg3"
    _util.CommandOne( "arg1", "arg2", "arg3" )

    -- prints "running command CommandTwo      with arguments  argA    argB"
    _util.CommandTwo( "argA", "argB" )

In this example, I've only slurped up unknown executions under _util rather than in the global table.

leander
(Lua gurus: please feel free to suggest better syntax or style changes, I'll be happy to incorporate them. I don't use lua all that often, unfortunately, despite being the one that integrated it into our engine at work.)
leander
+8  A: 

Another way to attack your question is by using upvalues. Basically, you register the C functions with the function below instead of lua_register:

void my_lua_register(lua_State *L, const char *name, lua_CFunction f)
{
      lua_pushstring(L, name);
      lua_pushcclosure(L, f, 1);
      lua_setglobal(L, name);
}

Then, getFunctionName is straight forward

const char* getFunctionName(lua_State* L)
{
    return lua_tostring(L, lua_upvalueindex(1));
}

That said, what you trying to do seems fishy - what are you trying to achieve? The runCommand function posted in the question looks like a horribly inefficient way to do something that Lua does for you anyway.

sbk
You can also put a `this` pointer into an upvalue/closure.
Norman Ramsey