Added two new stack disciplines to LuaStack

This commit is contained in:
2023-04-06 20:12:03 -04:00
parent b8df2bbc89
commit 7f000bc0fd
26 changed files with 401 additions and 271 deletions

View File

@@ -1,20 +1,20 @@
/////////////////////////////////////////////////////////
//
//
// LUASTACK
// LuaOldStack
//
// 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
// To make it easier, I've created this module, "LuaOldStack." 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
// the accessors inside class LuaOldStack, 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.
//
@@ -31,7 +31,7 @@
// 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);
// LuaOldStack LS(L, arg1, arg2, ret1, loc1, loc2, loc3);
//
// // manipulate the data in the lua local variables...
// LS.rawget(loc1, arg1, arg2);
@@ -39,15 +39,15 @@
// }
//
// Class LuaArg, LuaRet, and LuaVar are all lua local variables.
// The luastack constructor assigns each one of them a position on
// The LuaOldStack 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
// Class LuaOldStack 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
// provided by LuaOldStack take input and output from lua locals, not
// from the stack. For example, consider this:
//
// LS.rawget(value, tab, key);
@@ -56,20 +56,20 @@
// 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
// LuaOldStack add anything to the stack, or pop anything from the
// stack.
//
// Class LuaStack can also do automatic type conversions. For
// Class LuaOldStack 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
// variables. But if you pass a eng::string for key, then LuaOldStack will
// automatically convert it. In general, class LuaOldStack can
// convert lua_Integer, lua_Number, eng::string, bool, and LuaNil.
//
// On output, LuaStack can convert lua_Integers, lua_Numbers, and
// On output, LuaOldStack 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.
//
@@ -90,20 +90,20 @@
/////////////////////////////////////////////////////////
//
//
// LuaStack type checking
// LuaOldStack type checking
//
// LuaStack contains accessors for type checking. These include:
// LuaOldStack contains accessors for type checking. These include:
//
// bool LuaStack::isnumber(LuaSlot s)
// bool LuaStack::isinteger(LuaSlot s)
// bool LuaStack::isstring(LuaSlot s)
// bool LuaOldStack::isnumber(LuaSlot s)
// bool LuaOldStack::isinteger(LuaSlot s)
// bool LuaOldStack::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)
// void LuaOldStack::checknumber(LuaSlot s)
// void LuaOldStack::checkinteger(LuaSlot s)
// void LuaOldStack::checkstring(LuaSlot s)
// etc...
//
// These are different from the lua builtins in that they are strict.
@@ -112,10 +112,10 @@
//
// 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)
// lua_Integer LuaOldStack::ckinteger(LuaSlot s)
// lua_Number LuaOldStack::cknumber(LuaSlot s)
// eng::string LuaOldStack::ckstring(LuaSlot s)
// lua_State *LuaOldStack::ckthread(LuaSlot s)
//
// Like the other operations, they are strict.
//
@@ -151,8 +151,8 @@
/////////////////////////////////////////////////////////
#ifndef LUASTACK_HPP
#define LUASTACK_HPP
#ifndef LuaOldStack_HPP
#define LuaOldStack_HPP
#include "wrap-string.hpp"
#include "wrap-set.hpp"
@@ -180,7 +180,7 @@ public:
}
friend class LuaCoreStack;
friend class LuaStack;
friend class LuaOldStack;
friend class LuaExtStack;
};
@@ -476,7 +476,7 @@ public:
static bool int64_storable(int64_t v) { return (v <= MAXINT) && (v >= -MAXINT); }
};
class LuaStack : public LuaCoreStack {
class LuaOldStack : public LuaCoreStack {
private:
int narg_;
int ngap_;
@@ -549,7 +549,7 @@ private:
public:
template<class... SS>
LuaStack(lua_State *L, SS & ... stackslots) {
LuaOldStack(lua_State *L, SS & ... stackslots) {
L_ = L;
count_slots<0, 0, 0>(stackslots...);
if (lua_gettop(L) < narg_) {
@@ -573,10 +573,140 @@ public:
return nret_;
}
~LuaStack() {};
~LuaOldStack() {};
};
class LuaDefStack : public LuaCoreStack {
private:
int nret_;
int narg_;
int nvar_;
template<class... SS>
void assign_slots(int retp, int argp, int varp, LuaRet &v, SS & ... stackslots) {
v.index_ = retp;
assign_slots(retp+1, argp, varp, stackslots...);
}
template<class... SS>
void assign_slots(int retp, int argp, int varp, LuaArg &v, SS & ... stackslots) {
v.index_ = argp;
assign_slots(retp, argp + 1, varp, stackslots...);
}
template<class... SS>
void assign_slots(int retp, int argp, int varp, LuaVar &v, SS & ... stackslots) {
v.index_ = varp;
assign_slots(retp, argp, varp+1, stackslots...);
}
void assign_slots(int retp, int argp, int varp) {}
template<int NRET, int NARG, int NVAR, class... SS>
void count_slots(LuaRet &v, SS & ... stackslots)
{
count_slots<NRET+1, NARG, NVAR>(stackslots...);
}
template<int NRET, int NARG, int NVAR, class... SS>
void count_slots(LuaArg &v, SS & ... stackslots)
{
count_slots<NRET, NARG+1, NVAR>(stackslots...);
}
template<int NRET, int NARG, int NVAR, class... SS>
void count_slots(LuaVar &v, SS & ... stackslots)
{
count_slots<NRET, NARG, NVAR+1>(stackslots...);
}
template<int NRET, int NARG, int NVAR>
void count_slots() {
nret_ = NRET;
narg_ = NARG;
nvar_ = NVAR;
}
public:
template<class... SS>
LuaDefStack(lua_State *L, SS & ... stackslots) {
L_ = L;
count_slots<0, 0, 0>(stackslots...);
if (lua_gettop(L_) != narg_) {
luaL_error(L_, "function expects exactly %d arguments", narg_);
}
int tot = narg_ + nvar_ + nret_;
lua_checkstack(L, tot + 20);
for (int i = 0; i < nret_; i ++) {
lua_pushnil(L_);
lua_insert(L_, i + 1);
}
for (int i = 0; i < nvar_; i++) {
lua_pushnil(L_);
}
assign_slots(1, 1 + nret_, 1 + nret_ + narg_, stackslots...);
}
~LuaDefStack() {
if (!lua_isthrowing(L_)) {
lua_settop(L_, nret_);
};
}
};
class LuaExtStack : public LuaCoreStack {
private:
int oldtop_;
int nvar_;
template<class... SS>
void assign_slots(int varp, LuaVar &v, SS & ... stackslots) {
v.index_ = varp;
assign_slots(varp+1, stackslots...);
}
void assign_slots(int varp) {}
template<int NVAR, class... SS>
void count_slots(LuaVar &v, SS & ... stackslots)
{
count_slots<NVAR+1>(stackslots...);
}
template<int NVAR>
void count_slots() {
nvar_ = NVAR;
}
public:
template<class... SS>
LuaExtStack(lua_State *L, SS & ... stackslots) {
L_ = L;
count_slots<0>(stackslots...);
lua_checkstack(L_, nvar_ + 20);
oldtop_ = lua_gettop(L_);
for (int i = 0; i < nvar_; i++) {
lua_pushnil(L_);
}
assign_slots(oldtop_ + 1, stackslots...);
}
template<class... SS>
LuaExtStack(const LuaCoreStack &LS0, SS & ... stackslots) {
L_ = LS0.state();
count_slots<0>(stackslots...);
lua_checkstack(L_, nvar_ + 20);
oldtop_ = lua_gettop(L_);
for (int i = 0; i < nvar_; i++) {
lua_pushnil(L_);
}
assign_slots(oldtop_ + 1, stackslots...);
}
~LuaExtStack() {
if (!lua_isthrowing(L_)) {
lua_settop(L_, oldtop_);
}
}
void forcediscard() {
lua_settop(L_, oldtop_);
}
};
// This is a helper class to help parse tables full of keywords.
class LuaKeywordParser {
struct cmp_char {
@@ -595,7 +725,7 @@ 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()) {}
LuaKeywordParser(const LuaCoreStack &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.
@@ -682,4 +812,4 @@ public:
#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
#endif // LuaOldStack_HPP