Binding C++ to Lua, Part 2; Binding Our First Class

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 {
    Test(int x) : m_x(x) { }
    int getValue() const { return m_x; }
    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 {

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.

    Test m_test;

LUNA_CLASS(LuaTest, Test, Test) = {
    LUNA_METHOD(LuaTest, getValue),

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_dofile(l, argv[1]);
    return 0;

We create a very simple main function, compile it and pass it the following Lua code:

test = Test(1)
print("Test=" .. test:getValue())

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.