mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-21 22:24:07 +01:00
Convert lua::peek to return a PeekResult
This commit is contained in:
parent
9155242f76
commit
413dc34c47
2 changed files with 99 additions and 54 deletions
|
@ -156,31 +156,35 @@ StackIdx push(lua_State *L, const api::CompletionEvent &ev)
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek(lua_State *L, int *out, StackIdx idx)
|
PeekResult peek(lua_State *L, int *out, StackIdx idx)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
if (lua_isnumber(L, idx) == 0)
|
if (lua_isnumber(L, idx) == 0)
|
||||||
{
|
{
|
||||||
return false;
|
return {
|
||||||
|
false,
|
||||||
|
{QString("Expected an integer got %1").arg(luaL_typename(L, idx))}};
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = lua_tointeger(L, idx);
|
*out = lua_tointeger(L, idx);
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek(lua_State *L, bool *out, StackIdx idx)
|
PeekResult peek(lua_State *L, bool *out, StackIdx idx)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
if (!lua_isboolean(L, idx))
|
if (!lua_isboolean(L, idx))
|
||||||
{
|
{
|
||||||
return false;
|
return {
|
||||||
|
false,
|
||||||
|
{QString("Expected a boolean got %1").arg(luaL_typename(L, idx))}};
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = bool(lua_toboolean(L, idx));
|
*out = bool(lua_toboolean(L, idx));
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek(lua_State *L, double *out, StackIdx idx)
|
PeekResult peek(lua_State *L, double *out, StackIdx idx)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
int ok{0};
|
int ok{0};
|
||||||
|
@ -188,76 +192,91 @@ bool peek(lua_State *L, double *out, StackIdx idx)
|
||||||
if (ok != 0)
|
if (ok != 0)
|
||||||
{
|
{
|
||||||
*out = v;
|
*out = v;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
return ok != 0;
|
|
||||||
|
return PeekResult::ofTypeError(L, idx, "integer or float");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek(lua_State *L, QString *out, StackIdx idx)
|
PeekResult peek(lua_State *L, QString *out, StackIdx idx)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
size_t len{0};
|
size_t len{0};
|
||||||
const char *str = lua_tolstring(L, idx, &len);
|
const char *str = lua_tolstring(L, idx, &len);
|
||||||
if (str == nullptr)
|
if (str == nullptr)
|
||||||
{
|
{
|
||||||
return false;
|
return PeekResult::ofTypeError(L, idx, "string");
|
||||||
}
|
}
|
||||||
if (len >= INT_MAX)
|
if (len >= INT_MAX)
|
||||||
{
|
{
|
||||||
assert(false && "string longer than INT_MAX, shit's fucked, yo");
|
return {false,
|
||||||
|
{QString("Strings bigger than 2.1 gigabytes are not allowed")}};
|
||||||
}
|
}
|
||||||
*out = QString::fromUtf8(str, int(len));
|
*out = QString::fromUtf8(str, int(len));
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek(lua_State *L, QByteArray *out, StackIdx idx)
|
PeekResult peek(lua_State *L, QByteArray *out, StackIdx idx)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
size_t len{0};
|
size_t len{0};
|
||||||
const char *str = lua_tolstring(L, idx, &len);
|
const char *str = lua_tolstring(L, idx, &len);
|
||||||
if (str == nullptr)
|
if (str == nullptr)
|
||||||
{
|
{
|
||||||
return false;
|
return PeekResult::ofTypeError(L, idx, "string");
|
||||||
}
|
}
|
||||||
if (len >= INT_MAX)
|
if (len >= INT_MAX)
|
||||||
{
|
{
|
||||||
assert(false && "string longer than INT_MAX, shit's fucked, yo");
|
return {false,
|
||||||
|
{QString("Strings bigger than 2.1 gigabytes are not allowed")}};
|
||||||
}
|
}
|
||||||
*out = QByteArray(str, int(len));
|
*out = QByteArray(str, int(len));
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek(lua_State *L, std::string *out, StackIdx idx)
|
PeekResult peek(lua_State *L, std::string *out, StackIdx idx)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
size_t len{0};
|
size_t len{0};
|
||||||
const char *str = lua_tolstring(L, idx, &len);
|
const char *str = lua_tolstring(L, idx, &len);
|
||||||
if (str == nullptr)
|
if (str == nullptr)
|
||||||
{
|
{
|
||||||
return false;
|
return PeekResult::ofTypeError(L, idx, "string");
|
||||||
}
|
}
|
||||||
if (len >= INT_MAX)
|
if (len >= INT_MAX)
|
||||||
{
|
{
|
||||||
assert(false && "string longer than INT_MAX, shit's fucked, yo");
|
return {false,
|
||||||
|
{QString("Strings bigger than 2.1 gigabytes are not allowed")}};
|
||||||
}
|
}
|
||||||
*out = std::string(str, len);
|
*out = std::string(str, len);
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool peek(lua_State *L, api::CompletionList *out, StackIdx idx)
|
PeekResult peek(lua_State *L, api::CompletionList *out, StackIdx idx)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
int typ = lua_getfield(L, idx, "values");
|
int typ = lua_getfield(L, idx, "values");
|
||||||
if (typ != LUA_TTABLE)
|
if (typ != LUA_TTABLE)
|
||||||
{
|
{
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return false;
|
auto res = PeekResult::ofTypeError(L, idx, "string");
|
||||||
|
res.errorReason.emplace_back("While processing CompletionList.values");
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
if (!lua::pop(L, &out->values, -1))
|
auto pres = lua::pop(L, &out->values, -1);
|
||||||
|
if (!pres)
|
||||||
{
|
{
|
||||||
return false;
|
pres.errorReason.emplace_back("While processing CompletionList.values");
|
||||||
|
return pres;
|
||||||
}
|
}
|
||||||
lua_getfield(L, idx, "hide_others");
|
lua_getfield(L, idx, "hide_others");
|
||||||
return lua::pop(L, &out->hideOthers);
|
pres = lua::pop(L, &out->hideOthers);
|
||||||
|
if (!pres)
|
||||||
|
{
|
||||||
|
pres.errorReason.emplace_back(
|
||||||
|
"While processing CompletionList.hide_others");
|
||||||
|
}
|
||||||
|
return pres;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString toString(lua_State *L, StackIdx idx)
|
QString toString(lua_State *L, StackIdx idx)
|
||||||
|
@ -290,5 +309,13 @@ void PeekResult::throwAsLuaError(lua_State *L)
|
||||||
assert(false && "unreachable");
|
assert(false && "unreachable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PeekResult PeekResult::ofTypeError(lua_State *L, StackIdx idx,
|
||||||
|
const QString &expect)
|
||||||
|
{
|
||||||
|
return PeekResult{
|
||||||
|
.ok = false,
|
||||||
|
.errorReason = {
|
||||||
|
QString("Expected %1, got %2").arg(expect, luaL_typename(L, idx))}};
|
||||||
|
}
|
||||||
} // namespace chatterino::lua
|
} // namespace chatterino::lua
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||||
|
|
||||||
# include "common/QLogging.hpp"
|
# include "common/QLogging.hpp"
|
||||||
|
|
||||||
|
# include <boost/type_index.hpp>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
# include <lua.h>
|
# include <lua.h>
|
||||||
# include <lualib.h>
|
# include <lualib.h>
|
||||||
|
@ -19,7 +20,6 @@ extern "C" {
|
||||||
# include <variant>
|
# include <variant>
|
||||||
# include <vector>
|
# include <vector>
|
||||||
struct lua_State;
|
struct lua_State;
|
||||||
class QJsonObject;
|
|
||||||
namespace chatterino {
|
namespace chatterino {
|
||||||
struct CommandContext;
|
struct CommandContext;
|
||||||
} // namespace chatterino
|
} // namespace chatterino
|
||||||
|
@ -83,16 +83,19 @@ struct PeekResult {
|
||||||
* As luaL_error never returns this function does not either.
|
* As luaL_error never returns this function does not either.
|
||||||
*/
|
*/
|
||||||
[[noreturn]] void throwAsLuaError(lua_State *L);
|
[[noreturn]] void throwAsLuaError(lua_State *L);
|
||||||
|
|
||||||
|
static PeekResult ofTypeError(lua_State *L, StackIdx idx,
|
||||||
|
const QString &expect);
|
||||||
};
|
};
|
||||||
|
|
||||||
// returns OK?
|
// returns OK?
|
||||||
bool peek(lua_State *L, int *out, StackIdx idx = -1);
|
PeekResult peek(lua_State *L, int *out, StackIdx idx = -1);
|
||||||
bool peek(lua_State *L, bool *out, StackIdx idx = -1);
|
PeekResult peek(lua_State *L, bool *out, StackIdx idx = -1);
|
||||||
bool peek(lua_State *L, double *out, StackIdx idx = -1);
|
PeekResult peek(lua_State *L, double *out, StackIdx idx = -1);
|
||||||
bool peek(lua_State *L, QString *out, StackIdx idx = -1);
|
PeekResult peek(lua_State *L, QString *out, StackIdx idx = -1);
|
||||||
bool peek(lua_State *L, QByteArray *out, StackIdx idx = -1);
|
PeekResult peek(lua_State *L, QByteArray *out, StackIdx idx = -1);
|
||||||
bool peek(lua_State *L, std::string *out, StackIdx idx = -1);
|
PeekResult peek(lua_State *L, std::string *out, StackIdx idx = -1);
|
||||||
bool peek(lua_State *L, api::CompletionList *out, StackIdx idx = -1);
|
PeekResult peek(lua_State *L, api::CompletionList *out, StackIdx idx = -1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts Lua object at stack index idx to a string.
|
* @brief Converts Lua object at stack index idx to a string.
|
||||||
|
@ -170,12 +173,12 @@ StackIdx push(lua_State *L, std::optional<T> val)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool peek(lua_State *L, std::optional<T> *out, StackIdx idx = -1)
|
PeekResult peek(lua_State *L, std::optional<T> *out, StackIdx idx = -1)
|
||||||
{
|
{
|
||||||
if (lua_isnil(L, idx))
|
if (lua_isnil(L, idx))
|
||||||
{
|
{
|
||||||
*out = std::nullopt;
|
*out = std::nullopt;
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = T();
|
*out = T();
|
||||||
|
@ -183,7 +186,7 @@ bool peek(lua_State *L, std::optional<T> *out, StackIdx idx = -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool peek(lua_State *L, std::vector<T> *vec, StackIdx idx = -1)
|
PeekResult peek(lua_State *L, std::vector<T> *vec, StackIdx idx = -1)
|
||||||
{
|
{
|
||||||
StackGuard guard(L);
|
StackGuard guard(L);
|
||||||
|
|
||||||
|
@ -192,37 +195,44 @@ bool peek(lua_State *L, std::vector<T> *vec, StackIdx idx = -1)
|
||||||
lua::stackDump(L, "!table");
|
lua::stackDump(L, "!table");
|
||||||
qCDebug(chatterinoLua)
|
qCDebug(chatterinoLua)
|
||||||
<< "value is not a table, type is" << lua_type(L, idx);
|
<< "value is not a table, type is" << lua_type(L, idx);
|
||||||
return false;
|
return {false,
|
||||||
|
{QString("Expected value to be a table, its actual type is %1")
|
||||||
|
.arg(lua_typename(L, lua_type(L, idx)))}};
|
||||||
}
|
}
|
||||||
auto len = lua_rawlen(L, idx);
|
auto len = lua_rawlen(L, idx);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
{
|
{
|
||||||
qCDebug(chatterinoLua) << "value has 0 length";
|
qCDebug(chatterinoLua) << "value has 0 length";
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
if (len > 1'000'000)
|
if (len > 1'000'000)
|
||||||
{
|
{
|
||||||
qCDebug(chatterinoLua) << "value is too long";
|
qCDebug(chatterinoLua) << "value is too long";
|
||||||
return false;
|
return {
|
||||||
|
false,
|
||||||
|
{QString("Table is too long, %1 > 1_000_000 elements").arg(len)}};
|
||||||
}
|
}
|
||||||
// count like lua
|
// count like lua
|
||||||
for (int i = 1; i <= len; i++)
|
for (int i = 1; i <= len; i++)
|
||||||
{
|
{
|
||||||
lua_geti(L, idx, i);
|
lua_geti(L, idx, i);
|
||||||
std::optional<T> obj;
|
std::optional<T> obj;
|
||||||
if (!lua::peek(L, &obj))
|
PeekResult pres = lua::peek(L, &obj);
|
||||||
|
if (!pres)
|
||||||
{
|
{
|
||||||
//lua_seti(L, LUA_REGISTRYINDEX, 1); // lazy
|
|
||||||
qCDebug(chatterinoLua)
|
qCDebug(chatterinoLua)
|
||||||
<< "Failed to convert lua object into c++: at array index " << i
|
<< "Failed to convert lua object into c++: at array index " << i
|
||||||
<< ":";
|
<< ":";
|
||||||
stackDump(L, "bad conversion into string");
|
stackDump(L, "bad conversion");
|
||||||
return false;
|
pres.errorReason.push_back(
|
||||||
|
QString("At element %1 of a table").arg(i));
|
||||||
|
|
||||||
|
return pres;
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
vec->push_back(obj.value());
|
vec->push_back(obj.value());
|
||||||
}
|
}
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,21 +240,29 @@ bool peek(lua_State *L, std::vector<T> *vec, StackIdx idx = -1)
|
||||||
*/
|
*/
|
||||||
template <typename T,
|
template <typename T,
|
||||||
typename std::enable_if<std::is_enum_v<T>, bool>::type = true>
|
typename std::enable_if<std::is_enum_v<T>, bool>::type = true>
|
||||||
bool peek(lua_State *L, T *out, StackIdx idx = -1)
|
PeekResult peek(lua_State *L, T *out, StackIdx idx = -1)
|
||||||
{
|
{
|
||||||
std::string tmp;
|
std::string tmp;
|
||||||
if (!lua::peek(L, &tmp, idx))
|
auto pres = lua::peek(L, &tmp, idx);
|
||||||
|
if (!pres)
|
||||||
{
|
{
|
||||||
return false;
|
std::string type = boost::typeindex::type_id<T>().pretty_name();
|
||||||
|
pres.errorReason.push_back(QString("While converting to enum %1")
|
||||||
|
.arg(QString::fromStdString(type)));
|
||||||
|
return pres;
|
||||||
}
|
}
|
||||||
std::optional<T> opt = magic_enum::enum_cast<T>(tmp);
|
std::optional<T> opt = magic_enum::enum_cast<T>(tmp);
|
||||||
if (opt.has_value())
|
if (opt.has_value())
|
||||||
{
|
{
|
||||||
*out = opt.value();
|
*out = opt.value();
|
||||||
return true;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
std::string type = boost::typeindex::type_id<T>().pretty_name();
|
||||||
|
return {.ok = false,
|
||||||
|
.errorReason = {QString("Invalid enum value \"%1\" for enum %2")
|
||||||
|
.arg(QString::fromStdString(tmp),
|
||||||
|
QString::fromStdString(type))}};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -305,19 +323,19 @@ StackIdx push(lua_State *L, T inp)
|
||||||
* @brief Converts a Lua object into c++ and removes it from the stack.
|
* @brief Converts a Lua object into c++ and removes it from the stack.
|
||||||
* If peek fails, the object is still removed from the stack.
|
* If peek fails, the object is still removed from the stack.
|
||||||
*
|
*
|
||||||
* Relies on bool peek(lua_State*, T*, StackIdx) existing.
|
* Relies on PeekResult peek(lua_State*, T*, StackIdx) existing.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool pop(lua_State *L, T *out, StackIdx idx = -1)
|
PeekResult pop(lua_State *L, T *out, StackIdx idx = -1)
|
||||||
{
|
{
|
||||||
StackGuard guard(L, -1);
|
StackGuard guard(L, -1);
|
||||||
auto ok = peek(L, out, idx);
|
auto res = peek(L, out, idx);
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
{
|
{
|
||||||
idx = lua_gettop(L) + idx + 1;
|
idx = lua_gettop(L) + idx + 1;
|
||||||
}
|
}
|
||||||
lua_remove(L, idx);
|
lua_remove(L, idx);
|
||||||
return ok;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue