llGetSubString and llList2List could produce output longer than the input for some params. Fix that, and join the functions into one unique function for uniformity. Also, get rid of the special case of empty elements, because it can be treated properly by the general case, and it's not so common as to merit special attention.
When the input was of the form e.g. "%4%40", the second "%" was erroneously starting another quoted character. LSL doesn't behave that way: parsing resumes without starting another quoted character. Disturbingly, the expected result in the corresponding test was wrong. Fixed both the test case and the code to match actual LSL behaviour.
llBase64ToString hid another surprise: characters in range from U+0000 to U+001F are substituted by "?" except for tabs (\x09), form feeds (\x0A), shift ins (\x0F) and unit separators (\x1F), which were kept verbatim. So, mimic this behaviour.
There was a duplicate(ish) test, which tested float("nan") instead of NaN or Indet. On Windows it was not duplicate, because under Windows, float("nan") produces Indet, which was not tested. Change it to Indet so we know what we're testing.
When a function was successfully applied, the resulting constant node was not marked as side effect-free. This could potentially lead to poor optimization.
Testing shows that AGENT_LIST_xxx values are not used as a bitfield, but as an enum. There are only three possible valid values. Check only those three.
It doesn't make sense to check the output multiple times. It would if lslcommon.IsCalc were set to True, because then it wouldn't be distinguishable from a randomly obtained value. But in non-calc mode, it would raise ELSLCantCompute if it were unpredictable, so it's OK to check just once because if it doesn't raise, it's predictable and can be checked.
Lists can't contain lists at runtime, but they can at parse time, so the optimizer must behave properly when handling nested lists. And it didn't, because it neglected to preserve the previous state of self.listmode. So we fix that.
By default, catch exceptions and report them without a stack trace. When this option is specified, raise an actual Python exception (should show a strack trace).
Note: diff for this patch is best seen with -b (ignore-whitespace-change).
The function's SEF status was not taken into account when substituting functions with their values. This affected llModPow and llXorBase64Strings, both of which have a delay, and were erroneously substituted.
But allow them to be substituted when in calculator mode.
Option --scriptname did nothing, because the program expected --shortname instead. --scriptname is far more confusing, given that it's intended as the value that lands in the __SHORTFILE__ macro, so it has been renamed.
Improve the help text regarding that option; also fix the wording for what -O help does and add an example of how to use -O.
The test for two empty lists passed to llListFindList was duplicated. That case generates -1 under LSO, and that wasn't tested, so we add that as a test now. Check also that another corner case behaves properly under LSO.
When 'if', 'for', and 'while' statements have a label as the sub-statement, e.g. `while (FALSE) @label;`, the label was improperly removed in some cases, causing a potential compilation failure.
Why someone would want to do that, one never knows, but just to be sure, it has been fixed.
When a global list includes a reference to a global variable of type key, the corresponding list entry type is string, not key (SCR-295, possibly caused by SVC-1710 or SVC-4485).
This implementation is fishy, because it hard-codes the type in the node regardless of the child types. But in some quick experimenting, it seemed to work. And since the main purpose is to document LSO's behaviour, rather than actually being usable, it's OK like that.
The rationale for using -1 was that it had all bits set, but that's a pretty weak argument, really. Lack of optimization of the sign could be worse, so we change it to 1, which is the value of the constant TRUE.
Also change the wording of a comment, for clarity.