From e7db8576b8a4988dfdd206500199e59c3b57bf55 Mon Sep 17 00:00:00 2001
From: Nicolas Noble <pixel@nobis-crew.org>
Date: Tue, 30 Jul 2013 19:10:20 -0700
Subject: Changing things a bit in the Lua binding system. Now pushing a class
 template means pushing a table by its name, and the constructor is implicit
 in it.

---
 includes/BLua.h   | 37 +++++++++++++++++++++++++++++++++++++
 src/BLua.cc       |  2 ++
 tests/test-Lua.cc | 29 ++++++++++++++++++++++-------
 3 files changed, 61 insertions(+), 7 deletions(-)

diff --git a/includes/BLua.h b/includes/BLua.h
index e11c3fb..a6dd2bc 100644
--- a/includes/BLua.h
+++ b/includes/BLua.h
@@ -223,6 +223,16 @@ struct lua_functypes_t {
         true); \
     }
 
+#define DECLARE_CONSTRUCTOR(classname, enumvar) static int constructor(lua_State * L) { \
+    return LuaHelpers<classname>::method_multiplex( \
+        enumvar, \
+        L, \
+        NULL, \
+        sLua_##classname::classname##_proceed_statics, \
+        classname##_functions, \
+        false); \
+    }
+
 #define DECLARE_FUNCTION(classname, enumvar) static int function_##enumvar(lua_State * L) { \
     return LuaHelpers<classname>::method_multiplex( \
         enumvar, \
@@ -233,6 +243,16 @@ struct lua_functypes_t {
         false); \
     }
 
+#define DECLARE_STATIC(classname, enumvar) static int static_##enumvar(lua_State * L) { \
+    return LuaHelpers<classname>::method_multiplex( \
+        enumvar, \
+        L, \
+        NULL, \
+        sLua_##classname::classname##_proceed_statics, \
+        classname##_functions, \
+        false); \
+    }
+
 #define PUSH_METHOD(classname, enumvar) pushIt( \
     L, \
     classname##_methods[enumvar].name, \
