Last active
August 29, 2015 14:10
-
-
Save mniip/6ec0dd172e7a52cd791f to your computer and use it in GitHub Desktop.
(WIP) Stackless Lua api for C++ powered by template metaprogramming
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| inline void dumpstack(lua_State *L) | |
| { | |
| int n = lua_gettop(L); | |
| printf(" <%p> Stack dump: %d values\n", L, n); | |
| int i; | |
| for(int i = 1; i <= n; i++) | |
| { | |
| printf(" [%d] ", i); | |
| switch(lua_type(L, i)) | |
| { | |
| case LUA_TNIL: printf("nil"); break; | |
| case LUA_TBOOLEAN: printf("%s", lua_toboolean(L, i) ? "true" : "false"); break; | |
| case LUA_TNUMBER: printf("%.14f", lua_tonumber(L, i)); break; | |
| case LUA_TSTRING: printf("\"%s\"", lua_tostring(L, i)); break; | |
| default: printf("%s: %p", lua_typename(L, lua_type(L, i)), lua_topointer(L, i)); break; | |
| } | |
| printf("\n"); | |
| } | |
| } | |
| #ifdef ENABLE_DEBUG | |
| #define DEBUG(X, ptn, L, ...) (dumpstack(L), printf(#X "(<%p>" ptn ")\n", (L),## __VA_ARGS__), X((L),## __VA_ARGS__)) | |
| #else | |
| #define DEBUG(X, _, ...) X(__VA_ARGS__) | |
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| extern "C" | |
| { | |
| #include <lua.h> | |
| #include <lauxlib.h> | |
| #include <lualib.h> | |
| #include "ldb.h" | |
| } | |
| #include <vector> | |
| namespace Lua | |
| { | |
| class Index; | |
| class Local; | |
| class Context | |
| { | |
| public: | |
| lua_State *L; | |
| inline Context(lua_State *_L): L(_L) {} | |
| inline lua_CFunction atpanic(lua_CFunction f) { return DEBUG(lua_atpanic, ",%p", L, f); } | |
| inline lua_CFunction atpanic() | |
| { | |
| lua_CFunction f = atpanic(NULL); | |
| atpanic(f); | |
| return f; | |
| } | |
| inline int top() const { return DEBUG(lua_gettop, "", L); } | |
| inline void top(int pos) const { DEBUG(lua_settop, ",%d", L, pos); } | |
| inline int checkstack(int extra) const { return DEBUG(lua_checkstack, ",%d", L, extra); } | |
| inline int gc(int what, int data) const { return DEBUG(lua_gc, ",%d,%d", L, what, data); } | |
| inline lua_Hook hook() const { return DEBUG(lua_gethook, "", L); } | |
| inline int hookcount() const { return DEBUG(lua_gethookcount, "", L); } | |
| inline int hookmask() const { return DEBUG(lua_gethookmask, "", L); } | |
| inline lua_Alloc allocf(void **ud) const { return DEBUG(lua_getallocf, ",%p", L, ud); } | |
| inline void allocf(lua_Alloc f, void *ud) const { return DEBUG(lua_setallocf, ",%p,%p", L, f, ud); } | |
| inline int status() const { return DEBUG(lua_status, "", L); } | |
| inline const char *typestring(int tp) const { return DEBUG(lua_typename, ",%d", L, tp); } | |
| inline Index global() const; | |
| inline Index registry() const; | |
| inline Index arg(int n) const; | |
| template<typename A, typename B, typename C> inline void setTable(A table, B key, C v) const | |
| { | |
| castPutOnTop(*this, table); | |
| castPutOnTop(*this, key); | |
| castPutOnTop(*this, v); | |
| DEBUG(lua_settable, ",%d", L, -3); | |
| DEBUG(lua_replace, ",%d", L, -2); | |
| } | |
| template<typename A, typename B, typename C> inline void rawSet(A table, B key, C v) const | |
| { | |
| castPutOnTop(*this, table); | |
| castPutOnTop(*this, key); | |
| castPutOnTop(*this, v); | |
| DEBUG(lua_rawset, ",%d", L, -3); | |
| DEBUG(lua_replace, ",%d", L, -2); | |
| } | |
| }; | |
| template<typename A, typename B> class ValueConcat; | |
| template<typename A> class ValueGetMetatable; | |
| template<typename A> class ValueGetFEnv; | |
| template<typename A, typename B> class ValueGetTable; | |
| template<typename A, typename B> class ValueRawGet; | |
| template<typename A, typename B> class ListCall; | |
| #define methods(...) \ | |
| template<typename _B> inline ValueConcat<__VA_ARGS__, _B> concat(_B b) { return ValueConcat<__VA_ARGS__, _B>(*this, b); } \ | |
| inline ValueGetFEnv<__VA_ARGS__ > getFEnv() { return ValueGetFEnv<__VA_ARGS__ >(*this); } \ | |
| inline ValueGetMetatable<__VA_ARGS__ > getMetatable() { return ValueGetMetatable<__VA_ARGS__ >(*this); } \ | |
| template<typename _B> inline ValueGetTable<__VA_ARGS__, _B> operator[](_B b) { return ValueGetTable<__VA_ARGS__, _B>(*this, b); } \ | |
| template<typename _B> inline ValueRawGet<__VA_ARGS__, _B> rawGet(_B b) { return ValueRawGet<__VA_ARGS__, _B>(*this, b); } \ | |
| template<typename _B> inline ListCall<__VA_ARGS__, _B> operator()(_B b, int nret = LUA_MULTRET) { return ListCall<__VA_ARGS__, _B>(*this, b, nret); } | |
| template<typename A, typename B> class ValueConcat | |
| { | |
| A a; | |
| B b; | |
| public: | |
| inline ValueConcat(A _a, B _b): a(_a), b(_b) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| castPutOnTop(ctx, a); | |
| castPutOnTop(ctx, b); | |
| DEBUG(lua_concat, ",%d", ctx->L, 2); | |
| } | |
| methods(ValueConcat<A, B>) | |
| }; | |
| template<typename A, typename B> inline ValueConcat<A, B> concat(A a, B b) { return ValueConcat<A, B>(a, b); } | |
| template<typename A> class ValueGetFEnv | |
| { | |
| A a; | |
| public: | |
| inline ValueGetFEnv(A _a): a(_a) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| castPutOnTop(ctx, a); | |
| DEBUG(lua_getfenv, ",%d", ctx->L, -1); | |
| } | |
| methods(ValueGetFEnv<A>) | |
| }; | |
| template<typename A> class ValueGetMetatable | |
| { | |
| A a; | |
| public: | |
| inline ValueGetMetatable(A _a): a(_a) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| castPutOnTop(ctx, a); | |
| if(!DEBUG(lua_getmetatable, ",%d", ctx->L, -1)) | |
| DEBUG(lua_pushnil, "", ctx->L); | |
| DEBUG(lua_replace, ",%d", ctx->L, -2); | |
| } | |
| methods(ValueGetMetatable<A>) | |
| }; | |
| template<typename A, typename B> class ValueGetTable | |
| { | |
| A a; | |
| B b; | |
| public: | |
| inline ValueGetTable(A _a, B _b): a(_a), b(_b) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| castPutOnTop(ctx, a); | |
| castPutOnTop(ctx, b); | |
| DEBUG(lua_gettable, ",%d", ctx->L, -2); | |
| DEBUG(lua_replace, ",%d", ctx->L, -2); | |
| } | |
| methods(ValueGetTable<A, B>) | |
| }; | |
| class ValueNewTable | |
| { | |
| public: | |
| inline ValueNewTable() {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_newtable, "", ctx->L); | |
| } | |
| methods(ValueNewTable) | |
| }; | |
| class ValueNewUserdata | |
| { | |
| size_t length; | |
| void **userdata; | |
| public: | |
| inline ValueNewUserdata(size_t _length, void **_userdata): length(_length), userdata(_userdata) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| *userdata = DEBUG(lua_newuserdata, ",%ld", ctx->L, length); | |
| } | |
| methods(ValueNewUserdata) | |
| }; | |
| class ValuePushBoolean | |
| { | |
| bool v; | |
| public: | |
| inline ValuePushBoolean(bool _v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushboolean, ",%d", ctx->L, v); | |
| } | |
| methods(ValuePushBoolean) | |
| }; | |
| class ValuePushCFunction | |
| { | |
| lua_CFunction v; | |
| public: | |
| inline ValuePushCFunction(lua_CFunction _v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushcfunction, ",%p", ctx->L, v); | |
| } | |
| methods(ValuePushCFunction) | |
| }; | |
| class ValuePushInteger | |
| { | |
| lua_Integer v; | |
| public: | |
| inline ValuePushInteger(lua_Integer _v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushinteger, ",%ld", ctx->L, v); | |
| } | |
| methods(ValuePushInteger) | |
| }; | |
| class ValuePushLightUserdata | |
| { | |
| void *v; | |
| public: | |
| inline ValuePushLightUserdata(void * _v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushlightuserdata, ",%p", ctx->L, v); | |
| } | |
| methods(ValuePushLightUserdata) | |
| }; | |
| class ValuePushLString | |
| { | |
| const char *string; | |
| size_t length; | |
| public: | |
| inline ValuePushLString(const char * _string, size_t _length): string(_string), length(_length) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushlstring, ",%p,%ld", ctx->L, string, length); | |
| } | |
| methods(ValuePushLString) | |
| }; | |
| class ValuePushNil | |
| { | |
| public: | |
| inline ValuePushNil() {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushnil, "", ctx->L); | |
| } | |
| methods(ValuePushNil) | |
| }; | |
| class ValuePushNumber | |
| { | |
| lua_Number v; | |
| public: | |
| inline ValuePushNumber(lua_Number _v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushnumber, ",%.14f", ctx->L, v); | |
| } | |
| methods(ValuePushNumber) | |
| }; | |
| class ValuePushString | |
| { | |
| const char *v; | |
| public: | |
| inline ValuePushString(const char *_v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushstring, ",\"%s\"", ctx->L, v); | |
| } | |
| methods(ValuePushString) | |
| }; | |
| class ValuePushThread | |
| { | |
| lua_State *v; | |
| public: | |
| inline ValuePushThread(lua_State *_v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_pushthread, "", v); | |
| } | |
| methods(ValuePushThread) | |
| }; | |
| template<typename A, typename B> class ValueRawGet | |
| { | |
| A a; | |
| B b; | |
| public: | |
| inline ValueRawGet(A _a, B _b): a(_a), b(_b) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| castPutOnTop(ctx, a); | |
| castPutOnTop(ctx, b); | |
| DEBUG(lua_rawget, ",%d", ctx->L, -2); | |
| DEBUG(lua_replace, ",%d", ctx->L, -2); | |
| } | |
| methods(ValueRawGet<A, B>) | |
| }; | |
| template<typename A> class ValueList | |
| { | |
| A a; | |
| public: | |
| inline ValueList(A _a): a(_a) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| DEBUG(lua_newtable, "", ctx->L); | |
| int table = ctx->top(); | |
| int length = a.createAtTop(ctx); | |
| for(int i = length; i > 0; i--) | |
| DEBUG(lua_rawseti, ",%d,%d", ctx->L, table, i); | |
| } | |
| }; | |
| inline ValuePushBoolean boolean(bool v) { return ValuePushBoolean(v); } | |
| inline ValuePushCFunction cFunction(lua_CFunction v) { return ValuePushCFunction(v); } | |
| inline ValuePushInteger integer(lua_Integer v) { return ValuePushInteger(v); } | |
| inline ValuePushLightUserdata lightUserdata(void *v) { return ValuePushLightUserdata(v); } | |
| inline ValuePushNumber number(lua_Number v) { return ValuePushNumber(v); } | |
| inline ValuePushString string(const char *v) { return ValuePushString(v); } | |
| inline ValuePushLString string(const char *string, size_t length) { return ValuePushLString(string, length); } | |
| inline ValuePushThread thread(lua_State *v) { return ValuePushThread(v); } | |
| inline ValueNewUserdata userdata(size_t length, void **v) { return ValueNewUserdata(length, v); } | |
| inline ValuePushNil nil() { return ValuePushNil(); } | |
| inline ValueNewTable table() { return ValueNewTable(); } | |
| template <typename A> inline ValueList<A> list(A a) { return ValueList<A>(a); } | |
| class Index | |
| { | |
| public: | |
| const Context *ctx; | |
| int idx; | |
| inline Index(const Context *_ctx, int _idx): ctx(_ctx), idx(_idx) {} | |
| template<typename A> inline void operator=(A v) const { castPutOnTop(ctx, v); DEBUG(lua_replace, ",%d", ctx->L, idx); } | |
| inline void operator=(Local &v) const; | |
| inline operator bool() const { return DEBUG(lua_toboolean, ",%d", ctx->L, idx); } | |
| inline operator lua_CFunction() const { return DEBUG(lua_tocfunction, ",%d", ctx->L, idx); } | |
| inline operator lua_Integer() const { return DEBUG(lua_tointeger, ",%d", ctx->L, idx); } | |
| inline operator lua_Number() const { return DEBUG(lua_tonumber, ",%d", ctx->L, idx); } | |
| inline operator const char *() const { return DEBUG(lua_tostring, ",%d", ctx->L, idx); } | |
| inline operator lua_State *() const { return DEBUG(lua_tothread, ",%d", ctx->L, idx); } | |
| inline operator void *() const { return DEBUG(lua_touserdata, ",%d", ctx->L, idx); } | |
| methods(Index) | |
| }; | |
| class Local: public Index | |
| { | |
| public: | |
| inline Local(const Context &_ctx): Index(&_ctx, _ctx.top() + 1) { DEBUG(lua_pushnil, "", _ctx.L); } | |
| inline Local(Index i): Index(i) {} | |
| inline ~Local() { DEBUG(lua_pop, ",%d", ctx->L, 1); } | |
| template<typename A> inline void operator=(A v) const { castPutOnTop(ctx, v); DEBUG(lua_replace, ",%d", ctx->L, idx); } | |
| inline void operator=(Local &v) const; | |
| }; | |
| class ValuePushValue | |
| { | |
| Index v; | |
| public: | |
| inline ValuePushValue(Index _v): v(_v) {} | |
| inline void putOnTop(const Context *ctx) const | |
| { | |
| if(ctx->L == v.ctx->L) | |
| DEBUG(lua_pushvalue, ",%d", ctx->L, v.idx); | |
| else | |
| { | |
| DEBUG(lua_pushvalue, ",%d", v.ctx->L, v.idx); | |
| DEBUG(lua_xmove, ",%p,%d", v.ctx->L, ctx->L, 1); | |
| } | |
| } | |
| methods(ValuePushValue) | |
| }; | |
| #undef methods | |
| inline void castPutOnTop(const Context *ctx, bool v) { ValuePushBoolean(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, lua_CFunction v) { ValuePushCFunction(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, lua_Integer v) { ValuePushInteger(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, void *v) { ValuePushLightUserdata(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, lua_Number v) { ValuePushNumber(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, const char *v) { ValuePushString(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, lua_State *v) { ValuePushThread(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, Index v) { ValuePushValue(v).putOnTop(ctx); } | |
| inline void castPutOnTop(const Context *ctx, Local &v) { ValuePushValue(v).putOnTop(ctx); } | |
| template<typename A> inline void castPutOnTop(const Context *ctx, A a) { a.putOnTop(ctx); } | |
| inline Index Context::global() const { return Index(this, LUA_GLOBALSINDEX); } | |
| inline Index Context::registry() const { return Index(this, LUA_REGISTRYINDEX); } | |
| inline Index Context::arg(int n) const { return Index(this, n); } | |
| inline void Local::operator=(Local &v) const { ValuePushValue(v).putOnTop(ctx); DEBUG(lua_replace, ",%d", ctx->L, idx); } | |
| class EvaluatedList | |
| { | |
| const Context *ctx; | |
| int length; | |
| bool willDestroy; | |
| public: | |
| template<typename A> inline EvaluatedList(const Context *_ctx, A a): ctx(_ctx), length(a.createAtTop(ctx)), willDestroy(true) {} | |
| inline EvaluatedList(const Context *_ctx, int _length): ctx(_ctx), length(_length), willDestroy(true) {} | |
| inline ~EvaluatedList() { if(willDestroy) DEBUG(lua_pop, ",%d", ctx->L, length); } | |
| inline EvaluatedList pop(Local &l) { willDestroy = false; DEBUG(lua_replace, ",%d", ctx->L, l.idx); return EvaluatedList(ctx, length - 1); } | |
| inline EvaluatedList extract(int pos, Local &l) { willDestroy = false; l = ValuePushValue(Index(ctx, ctx->top() - length + pos + 1)); return EvaluatedList(ctx, length); } | |
| }; | |
| template<typename A, typename B> class ListAppend; | |
| template<typename A, typename B> class ListMerge; | |
| #define methods(...) \ | |
| inline EvaluatedList evaluate(Context &ctx) { return EvaluatedList(&ctx, *this); } \ | |
| inline ListAppend<__VA_ARGS__, Local &> append(Local &b) { return ListAppend<__VA_ARGS__, Local &>(*this, b); } \ | |
| template<typename _B> inline ListAppend<__VA_ARGS__, _B> append(_B b) { return ListAppend<__VA_ARGS__, _B>(*this, b); } \ | |
| template<typename _B> inline ListMerge<__VA_ARGS__, _B> merge(_B b) { return ListMerge<__VA_ARGS__, _B>(*this, b); } \ | |
| template<typename A, typename B> class ListAppend | |
| { | |
| A a; | |
| B b; | |
| public: | |
| inline ListAppend(A _a, B _b): a(_a), b(_b) {} | |
| inline int createAtTop(const Context *ctx) const | |
| { | |
| int length = a.createAtTop(ctx); | |
| castPutOnTop(ctx, b); | |
| return length + 1; | |
| } | |
| methods(ListAppend<A, B>) | |
| }; | |
| class List | |
| { | |
| public: | |
| inline List() {} | |
| inline int createAtTop(const Context *ctx) const { return 0; } | |
| methods(List); | |
| }; | |
| template<typename A, typename B> class ListMerge | |
| { | |
| A a; | |
| B b; | |
| public: | |
| inline ListMerge(A _a, B _b): a(_a), b(_b) {} | |
| inline int createAtTop(const Context *ctx) const | |
| { | |
| int length = a.createAtTop(ctx); | |
| return length + b.createAtTop(ctx); | |
| } | |
| methods(ListMerge<A, B>) | |
| }; | |
| template<typename A, typename B> class ListCall | |
| { | |
| A a; | |
| B b; | |
| int nret; | |
| public: | |
| inline ListCall(A _a, B _b, int _nret = LUA_MULTRET): a(_a), b(_b), nret(_nret) {} | |
| inline int createAtTop(const Context *ctx) const | |
| { | |
| int top = ctx->top(); | |
| castPutOnTop(ctx, a); | |
| int length = b.createAtTop(ctx); | |
| DEBUG(lua_call, ",%d,%d", ctx->L, length, nret); | |
| return ctx->top() - top; | |
| } | |
| methods(ListCall<A, B>) | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment