Calling Lua From Cpp

lua-users home
wiki

Description

Luna (see SimplerCppBinding) is good for calling C++ functions from Lua. But if you wish to call Lua functions from C++, then you'll need to stash your Lua function in a sub-table of either the registry or the table of globals, and then use lua_pcall to invoke it from your C++ code. This example uses Lunar (see CppBindingWithLunar) which is a revised version of Luna that makes this a bit easier.

You can find lunar.h on the CppBindingWithLunar page.

account.cc C++ code


extern "C" {

#include "lua.h"

#include "lauxlib.h"

#include "lualib.h"

}



#include "lunar.h"



class Account {

  lua_Number m_balance;

public:

  Account(double balance=0)    : m_balance(balance) { }

  void deposit(double amount)  { m_balance += amount; }

  void withdraw(double amount) { m_balance -= amount; }

  double balance(void)         { return m_balance; }

  ~Account() { printf("deleted Account (%p)\n", this); }



  // Lua interface

  Account(lua_State *L) :     m_balance(luaL_checknumber(L, 1)) { }

  int deposit (lua_State *L) { deposit (luaL_checknumber(L, 1)); return 0; }

  int withdraw(lua_State *L) { withdraw(luaL_checknumber(L, 1)); return 0; }

  int balance (lua_State *L) { lua_pushnumber(L, balance()); return 1; }



  static const char className[];

  static Lunar<Account>::RegType methods[];

};



const char Account::className[] = "Account";



#define method(class, name) {#name, &class::name}



Lunar<Account>::RegType Account::methods[] = {

  method(Account, deposit),

  method(Account, withdraw),

  method(Account, balance),

  {0,0}

};



static int report (lua_State *L, int status)

{

  if (status) {

    const char *msg = lua_tostring(L, -1);

    if (msg == NULL) msg = "(error with no message)";

    fprintf(stderr, "ERROR: %s\n", msg);

    lua_pop(L, 1);

  }

  return status;

}



static int application (lua_State *L)

{

  lua_settop(L, 0);

  lua_pushliteral(L, "_TRACEBACK");

  lua_gettable(L, LUA_GLOBALSINDEX);   // get traceback function

  int tb = lua_gettop(L);



  Account a;

  Account *b = new Account(30);



  int A = Lunar<Account>::push(L, &a);

  int B = Lunar<Account>::push(L, b, true);



  lua_pushliteral(L, "a");

  lua_pushvalue(L, A);

  lua_settable(L, LUA_GLOBALSINDEX);



  lua_pushliteral(L, "b");

  lua_pushvalue(L, B);

  lua_settable(L, LUA_GLOBALSINDEX);



  lua_pushvalue(L, A);

  lua_pushnumber(L, 100.00);

  report(L, Lunar<Account>::call(L, "deposit", 1, 0, tb) < 0);

  lua_pushvalue(L, A);

  report(L, Lunar<Account>::call(L, "show",    0, 0, tb) < 0);

  lua_pushvalue(L, B);

  report(L, Lunar<Account>::call(L, "show",    0, 0, tb) < 0);



  lua_pushliteral(L, "main");

  lua_gettable(L, LUA_GLOBALSINDEX);

  report(L, lua_pcall(L, 0, 0, tb));



  return 0;

}



int main (int argc, char *argv[])

{

  lua_State *L = lua_open();



  luaopen_base(L);

  luaopen_table(L);

  luaopen_io(L);

  luaopen_string(L);

  luaopen_math(L);

  luaopen_debug(L);



  Lunar<Account>::Register(L);



  if (argc>1) {

    printf("loading '%s'\n", argv[1]);

    if (report(L, luaL_loadfile(L, argv[1]) || lua_pcall(L, 0, 0, 0)) == 0) {

      printf("running application\n");

      if (report(L, lua_cpcall(L, &application, 0)) == 0) {

        printf("okay\n");

      }

    }

  }



  lua_setgcthreshold(L, 0);  // collected garbage

  printf("close\n");

  lua_close(L);

  printf("done\n");

  return 0;

}

Compiling the Code

This code can be compiled for Lua 5.0 as follows:


g++ -o test  account.cc -L/usr/local/lib -llua -llualib

Lua Test Code

function printf(...) io.write(string.format(unpack(arg))) end



function Account:show()

  printf("Account balance = $%0.02f\n", self:balance())

end



parent = {}



function parent:rob(amount)

  amount = amount or self:balance()

  self:withdraw(amount)

  return amount

end



getmetatable(Account).__index = parent



function main()

  print('a =', a)

  print('b =', b)

  print('metatable =', getmetatable(a))

  print('Account =', Account)

  table.foreach(Account, print)



  a:show() a:deposit(50.30) a:show() a:withdraw(25.10) a:show()

  debug.debug()

end

Test Code Output


$ ./test setup.lua

loading 'setup.lua'

running application

Account balance = $100.00

Account balance = $30.00

a =     Account (0x22fcb0)

b =     Account (0xa041d98)

metatable =     table: 0xa044f28

Account =       table: 0xa044f28

show    function: 0xa0464a0

balance function: 0xa0455f8

withdraw        function: 0xa045300

deposit function: 0xa045508

new     function: 0xa044fe8

Account balance = $100.00

Account balance = $150.30

Account balance = $125.20

lua_debug> a:show()

Account balance = $125.20

lua_debug> b:show()

Account balance = $30.00

lua_debug> b:deposit(0.01)  b:show()

Account balance = $30.01

lua_debug> c = Account(19.99)  c:deposit(b:rob())  c:show()

Account balance = $50.00

lua_debug> b:show()

Account balance = $0.00

lua_debug> b = nil

lua_debug> print('c =', c)

c =     Account (0xa048cf8)

lua_debug> cont

deleted Account (0x22fcb0)

okay

deleted Account (0xa041d98)

close

deleted Account (0xa048cf8)

done


RecentChanges · preferences
edit · history
Last edited January 6, 2007 6:32 pm GMT (diff)