2021-01-02 13:31:18 -05:00
|
|
|
/////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// LuaStack
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2021-01-17 16:23:10 -05:00
|
|
|
// 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.
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// Here's an example.
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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:
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// 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.
|
2023-04-07 14:20:45 -04:00
|
|
|
// LuaDefStack LS(L, arg1, arg2, ret1, loc1, loc2, loc3);
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// // manipulate the data in the lua local variables...
|
|
|
|
|
// LS.rawget(loc1, arg1, arg2);
|
|
|
|
|
// ... etc ...
|
|
|
|
|
// }
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// Class LuaArg, LuaRet, and LuaVar are all lua local variables. The LuaDefStack
|
|
|
|
|
// 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.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// Class LuaDefStack 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 LuaDefStack take input and output
|
|
|
|
|
// from lua locals, not from the stack. For example, consider this:
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// LS.rawget(value, tab, key);
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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 LuaDefStack add anything to the stack, or pop
|
|
|
|
|
// anything from the stack.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// Class LuaDefStack can also do automatic type conversions. For example,
|
|
|
|
|
// suppose you do this:
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// LS.rawget(value, tab, key);
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// Nominally, you would expect value, tab, and key to be lua local variables.
|
|
|
|
|
// But if you pass a eng::string for key, then LuaDefStack will automatically
|
|
|
|
|
// convert it.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// On output, LuaDefStack 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.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// You can use the operator 'set' to assign a value to a lua local variable:
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// LS.set(val1, val2);
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// LuaDefStack type checking
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// LuaDefStack contains accessors for type checking. These include:
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// bool LuaDefStack::isnumber(LuaSlot s)
|
|
|
|
|
// bool LuaDefStack::isinteger(LuaSlot s)
|
|
|
|
|
// bool LuaDefStack::isstring(LuaSlot s)
|
2021-01-02 13:31:18 -05:00
|
|
|
// etc...
|
|
|
|
|
//
|
|
|
|
|
// And it also contains operations that throw errors:
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// void LuaDefStack::checknumber(LuaSlot s)
|
|
|
|
|
// void LuaDefStack::checkinteger(LuaSlot s)
|
|
|
|
|
// void LuaDefStack::checkstring(LuaSlot s)
|
2021-01-02 13:31:18 -05:00
|
|
|
// etc...
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// These functions do checking and also conversion at the same time:
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// lua_Integer LuaDefStack::ckinteger(LuaSlot s)
|
|
|
|
|
// lua_Number LuaDefStack::cknumber(LuaSlot s)
|
|
|
|
|
// eng::string LuaDefStack::ckstring(LuaSlot s)
|
|
|
|
|
// lua_State *LuaDefStack::ckthread(LuaSlot s)
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// Like the other operations, they are strict.
|
|
|
|
|
//
|
|
|
|
|
//
|
2021-01-12 15:49:05 -05:00
|
|
|
// LUADEFINE
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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:
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
2021-12-15 23:03:43 -05:00
|
|
|
// LuaDefine(function_name, "arguments", "documentation") {
|
2021-01-02 13:31:18 -05:00
|
|
|
// ...
|
|
|
|
|
// }
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// This macroexpands into a function definition and a function registration.
|
|
|
|
|
// The function definition looks like this:
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
// int function_name(lua_State *L) {
|
|
|
|
|
// ...
|
|
|
|
|
// }
|
|
|
|
|
//
|
2023-04-07 14:20:45 -04:00
|
|
|
// 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.
|
2021-01-02 13:31:18 -05:00
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
/////////////////////////////////////////////////////////
|
2020-11-27 13:21:07 -05:00
|
|
|
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
#ifndef LUASTACK_HPP
|
|
|
|
|
#define LUASTACK_HPP
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2022-02-23 23:08:28 -05:00
|
|
|
#include "wrap-string.hpp"
|
2022-07-22 16:04:14 -04:00
|
|
|
#include "wrap-set.hpp"
|
|
|
|
|
#include <cstring>
|
2023-04-13 12:14:27 -04:00
|
|
|
#include <type_traits>
|
2022-02-23 23:08:28 -05:00
|
|
|
|
2020-11-27 13:21:07 -05:00
|
|
|
#include "lua.h"
|
2021-02-28 14:24:59 -05:00
|
|
|
#include "lauxlib.h"
|
2021-02-28 15:05:45 -05:00
|
|
|
#include "lualib.h"
|
2021-03-01 18:10:40 -05:00
|
|
|
#include "eris.h"
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2022-03-02 14:52:51 -05:00
|
|
|
class LuaSlot : public eng::nevernew {
|
2020-11-27 13:21:07 -05:00
|
|
|
protected:
|
|
|
|
|
int index_;
|
2023-04-13 13:26:45 -04:00
|
|
|
|
|
|
|
|
constexpr LuaSlot(int n) : index_(n) {}
|
|
|
|
|
|
2020-11-27 13:21:07 -05:00
|
|
|
private:
|
|
|
|
|
inline operator int() const {
|
|
|
|
|
return index_;
|
|
|
|
|
}
|
2023-04-13 13:26:45 -04:00
|
|
|
|
2020-11-27 13:21:07 -05:00
|
|
|
public:
|
2023-04-13 13:26:45 -04:00
|
|
|
constexpr LuaSlot() : index_(0) {}
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2023-04-13 13:26:45 -04:00
|
|
|
inline int index() const {
|
2020-11-27 13:21:07 -05:00
|
|
|
return index_;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-06 14:05:12 -04:00
|
|
|
friend class LuaCoreStack;
|
2023-04-06 20:12:03 -04:00
|
|
|
friend class LuaOldStack;
|
2023-04-07 12:58:05 -04:00
|
|
|
friend class LuaDefStack;
|
2023-04-06 14:05:12 -04:00
|
|
|
friend class LuaExtStack;
|
2020-11-27 13:21:07 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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:
|
2023-04-13 13:26:45 -04:00
|
|
|
constexpr LuaSpecial(int n) : LuaSlot(n) {}
|
2020-12-05 18:57:53 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern LuaSpecial LuaRegistry;
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2023-04-13 13:26:45 -04:00
|
|
|
class LuaExtraArgs {
|
|
|
|
|
private:
|
|
|
|
|
int index_;
|
|
|
|
|
int size_;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
LuaExtraArgs() {
|
|
|
|
|
index_ = 0;
|
|
|
|
|
size_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LuaSpecial operator[] (int n) const { return LuaSpecial(index_ + n); }
|
|
|
|
|
int size() const { return size_; }
|
|
|
|
|
|
|
|
|
|
friend class LuaCoreStack;
|
|
|
|
|
friend class LuaDefStack;
|
2020-11-27 13:21:07 -05:00
|
|
|
};
|
|
|
|
|
|
2023-04-13 13:26:45 -04:00
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
class LuaNilMarker {};
|
|
|
|
|
extern LuaNilMarker LuaNil;
|
|
|
|
|
|
2021-01-02 13:31:18 -05:00
|
|
|
class LuaNewTableMarker {};
|
|
|
|
|
extern LuaNewTableMarker LuaNewTable;
|
|
|
|
|
|
2021-01-06 15:10:21 -05:00
|
|
|
using LuaDeleterFn = void (*)(void *);
|
|
|
|
|
|
|
|
|
|
using LuaTypeTag = lua_CFunction;
|
|
|
|
|
template<typename T>
|
|
|
|
|
int LuaTypeTagValue(lua_State *L) { return 0; }
|
|
|
|
|
|
2021-08-23 23:34:30 -04:00
|
|
|
// Lua table types. These deliberately do not overlap
|
|
|
|
|
// with lua type values.
|
|
|
|
|
//
|
2023-04-04 15:24:25 -04:00
|
|
|
enum LuaTableType {
|
|
|
|
|
LUA_TT_GENERAL = LUA_NUMTAGS,
|
|
|
|
|
LUA_TT_REGISTRY,
|
|
|
|
|
LUA_TT_GLOBALENV,
|
|
|
|
|
LUA_TT_TANGIBLE,
|
|
|
|
|
LUA_TT_TANGIBLEMETA,
|
|
|
|
|
LUA_TT_CLASS,
|
|
|
|
|
|
|
|
|
|
LUA_TT_SENTINEL
|
|
|
|
|
};
|
2021-08-23 23:34:30 -04:00
|
|
|
|
2023-03-01 16:07:13 -05:00
|
|
|
// World types enum.
|
|
|
|
|
|
|
|
|
|
enum WorldType {
|
|
|
|
|
WORLD_TYPE_MASTER = 1,
|
|
|
|
|
WORLD_TYPE_PREDICTIVE = 2,
|
|
|
|
|
};
|
|
|
|
|
|
2022-06-06 23:03:26 -04:00
|
|
|
// 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;
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LuaCoreStack
|
|
|
|
|
//
|
|
|
|
|
// This class is not meant to be used directly: it doesn't contain any code to
|
|
|
|
|
// allocate a stack frame on the lua stack and allocate slots within the frame
|
|
|
|
|
// to lua local variables. That code is in derived classes, below. The only
|
|
|
|
|
// time this class is used directly is in the extremely rare case that you want
|
|
|
|
|
// to manually allocate stack slots yourself.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-04-06 14:05:12 -04:00
|
|
|
class LuaCoreStack : public eng::nevernew {
|
|
|
|
|
protected:
|
2020-11-27 13:21:07 -05:00
|
|
|
lua_State *L_;
|
2023-04-07 14:20:45 -04:00
|
|
|
|
2023-04-13 12:14:27 -04:00
|
|
|
protected:
|
|
|
|
|
struct Counts {
|
|
|
|
|
int nret;
|
|
|
|
|
int narg;
|
|
|
|
|
int nvar;
|
2023-04-13 13:26:45 -04:00
|
|
|
int nextra;
|
|
|
|
|
constexpr Counts(int nr, int na, int nv, int ne) : nret(nr), narg(na), nvar(nv), nextra(ne) {}
|
2023-04-13 12:14:27 -04:00
|
|
|
};
|
|
|
|
|
|
2023-04-13 13:26:45 -04:00
|
|
|
template<int NRET, int NARG, int NVAR, int NEXTRA, class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
constexpr static Counts count_slots(LuaRet &v, SS & ... stackslots)
|
|
|
|
|
{
|
2023-04-13 13:26:45 -04:00
|
|
|
return count_slots<NRET+1, NARG, NVAR, NEXTRA>(stackslots...);
|
2023-04-13 12:14:27 -04:00
|
|
|
}
|
2023-04-13 13:26:45 -04:00
|
|
|
template<int NRET, int NARG, int NVAR, int NEXTRA, class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
constexpr static Counts count_slots(LuaArg &v, SS & ... stackslots)
|
|
|
|
|
{
|
2023-04-13 13:26:45 -04:00
|
|
|
return count_slots<NRET, NARG+1, NVAR, NEXTRA>(stackslots...);
|
2023-04-13 12:14:27 -04:00
|
|
|
}
|
2023-04-13 13:26:45 -04:00
|
|
|
template<int NRET, int NARG, int NVAR, int NEXTRA, class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
constexpr static Counts count_slots(LuaVar &v, SS & ... stackslots)
|
|
|
|
|
{
|
2023-04-13 13:26:45 -04:00
|
|
|
return count_slots<NRET, NARG, NVAR+1, NEXTRA>(stackslots...);
|
|
|
|
|
}
|
|
|
|
|
template<int NRET, int NARG, int NVAR, int NEXTRA, class... SS>
|
|
|
|
|
constexpr static Counts count_slots(LuaExtraArgs &v, SS & ... stackslots)
|
|
|
|
|
{
|
|
|
|
|
return count_slots<NRET, NARG, NVAR, NEXTRA+1>(stackslots...);
|
2023-04-13 12:14:27 -04:00
|
|
|
}
|
2023-04-13 13:26:45 -04:00
|
|
|
template<int NRET, int NARG, int NVAR, int NEXTRA>
|
2023-04-13 12:14:27 -04:00
|
|
|
constexpr static Counts count_slots() {
|
2023-04-13 13:26:45 -04:00
|
|
|
return Counts(NRET, NARG, NVAR, NEXTRA);
|
2023-04-13 12:14:27 -04:00
|
|
|
}
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
private:
|
|
|
|
|
// Push any value on the stack, by type.
|
2021-01-02 13:31:18 -05:00
|
|
|
void push_any_value(LuaNewTableMarker s) const { lua_newtable(L_); }
|
2020-12-05 18:57:53 -05:00
|
|
|
void push_any_value(LuaNilMarker s) const { lua_pushnil(L_); }
|
|
|
|
|
void push_any_value(LuaSlot s) const { lua_pushvalue(L_, s); }
|
2022-02-24 02:17:41 -05:00
|
|
|
void push_any_value(const eng::string &s) const { lua_pushlstring(L_, s.c_str(), s.size()); }
|
2022-02-25 19:57:23 -05:00
|
|
|
void push_any_value(std::string_view s) const { lua_pushlstring(L_, s.data(), s.size()); }
|
2020-12-05 18:57:53 -05:00
|
|
|
void push_any_value(const char *s) const { lua_pushstring(L_, s); }
|
2021-01-02 13:31:18 -05:00
|
|
|
void push_any_value(float s) const { lua_pushnumber(L_, s); }
|
2020-12-05 18:57:53 -05:00
|
|
|
void push_any_value(double s) const { lua_pushnumber(L_, s); }
|
2021-01-02 13:31:18 -05:00
|
|
|
void push_any_value(int s) const { lua_pushinteger(L_, s); }
|
|
|
|
|
void push_any_value(lua_Integer s) const { lua_pushinteger(L_, s); }
|
2021-01-06 15:10:21 -05:00
|
|
|
void push_any_value(lua_CFunction s) const { lua_pushcfunction(L_, s); }
|
2020-12-05 18:57:53 -05:00
|
|
|
void push_any_value(bool b) const { lua_pushboolean(L_, b ? 1:0); }
|
2022-06-06 23:03:26 -04:00
|
|
|
void push_any_value(LuaToken token) const { lua_pushlightuserdata(L_, (void*)(token.value)); }
|
2020-12-05 18:57:53 -05:00
|
|
|
|
|
|
|
|
// 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() {
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-22 16:04:14 -04:00
|
|
|
void argerr(const char *arg, const char *tp) const;
|
|
|
|
|
|
2020-11-27 13:21:07 -05:00
|
|
|
public:
|
2023-04-07 14:20:45 -04:00
|
|
|
LuaCoreStack(lua_State *L) : L_(L) {}
|
|
|
|
|
|
2023-04-06 14:05:12 -04:00
|
|
|
lua_State *state() const { return L_; }
|
2021-01-02 13:31:18 -05:00
|
|
|
|
2022-03-31 17:15:15 -04:00
|
|
|
// 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;
|
|
|
|
|
|
2022-02-25 19:57:23 -05:00
|
|
|
static lua_State *newstate (lua_Alloc allocf);
|
|
|
|
|
|
2020-12-05 18:57:53 -05:00
|
|
|
int type(LuaSlot s) const { return lua_type(L_, s); }
|
2021-01-02 13:31:18 -05:00
|
|
|
void checktype(LuaSlot s, int type) const { luaL_checktype(L_, s, type); }
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2021-01-02 13:31:18 -05:00
|
|
|
bool istable(LuaSlot s) const { return lua_type(L_, s) == LUA_TTABLE; }
|
2020-11-27 14:24:37 -05:00
|
|
|
bool isstring(LuaSlot s) const { return lua_type(L_, s) == LUA_TSTRING; }
|
2021-01-02 13:31:18 -05:00
|
|
|
bool isnumber(LuaSlot s) const { return lua_type(L_, s) == LUA_TNUMBER; }
|
2022-04-15 17:24:07 -04:00
|
|
|
bool isinteger(LuaSlot s) const;
|
|
|
|
|
bool isint(LuaSlot s) const;
|
2021-01-02 13:31:18 -05:00
|
|
|
bool isthread(LuaSlot s) const { return lua_type(L_, s) == LUA_TTHREAD; }
|
|
|
|
|
bool isfunction(LuaSlot s) const { return lua_type(L_, s) == LUA_TFUNCTION; }
|
2022-07-22 16:04:14 -04:00
|
|
|
bool iscfunction(LuaSlot s) const { return lua_iscfunction(L_, s) != 0; }
|
2021-01-02 13:31:18 -05:00
|
|
|
bool isboolean(LuaSlot s) const { return lua_type(L_, s) == LUA_TBOOLEAN; }
|
|
|
|
|
bool isnil(LuaSlot s) const { return lua_type(L_, s) == LUA_TNIL; }
|
2022-06-06 23:03:26 -04:00
|
|
|
bool istoken(LuaSlot s) const { return lua_islightuserdata(L_, s) != 0; }
|
2021-01-02 13:31:18 -05:00
|
|
|
|
2022-07-22 16:04:14 -04:00
|
|
|
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"); }
|
|
|
|
|
|
2021-03-30 19:30:58 -04:00
|
|
|
bool ckboolean(LuaSlot s) const;
|
2021-02-28 14:01:59 -05:00
|
|
|
lua_Integer ckinteger(LuaSlot s) const;
|
2021-07-09 18:07:06 -04:00
|
|
|
int ckint(LuaSlot s) const;
|
2021-02-28 14:01:59 -05:00
|
|
|
lua_Number cknumber(LuaSlot s) const;
|
2022-02-24 02:17:41 -05:00
|
|
|
eng::string ckstring(LuaSlot s) const;
|
2022-06-06 23:03:26 -04:00
|
|
|
std::string_view ckstringview(LuaSlot s) const;
|
2021-02-28 14:01:59 -05:00
|
|
|
lua_State *ckthread(LuaSlot s) const;
|
2022-06-06 23:03:26 -04:00
|
|
|
LuaToken cktoken(LuaSlot s) const;
|
2021-02-28 14:01:59 -05:00
|
|
|
|
2020-11-27 14:24:37 -05:00
|
|
|
void clearmetatable(LuaSlot tab) const;
|
|
|
|
|
void setmetatable(LuaSlot tab, LuaSlot mt) const;
|
2021-08-13 17:02:35 -04:00
|
|
|
bool getmetatable(LuaSlot mt, LuaSlot tab) const;
|
2020-11-27 14:24:37 -05:00
|
|
|
|
|
|
|
|
void newtable(LuaSlot target) const;
|
2021-07-03 19:49:55 -04:00
|
|
|
void createtable(LuaSlot target, int narr, int nrec) const;
|
2021-02-17 13:38:22 -05:00
|
|
|
lua_State *newthread(LuaSlot target) const;
|
2021-02-28 16:32:42 -05:00
|
|
|
void getglobaltable(LuaSlot gltab) const;
|
2021-10-25 14:47:37 -04:00
|
|
|
void cleartable(LuaSlot tab, bool clearmeta) const;
|
2021-02-09 17:15:54 -05:00
|
|
|
|
2021-07-03 19:49:55 -04:00
|
|
|
int rawlen(LuaSlot val) const;
|
|
|
|
|
|
2023-04-13 16:55:48 -04:00
|
|
|
int nkeys(LuaSlot tab) const;
|
2023-04-14 14:52:44 -04:00
|
|
|
|
2020-11-27 14:24:37 -05:00
|
|
|
int next(LuaSlot tab, LuaSlot key, LuaSlot value) const;
|
2020-11-27 13:21:07 -05:00
|
|
|
|
2021-12-27 16:44:12 -05:00
|
|
|
// Return true if the classname is legal.
|
|
|
|
|
bool validclassname(LuaSlot value) const;
|
2022-02-25 19:57:23 -05:00
|
|
|
static bool validclassname(std::string_view cname);
|
2021-12-27 16:44:12 -05:00
|
|
|
|
|
|
|
|
// 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.
|
2022-02-24 02:17:41 -05:00
|
|
|
eng::string classname(LuaSlot x) const;
|
2021-12-27 16:44:12 -05:00
|
|
|
|
|
|
|
|
// 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.
|
2022-02-24 02:17:41 -05:00
|
|
|
eng::string getclass(LuaSlot tab, LuaSlot name) const;
|
2022-02-25 19:57:23 -05:00
|
|
|
eng::string getclass(LuaSlot tab, std::string_view name) const;
|
2021-12-27 16:44:12 -05:00
|
|
|
|
|
|
|
|
// 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!
|
2021-08-23 23:34:30 -04:00
|
|
|
void makeclass(LuaSlot tab, LuaSlot name) const;
|
2022-02-25 19:57:23 -05:00
|
|
|
void makeclass(LuaSlot tab, std::string_view name) const;
|
2021-11-26 12:28:59 -05:00
|
|
|
|
2023-03-16 23:31:29 -04:00
|
|
|
// Create a tangible, or look up an existing tangible.
|
2023-03-17 13:31:10 -04:00
|
|
|
// If the tangible doesn't exist yet, this creates a tangible stub.
|
|
|
|
|
// It is possible to use World::tangible_make to transform a tangible
|
|
|
|
|
// stub into a full blown tangible, and World::tangible_delete to turn
|
|
|
|
|
// a full-blown tangible back into a stub. A stub doesn't have a
|
|
|
|
|
// class or a thread table.
|
2023-03-16 23:31:29 -04:00
|
|
|
void maketan(LuaSlot tab, int64_t id) const;
|
|
|
|
|
|
|
|
|
|
// Return true if a tangible is empty (deleted or not yet created).
|
|
|
|
|
bool tanblank(LuaSlot tab) const;
|
|
|
|
|
|
|
|
|
|
// Get the ID of a tangible.
|
2021-11-26 12:28:59 -05:00
|
|
|
int64_t tanid(LuaSlot tab) const;
|
|
|
|
|
|
2021-12-27 17:03:42 -05:00
|
|
|
// 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.
|
2023-04-06 14:05:12 -04:00
|
|
|
void movesortablekey(LuaSlot val, LuaCoreStack &other, LuaSlot otherslot);
|
2021-08-13 17:02:35 -04:00
|
|
|
|
2021-02-28 14:45:09 -05:00
|
|
|
bool rawequal(LuaSlot v1, LuaSlot v2) const {
|
|
|
|
|
return lua_rawequal(L_, v1, v2);
|
2021-01-02 13:31:18 -05:00
|
|
|
}
|
2021-02-10 16:22:24 -05:00
|
|
|
|
2023-03-05 01:51:25 -05:00
|
|
|
template<typename VT>
|
|
|
|
|
bool rawequal(LuaSlot v1, VT value) const {
|
|
|
|
|
push_any_value(value);
|
2021-02-28 14:45:09 -05:00
|
|
|
bool result = lua_rawequal(L_, v1, -1);
|
2021-02-10 16:22:24 -05:00
|
|
|
lua_pop(L_, 1);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2021-01-02 13:31:18 -05:00
|
|
|
|
2021-12-27 17:03:42 -05:00
|
|
|
template<typename VT>
|
|
|
|
|
void set(LuaSlot target, VT value) const {
|
2021-01-02 13:31:18 -05:00
|
|
|
push_any_value(value);
|
2021-12-27 17:03:42 -05:00
|
|
|
lua_replace(L_, target);
|
2021-02-07 17:26:48 -05:00
|
|
|
}
|
|
|
|
|
|
2021-12-27 17:03:42 -05:00
|
|
|
template<typename KT>
|
|
|
|
|
void rawget(LuaSlot target, LuaSlot tab, KT key) const {
|
2020-12-05 18:57:53 -05:00
|
|
|
push_any_value(key);
|
2020-11-27 13:21:07 -05:00
|
|
|
lua_rawget(L_, tab);
|
2021-12-27 17:03:42 -05:00
|
|
|
lua_replace(L_, target);
|
2020-11-27 13:21:07 -05:00
|
|
|
}
|
|
|
|
|
|
2021-12-27 17:03:42 -05:00
|
|
|
void rawget(LuaSlot target, LuaSlot tab, int key) const {
|
|
|
|
|
lua_rawgeti(L_, tab, key);
|
|
|
|
|
lua_replace(L_, target);
|
2021-07-03 19:49:55 -04:00
|
|
|
}
|
2021-11-17 15:06:10 -05:00
|
|
|
|
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);
|
|
|
|
|
}
|
2021-02-20 19:17:20 -05:00
|
|
|
|
2021-07-03 19:49:55 -04:00
|
|
|
template<typename VT>
|
2021-11-17 15:11:55 -05:00
|
|
|
void rawset(LuaSlot tab, int key, VT value) const {
|
2021-07-03 19:49:55 -04:00
|
|
|
push_any_value(value);
|
|
|
|
|
lua_rawseti(L_, tab, key);
|
|
|
|
|
}
|
2021-12-15 23:03:43 -05:00
|
|
|
|
2021-08-10 10:41:06 -04:00
|
|
|
// Lua flagbits manipulation: Table types.
|
2021-08-23 23:34:30 -04:00
|
|
|
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;
|
2021-08-10 10:41:06 -04:00
|
|
|
|
|
|
|
|
// Lua flagbits manipulation: visited bit.
|
2021-08-23 23:34:30 -04:00
|
|
|
bool getvisited(LuaSlot tab) const;
|
|
|
|
|
void setvisited(LuaSlot tab, bool visited) const;
|
2022-06-06 23:03:26 -04:00
|
|
|
|
2023-03-01 16:07:13 -05:00
|
|
|
// Return the world type (from the registry).
|
|
|
|
|
WorldType world_type() const;
|
|
|
|
|
|
|
|
|
|
// World types that are authoritative.
|
|
|
|
|
static bool is_authoritative(WorldType t) { return (t == WORLD_TYPE_MASTER); }
|
|
|
|
|
bool is_authoritative() { return is_authoritative(world_type()); }
|
|
|
|
|
|
|
|
|
|
// Stop execution of this thread if in a nonauth model,
|
|
|
|
|
// and if the thread is not a probe.
|
|
|
|
|
void guard_nopredict(const char *fn);
|
|
|
|
|
|
2022-06-06 23:03:26 -04:00
|
|
|
// 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); }
|
2020-12-05 18:57:53 -05:00
|
|
|
};
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LuaOldStack
|
|
|
|
|
//
|
|
|
|
|
// This class is deprecated, we're phasing it out. This was the first piece of
|
|
|
|
|
// code we wrote to allocate stack slots, and it has issues. It is
|
|
|
|
|
// still in use in the difference transmitter and the source database,
|
|
|
|
|
// and a few other small spots.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2023-04-06 20:12:03 -04:00
|
|
|
class LuaOldStack : public LuaCoreStack {
|
2023-04-06 14:05:12 -04:00
|
|
|
private:
|
|
|
|
|
int narg_;
|
|
|
|
|
int ngap_;
|
|
|
|
|
int nvar_;
|
|
|
|
|
int nret_;
|
|
|
|
|
|
|
|
|
|
int argpos_;
|
|
|
|
|
int gappos_;
|
|
|
|
|
int varpos_;
|
|
|
|
|
int retpos_;
|
|
|
|
|
|
|
|
|
|
int rettop_;
|
|
|
|
|
int finaltop_;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
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) {}
|
|
|
|
|
|
|
|
|
|
template<int NARG, int NVAR, int NRET, class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
void count_slotsx(LuaArg &v, SS & ... stackslots)
|
2023-04-06 14:05:12 -04:00
|
|
|
{
|
2023-04-13 12:14:27 -04:00
|
|
|
count_slotsx<NARG+1, NVAR, NRET>(stackslots...);
|
2023-04-06 14:05:12 -04:00
|
|
|
}
|
|
|
|
|
template<int NARG, int NVAR, int NRET, class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
void count_slotsx(LuaVar &v, SS & ... stackslots)
|
2023-04-06 14:05:12 -04:00
|
|
|
{
|
2023-04-13 12:14:27 -04:00
|
|
|
count_slotsx<NARG, NVAR+1, NRET>(stackslots...);
|
2023-04-06 14:05:12 -04:00
|
|
|
}
|
|
|
|
|
template<int NARG, int NVAR, int NRET, class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
void count_slotsx(LuaRet &v, SS & ... stackslots)
|
2023-04-06 14:05:12 -04:00
|
|
|
{
|
2023-04-13 12:14:27 -04:00
|
|
|
count_slotsx<NARG, NVAR, NRET+1>(stackslots...);
|
2023-04-06 14:05:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<int NARG, int NVAR, int NRET>
|
2023-04-13 12:14:27 -04:00
|
|
|
void count_slotsx() {
|
2023-04-06 14:05:12 -04:00
|
|
|
narg_ = NARG;
|
|
|
|
|
nret_ = NRET;
|
|
|
|
|
nvar_ = NVAR;
|
|
|
|
|
ngap_ = NRET - NVAR - NARG;
|
|
|
|
|
if (ngap_ < 0) ngap_ = 0;
|
|
|
|
|
|
|
|
|
|
int argtop = lua_gettop(L_);
|
|
|
|
|
argpos_ = argtop + 1 - NARG;
|
|
|
|
|
gappos_ = argpos_ + NARG;
|
|
|
|
|
varpos_ = gappos_ + ngap_;
|
|
|
|
|
retpos_ = varpos_ + NVAR;
|
|
|
|
|
|
|
|
|
|
rettop_ = retpos_ + NRET - 1;
|
|
|
|
|
finaltop_ = argpos_ + NRET - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
template<class... SS>
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaOldStack(lua_State *L, SS & ... stackslots) : LuaCoreStack(L) {
|
2023-04-13 12:14:27 -04:00
|
|
|
count_slotsx<0, 0, 0>(stackslots...);
|
2023-04-06 14:05:12 -04:00
|
|
|
if (lua_gettop(L) < narg_) {
|
|
|
|
|
luaL_error(L, "not enough arguments to function");
|
|
|
|
|
}
|
|
|
|
|
assign_slots(argpos_, varpos_, retpos_, stackslots...);
|
|
|
|
|
lua_settop(L_, varpos_ - 1);
|
|
|
|
|
for (int i = 0; i < nvar_ + nret_; i++) {
|
|
|
|
|
lua_pushnil(L_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int result() {
|
|
|
|
|
lua_settop(L_, rettop_);
|
|
|
|
|
int i = finaltop_;
|
|
|
|
|
for (int j = 0; j < nret_; j++) {
|
|
|
|
|
lua_replace(L_, i);
|
|
|
|
|
i -= 1;
|
|
|
|
|
}
|
|
|
|
|
lua_settop(L_, finaltop_);
|
|
|
|
|
return nret_;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-06 20:12:03 -04:00
|
|
|
~LuaOldStack() {};
|
2023-04-06 14:05:12 -04:00
|
|
|
};
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LuaDefStack
|
|
|
|
|
//
|
|
|
|
|
// This version of LuaStack is meant to be used at the top level of a LuaDefine.
|
|
|
|
|
// It can assign stack slots to LuaArg, LuaRet, and LuaVar locals. It arranges
|
|
|
|
|
// for the arguments to be in the LuaArg variables, and it arranges for the
|
|
|
|
|
// LuaRet variables to be returned. It also makes sure that the function has
|
|
|
|
|
// the correct number of arguments.
|
|
|
|
|
//
|
|
|
|
|
// At the end of the LuaDefine function, you're supposed to return LS.result().
|
|
|
|
|
// LS.result causes the allocated stack slots to be freed except for the LuaRet
|
|
|
|
|
// values, which have to stay on the stack in order to pass them back as return
|
|
|
|
|
// values. LS.result returns the number of LuaRet variables left on the stack.
|
|
|
|
|
//
|
|
|
|
|
// If you terminate a LuaDefine by calling lua_error or lua_yield, then
|
|
|
|
|
// obviously, you don't get a chance to call LS.result. That's not a problem.
|
|
|
|
|
// The lua interpreter will clean up after an error or yield.
|
|
|
|
|
//
|
|
|
|
|
// Implementation note: LuaDefStack doesn't have a destructor to deallocate
|
|
|
|
|
// stack slots. That's deliberate: you shouldn't expect this class to clean
|
|
|
|
|
// up its stack frame, because after all, it has to leave return values on
|
|
|
|
|
// the stack. It would be deceptive to put a destructor, which then doesn't
|
|
|
|
|
// actually clean up anyway. Better to just let it be known that this
|
|
|
|
|
// class doesn't clean up its stack frame.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
2023-04-06 14:05:12 -04:00
|
|
|
|
2023-04-06 20:12:03 -04:00
|
|
|
class LuaDefStack : public LuaCoreStack {
|
|
|
|
|
private:
|
|
|
|
|
int nret_;
|
|
|
|
|
|
2023-04-13 13:26:45 -04:00
|
|
|
template<class... SS>
|
|
|
|
|
void vassign_slots(int retp, int argp, int varp, int extrap, int extrac, LuaRet &v, SS & ... stackslots) {
|
|
|
|
|
v.index_ = retp;
|
|
|
|
|
vassign_slots(retp+1, argp, varp, extrap, extrac, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
template<class... SS>
|
|
|
|
|
void vassign_slots(int retp, int argp, int varp, int extrap, int extrac, LuaArg &v, SS & ... stackslots) {
|
|
|
|
|
v.index_ = argp;
|
|
|
|
|
vassign_slots(retp, argp+1, varp, extrap, extrac, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
template<class... SS>
|
|
|
|
|
void vassign_slots(int retp, int argp, int varp, int extrap, int extrac, LuaVar &v, SS & ... stackslots) {
|
|
|
|
|
v.index_ = varp;
|
|
|
|
|
vassign_slots(retp, argp, varp+1, extrap, extrac, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
template<class... SS>
|
|
|
|
|
void vassign_slots(int retp, int argp, int varp, int extrap, int extrac, LuaExtraArgs &v, SS & ... stackslots) {
|
|
|
|
|
v.index_ = extrap;
|
|
|
|
|
v.size_ = extrac;
|
|
|
|
|
vassign_slots(retp, argp, varp, extrap, extrac, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
void vassign_slots(int retp, int argp, int varp, int extrap, int extrac) {}
|
|
|
|
|
|
|
|
|
|
|
2023-04-06 20:12:03 -04:00
|
|
|
public:
|
|
|
|
|
template<class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
inline LuaDefStack(lua_State *L, SS & ... stackslots) : LuaCoreStack(L) {
|
2023-04-13 13:26:45 -04:00
|
|
|
constexpr Counts counts = count_slots<0, 0, 0, 0>(stackslots...);
|
2023-04-13 14:55:21 -04:00
|
|
|
int nargs = lua_gettop(L);
|
|
|
|
|
if (counts.nextra == 0) {
|
|
|
|
|
if (nargs != counts.narg) {
|
|
|
|
|
luaL_error(L_, "function expects exactly %d arguments", counts.narg);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (nargs < counts.narg) {
|
|
|
|
|
luaL_error(L_, "function expects at least %d arguments", counts.narg);
|
|
|
|
|
}
|
2023-04-06 20:12:03 -04:00
|
|
|
}
|
2023-04-13 14:55:21 -04:00
|
|
|
lua_checkstack(L, counts.nret + counts.nvar + 20);
|
|
|
|
|
lua_insert_frame(L, counts.nret + counts.nvar);
|
|
|
|
|
vassign_slots(1, 1 + counts.nret + counts.nvar, 1 + counts.nret, 1 + counts.nret + counts.nvar + counts.narg, nargs - counts.narg, stackslots...);
|
2023-04-13 12:14:27 -04:00
|
|
|
nret_ = counts.nret;
|
2023-04-06 20:12:03 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-07 12:58:05 -04:00
|
|
|
int result() {
|
2023-04-13 14:55:21 -04:00
|
|
|
lua_settop(L_, nret_);
|
2023-04-07 12:58:05 -04:00
|
|
|
return nret_;
|
2023-04-06 20:12:03 -04:00
|
|
|
}
|
2023-04-07 12:58:05 -04:00
|
|
|
|
|
|
|
|
~LuaDefStack() { }
|
2023-04-06 20:12:03 -04:00
|
|
|
};
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LuaExtStack
|
|
|
|
|
//
|
|
|
|
|
// This version of LuaStack is meant to be used in any context where
|
|
|
|
|
// you want to assign stack slots to some LuaVars, and then you want
|
|
|
|
|
// to automatically deallocate those LuaVars when the LuaExtStack
|
|
|
|
|
// goes out of scope.
|
|
|
|
|
//
|
|
|
|
|
// Unlike LuaDefStack, this version of LuaStack is meant to fully
|
|
|
|
|
// deallocate its stack frame when it goes out of scope, so it does
|
|
|
|
|
// have a destructor to do that. There is a special case in the
|
|
|
|
|
// destructor: if lua is throwing an error, the destructor leaves
|
|
|
|
|
// the stack alone, in order to preserve the error message that's
|
|
|
|
|
// on the stack. After an error throw, the lua interpreter will
|
|
|
|
|
// clean up the stack.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
2023-04-06 20:12:03 -04:00
|
|
|
class LuaExtStack : public LuaCoreStack {
|
|
|
|
|
private:
|
|
|
|
|
int oldtop_;
|
|
|
|
|
|
|
|
|
|
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) {}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
template<class... SS>
|
2023-04-07 12:58:05 -04:00
|
|
|
LuaExtStack(lua_State *L, SS & ... stackslots) : LuaCoreStack(L) {
|
2023-04-13 13:26:45 -04:00
|
|
|
constexpr Counts counts = count_slots<0, 0, 0, 0>(stackslots...);
|
2023-04-13 12:14:27 -04:00
|
|
|
static_assert(counts.narg == 0, "LuaExtStack doesn't allow LuaArg parameters");
|
|
|
|
|
static_assert(counts.nret == 0, "LuaExtStack doesn't allow LuaRet parameters");
|
2023-04-13 13:26:45 -04:00
|
|
|
static_assert(counts.nextra == 0, "LuaExtStack doesn't allow LuaExtraArgs parameters");
|
2023-04-13 12:14:27 -04:00
|
|
|
lua_checkstack(L_, counts.nvar + 20);
|
2023-04-06 20:12:03 -04:00
|
|
|
oldtop_ = lua_gettop(L_);
|
2023-04-13 12:14:27 -04:00
|
|
|
for (int i = 0; i < counts.nvar; i++) {
|
2023-04-06 20:12:03 -04:00
|
|
|
lua_pushnil(L_);
|
|
|
|
|
}
|
|
|
|
|
assign_slots(oldtop_ + 1, stackslots...);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<class... SS>
|
2023-04-13 12:14:27 -04:00
|
|
|
LuaExtStack(const LuaCoreStack &LS0, SS & ... stackslots) : LuaCoreStack(LS0.state(), stackslots...) {}
|
2023-04-06 20:12:03 -04:00
|
|
|
|
|
|
|
|
~LuaExtStack() {
|
|
|
|
|
if (!lua_isthrowing(L_)) {
|
|
|
|
|
lua_settop(L_, oldtop_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LuaKeywordParser
|
|
|
|
|
//
|
2022-07-22 16:04:14 -04:00
|
|
|
// This is a helper class to help parse tables full of keywords.
|
2023-04-07 14:20:45 -04:00
|
|
|
// It is meant to make it easier to write LuaDefine functions that
|
|
|
|
|
// accept keyword arguments. It helps with the following tasks:
|
|
|
|
|
//
|
|
|
|
|
// * It makes sure the keyword table actually is a table.
|
|
|
|
|
//
|
|
|
|
|
// * It makes sure that you didn't put an unrecognized keyword
|
|
|
|
|
// into the keyword table. Unrecognized keywords are defined
|
|
|
|
|
// as keywords that are never checked using 'parse'.
|
|
|
|
|
//
|
|
|
|
|
// * It makes sure that you didn't put anything that isn't a
|
|
|
|
|
// keyword into the keyword table.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2022-07-22 16:04:14 -04:00
|
|
|
class LuaKeywordParser {
|
|
|
|
|
struct cmp_char {
|
|
|
|
|
bool operator () (const char *s1, const char *s2) const {
|
|
|
|
|
return strcmp(s1, s2) < 0;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
private:
|
2022-07-22 17:07:40 -04:00
|
|
|
bool not_table_;
|
2022-07-22 16:04:14 -04:00
|
|
|
lua_State *L_;
|
|
|
|
|
int slot_;
|
|
|
|
|
eng::set<const char *, cmp_char> parsed_;
|
|
|
|
|
|
|
|
|
|
void init(const lua_State *L, int slot);
|
|
|
|
|
public:
|
2022-07-22 17:07:40 -04:00
|
|
|
// If the slot is not a table, sets the not_table
|
|
|
|
|
// flag and creates a dummy table in the slot.
|
2022-07-22 16:04:14 -04:00
|
|
|
LuaKeywordParser(lua_State *L, int slot);
|
2023-04-06 20:12:03 -04:00
|
|
|
LuaKeywordParser(const LuaCoreStack &LS, LuaSlot slot) : LuaKeywordParser(LS.state(), slot.index()) {}
|
2022-07-22 16:04:14 -04:00
|
|
|
|
|
|
|
|
// Fetch a value from the table. This never throws.
|
|
|
|
|
// Return true if the value is non-nil.
|
|
|
|
|
bool parse(LuaSlot slot, const char *kw);
|
|
|
|
|
|
2022-07-22 17:07:40 -04:00
|
|
|
// 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();
|
2022-07-22 16:04:14 -04:00
|
|
|
|
|
|
|
|
// Fetch the state pointer.
|
|
|
|
|
lua_State *state() const { return L_; }
|
|
|
|
|
};
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// The Lua Constant Registry
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2022-06-06 23:03:26 -04:00
|
|
|
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_; }
|
|
|
|
|
};
|
2021-01-06 15:10:21 -05:00
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// The Lua Function Registry
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2022-03-02 14:52:51 -05:00
|
|
|
class LuaFunctionReg : public eng::nevernew {
|
2020-12-05 18:57:53 -05:00
|
|
|
private:
|
|
|
|
|
const char *name_;
|
2021-12-15 23:03:43 -05:00
|
|
|
const char *args_;
|
|
|
|
|
const char *docs_;
|
2022-03-16 17:05:20 -04:00
|
|
|
bool sandbox_;
|
2020-12-05 18:57:53 -05:00
|
|
|
lua_CFunction func_;
|
|
|
|
|
LuaFunctionReg *next_;
|
|
|
|
|
|
|
|
|
|
public:
|
2022-02-25 19:57:23 -05:00
|
|
|
static LuaFunctionReg *All;
|
2022-03-16 17:05:20 -04:00
|
|
|
LuaFunctionReg(const char *name, const char *args, const char *docs, bool sand, lua_CFunction f);
|
2021-12-15 23:03:43 -05:00
|
|
|
static const LuaFunctionReg *lookup(lua_CFunction fn);
|
2020-12-05 18:57:53 -05:00
|
|
|
|
|
|
|
|
const char *get_name() const { return name_; }
|
2021-12-15 23:03:43 -05:00
|
|
|
const char *get_args() const { return args_; }
|
|
|
|
|
const char *get_docs() const { return docs_; }
|
2020-12-05 18:57:53 -05:00
|
|
|
lua_CFunction get_func() const { return func_; }
|
2022-03-16 17:05:20 -04:00
|
|
|
bool get_sandbox() const { return sandbox_; }
|
2022-02-25 19:57:23 -05:00
|
|
|
LuaFunctionReg *next() const { return next_; }
|
2021-12-16 13:06:15 -05:00
|
|
|
void set_func(lua_CFunction fn) { func_ = fn; }
|
2020-11-27 13:21:07 -05:00
|
|
|
};
|
|
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// LuaDefine and friends.
|
|
|
|
|
//
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2022-06-06 23:03:26 -04:00
|
|
|
#define LuaTokenConstant(name, tvalue, docs) \
|
2023-03-05 01:51:25 -05:00
|
|
|
LuaToken ltoken_##name(tvalue); \
|
2022-06-06 23:03:26 -04:00
|
|
|
LuaConstantReg reg_##name(#name, docs, LuaToken(tvalue), 0);
|
|
|
|
|
|
|
|
|
|
#define LuaNumberConstant(name, nvalue, docs) \
|
2023-03-05 01:51:25 -05:00
|
|
|
lua_Number lnumber_##name(nvalue); \
|
2022-06-06 23:03:26 -04:00
|
|
|
LuaConstantReg reg_##name(#name, docs, LuaToken(), nvalue);
|
2021-01-06 15:10:21 -05:00
|
|
|
|
2021-12-15 23:03:43 -05:00
|
|
|
#define LuaDefine(name, args, docs) \
|
2021-09-07 17:37:23 -04:00
|
|
|
int lfn_##name(lua_State *L); \
|
2023-04-14 14:52:44 -04:00
|
|
|
const char *lfnarg_##name = args; \
|
|
|
|
|
const char *lfndoc_##name = docs; \
|
|
|
|
|
LuaFunctionReg reg_##name(#name, lfnarg_##name, lfndoc_##name, false, lfn_##name); \
|
2021-09-07 17:37:23 -04:00
|
|
|
int lfn_##name(lua_State *L)
|
2020-12-05 18:57:53 -05:00
|
|
|
|
2023-04-14 14:52:44 -04:00
|
|
|
#define LuaDefineAlias(name1, name2) \
|
|
|
|
|
LuaFunctionReg reg_##name1(#name1, lfnarg_##name2, lfndoc_##name2, false, lfn_##name2); \
|
2020-12-05 18:57:53 -05:00
|
|
|
|
2021-12-16 13:06:15 -05:00
|
|
|
#define LuaDefineBuiltin(name, args, docs) \
|
2022-03-16 17:05:20 -04:00
|
|
|
LuaFunctionReg reg_##name(#name, args, docs, false, nullptr);
|
2021-12-16 13:06:15 -05:00
|
|
|
|
2022-03-16 17:05:20 -04:00
|
|
|
#define LuaSandboxBuiltin(name, args, docs) \
|
|
|
|
|
LuaFunctionReg reg_##name(#name, args, docs, true, nullptr);
|
2021-12-16 13:06:15 -05:00
|
|
|
|
2021-01-12 15:49:05 -05:00
|
|
|
#define LuaStringify(x) #x
|
|
|
|
|
#define LuaAssert(L, x) if (!(x)) { luaL_error((L), "Assert failed: %s (file %s line %d)", LuaStringify(x), __FILE__, __LINE__); }
|
2022-02-24 02:17:41 -05:00
|
|
|
#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__); }
|
2022-06-06 23:03:26 -04:00
|
|
|
|
2023-04-07 14:20:45 -04:00
|
|
|
#endif // LUASTACK_HPP
|