This part will be rather short and summarize part one by providing a very simple sample using our Luna implementation.
Let’s begin by creating a very simple class which we call Test along with a Lua binding LuaTest which will be the intermediate between C++ and Lua.
#include <iostream>
#include "Luna.hpp"
class Test {
public:
Test(int x) : m_x(x) { }
int getValue() const { return m_x; }
private:
int m_x;
};
The test class is a simple getter that provides a method, getValue, which will return the value set in the constructor.
In order to make this class available from Lua we need to write a binder class which translates to and from C++ and Lua code, called LuaTest for the sake of simplicity.
class LuaTest {
public:
LUNA_TYPES(LuaTest);
LUNA_TYPES(LuaTest); is a simple macro which injects the class with a couple of placeholder variables used by Luna.
LuaTest(lua_State* l) : m_test(luaL_checknumber(l, 1)) { }
LuaTest(int x) : m_test(x) { }
We need to set up two constructors, one for Lua and one for C++ which emulates the same functionality as the C++ version. The C++ constructor for LuaTest is pretty straightforward but the Lua version is a bit more tricky.
All Lua calls only take a pointer to the actual Lua state since all values are pushed and pulled onto the stack. in this case we use luaL_checknumber(l, 1). This function call will return the first element on the top of the stack assuming it’s a number otherwise it will trigger an error.
int getValue(lua_State* l) {
lua_pushnumber(l, static_cast<double>(m_test.getValue()));
return 1;
}
This time we use lua_pushnumber(l, static_cast<double>(m_test.getValue())); to get the value from the stored Test object instance. Not that all numbers in Lua are in double so we need to cast them when expecting something else.
private:
Test m_test;
};
LUNA_CLASS(LuaTest, Test, Test) = {
LUNA_METHOD(LuaTest, getValue),
{0}
};
The LUNA_CLASS macro is used to register the class along with exposing methods calls, if any, the list has to be terminated with a {0}. The first argument to LUNA_CLASS is the name of the binding class, the second the actual C++ class name and the last the identifier to be used from Lua scripts. This way you can for instance bind a boost class to Lua like: LUNA_CLASS(LuaDate, boost::gregorian::date, Date)
int main(int argc, char** argv)
{
lua_State* l = lua_open();
luaL_openlibs(l);
Luna<LuaTest>::commit(l);
luaL_dofile(l, argv[1]);
lua_close(l);
return 0;
}
We create a very simple main function, compile it and pass it the following Lua code:
print("begin")
test = Test(1)
print("Test=" .. test:getValue())
print("end")
The resulting output is left as an exercise to the reader.
In the next installment I will move on to some more advanced features such as instantiating specific C++ classes from within Lua scripts.