2020-11-27 13:21:07 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LUASTACK_HPP
|
|
|
|
|
#define LUASTACK_HPP
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
#include "lua.h"
|
|
|
|
|
#include "lauxlib.h"
|
|
|
|
|
#include "lualib.h"
|
|
|
|
|
#include "luajit.h"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include <string>
|
2020-12-05 18:57:53 -05:00
|
|
|
#include <vector>
|
2020-11-27 13:21:07 -05:00
|
|
|
|
|
|
|
|
// LuaSlot
|
|
|
|
|
//
|
|
|
|
|
// An LuaSlot contains a lua stack index. It is initialized by the
|
|
|
|
|
// LuaStack and contains the same index until the LuaStack
|
|
|
|
|
// is destroyed. You can convert an LuaSlot into a lua stack index
|
|
|
|
|
// by simply coercing it to 'int'.
|
|
|
|
|
//
|
|
|
|
|
// There are three variants of LuaSlot that you can use: LuaArg (function
|
|
|
|
|
// argument), LuaRet (function return value), and LuaVar (function local
|
|
|
|
|
// variable).
|
|
|
|
|
//
|
|
|
|
|
class LuaSlot {
|
|
|
|
|
protected:
|
|
|
|
|
int index_;
|
|
|
|
|
private:
|
|
|
|
|
inline operator int() const {
|
|
|
|
|
return index_;
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
LuaSlot() {
|
|
|
|
|
index_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int index() const {
|
|
|
|
|
return index_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
friend class LuaStack;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class LuaArg : public LuaSlot {};
|
|
|
|
|
class LuaRet : public LuaSlot {};
|
|
|
|
|
class LuaVar : public LuaSlot {};
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
class LuaSpecial : public LuaSlot {
|
|
|
|
|
public:
|
|
|
|
|
LuaSpecial(int n) {
|
|
|
|
|
index_ = n;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern LuaSpecial LuaRegistry;
|
|
|
|
|
extern LuaSpecial LuaGlobals;
|
2020-11-27 13:21:07 -05:00
|
|
|
|
|
|
|
|
class LuaUpvalue : public LuaSlot {
|
|
|
|
|
public:
|
|
|
|
|
LuaUpvalue(int n) {
|
|
|
|
|
index_ = lua_upvalueindex(n);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
class LuaNilMarker {};
|
|
|
|
|
extern LuaNilMarker LuaNil;
|
|
|
|
|
|
2020-11-27 13:21:07 -05:00
|
|
|
class LuaStack {
|
|
|
|
|
private:
|
|
|
|
|
int narg_;
|
|
|
|
|
int ngap_;
|
|
|
|
|
int nvar_;
|
|
|
|
|
int nret_;
|
|
|
|
|
|
|
|
|
|
int argpos_;
|
|
|
|
|
int gappos_;
|
|
|
|
|
int varpos_;
|
|
|
|
|
int retpos_;
|
|
|
|
|
|
|
|
|
|
int rettop_;
|
|
|
|
|
int finaltop_;
|
|
|
|
|
|
|
|
|
|
lua_State *L_;
|
|
|
|
|
|
|
|
|
|
template<int NARG, int NVAR, int NRET, class... SS>
|
|
|
|
|
void count_slots(LuaArg &v, SS & ... stackslots)
|
|
|
|
|
{
|
|
|
|
|
count_slots<NARG+1, NRET, NVAR>(stackslots...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<int NARG, int NVAR, int NRET, class... SS>
|
|
|
|
|
void count_slots(LuaVar &v, SS & ... stackslots)
|
|
|
|
|
{
|
|
|
|
|
count_slots<NARG, NVAR+1, NRET>(stackslots...);
|
|
|
|
|
}
|
|
|
|
|
template<int NARG, int NVAR, int NRET, class... SS>
|
|
|
|
|
void count_slots(LuaRet &v, SS & ... stackslots)
|
|
|
|
|
{
|
|
|
|
|
count_slots<NARG, NVAR, NRET+1>(stackslots...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<int NARG, int NVAR, int NRET>
|
|
|
|
|
void count_slots() {
|
|
|
|
|
count_slots_finalize(NARG, NVAR, NRET);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void count_slots_finalize(int narg, int nvar, int nret);
|
|
|
|
|
|
|
|
|
|
template<class... SS>
|
|
|
|
|
void assign_slots(int argp, int varp, int retp, LuaArg &v, SS & ... stackslots) {
|
|
|
|
|
v.index_ = argp;
|
|
|
|
|
assign_slots(argp + 1, varp, retp, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class... SS>
|
|
|
|
|
void assign_slots(int argp, int varp, int retp, LuaVar &v, SS & ... stackslots) {
|
|
|
|
|
v.index_ = varp;
|
|
|
|
|
assign_slots(argp, varp+1, retp, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class... SS>
|
|
|
|
|
void assign_slots(int argp, int varp, int retp, LuaRet &v, SS & ... stackslots) {
|
|
|
|
|
v.index_ = retp;
|
|
|
|
|
assign_slots(argp, varp, retp+1, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void assign_slots(int argp, int varp, int retp) {}
|
|
|
|
|
|
|
|
|
|
void clear_frame();
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
template<class... SS>
|
|
|
|
|
LuaStack(lua_State *L, SS & ... stackslots) {
|
|
|
|
|
L_ = L;
|
|
|
|
|
count_slots<0, 0, 0>(stackslots...);
|
2020-12-05 18:57:53 -05:00
|
|
|
if (lua_gettop(L) < narg_) {
|
|
|
|
|
luaL_error(L, "not enough arguments on stack");
|
|
|
|
|
}
|
2020-11-27 13:21:07 -05:00
|
|
|
assign_slots(argpos_, varpos_, retpos_, stackslots...);
|
|
|
|
|
clear_frame();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~LuaStack() {};
|
|
|
|
|
|
|
|
|
|
int result();
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
private:
|
|
|
|
|
// Push any value on the stack, by type.
|
|
|
|
|
void push_any_value(LuaNilMarker s) const { lua_pushnil(L_); }
|
|
|
|
|
void push_any_value(LuaSlot s) const { lua_pushvalue(L_, s); }
|
|
|
|
|
void push_any_value(const std::string &s) const { lua_pushlstring(L_, s.c_str(), s.size()); }
|
|
|
|
|
void push_any_value(const char *s) const { lua_pushstring(L_, s); }
|
|
|
|
|
void push_any_value(double s) const { lua_pushnumber(L_, s); }
|
|
|
|
|
void push_any_value(int s) const { lua_pushnumber(L_, s); }
|
|
|
|
|
void push_any_value(bool b) const { lua_pushboolean(L_, b ? 1:0); }
|
|
|
|
|
|
|
|
|
|
// Push multiple values on the stack, in order, by type.
|
|
|
|
|
template<typename T0, typename... T>
|
|
|
|
|
void push_any_values(T0 arg0, T... args) {
|
|
|
|
|
push_any_value(arg0);
|
|
|
|
|
push_any_values(args...);
|
|
|
|
|
}
|
|
|
|
|
void push_any_values() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// Push everything after the CFunction. Used in the implementation
|
|
|
|
|
// of the 'call' template function.
|
|
|
|
|
template<typename... T>
|
|
|
|
|
void push_after_cfunction(LuaSlot s, T... args) {
|
|
|
|
|
push_after_cfunction(args...);
|
|
|
|
|
}
|
|
|
|
|
template<typename... T>
|
|
|
|
|
void push_after_cfunction(lua_CFunction f, T... args) {
|
|
|
|
|
push_any_values(args...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Call the CFunction, verify that the number of return values is
|
|
|
|
|
// correct, and pop everything before the CFunction. Used in the
|
|
|
|
|
// implementation of the 'call' template function.
|
|
|
|
|
template<int NRET, typename... T>
|
|
|
|
|
void call_cfunction_and_pop(int otop, LuaSlot s, T... args) {
|
|
|
|
|
call_cfunction_and_pop<NRET+1>(otop, args...);
|
|
|
|
|
lua_replace(L_, s);
|
|
|
|
|
}
|
|
|
|
|
template<int NRET, typename... T>
|
|
|
|
|
void call_cfunction_and_pop(int otop, lua_CFunction fn, T... args) {
|
|
|
|
|
int nret = fn(L_);
|
|
|
|
|
check_nret(NRET, otop, nret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check number of return values: xpected number of return values,
|
|
|
|
|
// original stack top, and number of declared return values.
|
|
|
|
|
void check_nret(int xnret, int otop, int nret) const;
|
2020-11-27 13:21:07 -05:00
|
|
|
public:
|
2020-12-05 18:57:53 -05:00
|
|
|
template<typename T>
|
|
|
|
|
void set(LuaSlot target, T value) const {
|
|
|
|
|
push_any_value(value);
|
|
|
|
|
lua_replace(L_, target);
|
|
|
|
|
}
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
int type(LuaSlot s) const { return lua_type(L_, s); }
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2020-11-27 14:24:37 -05:00
|
|
|
bool isboolean(LuaSlot s) const { return lua_isboolean(L_, s); }
|
|
|
|
|
bool iscfunction(LuaSlot s) const { return lua_iscfunction(L_, s); }
|
|
|
|
|
bool isfunction(LuaSlot s) const { return lua_isfunction(L_, s); }
|
|
|
|
|
bool islightuserdata(LuaSlot s) const { return lua_islightuserdata(L_, s); }
|
|
|
|
|
bool isnil(LuaSlot s) const { return lua_isnil(L_, s); }
|
|
|
|
|
bool isnumber(LuaSlot s) const { return lua_type(L_, s) == LUA_TNUMBER; }
|
|
|
|
|
bool isstring(LuaSlot s) const { return lua_type(L_, s) == LUA_TSTRING; }
|
|
|
|
|
bool istable(LuaSlot s) const { return lua_istable(L_, s); }
|
|
|
|
|
bool isthread(LuaSlot s) const { return lua_isthread(L_, s); }
|
|
|
|
|
bool isuserdata(LuaSlot s) const { return lua_isuserdata(L_, s); }
|
|
|
|
|
|
|
|
|
|
bool toboolean(LuaSlot s) const { return lua_toboolean(L_, s); }
|
|
|
|
|
int tointeger(LuaSlot s) const { return lua_tointeger(L_, s); }
|
|
|
|
|
double tonumber(LuaSlot s) const { return lua_tonumber(L_, s); }
|
|
|
|
|
std::string tostring(LuaSlot s) const;
|
|
|
|
|
lua_State *tothread(LuaSlot s) const { return lua_tothread(L_, s); }
|
|
|
|
|
|
|
|
|
|
int checkint(LuaSlot s) const { return luaL_checkint(L_, s); }
|
|
|
|
|
long checklong(LuaSlot s) const { return luaL_checklong(L_, s); }
|
|
|
|
|
double checknumber(LuaSlot s) const { return luaL_checknumber(L_, s); }
|
|
|
|
|
std::string checkstring(LuaSlot s) const;
|
|
|
|
|
void checktype(LuaSlot s, int t) const { return luaL_checktype(L_, s, t); }
|
|
|
|
|
|
|
|
|
|
void clearmetatable(LuaSlot tab) const;
|
|
|
|
|
void setmetatable(LuaSlot tab, LuaSlot mt) const;
|
|
|
|
|
void checknometa(LuaSlot index) const;
|
|
|
|
|
|
|
|
|
|
void newtable(LuaSlot target) const;
|
|
|
|
|
|
|
|
|
|
int next(LuaSlot tab, LuaSlot key, LuaSlot value) const;
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
template<typename KT>
|
|
|
|
|
void rawget(LuaSlot target, LuaSlot tab, KT key) const {
|
|
|
|
|
push_any_value(key);
|
2020-11-27 13:21:07 -05:00
|
|
|
lua_rawget(L_, tab);
|
|
|
|
|
lua_replace(L_, target);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
template<typename KT, typename VT>
|
|
|
|
|
void rawset(LuaSlot tab, KT key, VT value) const {
|
|
|
|
|
push_any_value(key);
|
|
|
|
|
push_any_value(value);
|
2020-11-27 13:21:07 -05:00
|
|
|
lua_rawset(L_, tab);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
template<typename VT>
|
|
|
|
|
void setfield(LuaSlot tab, const char *field, VT value) const {
|
|
|
|
|
push_any_value(value);
|
2020-11-27 13:21:07 -05:00
|
|
|
lua_setfield(L_, tab, field);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void getfield(LuaSlot target, LuaSlot tab, const char *field) const {
|
|
|
|
|
lua_getfield(L_, tab, field);
|
|
|
|
|
lua_replace(L_, target);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
// Call invokes any C function. It pushes the arguments on the stack,
|
|
|
|
|
// calls the cfunction, verifies that the number of return values is as
|
|
|
|
|
// expected, and pops the return values into LuaVars.
|
|
|
|
|
template<typename... T>
|
|
|
|
|
void call(T... args) {
|
|
|
|
|
int otop = lua_gettop(L_);
|
|
|
|
|
push_after_cfunction(args...);
|
|
|
|
|
call_cfunction_and_pop<0>(otop, args...);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class LuaFunctionReg {
|
|
|
|
|
private:
|
|
|
|
|
int mode_;
|
|
|
|
|
const char *name_;
|
|
|
|
|
lua_CFunction func_;
|
|
|
|
|
LuaFunctionReg *next_;
|
|
|
|
|
|
|
|
|
|
static LuaFunctionReg *LuaFunctionRegistry;
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
public:
|
|
|
|
|
using List = std::vector<const LuaFunctionReg *>;
|
|
|
|
|
|
|
|
|
|
LuaFunctionReg(int m, const char *n, lua_CFunction f);
|
|
|
|
|
static List all();
|
|
|
|
|
|
|
|
|
|
int get_mode() const { return mode_; }
|
|
|
|
|
const char *get_name() const { return name_; }
|
|
|
|
|
lua_CFunction get_func() const { return func_; }
|
2020-11-27 13:21:07 -05:00
|
|
|
};
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
#define LuaDefineHidden(name) LuaDefineCore(name, 0)
|
|
|
|
|
#define LuaDefineGlobalFunction(name) LuaDefineCore(name, 1)
|
|
|
|
|
#define LuaDefineGlobalMethod(name) LuaDefineCore(name, 2)
|
|
|
|
|
#define LuaDefineClassMethod(name) LuaDefineCore(name, 3)
|
|
|
|
|
|
|
|
|
|
#define LuaDefineCore(name, mode) \
|
|
|
|
|
int name(lua_State *L); \
|
|
|
|
|
LuaFunctionReg reg_##name(mode, #name, name); \
|
|
|
|
|
int name(lua_State *L)
|
|
|
|
|
|
|
|
|
|
|
2020-11-27 13:21:07 -05:00
|
|
|
|
|
|
|
|
#endif // LUASTACK_HPP
|