summaryrefslogtreecommitdiff
path: root/includes/BLua.h
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2011-10-26 15:06:49 -0700
committerPixel <pixel@nobis-crew.org>2011-10-26 15:06:49 -0700
commit58327525051d0e282b4bc2d0d7ddd1bbad2e9b65 (patch)
treee2d524de47749521e1b8c032a5af512e82fb1c49 /includes/BLua.h
parente5804f2cb929083713c0082f39182a858c082587 (diff)
Adding Lua.
Diffstat (limited to 'includes/BLua.h')
-rw-r--r--includes/BLua.h335
1 files changed, 335 insertions, 0 deletions
diff --git a/includes/BLua.h b/includes/BLua.h
new file mode 100644
index 0000000..addd081
--- /dev/null
+++ b/includes/BLua.h
@@ -0,0 +1,335 @@
+#pragma once
+
+#include <typeinfo>
+
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+
+#include <Exceptions.h>
+#include <Handle.h>
+
+namespace Balau {
+
+class Lua;
+
+class LuaExport {
+ public:
+ virtual ~LuaExport() { }
+};
+
+class LuaObject {
+ public:
+ LuaObject() : m_wantsDestruct(false), m_pushed(false) { }
+ virtual void push(Lua & L) throw (GeneralException);
+ void pushDestruct(Lua & L) throw (GeneralException);
+ 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);
+ 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);
+ friend class Lua;
+ private:
+ bool m_wantsDestruct, m_pushed;
+};
+
+typedef int (*openlualib_t)(lua_State * L);
+
+class Lua {
+ public:
+ Lua();
+ Lua(lua_State * __L) : L(__L) { }
+ Lua(const Lua &) throw (GeneralException) { throw GeneralException("Error: can't duplicate a Lua object."); }
+
+ typedef int (*lua_CallWrapper)(lua_State *, lua_CFunction);
+
+ int ref(int t = -2) { luaL_ref(L, t); }
+ void unref(int ref, int t = -1) { luaL_unref(L, t, ref); }
+
+ void open_base();
+ void open_table();
+ void open_string();
+ void open_math();
+ void open_debug();
+ void open_bit();
+ void open_jit();
+ int wrap_open(openlualib_t open) { int n = gettop(); int r = open(L); while (n < gettop()) remove(n); }
+ void openlib(const String & libname, const struct luaL_reg *l, int nup) { luaL_openlib(L, libname.to_charp(), l, nup); }
+
+ void setCallWrap(lua_CallWrapper wrapper);
+ void declareFunc(const char * funcName, lua_CFunction f, int tableIdx = LUA_GLOBALSINDEX);
+
+ void call(const char * funcName, int tableIdx = LUA_GLOBALSINDEX, int nArgs = 0);
+ void call(int nArgs = 0) { resume(nArgs); }
+
+ void push() { checkstack(); lua_pushnil(L); }
+ void push(lua_Number n) { checkstack(); lua_pushnumber(L, n); }
+ void push(const String & s) { checkstack(); lua_pushlstring(L, s.to_charp(), s.strlen()); }
+ void push(bool b) { checkstack(); lua_pushboolean(L, b); }
+ void push(const char * str, int size = -1) { if (size < 0) size = strlen(str); checkstack(); lua_pushlstring(L, str, size); }
+ void push(void * p) { checkstack(); lua_pushlightuserdata(L, p); }
+ void push(lua_CFunction f, int n = 0) { checkstack(); lua_pushcclosure(L, f, n); }
+ void pop(int idx = 1) { lua_pop(L, idx); }
+ int checkstack(int extra = 1) { return lua_checkstack(L, extra); }
+
+ int next(int t = -2) { return lua_next(L, t); }
+ void copy(int n = -1) { checkstack(); lua_pushvalue(L, n); }
+ void remove(int n = 1) { lua_remove(L, n); }
+ void insert(int n = 1) { checkstack(); lua_insert(L, n); }
+ void replace(int n = 1) { lua_replace(L, n); }
+ void newtable() { checkstack(); lua_newtable(L); }
+ void * newuser(size_t s) { checkstack(); return lua_newuserdata(L, s); }
+ void settable(int tableIdx = -3, bool raw = false);
+ void gettable(int tableIdx = -2, bool raw = false);
+ void rawseti(int idx, int tableIdx = -2) { lua_rawseti(L, tableIdx, idx); }
+ void rawgeti(int idx, int tableIdx = -1) { lua_rawgeti(L, tableIdx, idx); }
+ void setvar() { lua_settable(L, LUA_GLOBALSINDEX); }
+ int gettop() { return lua_gettop(L); }
+ void getglobal(const char * name) throw (GeneralException);
+ void pushLuaContext();
+ void error(const char * msg);
+ void error(const String & msg) { error(msg.to_charp()); }
+
+ int type(int i = -1) { return lua_type(L, i); }
+ bool isnil(int i = -1) { return lua_isnil(L, i); }
+ bool isboolean(int i = -1) { return lua_isboolean(L, i); }
+ bool isnumber(int i = -1) { return lua_isnumber(L, i); }
+ bool isstring(int i = -1) { return lua_isstring(L, i); }
+ bool istable(int i = -1) { return lua_istable(L, i); }
+ bool isfunction(int i = -1) { return lua_isfunction(L, i); }
+ bool iscfunction(int i = -1) { return lua_iscfunction(L, i); }
+ bool isuserdata(int i = -1) { return lua_isuserdata(L, i); }
+ bool islightuserdata(int i = -1) { return lua_islightuserdata(L, i); }
+ bool isobject(int i = -1);
+
+ bool toboolean(int i = -1) { return lua_toboolean(L, i); }
+ lua_Number tonumber(int i = -1) { return lua_tonumber(L, i); }
+ String tostring(int i = -1);
+ lua_CFunction tocfunction(int i = -1) { return lua_tocfunction(L, i); }
+ void * touserdata(int i = -1) { return lua_touserdata(L, i); }
+
+ String escapeString(const String &);
+ void load(IO<Handle> in, bool docall = true) throw (GeneralException);
+ void load(const String &, bool docall = true) throw (GeneralException);
+ void dumpvars(IO<Handle> out, const String & prefix, int idx = -1);
+ Lua thread(bool saveit = true);
+ Lua thread(const String &, int nargs = 0, bool saveit = true);
+ Lua thread(IO<Handle> in, int nargs = 0, bool saveit = true);
+ int yield(int nresults = 0) { return lua_yield(L, nresults); }
+ bool resume(int nargs = 0) throw (GeneralException);
+ bool resume(const String &, int nargs = 0);
+ bool resume(IO<Handle> in, int nargs = 0);
+ void showstack(int level = M_INFO);
+ void showerror();
+ int getmetatable(int i = -1) { checkstack(); return lua_getmetatable(L, i); }
+ int setmetatable(int i = -2) { return lua_setmetatable(L, i); }
+ int sethook(lua_Hook func, int mask, int count) { return lua_sethook(L, func, mask, count); }
+ void weaken();
+
+ template<class T>
+ T * recast(int n = 1) {
+ LuaExport * b;
+ T * r;
+
+ b = (LuaExport *) LuaObject::getMeInternal(*this, n);
+ if (!b)
+ error("LuaExport base object required; got null.");
+
+ r = dynamic_cast<T *>(b);
+
+ if (!r)
+ error(String("Object not compatible; expecting ") + typeid(r).name() + " but got *" + typeid(*b).name() + " instead.");
+
+ return r;
+ }
+
+ lua_State * getState() { return L; }
+ protected:
+
+ private:
+ void dumpvars_r(IO<Handle> out, int idx, int depth = 0) throw (GeneralException);
+
+ lua_State * L;
+
+ friend class LuaStatics;
+};
+
+class LuaException : public GeneralException {
+ public:
+ LuaException(String fn) : GeneralException(fn) { }
+ protected:
+ LuaException() { }
+};
+
+enum Lua_types_t {
+ BLUA_OBJECT = 0x01,
+ BLUA_TABLE = 0x02,
+ BLUA_BOOLEAN = 0x04,
+ BLUA_NUMBER = 0x08,
+ BLUA_STRING = 0x10,
+ BLUA_FUNCTION = 0x20,
+ BLUA_NIL = 0x40,
+ BLUA_USERDATA = 0x80,
+ BLUA_ANY = 0xff,
+};
+
+#define MAX_TYPE 8
+
+#define MAXARGS 32
+
+struct lua_functypes_t {
+ int number;
+ const char * name;
+ int minargs, maxargs;
+ int argtypes[MAXARGS];
+};
+
+#define DECLARE_METHOD(classname, enumvar) static int method_##enumvar(lua_State * L) { \
+ return LuaHelpers<classname>::method_multiplex( \
+ enumvar, \
+ L, \
+ sLua_##classname::classname##_proceed, \
+ 0, \
+ classname##_methods, \
+ true); \
+ }
+
+#define DECLARE_FUNCTION(classname, enumvar) static int function_##enumvar(lua_State * L) { \
+ return LuaHelpers<classname>::method_multiplex( \
+ enumvar, \
+ L, \
+ 0, \
+ sLua_##classname::classname##_proceed_statics, \
+ classname##_functions, \
+ false); \
+ }
+
+#define PUSH_METHOD(classname, enumvar) pushit( \
+ L, \
+ classname##_methods[enumvar].name, \
+ sLua_##classname::method_##enumvar)
+
+#define PUSH_METAMETHOD(classname, enumvar) pushmeta( \
+ L, \
+ String("__") + classname##_methods[enumvar].name, \
+ sLua_##classname::method_##enumvar)
+
+#define PUSH_FUNCTION(classname, enumvar) L->declarefunc( \
+ classname##_functions[enumvar].name, \
+ sLua_##classname::function_##enumvar)
+
+#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!"); \
+ } \
+ i++; \
+ } \
+}
+
+#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!"); \
+ } \
+ i++; \
+ } \
+}
+
+template <class T>
+T * LuaObject::getMe(Lua & L, int idx) { return L.recast<T>(idx); }
+
+template <class T>
+class LuaHelpers {
+ public:
+ static int method_multiplex(int caller, lua_State * __L, int (*proceed)(Lua & L, int n, T * obj, int caller), int (*proceed_static)(Lua & L, int n, int caller), lua_functypes_t * tab, bool method) {
+ Lua L(__L);
+ int add = method ? 1 : 0;
+ int n = L.gettop() - add;
+ T * obj = 0;
+ int i, j, mask;
+ bool invalid = false, arg_valid;
+
+ if (method)
+ obj = LuaObject::getMe<T>(L);
+
+ if ((n < tab[caller].minargs) || (n > tab[caller].maxargs)) {
+ invalid = true;
+ } else {
+ for (i = 0; i < tab[caller].maxargs && !invalid; i++) {
+ if (n >= (i + 1)) {
+ arg_valid = false;
+ for (j = 0; j < MAX_TYPE && !arg_valid; j++) {
+ mask = 1 << j;
+ if (tab[caller].argtypes[i] & mask) {
+ switch(mask) {
+ case BLUA_OBJECT:
+ if (L.istable(i + 1 + add)) {
+ L.push("__obj");
+ L.gettable(i + 1 + add);
+ arg_valid = L.isuserdata();
+ L.pop();
+ } else {
+ arg_valid = L.isnil(i + 1 + add);
+ }
+ break;
+ case BLUA_TABLE:
+ arg_valid = L.istable(i + 1 + add);
+ break;
+ case BLUA_BOOLEAN:
+ arg_valid = L.isboolean(i + 1 + add);
+ break;
+ case BLUA_NUMBER:
+ arg_valid = L.isnumber(i + 1 + add);
+ break;
+ case BLUA_STRING:
+ arg_valid = L.isstring(i + 1 + add);
+ break;
+ case BLUA_FUNCTION:
+ arg_valid = L.isfunction(i + 1 + add);
+ break;
+ case BLUA_NIL:
+ arg_valid = L.isnil(i + 1 + add);
+ break;
+ case BLUA_USERDATA:
+ arg_valid = L.isuserdata(i + 1 + add) || L.islightuserdata(i + 1 + add);
+ break;
+ }
+ }
+ }
+ invalid = !arg_valid;
+ }
+ }
+ }
+
+ if (invalid) {
+ if (method) {
+ L.error(String("Invalid arguments to method `") + typeid(T).name() + "::" + tab[caller].name + "'");
+ } else {
+ L.error(String("Invalid arguments to function `") + typeid(T).name() + " " + tab[caller].name + "'");
+ }
+ }
+
+ if (method) {
+ return proceed(L, n, obj, caller);
+ } else {
+ return proceed_static(L, n, caller);
+ }
+ }
+};
+
+template<class T> T * lua_recast(Lua & L, int n = 1) { return L.recast<T>(n); }
+
+};