Age | Commit message (Collapse) | Author |
|
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.
|
|
Disable copy assignment operator as well as copy constructor.
Use std::uncaught_exceptions() in destructor to report whether there's an
in-flight exception at block exit. Since that was the whole point of the
DEBUGIN / DEBUGEND macros, those become obsolete. Ditch them and their
existing invocations.
|
|
|
|
debug.h #defines a couple of macros intended to enclose the entire body of a
function to track its entry and (possibly exceptional) exit. The trouble is
that these macros used to be called BEGIN and END, which is far too generic --
especially considering that END is used as an enum value in some parts of the
viewer.
Rename them DEBUGIN and DEBUGEND, which is ugly but unlikely to collide with
anything else.
|
|
|
|
|
|
|
|
Remove where it isn't.
|
|
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.
|
|
If post() can't find the requested pump, say so.
|
|
|
|
|
|
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.
|
|
help() with no argument lists all our viewer builtins.
help(function, function, ...) shows help text for each named function. Each
argument can be either a string or the function in question (e.g. help(help)).
To support Lua-related text containing line breaks, make LLTextEditor::
pasteTextWithLinebreaks() a public template method. Change the existing
implementation, which specifically accepts (const LLWString&), into its
LLWString specialization. The generic template passes llconvert(arg) to that
specialization, the one real implementation.
Make LLFloaterLUADebug methods call pasteTextWithLinebreaks() instead of
insertText(), which ignores newline characters.
To allow help() to accept an actual function as well as a string name, add a
lookup-by-function-pointer map to LuaFunction. (A Lua function does not store
a name.) Make the constructor store an entry in the new lookup map as well as
in the original registry map.
Change LuaFunction::getRegistry() and getRegistered() to getState() and
getRState(), respectively. Each returns a std::pair, but the first binds
non-const references while the second binds const references.
|
|
|
|
As a function parameter, an assignment expression or a `return` expression,
`ll_convert()` can infer its target type.
When it's important to specify the TOTYPE explicitly, rename the old
`ll_convert()` function template to `ll_convert_to()`. Fix existing usage.
|
|
|
|
We add a suffix to let us publish a Lua foo() function that wraps a C++ foo()
function. Of course the lua_CFunction must accept lua_State* and extract its
parameters from the Lua stack, so it must invoke different C++ code than the
C++ foo() function it's trying to reach. So the lua_CFunction is a method of
the LuaFunction subclass instance named foo_lua.
The suffix was _luadecl, but since the class name shows up in log messages,
make it the more streamlined _lua instead.
|
|
Extend the LuaFunction::Registry map to store helptext as well as the function
pointer.
Add help text to every existing lua_function() invocation.
|
|
|
|
macOS clang produces fatal warnings when trying to pass a const char*
parameter to luaL_error() (-Wformat-security). Temporarily suppressing that
requires #pragma clang directives which, in turn, produce fatal warnings in
VS.
Moreover, VS recognizes that luaL_error() never returns, and so diagnoses the
following return statement as unreachable code. But that return statement is
the whole reason for lluau::error()'s existence...
|
|
|
|
We were calling lua_pcall() in such a way as to discard any values returned by
the Lua chunk.
Work around Luau's broken lua_tointegerx(), which unlike vanilla Lua's does
not report whether the value at the specified index is or is not an integer.
|
|
|
|
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().
|
|
The intention is to decentralize Luau entry points into our C++ code,
permitting a given entry point to be added to the .cpp file that already deals
with that class or functional area. Continuing to add every such entry point
to llluamanager.cpp doesn't scale well.
Extract LuaListener class from llluamanager.cpp to its own header and .cpp
file.
Extract from llluamanager into lua_function.h (and .cpp) declarations useful
for adding a lua_function Luau entry point, e.g.:
lua_register()
lua_rawlen()
lua_tostdstring()
lua_pushstdstring()
lua_tollsd()
lua_pushllsd()
LuaPopper
lua_function() and LuaFunction class
LuaState
lua_what
lua_stack
DebugExit
|
|
LLDispatchListener::getPumpName() went away when LLEventStream became one of
its base classes. The assumption was that LLEventStream::getName() would
suffice. Re-add getPumpName(), forwarding to getName(), for backwards
compatibility.
|
|
|
|
# Conflicts:
# indra/llcommon/CMakeLists.txt
# indra/newview/llspatialpartition.cpp
# indra/newview/llviewergenericmessage.cpp
# indra/newview/llvoavatar.cpp
|
|
using for DRTVWR-559
|
|
ensure inventory skeleton loading doesn't block the message system from processing packets.
|
|
Also ditch crufty CMake logic related to lleventhost, which we haven't used
for years.
|
|
If not, the resulting error message is so mysterious that it's worth adding an
error check to explain how to avoid it.
|
|
|
|
|
|
We define a specialization of LLSDParam<const char*> to support passing an
LLSD object to a const char* function parameter. Needless to remark, passing
object.asString().c_str() would be Bad: destroying the temporary std::string
returned by asString() would immediately invalidate the pointer returned by
its c_str(). But when you pass LLSDParam<const char*>(object) as the
parameter, that specialization itself stores the std::string so the c_str()
pointer remains valid as long as the LLSDParam object does.
Then there's LLSDParam<LLSD>, used when we don't have the parameter type
available to select the LLSDParam specialization. LLSDParam<LLSD> defines a
templated conversion operator T() that constructs an LLSDParam<T> to provide
the actual parameter value. So far, so good.
The trouble was with the implementation of LLSDParam<LLSD>: it constructed a
_temporary_ LLSDParam<T>, implicitly called its operator T() and immediately
destroyed it. Destroying LLSDParam<const char*> destroyed its stored string,
thus invalidating the c_str() pointer before the target function was entered.
Instead, make LLSDParam<LLSD>::operator T() capture each LLSDParam<T> it
constructs, extending its lifespan to the lifespan of the LLSDParam<LLSD>
instance. For this, derive each LLSDParam specialization from LLSDParamBase, a
trivial base class that simply establishes the virtual destructor. We can then
capture any specialization as a pointer to LLSDParamBase.
Also restore LazyEventAPI tests on Mac.
|
|
They do work fine on clang... unblocking the rest of the team during diagnosis.
|
|
|
|
|
|
# Conflicts:
# autobuild.xml
# indra/llcommon/tests/llleap_test.cpp
# indra/newview/viewer_manifest.py
|
|
clang has gotten smart enough to recognize an inline attempt to store to
address zero. Fool it by storing to an address passed as a parameter, and pass
nullptr from a different source file.
|
|
The header file documents that no llrand function should ever return a value
equal to the passed extent, so the one test in llrand_test.cpp that checked
less than or equal to the high end of the range was anomalous.
But changing that to an exclusive range means that we no longer need separate
exclusive range and inclusive range functions. Replace
ensure_in_range_using(), ensure_in_exc_range() and ensure_in_inc_range() with
a grand unified (simplified) ensure_in_range() function.
|
|
It's frustrating and unactionable to have a failing test report merely that
the random value was greater than the specified high end. Okay, so what was
the value? If it's supposed to be less than the high end, did it happen to be
equal? Or was it garbage? We can't reproduce the failure by rerunning!
The new ensure_in_exc_range(), ensure_in_inc_range() mechanism is somewhat
complex because exactly one test allows equality with the high end of the
expected range, where the rest mandate that the function return less than the
high end. If that's a bug in the test -- if every llrand function is supposed
to return less than the high end -- then we could simplify the test logic.
|
|
Add from_lua() function to run a small Lua script that constructs a specified
Lua object and posts it back to the test program via a temporary LLEventPump.
Call this with a variety of Lua objects, comparing to the expected LLSD.
Add round_trip() function to run another small Lua script that listens for
incoming LLEventPump events and, for each, posts the received Lua data back to
the test program as LLSD. Call this with a variety of LLSD objects, comparing
to the expected LLSD. Also collect these objects into an LLSD array and send
that for a round trip; also collect into an LLSD map and send that.
Sadly, tests currently drive an access violation when trying to convert a
nested Lua table to LLSD.
Add verbose debug logging to lua_tollsd() to identify the context at which we
hit the access violation.
Add comments describing further exceptions to LLSD-to-Lua round trip identity.
Add lua_what() iostream manipulator to stream whatever we can readily
discover about a value at a specified Lua stack index.
Add lua_stack() to report the contents of the Lua stack. Since the stack is
created anew for every call to a C function, this shouldn't usually be
enormous.
Add hexdump.h with iostream manipulators to dump a byte range as hex digits,
or to produce readable text from a mix of printing and nonprinting ASCII
characters.
|
|
|
|
looks like pool regularly gets corrupted, try using separate pool
|
|
|
|
# Conflicts:
# indra/newview/llinventorymodel.cpp
# indra/newview/llvovolume.cpp
|
|
# Conflicts:
# indra/newview/CMakeLists.txt
# indra/newview/VIEWER_VERSION.txt
# indra/newview/llagent.cpp
# indra/newview/llfloaternewfeaturenotification.cpp
# indra/newview/llinventorybridge.cpp
# indra/newview/llinventorymodel.cpp
# indra/newview/lloutfitgallery.cpp
# indra/newview/llpanelmaininventory.cpp
# indra/newview/llpanelmaininventory.h
# indra/newview/llsidepaneltaskinfo.cpp
# indra/newview/llsidepaneltaskinfo.h
# indra/newview/lltexturectrl.cpp
# indra/newview/lltexturectrl.h
# indra/newview/llviewerinventory.cpp
# indra/newview/llviewerobject.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/llviewertexturelist.h
# indra/newview/skins/default/xui/en/floater_new_feature_notification.xml
# indra/newview/skins/default/xui/en/menu_inventory.xml
|
|
The first test runs a Lua script that calls post_on(), listen_events() and
await_event() to engage in LLEventPump handshakes with the test program.
Make llluamanager.cpp testable by putting LL_TEST conditionals around lots of
viewer-internals headers and the lua_function definitions that engage them.
Since LuaListener::connect() is called by its constructor, make it a static
method that explicitly accepts the lua_State* (instead of finding it as
mState). Add that parameter to its two existing calls.
Add a debug log message when LuaListener is destroyed. This surfaced the need
to pass a no-op deleter when listen_events() constructs a LuaListener::ptr_t.
When compiled for LL_TEST, make LuaListener::mReplyPump an
LLEventLogProxyFor<LLEventStream> instead of a plain LLEventStream.
For debugging purposes, add a type string "LLEventLogProxy" for
LLEventPumps::make(). A make() call with this type will return an
LLEventLogProxyFor<LLEventStream>.
|