All three functions have in SL the Intel problem of inaccuracy with high values. Since we work in single precision, it's barely detectable usually, but for large input numbers the difference between the imprecise results of SL and the more accurate results of recent glibc become more obvious.
This change brings back the Intel inaccuracy, even across systems (different versions of Python/C might behave differently otherwise).
Reference:
https://randomascii.wordpress.com/2014/10/09/intel-underestimates-error-bounds-by-1-3-quintillion/
It was designed so that only ints and floats should be accepted. But for safety, and for reuse, make that "any non-float" so that long integers are also truncated to F32.
One big disappointment is that Python doesn't allow redefining float.__repr__, leading to a much increased difficulty in checking and reporting differences in NaN vs. Indet. We do what we can, though. We re-enable the recursive comparison as opposed to the repr comparison.
As a result, many of the tests reported wrong results. Fixed them. Fix also a problem with comparing infinities (they can't be compared to a tolerance).
This commit also changes the struct.pack check to math.copysing as in the previous commit.
We were using a very dubious method to distinguish an indeterminate from a NaN, via struct.unpack. Turns out that math.copysign gets the job done and seems more robust.
reallyequal: Compare the sign of NaN when checking if the args are NaN.
Tests added:
- llAsin, llAcos with out-of-range argument produces NaN.
- llAtan2 with (0, 0) produces 0.
- Sign of NaN is not distinguished in lists, even if NaN compares equal to NaN.
Besides dividing by zero, any result producing NaN including inf/inf, NaN/anything, anything/NaN causes a math error as well. We only contemplated NaN/anything and neglected the rest, so we generalize it.
Well, within reasonable limits.
For break, it's explained in the code. If the block is empty of actual code (code that generates output), then the break position is eliminated.
For default, if the default label is at the top of the block, the jump and the label are both eliminated. This check doesn't include verifying that there are other non-code-generating statements in between, so there's room for improvement (added corresponding TODO item).
This way, we're on par with FS, in case someone (ab)used the FS brokeness when the 'default' label was absent. All one has to do now is add the default label at the top, and the generated code will be the same as it was in FS when abusing that bug, with no extra burden.
Example: In FS, the code at the top acted as default and there was no jump for it:
default { timer() {
switch(1)
{
0;
case 1:
1;
}
}}
This generated roughly:
default { timer() {
{
if (1 == 1) jump CASE_1;
0;
@CASE_1;
1;
}
}}
In this system, it would trigger an error by default. To obtain the FS behaviour, the scripter can do instead:
default { timer() {
switch(1)
{
default:
0;
case 1:
1;
}
}}
Thanks to this optimization, the code will be the same as in FS. Without it, an extra default label and corresponding jump would be present.
Commit 5804a9a introduced a bug where having the foldtabs option disabled (normal) prevented optimizations of functions. Fix it for good (hopefully). While on it, rename the nofoldtabs option to warntabs, making it default, and use it to disable a warning when there are tabs in a string.
If the last line of the file didn't end in LF, and an error was reported right in that line, two characters would be missing from that line in the output. Fixed.
Changed my mind. This looks saner. Now, if the 'default:' label is missing, an error will be thrown by default. It has to be explicitly disabled if normal C-like behaviour is desired (namely to jump to the 'break' label if no condition is met).
In the absence of a 'default' label within a switch, FS falls through to the first CASE label (or to the code before the first CASE if there's any).
This commit adds an option, active by default for FS compatibility, that mimics this broken behaviour, as well as a warning in case the 'default' label is absent, which also triggers another warning when the option is active.
For example, this script reported the type mismatch in default:
key k=0;
default{timer(){}}
Now it's reported at the semicolon, which is as early as it can be identified and much more meaningful.
When a function folds to a string that contains a tab, e.g. llUnescapeURL("%09"), or to a list that contains a string that contains a tab, a warning is emitted unless the foldtabs option (which forces the optimization) is used. This option allows to quiet the warning without forcing the optimization.
Resolving some constant function calls may generate tabs, e.g. llUnescapeURL("%09"). That can't be pasted into a script, and a warning is emitted. The warning text was misleading, making one think that something went wrong when all that happened is that an optimization couldn't be applied. Rewrite the text of the warning to be clearer about what the problem is.
Identifiers can be equal if they belong to different syntactic scopes. That will allow better reuse and less creation of new identifiers, most notably as function and event parameter names.
The implementation would require a stack of counters where the current value is pushed when entering a new scope, and popped when exiting, rather than using a single counter for the whole program.