summaryrefslogtreecommitdiff
path: root/indra/newview/llluamanager.cpp
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-02-07 12:50:26 -0500
committerNat Goodspeed <nat@lindenlab.com>2024-02-07 12:50:26 -0500
commit5b0404961e35ecca46148b90f2c27aed1bad607f (patch)
tree2ea3cd1c19e719536a57ff96aecb5e0347eb19c9 /indra/newview/llluamanager.cpp
parentf664c2ea26fb63f162f3d988b6d00f1483be5d45 (diff)
Add machinery to capture result of running a Lua script or snippet.
Add LuaState::expr() that evaluates a Lua snippet and reports back any result (or error) left on the stack. Add LLLUAmanager::runScriptFile() and runScriptLine() overloads that accept a callback with an (int count, LLSD result) signature. The count disambiguates (error, no result, one result, array of results). Also add overloads that accept an existing LuaState instance. Also add waitScriptFile() and waitScriptLine() methods that pause the calling coroutine until the Lua script completes, and return its results. Instead of giving LuaState a description to use for all subsequent checkLua() calls, remove description from its constructor and data members. Move to expr() and checkLua() parameters: we want a description specific to each operation, rather than for the LuaState as a whole. This prepares for persistent LuaState instances. For now, the existing script_finished_fn semantics remain: the callback will be called only when the LuaState is destroyed. This may need to change as we migrate towards longer-lasting LuaState instances. Make lua_function(name) macro append suffixes to the name for both the LuaFunction subclass declaration and the instance declaration. This allows publishing a lua_function() name such as sleep(), which already has a different C++ declaration. Move the Lua sleep() entry point to a standalone lua_function(sleep), instead of a lambda in the body of runScriptFile().
Diffstat (limited to 'indra/newview/llluamanager.cpp')
-rw-r--r--indra/newview/llluamanager.cpp93
1 files changed, 76 insertions, 17 deletions
diff --git a/indra/newview/llluamanager.cpp b/indra/newview/llluamanager.cpp
index 596d8cab56..44c7a6ba3b 100644
--- a/indra/newview/llluamanager.cpp
+++ b/indra/newview/llluamanager.cpp
@@ -28,6 +28,7 @@
#include "llviewerprecompiledheaders.h"
#include "llluamanager.h"
+#include "llcoros.h"
#include "llerror.h"
#include "lleventcoro.h"
#include "lua_function.h"
@@ -55,6 +56,14 @@ extern LLUIListener sUIListener;
#include <string_view>
#include <vector>
+lua_function(sleep)
+{
+ F32 seconds = lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ llcoro::suspendUntilTimeout(seconds);
+ return 0;
+};
+
/*
// This function consumes ALL Lua stack arguments and returns concatenated
// message string
@@ -262,21 +271,34 @@ lua_function(await_event)
void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn cb)
{
- std::string desc{ stringize("runScriptFile('", filename, "')") };
- LLCoros::instance().launch(desc, [desc, filename, cb]()
- {
- LuaState L(desc, cb);
+ // A script_finished_fn is used to initialize the LuaState.
+ // It will be called when the LuaState is destroyed.
+ LuaState L(cb);
+ runScriptFile(L, filename);
+}
- auto LUA_sleep_func = [](lua_State *L)
- {
- F32 seconds = lua_tonumber(L, -1);
- lua_pop(L, 1);
- llcoro::suspendUntilTimeout(seconds);
- return 0;
- };
+void LLLUAmanager::runScriptFile(const std::string& filename, script_result_fn cb)
+{
+ LuaState L;
+ // A script_result_fn will be called when LuaState::expr() completes.
+ runScriptFile(L, filename, cb);
+}
- lua_register(L, "sleep", LUA_sleep_func);
+std::pair<int, LLSD> LLLUAmanager::waitScriptFile(LuaState& L, const std::string& filename)
+{
+ LLCoros::Promise<std::pair<int, LLSD>> promise;
+ auto future{ LLCoros::getFuture(promise) };
+ runScriptFile(L, filename,
+ [&promise](int count, LLSD result)
+ { promise.set_value({ count, result }); });
+ return future.get();
+}
+void LLLUAmanager::runScriptFile(LuaState& L, const std::string& filename, script_result_fn cb)
+{
+ std::string desc{ stringize("runScriptFile('", filename, "')") };
+ LLCoros::instance().launch(desc, [&L, desc, filename, cb]()
+ {
llifstream in_file;
in_file.open(filename.c_str());
@@ -284,17 +306,51 @@ void LLLUAmanager::runScriptFile(const std::string& filename, script_finished_fn
{
std::string text{std::istreambuf_iterator<char>(in_file),
std::istreambuf_iterator<char>()};
- L.checkLua(lluau::dostring(L, desc, text));
+ auto [count, result] = L.expr(desc, text);
+ if (cb)
+ {
+ cb(count, result);
+ }
}
else
{
- LL_WARNS("Lua") << "unable to open script file '" << filename << "'" << LL_ENDL;
+ auto msg{ stringize("unable to open script file '", filename, "'") };
+ LL_WARNS("Lua") << msg << LL_ENDL;
+ if (cb)
+ {
+ cb(-1, msg);
+ }
}
});
}
void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb)
{
+ // A script_finished_fn is used to initialize the LuaState.
+ // It will be called when the LuaState is destroyed.
+ LuaState L(cb);
+ runScriptLine(L, cmd);
+}
+
+void LLLUAmanager::runScriptLine(const std::string& cmd, script_result_fn cb)
+{
+ LuaState L;
+ // A script_result_fn will be called when LuaState::expr() completes.
+ runScriptLine(L, cmd, cb);
+}
+
+std::pair<int, LLSD> LLLUAmanager::waitScriptLine(LuaState& L, const std::string& cmd)
+{
+ LLCoros::Promise<std::pair<int, LLSD>> promise;
+ auto future{ LLCoros::getFuture(promise) };
+ runScriptLine(L, cmd,
+ [&promise](int count, LLSD result)
+ { promise.set_value({ count, result }); });
+ return future.get();
+}
+
+void LLLUAmanager::runScriptLine(LuaState& L, const std::string& cmd, script_result_fn cb)
+{
// find a suitable abbreviation for the cmd string
std::string_view shortcmd{ cmd };
const size_t shortlen = 40;
@@ -305,10 +361,13 @@ void LLLUAmanager::runScriptLine(const std::string& cmd, script_finished_fn cb)
shortcmd = stringize(shortcmd.substr(0, shortlen), "...");
std::string desc{ stringize("runScriptLine('", shortcmd, "')") };
- LLCoros::instance().launch(desc, [desc, cmd, cb]()
+ LLCoros::instance().launch(desc, [&L, desc, cmd, cb]()
{
- LuaState L(desc, cb);
- L.checkLua(lluau::dostring(L, desc, cmd));
+ auto [count, result] = L.expr(desc, cmd);
+ if (cb)
+ {
+ cb(count, result);
+ }
});
}