From 58327525051d0e282b4bc2d0d7ddd1bbad2e9b65 Mon Sep 17 00:00:00 2001 From: Pixel Date: Wed, 26 Oct 2011 15:06:49 -0700 Subject: Adding Lua. --- includes/BLua.h | 335 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 includes/BLua.h (limited to 'includes/BLua.h') 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 + +extern "C" { +#include +#include +} + +#include +#include + +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 + 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 in, bool docall = true) throw (GeneralException); + void load(const String &, bool docall = true) throw (GeneralException); + void dumpvars(IO 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 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 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 + 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(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 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::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::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 +T * LuaObject::getMe(Lua & L, int idx) { return L.recast(idx); } + +template +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(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 T * lua_recast(Lua & L, int n = 1) { return L.recast(n); } + +}; -- cgit v1.2.3