Skip to content

Instantly share code, notes, and snippets.

@mniip
Last active August 29, 2015 14:10
Show Gist options
  • Select an option

  • Save mniip/6ec0dd172e7a52cd791f to your computer and use it in GitHub Desktop.

Select an option

Save mniip/6ec0dd172e7a52cd791f to your computer and use it in GitHub Desktop.
(WIP) Stackless Lua api for C++ powered by template metaprogramming
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
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