Change directory structure
This commit is contained in:
629
luprex/cpp/core/luastack.hpp
Normal file
629
luprex/cpp/core/luastack.hpp
Normal file
@@ -0,0 +1,629 @@
|
||||
/////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// LUASTACK
|
||||
//
|
||||
// The standard lua C API asks you to work with a stack machine. You're supposed
|
||||
// to manually push and pop values on the lua stack. I find this difficult, I
|
||||
// find it hard to remember what stack position contains what value.
|
||||
//
|
||||
// To make it easier, I've created this module, "LuaStack." This module
|
||||
// creates the illusion that you're working with local variables that contain
|
||||
// lua values.
|
||||
//
|
||||
// Of course, this is all using the lua stack under the covers. Lua
|
||||
// local variables are actually just lua stack addresses. But that's
|
||||
// all kept fairly well hidden. When you use Lua local variables, and
|
||||
// the accessors inside class LuaStack, it appears that you're
|
||||
// manipulating data using local variables instead of using a stack.
|
||||
// For people like me, that's easier to think about.
|
||||
//
|
||||
// Here's an example.
|
||||
//
|
||||
// let's say you have a function that takes two arguments
|
||||
// ARG1 and ARG2, has a single return value RET1, and needs two local
|
||||
// variables LOC1 and LOC2. We would declare it like this:
|
||||
//
|
||||
// int myfunc(lua_State *L) {
|
||||
//
|
||||
// LuaArg arg1, arg2; // Declare local variables to hold the arguments.
|
||||
// LuaRet ret1; // Declare local variables to hold the return values.
|
||||
// LuaVar loc1, loc2, loc3; // Declare local variables for other purposes.
|
||||
//
|
||||
// // Assign every local var a stack index.
|
||||
// LuaStack LS(L, arg1, arg2, ret1, loc1, loc2, loc3);
|
||||
//
|
||||
// // manipulate the data in the lua local variables...
|
||||
// LS.rawget(loc1, arg1, arg2);
|
||||
// ... etc ...
|
||||
// }
|
||||
//
|
||||
// Class LuaArg, LuaRet, and LuaVar are all lua local variables.
|
||||
// The luastack constructor assigns each one of them a position on
|
||||
// the lua stack. It also makes sure that the arguments are in
|
||||
// the LuaArg variables, and it makes sure that the LuaRet values
|
||||
// are the only thing left on the stack at return time.
|
||||
//
|
||||
// Class LuaStack provides a complete catalog of accessors
|
||||
// like 'rawget' - roughly speaking, it provides equivalents to
|
||||
// every major accessor in the lua API. However, the accessors
|
||||
// provided by LuaStack take input and output from lua locals, not
|
||||
// from the stack. For example, consider this:
|
||||
//
|
||||
// LS.rawget(value, tab, key);
|
||||
//
|
||||
// In the above, value, tab, and key should be lua local variables.
|
||||
// This does a rawget on 'table', with the specified 'key', and
|
||||
// stores the result in 'value'. Nothing is added to or removed
|
||||
// from the lua stack. In general, none of the accessors in class
|
||||
// LuaStack add anything to the stack, or pop anything from the
|
||||
// stack.
|
||||
//
|
||||
// Class LuaStack can also do automatic type conversions. For
|
||||
// example, suppose you do this:
|
||||
//
|
||||
// LS.rawget(value, tab, key);
|
||||
//
|
||||
// Nominally, you would expect value, tab, and key to be lua local
|
||||
// variables. But if you pass a eng::string for key, then LuaStack will
|
||||
// automatically convert it. In general, class LuaStack can
|
||||
// convert lua_Integer, lua_Number, eng::string, bool, and LuaNil.
|
||||
//
|
||||
// On output, LuaStack can convert lua_Integers, lua_Numbers, and
|
||||
// eng::strings. In this case, strict type checking is done. If
|
||||
// there is a type mismatch, a lua error is thrown.
|
||||
//
|
||||
// You can use the operator 'set' to assign a value to a lua local
|
||||
// variable:
|
||||
//
|
||||
// LS.set(val1, val2);
|
||||
//
|
||||
// This is actually a copy operation that copies from one lua local
|
||||
// variable to another. But using type conversions, it can also be
|
||||
// used to assign arbitrary values to lua local variables, or to
|
||||
// get values from lua local variables.
|
||||
//
|
||||
// Passing LuaNewTable as an input will cause a new table to be
|
||||
// created before calling the specified operation.
|
||||
//
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
//
|
||||
//
|
||||
// LuaStack type checking
|
||||
//
|
||||
// LuaStack contains accessors for type checking. These include:
|
||||
//
|
||||
// bool LuaStack::isnumber(LuaSlot s)
|
||||
// bool LuaStack::isinteger(LuaSlot s)
|
||||
// bool LuaStack::isstring(LuaSlot s)
|
||||
// etc...
|
||||
//
|
||||
// And it also contains operations that throw errors:
|
||||
//
|
||||
// void LuaStack::checknumber(LuaSlot s)
|
||||
// void LuaStack::checkinteger(LuaSlot s)
|
||||
// void LuaStack::checkstring(LuaSlot s)
|
||||
// etc...
|
||||
//
|
||||
// These are different from the lua builtins in that they are strict.
|
||||
// For example, 'isnumber' only returns true if the value in the
|
||||
// lua local variable is already a number. No conversions are done.
|
||||
//
|
||||
// These functions do checking and also conversion at the same time:
|
||||
//
|
||||
// lua_Integer LuaStack::ckinteger(LuaSlot s)
|
||||
// lua_Number LuaStack::cknumber(LuaSlot s)
|
||||
// eng::string LuaStack::ckstring(LuaSlot s)
|
||||
// lua_State *LuaStack::ckthread(LuaSlot s)
|
||||
//
|
||||
// Like the other operations, they are strict.
|
||||
//
|
||||
//
|
||||
// LUADEFINE
|
||||
//
|
||||
// LuaDefine is a macro that defines a C function which is
|
||||
// exposed to lua. It creates a global registry of functions
|
||||
// created with LuaDefine. You use it like so:
|
||||
//
|
||||
// LuaDefine(function_name, "arguments", "documentation") {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// This macroexpands into a function definition and a function
|
||||
// registration. The function definition looks like this:
|
||||
//
|
||||
// int function_name(lua_State *L) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// The macro expansion generates this function definition, but it
|
||||
// also generates a "registration object" whose constructor puts
|
||||
// this function into a global registry of lua-callable C functions.
|
||||
// This global registry is later used to inject these C functions
|
||||
// into the lua intepreter. The mode is a string that contain
|
||||
// the following characters:
|
||||
//
|
||||
// c - create a class, and put a function into it.
|
||||
// f - create a global function not inside a class.
|
||||
//
|
||||
//
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifndef LUASTACK_HPP
|
||||
#define LUASTACK_HPP
|
||||
|
||||
#include "wrap-string.hpp"
|
||||
#include "wrap-set.hpp"
|
||||
#include <cstring>
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
#include "eris.h"
|
||||
}
|
||||
|
||||
class LuaSlot : public eng::nevernew {
|
||||
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 {};
|
||||
|
||||
class LuaSpecial : public LuaSlot {
|
||||
public:
|
||||
LuaSpecial(int n) {
|
||||
index_ = n;
|
||||
}
|
||||
};
|
||||
|
||||
extern LuaSpecial LuaRegistry;
|
||||
|
||||
class LuaUpvalue : public LuaSlot {
|
||||
public:
|
||||
LuaUpvalue(int n) {
|
||||
index_ = lua_upvalueindex(n);
|
||||
}
|
||||
};
|
||||
|
||||
class LuaNilMarker {};
|
||||
extern LuaNilMarker LuaNil;
|
||||
|
||||
class LuaNewTableMarker {};
|
||||
extern LuaNewTableMarker LuaNewTable;
|
||||
|
||||
using LuaDeleterFn = void (*)(void *);
|
||||
|
||||
using LuaTypeTag = lua_CFunction;
|
||||
template<typename T>
|
||||
int LuaTypeTagValue(lua_State *L) { return 0; }
|
||||
|
||||
// Lua table types. These deliberately do not overlap
|
||||
// with lua type values.
|
||||
//
|
||||
#define LUA_TT_GENERAL 16
|
||||
#define LUA_TT_REGISTRY 17
|
||||
#define LUA_TT_GLOBALENV 18
|
||||
#define LUA_TT_TANGIBLE 19
|
||||
#define LUA_TT_TANGIBLEMETA 20
|
||||
#define LUA_TT_DEADTANGIBLE 21
|
||||
#define LUA_TT_GLOBALDB 22
|
||||
#define LUA_TT_CLASS 23
|
||||
|
||||
// We use lightuserdata to store 'tokens': short
|
||||
// strings of 8 characters or less. These tokens
|
||||
// are useful as unique markers. The 8 characters
|
||||
// are packed into a uint64.
|
||||
|
||||
struct LuaToken {
|
||||
private:
|
||||
static constexpr uint64_t literal_to_token(const char *str) {
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
unsigned char c = *str;
|
||||
result = (result << 8) + c;
|
||||
if (*str) str++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public:
|
||||
uint64_t value;
|
||||
|
||||
template<class T>
|
||||
LuaToken(T arg) = delete;
|
||||
|
||||
constexpr LuaToken(const char *str) : value(literal_to_token(str)) {}
|
||||
LuaToken(uint64_t v) : value(v) {}
|
||||
LuaToken(void *v) : value((uint64_t)v) {}
|
||||
LuaToken() : value(0) {}
|
||||
|
||||
bool empty() const { return value == 0; }
|
||||
bool operator ==(const LuaToken &other) const { return value == other.value; }
|
||||
void *voidvalue() const { return (void*)value; }
|
||||
|
||||
eng::string str() const;
|
||||
};
|
||||
|
||||
class LuaStack : public eng::nevernew {
|
||||
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, NVAR, NRET>(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();
|
||||
|
||||
private:
|
||||
// Push any value on the stack, by type.
|
||||
void push_any_value(LuaNewTableMarker s) const { lua_newtable(L_); }
|
||||
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 eng::string &s) const { lua_pushlstring(L_, s.c_str(), s.size()); }
|
||||
void push_any_value(std::string_view s) const { lua_pushlstring(L_, s.data(), s.size()); }
|
||||
void push_any_value(const char *s) const { lua_pushstring(L_, s); }
|
||||
void push_any_value(float s) const { lua_pushnumber(L_, s); }
|
||||
void push_any_value(double s) const { lua_pushnumber(L_, s); }
|
||||
void push_any_value(int s) const { lua_pushinteger(L_, s); }
|
||||
void push_any_value(lua_Integer s) const { lua_pushinteger(L_, s); }
|
||||
void push_any_value(lua_CFunction s) const { lua_pushcfunction(L_, s); }
|
||||
void push_any_value(bool b) const { lua_pushboolean(L_, b ? 1:0); }
|
||||
void push_any_value(LuaToken token) const { lua_pushlightuserdata(L_, (void*)(token.value)); }
|
||||
|
||||
// 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() {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void delete_pointer(void *p) { delete (T*)p; }
|
||||
static void do_not_delete(void *p) { }
|
||||
|
||||
void argerr(const char *arg, const char *tp) const;
|
||||
|
||||
public:
|
||||
template<class... SS>
|
||||
LuaStack(lua_State *L, SS & ... stackslots) {
|
||||
L_ = L;
|
||||
count_slots<0, 0, 0>(stackslots...);
|
||||
if (lua_gettop(L) < narg_) {
|
||||
luaL_error(L, "not enough arguments to function");
|
||||
}
|
||||
assign_slots(argpos_, varpos_, retpos_, stackslots...);
|
||||
clear_frame();
|
||||
}
|
||||
|
||||
~LuaStack() {};
|
||||
|
||||
int result();
|
||||
|
||||
public:
|
||||
// This is the largest integer that can be stored in a lua_Number.
|
||||
// In other words, any 53-bit number can be stored.
|
||||
static const int64_t MAXINT = 0x001FFFFFFFFFFFFF;
|
||||
|
||||
static lua_State *newstate (lua_Alloc allocf);
|
||||
|
||||
lua_State *state() const { return L_; }
|
||||
|
||||
int type(LuaSlot s) const { return lua_type(L_, s); }
|
||||
void checktype(LuaSlot s, int type) const { luaL_checktype(L_, s, type); }
|
||||
|
||||
bool istable(LuaSlot s) const { return lua_type(L_, s) == LUA_TTABLE; }
|
||||
bool isstring(LuaSlot s) const { return lua_type(L_, s) == LUA_TSTRING; }
|
||||
bool isnumber(LuaSlot s) const { return lua_type(L_, s) == LUA_TNUMBER; }
|
||||
bool isinteger(LuaSlot s) const;
|
||||
bool isint(LuaSlot s) const;
|
||||
bool isthread(LuaSlot s) const { return lua_type(L_, s) == LUA_TTHREAD; }
|
||||
bool isfunction(LuaSlot s) const { return lua_type(L_, s) == LUA_TFUNCTION; }
|
||||
bool iscfunction(LuaSlot s) const { return lua_iscfunction(L_, s) != 0; }
|
||||
bool isboolean(LuaSlot s) const { return lua_type(L_, s) == LUA_TBOOLEAN; }
|
||||
bool isnil(LuaSlot s) const { return lua_type(L_, s) == LUA_TNIL; }
|
||||
bool istoken(LuaSlot s) const { return lua_islightuserdata(L_, s) != 0; }
|
||||
|
||||
void checktable(LuaSlot s, const char *n) const { if (!istable(s)) argerr(n, "table"); }
|
||||
void checkstring(LuaSlot s, const char *n) const { if (!isstring(s)) argerr(n, "string"); }
|
||||
void checknumber(LuaSlot s, const char *n) const { if (!isnumber(s)) argerr(n, "number"); }
|
||||
void checkinteger(LuaSlot s, const char *n) const { if (!isinteger(s)) argerr(n, "integer"); }
|
||||
void checkint(LuaSlot s, const char *n) const { if (!isint(s)) argerr(n, "int"); }
|
||||
void checkthread(LuaSlot s, const char *n) const { if (!isthread(s)) argerr(n, "thread"); }
|
||||
void checkfunction(LuaSlot s, const char *n) const { if (!isfunction(s)) argerr(n, "function"); }
|
||||
void checkcfunction(LuaSlot s, const char *n) const { if (!iscfunction(s)) argerr(n, "cfunction"); }
|
||||
void checkboolean(LuaSlot s, const char *n) const { if (!isboolean(s)) argerr(n, "boolean"); }
|
||||
void checknil(LuaSlot s, const char *n) const { if (!isnil(s)) argerr(n, "nil"); }
|
||||
void checktoken(LuaSlot s, const char *n) const { if (!istoken(s)) argerr(n, "token"); }
|
||||
|
||||
bool ckboolean(LuaSlot s) const;
|
||||
lua_Integer ckinteger(LuaSlot s) const;
|
||||
int ckint(LuaSlot s) const;
|
||||
lua_Number cknumber(LuaSlot s) const;
|
||||
eng::string ckstring(LuaSlot s) const;
|
||||
std::string_view ckstringview(LuaSlot s) const;
|
||||
lua_State *ckthread(LuaSlot s) const;
|
||||
LuaToken cktoken(LuaSlot s) const;
|
||||
|
||||
void clearmetatable(LuaSlot tab) const;
|
||||
void setmetatable(LuaSlot tab, LuaSlot mt) const;
|
||||
bool getmetatable(LuaSlot mt, LuaSlot tab) const;
|
||||
|
||||
void newtable(LuaSlot target) const;
|
||||
void createtable(LuaSlot target, int narr, int nrec) const;
|
||||
lua_State *newthread(LuaSlot target) const;
|
||||
void getglobaltable(LuaSlot gltab) const;
|
||||
void cleartable(LuaSlot tab, bool clearmeta) const;
|
||||
|
||||
int rawlen(LuaSlot val) const;
|
||||
|
||||
int next(LuaSlot tab, LuaSlot key, LuaSlot value) const;
|
||||
|
||||
// Return true if the classname is legal.
|
||||
bool validclassname(LuaSlot value) const;
|
||||
static bool validclassname(std::string_view cname);
|
||||
|
||||
// Return the class name if x is a valid classtab.
|
||||
// Otherwise, returns empty string. If nonempty, the
|
||||
// result is guaranteed to be a validclassname.
|
||||
// This can also function as an "isclass" operator.
|
||||
eng::string classname(LuaSlot x) const;
|
||||
|
||||
// Look up a class.
|
||||
// If there is a problem, returns an error message.
|
||||
// There are lots of error conditions, including such things
|
||||
// as no such class, corrupted class, classname invalid, etc.
|
||||
eng::string getclass(LuaSlot tab, LuaSlot name) const;
|
||||
eng::string getclass(LuaSlot tab, std::string_view name) const;
|
||||
|
||||
// Create a class, or look up an existing class.
|
||||
// WARNING: this routine assert-fails if the parameter is not
|
||||
// a valid classname. Check the classname before calling this!
|
||||
void makeclass(LuaSlot tab, LuaSlot name) const;
|
||||
void makeclass(LuaSlot tab, std::string_view name) const;
|
||||
|
||||
// Get the ID of a tangible. It's a little weird to put this in
|
||||
// this module.
|
||||
int64_t tanid(LuaSlot tab) const;
|
||||
|
||||
// Return true if the value is a sortable key (string, number, or boolean).
|
||||
bool issortablekey(LuaSlot s) const;
|
||||
|
||||
// Move a sortable key (string, number, or boolean) from one lua
|
||||
// environment to another lua environment. WARNING: this assert-fails
|
||||
// if the value is not a sortable key.
|
||||
void movesortablekey(LuaSlot val, LuaStack &other, LuaSlot otherslot);
|
||||
|
||||
bool rawequal(LuaSlot v1, LuaSlot v2) const {
|
||||
return lua_rawequal(L_, v1, v2);
|
||||
}
|
||||
|
||||
bool rawequal(LuaSlot v1, const char *name) const {
|
||||
push_any_value(name);
|
||||
bool result = lua_rawequal(L_, v1, -1);
|
||||
lua_pop(L_, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename VT>
|
||||
void set(LuaSlot target, VT value) const {
|
||||
push_any_value(value);
|
||||
lua_replace(L_, target);
|
||||
}
|
||||
|
||||
template<typename KT>
|
||||
void rawget(LuaSlot target, LuaSlot tab, KT key) const {
|
||||
push_any_value(key);
|
||||
lua_rawget(L_, tab);
|
||||
lua_replace(L_, target);
|
||||
}
|
||||
|
||||
void rawget(LuaSlot target, LuaSlot tab, int key) const {
|
||||
lua_rawgeti(L_, tab, key);
|
||||
lua_replace(L_, target);
|
||||
}
|
||||
|
||||
template<typename KT, typename VT>
|
||||
void rawset(LuaSlot tab, KT key, VT value) const {
|
||||
push_any_value(key);
|
||||
push_any_value(value);
|
||||
lua_rawset(L_, tab);
|
||||
}
|
||||
|
||||
template<typename VT>
|
||||
void rawset(LuaSlot tab, int key, VT value) const {
|
||||
push_any_value(value);
|
||||
lua_rawseti(L_, tab, key);
|
||||
}
|
||||
|
||||
// Lua flagbits manipulation: Table types.
|
||||
int gettabletype(LuaSlot tab) const;
|
||||
void settabletype(LuaSlot tab, int t) const;
|
||||
|
||||
// If slot is a table, returns the LUA_TT_XXX table type.
|
||||
// If slot is not a table, returns the LUA_TXXX general type.
|
||||
int xtype(LuaSlot slot) const;
|
||||
|
||||
// Lua flagbits manipulation: visited bit.
|
||||
bool getvisited(LuaSlot tab) const;
|
||||
void setvisited(LuaSlot tab, bool visited) const;
|
||||
|
||||
// Return true if the int64 value can be stored as a lua number.
|
||||
static bool int64_storable(int64_t v) { return (v <= MAXINT) && (v >= -MAXINT); }
|
||||
};
|
||||
|
||||
// This is a helper class to help parse tables full of keywords.
|
||||
class LuaKeywordParser {
|
||||
struct cmp_char {
|
||||
bool operator () (const char *s1, const char *s2) const {
|
||||
return strcmp(s1, s2) < 0;
|
||||
};
|
||||
};
|
||||
private:
|
||||
bool not_table_;
|
||||
lua_State *L_;
|
||||
int slot_;
|
||||
eng::set<const char *, cmp_char> parsed_;
|
||||
|
||||
void init(const lua_State *L, int slot);
|
||||
public:
|
||||
// If the slot is not a table, sets the not_table
|
||||
// flag and creates a dummy table in the slot.
|
||||
LuaKeywordParser(lua_State *L, int slot);
|
||||
LuaKeywordParser(const LuaStack &LS, LuaSlot slot) : LuaKeywordParser(LS.state(), slot.index()) {}
|
||||
|
||||
// Fetch a value from the table. This never throws.
|
||||
// Return true if the value is non-nil.
|
||||
bool parse(LuaSlot slot, const char *kw);
|
||||
|
||||
// Check if there were any errors. If so, return an
|
||||
// error message.
|
||||
eng::string final_check();
|
||||
|
||||
// Check if there are any errors. If so, throw a lua error.
|
||||
void final_check_throw();
|
||||
|
||||
// Fetch the state pointer.
|
||||
lua_State *state() const { return L_; }
|
||||
};
|
||||
|
||||
class LuaConstantReg : public eng::nevernew {
|
||||
private:
|
||||
const char *name_;
|
||||
const char *docs_;
|
||||
LuaToken tokenvalue_;
|
||||
lua_Number numbervalue_;
|
||||
LuaConstantReg *next_;
|
||||
|
||||
public:
|
||||
static LuaConstantReg *All;
|
||||
LuaConstantReg(const char *name, const char *docs, LuaToken tokenvalue, lua_Number numbervalue);
|
||||
|
||||
const char *get_name() const { return name_; }
|
||||
const char *get_docs() const { return docs_; }
|
||||
LuaToken get_tokenvalue() const { return tokenvalue_; }
|
||||
lua_Number get_numbervalue() const { return numbervalue_; }
|
||||
LuaConstantReg *next() const { return next_; }
|
||||
};
|
||||
|
||||
class LuaFunctionReg : public eng::nevernew {
|
||||
private:
|
||||
const char *name_;
|
||||
const char *args_;
|
||||
const char *docs_;
|
||||
bool sandbox_;
|
||||
lua_CFunction func_;
|
||||
LuaFunctionReg *next_;
|
||||
|
||||
public:
|
||||
static LuaFunctionReg *All;
|
||||
LuaFunctionReg(const char *name, const char *args, const char *docs, bool sand, lua_CFunction f);
|
||||
static const LuaFunctionReg *lookup(lua_CFunction fn);
|
||||
|
||||
const char *get_name() const { return name_; }
|
||||
const char *get_args() const { return args_; }
|
||||
const char *get_docs() const { return docs_; }
|
||||
lua_CFunction get_func() const { return func_; }
|
||||
bool get_sandbox() const { return sandbox_; }
|
||||
LuaFunctionReg *next() const { return next_; }
|
||||
void set_func(lua_CFunction fn) { func_ = fn; }
|
||||
};
|
||||
|
||||
#define LuaTokenConstant(name, tvalue, docs) \
|
||||
LuaConstantReg reg_##name(#name, docs, LuaToken(tvalue), 0);
|
||||
|
||||
#define LuaNumberConstant(name, nvalue, docs) \
|
||||
LuaConstantReg reg_##name(#name, docs, LuaToken(), nvalue);
|
||||
|
||||
#define LuaDefine(name, args, docs) \
|
||||
int lfn_##name(lua_State *L); \
|
||||
LuaFunctionReg reg_##name(#name, args, docs, false, lfn_##name); \
|
||||
int lfn_##name(lua_State *L)
|
||||
|
||||
#define LuaSandbox(name, args, docs) \
|
||||
int lfn_##name(lua_State *L); \
|
||||
LuaFunctionReg reg_##name(#name, args, docs, true, lfn_##name); \
|
||||
int lfn_##name(lua_State *L)
|
||||
|
||||
#define LuaDefineBuiltin(name, args, docs) \
|
||||
LuaFunctionReg reg_##name(#name, args, docs, false, nullptr);
|
||||
|
||||
#define LuaSandboxBuiltin(name, args, docs) \
|
||||
LuaFunctionReg reg_##name(#name, args, docs, true, nullptr);
|
||||
|
||||
#define LuaStringify(x) #x
|
||||
#define LuaAssert(L, x) if (!(x)) { luaL_error((L), "Assert failed: %s (file %s line %d)", LuaStringify(x), __FILE__, __LINE__); }
|
||||
#define LuaAssertStrEq(L, x, y) { eng::string _s1_(x); eng::string _s2_(y); if (_s1_ != _s2_) luaL_error((L), "Assert failed: value=%s (file %s line %d)", _s1_.c_str(), __FILE__, __LINE__); }
|
||||
|
||||
#endif // LUASTACK_HPP
|
||||
Reference in New Issue
Block a user