Age | Commit message (Collapse) | Author |
|
We weren't passing the WaitForReqid instance to WaitForReqid:wait().
Also remove 'reqid' from responses returned by leap.request() and generate().
|
|
request() test ensures that the response for a given reqid is routed to the
correct coroutine even when responses arrive out of order.
|
|
|
|
|
|
|
|
coro.resume() checks the ok boolean returned by coroutine.resume() and, if not
ok, propagates the error. This avoids coroutine errors getting swallowed.
|
|
|
|
|
|
|
|
Add usage comments at the top.
Add leap.done() function.
Make leap.process() honor leap.done(), also recognize an incoming nil from the
viewer to mean it's all done.
Support leap.WaitFor with nil priority to mean "don't self-enable." This
obviates leap.WaitForReqid:enable() and disable() overrides that do nothing.
Add diagnostic logging.
|
|
That is, skip coroutines that have gone dead since they decided to wait on
Dequeue().
|
|
|
|
|
|
Sketch in an initial test that requires one of our bundled Lua modules.
Each time we run Lua, report any error returned by the Lua engine.
Use llcoro::suspendUntilEventOn(LLEventMailDrop) as shorthand for initializing
an explicit LLTempBoundListener with a listen() call with a lambda.
|
|
|
|
|
|
For WaitQueue, nail down the mechanism for declaring a subclass and for
calling a base-class method from a subclass override. Break out new
_wake_waiters() method from Enqueue(): we need to do the same from close(), in
case there are waiting consumers. Also, in Lua, 0 is not false.
Instead of bundling a normal/error flag with every queued value, make
ErrorQueue overload its _closed attribute. Once you call ErrorQueue:Error(),
every subsequent Dequeue() call by any consumer will re-raise the same error.
util.count() literally counts entries in a table, since #t is documented to be
unreliable. (If you create a list with 5 entries and delete the middle one, #t
might return 2 or it might return 5, but it won't return 4.)
util.join() fixes a curious omission from Luau's string library: like Python's
str.join(), it concatenates all the strings from a list with an optional
separator. We assume that incrementally building a list of strings and then
doing a single allocation for the desired result string is cheaper than
reallocating each of a sequence of partial concatenated results.
Add qtest test that posts individual items to a WaitQueue, waking waiting
consumers to retrieve the next available result. Add test proving that calling
ErrorQueue:Error() propagates the error to all consumers.
|
|
Also qtest.lua to exercise the queue classes and inspect.lua (from
https://github.com/kikito/inspect.lua) for debugging.
|
|
following promotion of secondlife/viewer #673
|
|
|
|
|
|
|
|
The code to save the loaded module was using the wrong key.
|
|
|
|
Push throwing Lua errors down into LLRequireResolver::findModule() and
findModuleImpl() so their callers don't have to handle the error case. That
eliminates finishrequire().
require() itself now only retrieves (and pops) the passed module name and
calls LLRequireResolver::resolveRequire() to do the actual work.
resolveRequire() is now void. It only instantiates LLRequireResolver and calls
its findModule().
findModule() is now also void. It's guaranteed to either push the loaded Lua
module or throw a Lua error. In particular, when findPathImpl() cannot find
the specified module, findModule() throws an error. That replaces
ModuleStatus::NotFound.
Since std::filesystem::path::append() aka operator/() detects when its right
operand is absolute and, in that case, discards the left operand, we no longer
need resolveAndStoreDefaultPaths(): we can just invoke that operation inline.
When findModule() pushes _MODULES on the Lua stack, it uses LuaRemover (below)
to ensure that _MODULES is removed again no matter how findModules() exits.
findModuleImpl() now accepts the candidate pathname as its argument. That
eliminates mAbsolutePath.
findModuleImpl() now returns only bool: true means the module was found and
loaded and pushed on the Lua stack, false means not found and nothing was
pushed; no return means an error was reported.
Push running a newly found module's source file down into findModuleImpl().
That eliminates the distinction between Cached and FileRead, which obviates
ModuleStatus: a bool return means either "previously cached" or "we read it,
compiled it, loaded it and ran it." That also eliminates the need to store the
module's textual content in mSourceCode.
Similarly, once loading the module succeeds, findModuleImpl() caches it in
_MODULES right away. That eliminates ResolvedRequire since we need not pass
the full pathname of the found module (or its contents) back up through the
call chain.
Move require() code that runs the new module into private runModule() method,
called by findModuleImpl() in the not-cached case. runModule() is the only
remaining method that can push either a string error message or the desired
module, because of its funny stack manipulations. That means the check for a
string error message on the stack top can move down to findModuleImpl().
Add LuaRemover class to ensure that on exit from some particular C++ block,
the specified Lua stack entry will definitely be removed. This is different
from LuaPopper in that it engages lua_remove() rather than lua_pop().
Also ditch obsolete await_event() Lua entry point.
|
|
|
|
|
|
|
|
|
|
Don't set up a Lua callback to receive incoming events, a la listen_events().
Don't listen on an arbitrary event pump, a la await_event().
Instead, the new get_event_pumps() entry point simply delivers the reply pump
and command pump names (as listen_events() did) without storing a Lua
callback.
Make LuaListener capture incoming events on the reply pump in a queue. This
avoids the problem of multiple events arriving too quickly for the Lua script
to retrieve. If the queue gets too big, discard the excess instead of blocking
the caller of post().
Then the new get_event_next() entry point retrieves the next (pump, data) pair
from the queue, blocking the Lua script until a suitable event arrives. This
is closer to the use of stdin for a LEAP plugin. It also addresses the
question: what should the Lua script's C++ coroutine do while waiting for an
incoming reply pump event?
Recast llluamanager_test.cpp for this new, more straightforward API.
Move LLLeap's and LuaListener's reply LLEventPump into LLLeapListener, which
they both use. This simplifies LLLeapListener's API, which was a little
convoluted: the caller supplied a connect callback to allow LLLeapListener to
connect some listener to the caller's reply pump. Now, instead, the caller
simply passes a bool(pumpname, data) callback to receive events incoming on
LLLeapListener's own reply pump.
Fix a latent bug in LLLeapListener: if a plugin called listen() more than once
with the same listener name, the new connection would not have been saved.
While at it, replace some older Boost features in LLLeapListener and LLLeap.
|
|
|
|
|
|
|
|
leaphelp() (no argument) shows a list of all LEAP APIs.
leaphelp(API) shows further help for a specific API.
Both forms query LuaListener's LeapListener and report its responses. In
future we might reimplement leaphelp() as a Lua function.
Add LuaState::getListener() method, which checks whether there's a LuaListener
associated with this LuaState and returns a pointer if so.
Add LuaState::obtainListener() method, which finds or creates a LuaListener
for this LuaState and returns its pointer.
Both the above use logic migrated from the Lua listen_events() entry point,
which now calls obtainListener() instead.
|
|
|
|
|
|
|
|
|
|
--lua "chunk" runs the specified Lua chunk at startup time.
--luafile pathname runs the specified Lua script file at startup time.
You may specify more than one --lua or --luafile switch on the command line.
|
|
Since the description shows up in the log output, it's better to see just the
script filename than to see "runScriptFile('filename')".
|
|
That means that as you use the floater, variables that you assign and
functions that you define are available to subsequent Lua chunks.
|
|
|
|
The chunk:
return 1, 2, {}
differs in two ways from:
print(1, 2, {})
First, print() engages the Lua tostring() builtin, so it displays values as
Lua sees them. (For a table, tostring() displays "table: hex", which isn't so
wonderful.) But LLFloaterLUADebug serializes the LLSD converted from the Lua
return values.
Second, we've overridden print() to engage a function that writes to the
viewer log as well as displaying to LLFloaterLUADebug. (As we go forward, most
Lua scripts won't be run manually by LLFloaterLUADebug.) The values returned
by a Lua chunk aren't implicitly logged. Each C++ caller wanting to evaluate a
Lua expression can choose whether to log the results.
|
|
|
|
Extend the LuaFunction::Registry map to store helptext as well as the function
pointer.
Add help text to every existing lua_function() invocation.
|
|
|
|
Add a new test<1>() that tests returning values from a Lua chunk using
LLLUAmanager::waitScriptLine(). This exercises lua_tollsd() without yet
involving LLEventPump machinery.
For that purpose, extract from test<2>() the sequence of (description,
expression, LLSD expected) triples into a static C array. The new test<1>()
returns each such expression as a result; test<2>() posts each such expression
to a test LLEventPump.
test<2>() now uses waitScriptLine() instead of pumping the coroutine scheduler
a few times and hoping. The pump-and-hope tactic worked before, but no longer
does. waitScriptLine() is more robust anyway.
Move the former test<1>() to test<3>() because it exercises still more
machinery, specifically listen_events() and await_event(). Because this test
involves a handshake with C++ code, use startScriptLine() to launch the Lua
coroutine while providing a definite way to wait for completion later. Again,
startScriptLine() followed by get() on the returned future is more robust
than the previous pump-and-hope code.
Similarly, the former test<3>(), now renamed test<4>(), uses startScriptLine()
and Future::get() instead of pump-and-hope.
|
|
Break out for LLLUAmanager consumers the promise/future semantics of
waitScriptFile() and waitScriptLine(). startScriptMumble() uses
runScriptMumble() to launch a coroutine to run the specified Lua script or
chunk, providing an internal adapter callback to set a promise on completion.
It then returns to its caller the future obtained from that promise. This
allows a caller to call startScriptMumble(), run in parallel with the Lua
coroutine for a while and then call get() on the returned future to wait for
results.
waitScriptMumble() is then trivially implemented using startScriptMumble().
Fix runScriptLine()'s logic to abbreviate the passed Lua chunk for use as the
description. We were erroneously assigning back through a string_view of the
parameter, which overwrote a temporary string in the argument list.
With Lua 5.4, listen_events() tried to discover the main "thread" (Lua
coroutine) associated with the current lua_State so we could call async
callbacks on that thread. Luau doesn't seem to provide that feature, so run
callbacks on whichever thread calls listen_events().
Reinstate original multi-argument lua_print_msg(), tweaked to avoid the Lua
5.4 lua_rotate() function, which is missing from Luau.
|
|
|
|
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().
|