diff --git a/src/controllers/plugins/LuaAPI.cpp b/src/controllers/plugins/LuaAPI.cpp index d70be6489..274f3fe9f 100644 --- a/src/controllers/plugins/LuaAPI.cpp +++ b/src/controllers/plugins/LuaAPI.cpp @@ -15,6 +15,7 @@ extern "C" { # include } # include +# include # include # include # include @@ -209,6 +210,28 @@ int c2_later(lua_State *L) return 0; } +int c2_json_load(lua_State *L) +{ + lua::StackGuard guard(L, 0); // 1 in, 1 out + + std::string str; + if (!lua::pop(L, &str)) + { + return luaL_error( + L, "Cannot get json_data (only argument of c2.json_load, " + "expected a string)"); + } + QJsonParseError err{}; + auto doc = QJsonDocument::fromJson(QByteArray::fromStdString(str), &err); + if (err.error != QJsonParseError::NoError) + { + return luaL_error(L, "Failed to parse JSON data: %s", + err.errorString().toStdString().c_str()); + } + lua::push(L, doc); + return 1; +} + int g_load(lua_State *L) { # ifdef NDEBUG diff --git a/src/controllers/plugins/LuaAPI.hpp b/src/controllers/plugins/LuaAPI.hpp index fd2c12e41..65de2e6e6 100644 --- a/src/controllers/plugins/LuaAPI.hpp +++ b/src/controllers/plugins/LuaAPI.hpp @@ -121,6 +121,18 @@ int c2_log(lua_State *L); */ int c2_later(lua_State *L); +/** + * @lua@alias AnyJSON integer|boolean|string|number|table + */ + +/** + * Loads json data from a string into Lua tables. + * + * @lua@param json_data string Data you want to load + * @lua@return AnyJSON Deserialized data. + */ +int c2_json_load(lua_State *L); + // These ones are global int g_load(lua_State *L); int g_print(lua_State *L); diff --git a/src/controllers/plugins/LuaUtilities.cpp b/src/controllers/plugins/LuaUtilities.cpp index 64af18c01..b3d0254ce 100644 --- a/src/controllers/plugins/LuaUtilities.cpp +++ b/src/controllers/plugins/LuaUtilities.cpp @@ -7,6 +7,8 @@ # include "controllers/plugins/api/ChannelRef.hpp" # include "controllers/plugins/LuaAPI.hpp" +# include + extern "C" { # include # include @@ -142,6 +144,12 @@ StackIdx push(lua_State *L, const int &b) return lua_gettop(L); } +StackIdx push(lua_State *L, const double &n) +{ + lua_pushnumber(L, n); + return lua_gettop(L); +} + StackIdx push(lua_State *L, const api::CompletionEvent &ev) { auto idx = pushEmptyTable(L, 4); @@ -156,6 +164,76 @@ StackIdx push(lua_State *L, const api::CompletionEvent &ev) return idx; } +StackIdx push(lua_State *L, const QJsonDocument &doc) +{ + if (doc.isNull()) + { + lua_pushnil(L); + return lua_gettop(L); + } + + if (doc.isArray()) + { + return push(L, doc.array()); + } + if (doc.isObject()) + { + return push(L, doc.object()); + } + assert(false && "A QJsonDocument must be null, an array or an object"); + return 0; +} + +StackIdx push(lua_State *L, const QJsonArray &arr) +{ + auto out = pushEmptyArray(L, arr.size()); + int index = 1; + for (const auto &val : arr) + { + lua::push(L, val); + lua_seti(L, out, index); + index += 1; + } + return out; +} + +StackIdx push(lua_State *L, const QJsonObject &obj) +{ + auto out = pushEmptyTable(L, obj.size()); + for (const auto &key : obj.keys()) + { + const auto &value = obj.value(key); + lua::push(L, value); + lua_setfield(L, out, key.toStdString().c_str()); + } + return out; +} +StackIdx push(lua_State *L, const QJsonValue &val) +{ + switch (val.type()) + { + case QJsonValue::Null: + lua_pushnil(L); + return lua_gettop(L); + case QJsonValue::Bool: + return push(L, val.toBool()); + case QJsonValue::String: + return push(L, val.toString()); + case QJsonValue::Array: + return push(L, val.toArray()); + case QJsonValue::Object: + return push(L, val.toObject()); + case QJsonValue::Double: + return push(L, val.toDouble()); + + case QJsonValue::Undefined: + assert(false && "Tried to push undefined/erroneous QJsonValue into " + "Lua, this is not allowed."); + default: + assert(false && "Malformed QJsonValue type. This never happens"); + } +} + bool peek(lua_State *L, int *out, StackIdx idx) { StackGuard guard(L); diff --git a/src/controllers/plugins/LuaUtilities.hpp b/src/controllers/plugins/LuaUtilities.hpp index 5443a751f..c39cb6d89 100644 --- a/src/controllers/plugins/LuaUtilities.hpp +++ b/src/controllers/plugins/LuaUtilities.hpp @@ -9,6 +9,7 @@ extern "C" { # include } # include +# include # include # include @@ -67,7 +68,12 @@ StackIdx push(lua_State *L, const QString &str); StackIdx push(lua_State *L, const std::string &str); StackIdx push(lua_State *L, const bool &b); StackIdx push(lua_State *L, const int &b); +StackIdx push(lua_State *L, const double &n); StackIdx push(lua_State *L, const api::CompletionEvent &ev); +StackIdx push(lua_State *L, const QJsonDocument &doc); +StackIdx push(lua_State *L, const QJsonArray &arr); +StackIdx push(lua_State *L, const QJsonObject &obj); +StackIdx push(lua_State *L, const QJsonValue &val); // returns OK? bool peek(lua_State *L, int *out, StackIdx idx = -1); diff --git a/src/controllers/plugins/PluginController.cpp b/src/controllers/plugins/PluginController.cpp index 199e0f4e4..b5525b91a 100644 --- a/src/controllers/plugins/PluginController.cpp +++ b/src/controllers/plugins/PluginController.cpp @@ -152,6 +152,7 @@ void PluginController::openLibrariesFor(lua_State *L, const PluginMeta &meta, {"register_callback", lua::api::c2_register_callback}, {"log", lua::api::c2_log}, {"later", lua::api::c2_later}, + {"json_load", lua::api::c2_json_load}, {nullptr, nullptr}, }; lua_pushglobaltable(L);