This post covers a basic C++ example using Luna Five with Lua 5.2. The example implements an account class in C++ and binds the class to the Lua environment using Luna Five and was inspired by the example in [3].
If one starts with C++ Account class header, seen below, one can see that the methods take the lua_State as a parameter. This allows these functions to push and pop parameters on and off the Lua stack. When a function pushes elements onto the stack, it returns the number of parameters it pushed onto the Lua stack.
The class also contains the following public static variables:
- className - The name used to address the class type in a Lua script
- properties - An array of all the properties and each of their accessor and mutator methods.
- methods - An array of methods provided by the class.
//account.h file class Account { public: Account(lua_State *L); ~Account(void); int Deposit(lua_State *L); int Withdraw(lua_State *L); int Balance(lua_State *L); //Class Constants static const char className[]; static const Luna<Account>::PropertyType properties[]; static const Luna<Account>::FunctionType methods[]; private: int m_balance; //Account balance };
Below is the implementation of the account header:
//account.cpp file #include "account.h" #define method(class, name) {#name, &class::name} //Name to use to address the class in Lua const char Account::className[] = "Account"; //List of class properties that one can set/get from Lua const Luna::PropertyType Account::properties[] = { {0,0} }; //List of class methods to make available in Lua const Luna::FunctionType Account::methods[] = { method(Account, Deposit), method(Account, Withdraw), method(Account, Balance), {0,0} }; /** Constructor @param L The Lua state */ Account::Account(lua_State *L) { m_balance = lua_tointeger(L, 1); } /** Destructor */ Account::~Account() { printf("C++: Deleted Account (%p)\n", this); } /** Deposits an amount into the account @param L The Lua state @return The number of returned variables pushed on to the Lua stack. */ int Account::Deposit(lua_State *L) { m_balance += lua_tointeger(L, 1); return 0; } /** Withdraws an amount from the account @param L The Lua state @return The number of returned variables pushed on to the Lua stack. */ int Account::Withdraw(lua_State *L) { m_balance -= lua_tointeger(L, 1); return 0; } /** Accessor Method Get the balance for the account @param L The Lua state @return The number of returned variables pushed on to the Lua stack. */ int Account::Balance(lua_State *L) { lua_pushnumber(L, m_balance); return 1; }
lua_tointeger is used to get C++ integer values from the Lua stack and lua_pushnumber is used to push an integer onto the Lua stack such that it can be accessed from within the Lua script.
Below is the main function used to create the Lua state, register the account class with the Lua start and run a Lua script:
//main.cpp #include "account.h" int main(int argc, char *argv[]) { //Check if a Lua Script was specified if(argc != 2){ printf("Error! No Lua script or too many scripts were specified.\n"); printf("Usage: %s <file>.lua\n", argv[0]); return -1; } //Create a new Lua state lua_State *L = luaL_newstate(); //Load Lua base library luaopen_base(L); //Register "Account" Class with Lua Luna<Account>::Register(L); //Execute the Lua script printf("C++: Executing Lua Script: %s\n",argv[1]); if(luaL_dofile(L, argv[1]) != 0){ printf("Lua Error: %s\n", lua_tostring(L,-1)); } //Close Lua state lua_close(L); return 0; }
Here one can see how simple Luna makes it to register C++ classes with Lua. Below is a script to demonstrate the interaction between Lua and C++:
//account.lua Script -- Override Lua Print() local print = function (x) print("Lua: "..x) end local a1 = Account(100) print("Created Account 1 with $"..a1:Balance().." balance") cash = 50 a1.Deposit(cash) print("Account 1: Depositing $"..cash) print("Account 1: New Balance is $"..a1:Balance()) cash = 25 a1.Withdraw(cash) print("Account 1: Withdrawing $"..cash) print("Account 1: New Balance is $"..a1:Balance()) -- Open a 2nd Account local a2 = Account(1000) print("Created Account 2 with $"..a2:Balance().." balance") cash = 500 a2.Deposit(cash) print("Account 2: Depositing $"..cash) print("Account 2: New Balance is $"..a2:Balance()) cash = 250 a2.Withdraw(cash) print("Account 2: Withdrawing $"..cash) print("Account 2: New Balance is $"..a2:Balance()) -- Check the 1st Account Again print("Account 1: New Balance is $"..a1:Balance()) cash = 25 a1.Withdraw(cash) print("Account 1: Withdrawing $"..cash) print("Account 1: New Balance is $"..a1:Balance()) print("End of Script")
One is able to create multiple instances of the class and manipulate the balance variable within each of these instances easily. All the files can be downloaded used the download link provided below.
Program Output
$ ./account account.lua
C++: Executing Lua Script: account.lua
Lua: Created Account 1 with $100 balance
Lua: Account 1: Depositing $50
Lua: Account 1: New Balance is $150
Lua: Account 1: Withdrawing $25
Lua: Account 1: New Balance is $125
Lua: Created Account 2 with $1000 balance
Lua: Account 2: Depositing $500
Lua: Account 2: New Balance is $1500
Lua: Account 2: Withdrawing $250
Lua: Account 2: New Balance is $1250
Lua: Account 1: New Balance is $125
Lua: Account 1: Withdrawing $25
Lua: Account 1: New Balance is $100
Lua: End of Script
C++: Deleted Account (0x97059f0)
C++: Deleted Account (0x97053a0)
Download
Download Lua 5.2 and Luna Five Account Example
References
[1] Lua 5.2 Reference Manual, http://www.lua.org/manual/5.2/
[2] Luna Five, http://lua-users.org/wiki/LunaFive, Viewed 15 May 2013
[3] Cpp Binding with Lunar, http://lua-users.org/wiki/CppBindingWithLunar