@@ -243,6 +263,21 @@ struct lua_functypes_t {
     String("__") + classname##_methods[enumvar].name, \
     sLua_##classname::method_##enumvar)
 
+#define PUSH_CONSTRUCTOR(classname, enumvar) \
+    bool constructorPushed = true; \
+    L.newtable(); \
+    L.push(#classname); \
+    L.copy(-2); \
+    L.setvar(); \
+    L.declareFunc("new", sLua_##classname::constructor, -1)
+
+#define PUSH_STATIC(classname, enumvar) \
+    AAssert(constructorPushed, "Please call PUSH_CONSTRUCTOR first"); \
+    L.declareFunc( \
+    classname##_functions[enumvar].name, \
+    sLua_##classname::static_##enumvar, \
+    -1)
+
 #define PUSH_FUNCTION(classname, enumvar) L.declareFunc( \
     classname##_functions[enumvar].name, \
     sLua_##classname::function_##enumvar)
@@ -252,6 +287,8 @@ struct lua_functypes_t {
     sLua_##classname::function_##enumvar, \
     array)
 
+#define PUSH_CLASS_DONE() L.pop()
+
 #define CHECK_METHODS(classname) { \
     int i = 0; \
     while (classname##_methods[i].number != -1) { \
diff --git a/src/BLua.cc b/src/BLua.cc
index 62e4010..cb0e645 100644
--- a/src/BLua.cc
+++ b/src/BLua.cc
@@ -382,6 +382,8 @@ void Balau::Lua::declareFunc(const char * name, lua_CFunction f, int i) {
     checkstack(2);
     lua_pushstring(L, name);
     lua_pushcfunction(L, f);
+    if ((i < 0) && (i > LUA_REGISTRYINDEX))
+        i += 2;
     lua_settable(L, i);
 }
 
diff --git a/tests/test-Lua.cc b/tests/test-Lua.cc
index 724369f..1925033 100644
--- a/tests/test-Lua.cc
+++ b/tests/test-Lua.cc
@@ -15,6 +15,7 @@ class ObjectTest {
     void someMethod1() { Printer::log(M_DEBUG, "ObjectTest::someMethod1() called on %p.", this); callCount++; }
     int someMethod2(int p) { Printer::log(M_DEBUG, "ObjectTest::someMethod2() called on %p.", this); callCount++; return p * 2; }
     static void someFunction() { Printer::log(M_DEBUG, "ObjectTest::someFunction() called."); callCount++; }
+    static void someStatic() { Printer::log(M_DEBUG, "ObjectTest::someStatic() called."); callCount++; }
 };
 
 enum ObjectTest_methods_t {
@@ -23,8 +24,9 @@ enum ObjectTest_methods_t {
 };
 
 enum ObjectTest_functions_t {
-    OBJECTTEST_CREATEOBJECTTEST,
+    OBJECTTEST_CONSTRUCTOR,
     OBJECTTEST_SOMEFUNCTION,
+    OBJECTTEST_SOMESTATIC,
     OBJECTTEST_YIELDTEST,
 };
 
@@ -35,8 +37,9 @@ struct lua_functypes_t ObjectTest_methods[] = {
 };
 
 struct lua_functypes_t ObjectTest_functions[] = {
-    { OBJECTTEST_CREATEOBJECTTEST,      "createObjectTest",     0, 0, { } },
+    { OBJECTTEST_CONSTRUCTOR,           NULL,                   0, 0, { } },
     { OBJECTTEST_SOMEFUNCTION,          "ObjectTestFunction",   0, 0, { } },
+    { OBJECTTEST_SOMESTATIC,            "SomeStatic",           0, 0, { } },
     { OBJECTTEST_YIELDTEST,             "yieldTest",            1, 1, { BLUA_NUMBER } },
     { -1, 0, 0, 0, 0 },
 };
@@ -46,7 +49,8 @@ class sLua_ObjectTest {
     DECLARE_METHOD(ObjectTest, OBJECTTEST_SOMEMETHOD1);
     DECLARE_METHOD(ObjectTest, OBJECTTEST_SOMEMETHOD2);
 
-    DECLARE_FUNCTION(ObjectTest, OBJECTTEST_CREATEOBJECTTEST);
+    DECLARE_CONSTRUCTOR(ObjectTest, OBJECTTEST_CONSTRUCTOR);
+    DECLARE_STATIC(ObjectTest, OBJECTTEST_SOMESTATIC);
     DECLARE_FUNCTION(ObjectTest, OBJECTTEST_SOMEFUNCTION);
     DECLARE_FUNCTION(ObjectTest, OBJECTTEST_YIELDTEST);
   private:
@@ -61,9 +65,11 @@ class LuaObjectTestFactory : public LuaObjectFactory {
         CHECK_METHODS(ObjectTest);
         CHECK_FUNCTIONS(ObjectTest);
 
-        PUSH_FUNCTION(ObjectTest, OBJECTTEST_CREATEOBJECTTEST);
+        PUSH_CONSTRUCTOR(ObjectTest, OBJECTTEST_CONSTRUCTOR);
+        PUSH_STATIC(ObjectTest, OBJECTTEST_SOMESTATIC);
         PUSH_FUNCTION(ObjectTest, OBJECTTEST_SOMEFUNCTION);
         PUSH_FUNCTION(ObjectTest, OBJECTTEST_YIELDTEST);
+        PUSH_CLASS_DONE();
     }
   private:
     void pushObjectAndMembers(Lua & L) {
@@ -96,7 +102,7 @@ int sLua_ObjectTest::ObjectTest_proceed_statics(Lua & L, int n, int caller) thro
     int y;
 
     switch (caller) {
-    case OBJECTTEST_CREATEOBJECTTEST:
+    case OBJECTTEST_CONSTRUCTOR:
         {
             ObjectTest * ot = new ObjectTest;
             LuaObjectTestFactory factory(ot);
@@ -105,6 +111,10 @@ int sLua_ObjectTest::ObjectTest_proceed_statics(Lua & L, int n, int caller) thro
         return 1;
         break;
 
+    case OBJECTTEST_SOMESTATIC:
+        ObjectTest::someStatic();
+        break;
+
     case OBJECTTEST_SOMEFUNCTION:
         ObjectTest::someFunction();
         break;
@@ -187,6 +197,11 @@ void MainTask::Do() {
 
     TAssert(callCount == 3);
 
+    L.load("ObjectTest.SomeStatic()");
+    TAssert(L.gettop() == 0);
+
+    TAssert(callCount == 4);
+
     L.load("yieldTest(0)");
     while (L.yielded()) {
         waitFor(LuaHelpersBase::getEvent(L));
@@ -201,9 +216,9 @@ void MainTask::Do() {
     TAssert(L.gettop() == 0);
 
     TAssert(objGotDestroyed == 0);
-    L.load("obj2 = createObjectTest() obj2:destroy()");
+    L.load("obj2 = ObjectTest.new() obj2:destroy()");
     TAssert(objGotDestroyed == 1);
-    L.load("createObjectTest() collectgarbage('collect')");
+    L.load("ObjectTest.new() collectgarbage('collect')");
     TAssert(objGotDestroyed == 2);
     L.close();
     TAssert(objGotDestroyed == 3);
-- 
cgit v1.2.3