Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you pass a Lua Function to a C Function and execute the Lua Function Several Times?

What I want to do is create a function that will iterate through some objects and call a function for each function. I'm using BlitzMax, not C, but that is besides the point because it has a full wrapper of Lua's C functions. Lua has a lua_pushcfunction() command, but where's it's lua_pushfunction() command? It is very easy to call functions that have a name, but how do you call a function that was passed as a argument?

Something like:

ForEach( PlanetList, function (planet)
    if(planet.exists == true) then
        Planet_Count = Planet_Count + 1
    end
end )

Usually you just say "lua_getglobal(L,name)" and it puts the lua function nicely on the stack, but how do you get it from an argument?

EDIT

I went back and and actually tried using luaL_ref() from this question I found earlier. What I am doing is using luaL_ref() to pop the function value from the top of the stack and put it into a temporary register, I used the value returned from luaL_ref() to use lua_rawgeti() for each of the items in the list. And then used luaL_unref() after the list was finished to release that register.

like image 264
Galaxy613 Avatar asked Feb 08 '11 02:02

Galaxy613


People also ask

How do you call a function in C Lua?

Moreover, for a C function to be called from Lua, we must register it, that is, we must give its address to Lua in an appropriate way. When Lua calls a C function, it uses the same kind of stack that C uses to call Lua. The C function gets its arguments from the stack and pushes the results on the stack.

Can you write C in Lua?

Many users interact with Lua by using the official interpreter, but even this interpreter is built on top of the C API, without any special access to the language's implementation. In other words, Lua is not only written in C; it is also written to be used from C.

Is Lua pass by reference?

Lua's function , table , userdata and thread (coroutine) types are passed by reference. The other types are passed by value.

What does three dots mean in Lua?

The three dots ( ... ) in the parameter list indicate that the function has a variable number of arguments. When this function is called, all its arguments are collected in a single table, which the function accesses as a hidden parameter named arg .


2 Answers

I was having the same question since I'm new to Lua myself. Since, in my opinion, there was no satisfactory answer I figured I would write one, even though this question may not ever be closed. Hopefully this will help some else in this situation.

main.c

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

/* this keeps our Lua reference to the Lua function */
int callback_reference = 0;

/* this is called by Lua to register its function */
int lua_registerCallback( lua_State *L ) {

  /* store the reference to the Lua function in a variable to be used later */
  callback_reference = luaL_ref( L, LUA_REGISTRYINDEX );

  return 0;
}

/* calls our Lua callback function and resets the callback reference */
void call_callback( lua_State *L ) {

  /* push the callback onto the stack using the Lua reference we */
  /*  stored in the registry */
  lua_rawgeti( L, LUA_REGISTRYINDEX, callback_reference );

  /* duplicate the value on the stack */
  /* NOTE: This is unnecessary, but it shows how you keep the */
  /*  callback for later */
  lua_pushvalue( L, 1 );

  /* call the callback */
  /* NOTE: This is using the one we duplicated with lua_pushvalue */
  if ( 0 != lua_pcall( L, 0, 0, 0 ) ) {
    printf("Failed to call the callback!\n %s\n", lua_tostring( L, -1 ) );
    return;
  }

  /* get a new reference to the Lua function and store it again */
  /* NOTE: This is only used in conjunction with the lua_pushvalue */
  /*  above and can be removed if you remove that */
  callback_reference = luaL_ref( L, LUA_REGISTRYINDEX );
}

int main( void ) {

  /* set up Lua */
  lua_State *L = lua_open();
  luaL_openlibs( L );

  /* register the lua_registerCallback function as */
  /*  "RegisterCallback" so it can be called by Lua */
  lua_pushcfunction( L, lua_registerCallback );
  lua_setglobal( L, "RegisterCallback" );

  /* run our Lua file */
  if ( 0 != luaL_dofile( L, "callback.lua" ) ) {
    printf("Failed to load calback.lua!\n %s",
      lua_tostring( L, -1 ) );
    lua_close( L );
    return 1;
  }

  /* call the callback */
  call_callback( L );

  /* call the callback again if you want (because we restored */
  /*  the Lua function reference) */
  call_callback( L );

  /* remove the reference to the callback */
  /* NOTE: This is also unnecessary if you didn't re-add the */
  /*  function to the registry */
  luaL_unref( L, LUA_REGISTRYINDEX, callback_reference );

  /* uninitialize Lua */
  lua_close( L );

  return 0;
}

callback.lua

function MyCallback()
  print("Hello World!")
end

RegisterCallback( MyCallback )
like image 167
John Sampson Avatar answered Oct 11 '22 07:10

John Sampson


Use lua_pushvalue once you have the function on the stack to duplicate it.

Update: You will need to call lua_pushvalue() each time you want to call the function as actually calling the function with lua_pcall() or lua_call() will pop the function from the stack.

like image 44
lhf Avatar answered Oct 11 '22 07:10

lhf