summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas "Pixel" Noble <pixel@nobis-crew.org>2012-09-09 20:49:03 -0700
committerNicolas "Pixel" Noble <pixel@nobis-crew.org>2012-09-09 21:02:44 -0700
commit223f2d727e148aa31c4c8c5b45a21e0760fad833 (patch)
tree6543b51b15a7964087fda72988a118831eee79ec
parentc79fc0cfcabb252b18210c9880f6eb4427c21f38 (diff)
Got LuaObjects working again, and in a quite better shape I would add.
-rw-r--r--includes/BLua.h66
-rw-r--r--src/BLua.cc69
-rw-r--r--tests/test-Lua.cc145
3 files changed, 223 insertions, 57 deletions
diff --git a/includes/BLua.h b/includes/BLua.h
index 12e921f..3e255f2 100644
--- a/includes/BLua.h
+++ b/includes/BLua.h
@@ -12,28 +12,45 @@ namespace Balau {
class Lua;
-class LuaObject {
+class LuaObjectBase {
public:
- virtual ~LuaObject() { }
+ virtual void destroy() { }
+ void detach() { m_detached = true; }
+ protected:
+ bool isDetached() { return m_detached; }
+ private:
+ bool m_detached = false;
+};
+
+template<class T>
+class LuaObject : public LuaObjectBase {
+ public:
+ LuaObject(T * obj) : m_obj(obj) { }
+ virtual void destroy() { if (!isDetached() && m_obj) delete m_obj; detach(); }
+ T * getObj() { return m_obj; }
+ private:
+ T * m_obj;
};
class LuaObjectFactory {
public:
- LuaObjectFactory() : m_wantsDestruct(false), m_pushed(false) { }
+ LuaObjectFactory() { }
virtual ~LuaObjectFactory() { }
virtual void push(Lua & L);
void pushDestruct(Lua & L);
template<class T>
static T * getMe(Lua & L, int idx = 1);
protected:
- virtual void pushMembers(Lua & L) = 0;
- void pushMe(Lua & L, void * obj = 0, const char * name = NULL, bool isObj = true);
+ virtual void pushObjectAndMembers(Lua & L) = 0;
+ template<class T>
+ void pushObj(Lua & L, T * obj, const char * name = NULL);
static void pushIt(Lua & L, const char * name, lua_CFunction func);
static void pushMeta(Lua & L, const char * name, lua_CFunction func);
- static void * getMeInternal(Lua & L, int idx);
+ static LuaObjectBase * getMeInternal(Lua & L, int idx);
friend class Lua;
private:
- bool m_wantsDestruct, m_pushed;
+ void pushMe(Lua & L, LuaObjectBase * o, const char * name = NULL);
+ bool m_wantsDestruct = false, m_pushed = false;
LuaObjectFactory & operator=(const LuaObjectFactory &) = delete;
LuaObjectFactory(const LuaObjectFactory &) = delete;
};
@@ -61,6 +78,7 @@ class Lua {
void open_debug();
void open_bit();
void open_jit();
+ void open_ffi();
int wrap_open(openlualib_t open) { int n = gettop(); int r = open(L); while (n < gettop()) remove(n); return r; }
void openlib(const String & libname, const struct luaL_reg *l, int nup) { luaL_openlib(L, libname.to_charp(), l, nup); }
@@ -136,19 +154,19 @@ class Lua {
template<class T>
T * recast(int n = 1) {
- LuaObject * b;
- T * r;
+ LuaObjectBase * b;
+ LuaObject<T> * r;
- b = (LuaObject *) LuaObjectFactory::getMeInternal(*this, n);
+ b = LuaObjectFactory::getMeInternal(*this, n);
if (!b)
error("LuaObject base object required; got null.");
- r = dynamic_cast<T *>(b);
+ r = dynamic_cast<LuaObject<T> *>(b);
if (!r)
error(String("Object not compatible; expecting ") + ClassName(r).c_str() + " but got *" + ClassName(b).c_str() + " instead.");
- return r;
+ return r->getObj();
}
lua_State * getState() { return L; }
@@ -215,32 +233,30 @@ struct lua_functypes_t {
false); \
}
-#define PUSH_METHOD(classname, enumvar) pushit( \
+#define PUSH_METHOD(classname, enumvar) pushIt( \
L, \
classname##_methods[enumvar].name, \
sLua_##classname::method_##enumvar)
-#define PUSH_METAMETHOD(classname, enumvar) pushmeta( \
+#define PUSH_METAMETHOD(classname, enumvar) pushMeta( \
L, \
String("__") + classname##_methods[enumvar].name, \
sLua_##classname::method_##enumvar)
-#define PUSH_FUNCTION(classname, enumvar) L->declarefunc( \
+#define PUSH_FUNCTION(classname, enumvar) L.declareFunc( \
classname##_functions[enumvar].name, \
sLua_##classname::function_##enumvar)
-#define PUSH_SUBFUNCTION(classname, enumvar, array) L->declarefunc( \
+#define PUSH_SUBFUNCTION(classname, enumvar, array) L.declareFunc( \
classname##_functions[enumvar].name, \
sLua_##classname::function_##enumvar, \
array)
-
#define CHECK_METHODS(classname) { \
int i = 0; \
while (classname##_methods[i].number != -1) { \
- if (i != classname##_methods[i].number) { \
- throw GeneralException("Data of " #classname "_methods inconsistants!"); \
- } \
+ lua_functypes_t & func = classname##_methods[i]; \
+ AAssert(i == func.number, "Mismatched method in class " #classname); \
i++; \
} \
}
@@ -248,9 +264,8 @@ struct lua_functypes_t {
#define CHECK_FUNCTIONS(classname) { \
int i = 0; \
while (classname##_functions[i].number != -1) { \
- if (i != classname##_functions[i].number) { \
- throw GeneralException("Data of " #classname "_functions inconsistants!"); \
- } \
+ lua_functypes_t & func = classname##_functions[i]; \
+ AAssert(i == func.number, "Mismatched function in class " #classname); \
i++; \
} \
}
@@ -339,4 +354,9 @@ class LuaHelpers {
template<class T> T * lua_recast(Lua & L, int n = 1) { return L.recast<T>(n); }
+template<class T>
+void LuaObjectFactory::pushObj(Lua & L, T * obj, const char * name) {
+ pushMe(L, new (L.newuser(sizeof(LuaObject<T>))) LuaObject<T>(obj), name);
+}
+
};
diff --git a/src/BLua.cc b/src/BLua.cc
index 2114124..21a7452 100644
--- a/src/BLua.cc
+++ b/src/BLua.cc
@@ -223,30 +223,23 @@ int Balau::LuaStatics::callwrap(lua_State * __L, lua_CFunction func) {
return 0;
}
-struct ObjData {
- void * ptr;
- bool isObj;
-};
-
int Balau::LuaStatics::collector(lua_State * __L) {
Lua L(__L);
- ObjData * u = (ObjData *) L.touserdata();
- if (u->isObj) {
- LuaObject * obj = (LuaObject *) u->ptr;
- delete obj;
- } else {
- free(u->ptr);
- }
- u->ptr = NULL;
+ LuaObjectBase * o = (LuaObjectBase *) L.touserdata();
+ o->destroy();
return 0;
}
int Balau::LuaStatics::destructor(lua_State * __L) {
Lua L(__L);
L.push("__obj");
- L.gettable(-2, true);
+ L.copy();
+ L.gettable(-3, true);
collector(__L);
L.pop();
+ L.push();
+ L.settable(-3, true);
+ L.pop();
return 0;
}
@@ -372,6 +365,12 @@ void Balau::Lua::open_jit() {
while (n < gettop()) remove(n);
}
+void Balau::Lua::open_ffi() {
+ int n = gettop();
+ luaopen_ffi(L);
+ while (n < gettop()) remove(n);
+}
+
void Balau::Lua::open_bit() {
int n = gettop();
luaopen_bit(L);
@@ -779,6 +778,15 @@ void Balau::Lua::showstack(int level) {
case LUA_TFUNCTION:
t = "(Function)";
break;
+ case LUA_TUSERDATA:
+ t = "(Userdata)";
+ break;
+ case LUA_TLIGHTUSERDATA:
+ t = "(Lightuserdata)";
+ break;
+ case LUA_TTHREAD:
+ t = "(Thread)";
+ break;
default:
t = "Unknown";
}
@@ -796,42 +804,41 @@ void Balau::Lua::showerror() {
void Balau::LuaObjectFactory::push(Lua & L) {
AAssert(!(m_pushed && m_wantsDestruct), "Error: object is owned by the LUA script and can not be pushed.");
L.newtable();
- pushMembers(L);
+ pushObjectAndMembers(L);
m_pushed = true;
}
-void Balau::LuaObjectFactory::pushMe(Lua & L, void * o, const char * objname, bool obj) {
- ObjData * u;
+void Balau::LuaObjectFactory::pushMe(Lua & L, LuaObjectBase * o, const char * objname) {
L.push("__obj");
- u = (ObjData *) L.newuser(sizeof(ObjData));
- u->ptr = o;
- u->isObj = obj;
+ L.insert(-2);
+ pushMeta(L, "__gc", LuaStatics::collector);
L.settable(-3, true);
if (objname && *objname) {
L.push("__objname");
L.push(objname);
L.settable(-3, true);
}
+ pushIt(L, "destroy", LuaStatics::destructor);
+ if (!m_wantsDestruct)
+ o->detach();
}
-void * Balau::LuaObjectFactory::getMeInternal(Lua & L, int i) {
- ObjData * u = NULL;
+Balau::LuaObjectBase * Balau::LuaObjectFactory::getMeInternal(Lua & L, int i) {
+ LuaObjectBase * o;
if (L.istable(i)) {
L.push("__obj");
L.gettable(i, true);
- if (!(u = (ObjData *) L.touserdata()))
+ if (!(o = (LuaObjectBase *) L.touserdata()))
L.error("Table is not an object.");
- if (!u->ptr)
- L.error("Object already destroyed.");
L.pop();
} else if (L.isnil(i)) {
- u = NULL;
+ o = NULL;
} else {
L.error("Not an object (not even a table).");
}
- return u ? u->ptr : NULL;
+ return o;
}
void Balau::LuaObjectFactory::pushIt(Lua & L, const char * s, lua_CFunction f) {
@@ -851,12 +858,6 @@ void Balau::LuaObjectFactory::pushMeta(Lua & L, const char * s, lua_CFunction f)
void Balau::LuaObjectFactory::pushDestruct(Lua & L) {
AAssert(!m_pushed, "Error: can't push destructor, object already pushed");
- push(L);
- L.push("__obj");
- L.gettable(-2, true);
- pushMeta(L, "__gc", LuaStatics::collector);
- L.pop();
- pushIt(L, "destroy", LuaStatics::destructor);
-
m_wantsDestruct = true;
+ push(L);
}
diff --git a/tests/test-Lua.cc b/tests/test-Lua.cc
index 8ba3785..39ccbee 100644
--- a/tests/test-Lua.cc
+++ b/tests/test-Lua.cc
@@ -3,6 +3,107 @@
using namespace Balau;
+static int objGotDestroyed = 0;
+
+static int callCount = 0;
+
+class ObjectTest {
+ public:
+ ObjectTest() { Printer::log(M_DEBUG, "ObjectTest at %p created.", this); }
+ ~ObjectTest() { Printer::log(M_DEBUG, "ObjectTest at %p destroyed.", this); objGotDestroyed++; }
+ 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++; }
+};
+
+enum ObjectTest_methods_t {
+ OBJECTTEST_SOMEMETHOD1,
+ OBJECTTEST_SOMEMETHOD2,
+};
+
+enum ObjectTest_functions_t {
+ OBJECTTEST_CREATEOBJECTTEST,
+ OBJECTTEST_SOMEFUNCTION,
+};
+
+struct lua_functypes_t ObjectTest_methods[] = {
+ { OBJECTTEST_SOMEMETHOD1, "someMethod1", 0, 0, { } },
+ { OBJECTTEST_SOMEMETHOD2, "someMethod2", 1, 1, { BLUA_NUMBER } },
+ { -1, 0, 0, 0, 0 },
+};
+
+struct lua_functypes_t ObjectTest_functions[] = {
+ { OBJECTTEST_CREATEOBJECTTEST, "createObjectTest", 0, 0, { } },
+ { OBJECTTEST_SOMEFUNCTION, "ObjectTestFunction", 0, 0, { } },
+ { -1, 0, 0, 0, 0 },
+};
+
+class sLua_ObjectTest {
+ public:
+ DECLARE_METHOD(ObjectTest, OBJECTTEST_SOMEMETHOD1);
+ DECLARE_METHOD(ObjectTest, OBJECTTEST_SOMEMETHOD2);
+
+ DECLARE_FUNCTION(ObjectTest, OBJECTTEST_CREATEOBJECTTEST);
+ DECLARE_FUNCTION(ObjectTest, OBJECTTEST_SOMEFUNCTION);
+ private:
+ static int ObjectTest_proceed(Lua & L, int n, ObjectTest * obj, int caller);
+ static int ObjectTest_proceed_statics(Lua & L, int n, int caller);
+};
+
+class LuaObjectTestFactory : public LuaObjectFactory {
+ public:
+ LuaObjectTestFactory(ObjectTest * obj) : m_obj(obj) { }
+ static void pushStatics(Lua & L) {
+ CHECK_METHODS(ObjectTest);
+ CHECK_FUNCTIONS(ObjectTest);
+
+ PUSH_FUNCTION(ObjectTest, OBJECTTEST_CREATEOBJECTTEST);
+ PUSH_FUNCTION(ObjectTest, OBJECTTEST_SOMEFUNCTION);
+ }
+ private:
+ void pushObjectAndMembers(Lua & L) {
+ pushObj(L, m_obj, "ObjectTest");
+
+ PUSH_METHOD(ObjectTest, OBJECTTEST_SOMEMETHOD1);
+ PUSH_METHOD(ObjectTest, OBJECTTEST_SOMEMETHOD2);
+ }
+ ObjectTest * m_obj;
+};
+
+int sLua_ObjectTest::ObjectTest_proceed(Lua & L, int n, ObjectTest * obj, int caller) {
+ switch (caller) {
+ case OBJECTTEST_SOMEMETHOD1:
+ obj->someMethod1();
+ break;
+
+ case OBJECTTEST_SOMEMETHOD2:
+ L.push((lua_Number) obj->someMethod2(L.tonumber(-1)));
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+int sLua_ObjectTest::ObjectTest_proceed_statics(Lua & L, int n, int caller) {
+ switch (caller) {
+ case OBJECTTEST_CREATEOBJECTTEST:
+ {
+ ObjectTest * ot = new ObjectTest;
+ LuaObjectTestFactory factory(ot);
+ factory.pushDestruct(L);
+ }
+ return 1;
+ break;
+
+ case OBJECTTEST_SOMEFUNCTION:
+ ObjectTest::someFunction();
+ break;
+ }
+
+ return 0;
+}
+
void MainTask::Do() {
Printer::log(M_STATUS, "Test::Lua running.");
@@ -18,6 +119,9 @@ void MainTask::Do() {
L.open_debug();
L.open_bit();
L.open_jit();
+ L.open_ffi();
+
+ LuaObjectTestFactory::pushStatics(L);
TAssert(L.gettop() == 0);
L.load("return 42");
@@ -27,5 +131,46 @@ void MainTask::Do() {
L.pop();
TAssert(L.gettop() == 0);
+ L.push("obj");
+ {
+ ObjectTest * ot = new ObjectTest;
+ LuaObjectTestFactory factory(ot);
+ factory.pushDestruct(L);
+ }
+ L.settable(LUA_GLOBALSINDEX);
+
+ L.load("return type(obj)");
+ TAssert(L.gettop() == 1);
+ String t = L.tostring();
+ TAssert(t == "table");
+ L.pop();
+
+ TAssert(callCount == 0);
+
+ L.load("obj:someMethod1()");
+ TAssert(L.gettop() == 0);
+
+ TAssert(callCount == 1);
+
+ L.load("return obj:someMethod2(21)");
+ TAssert(L.gettop() == 1);
+ TAssert(L.tonumber() == 42);
+ L.pop();
+
+ TAssert(callCount == 2);
+
+ L.load("ObjectTestFunction()");
+ TAssert(L.gettop() == 0);
+
+ TAssert(callCount == 3);
+
+ TAssert(objGotDestroyed == 0);
+ L.load("obj2 = createObjectTest() obj2:destroy()");
+ TAssert(objGotDestroyed == 1);
+ L.load("createObjectTest() collectgarbage('collect')");
+ TAssert(objGotDestroyed == 2);
+ L.close();
+ TAssert(objGotDestroyed == 3);
+
Printer::log(M_STATUS, "Test::Lua passed.");
}