We had dormant code to check for boolean-ness of functions, which is now active. But it didn't cover all possible booleans. Now it does.
An idea for the future is to associate ranges to expressions, and attach them to calculable functions. For example, (integer)llFrand(2) could be resolved to a boolean.
This solves a long-standing issue where we needed more data about LSL functions than just whether it's side-effect-free.
There's still some debug code, which is kept for history purposes.
- Separate library loading code into a new module. parser.__init__() no longer loads the library; it accepts (but does not depend on) a library as a parameter.
- Add an optional library argument to parse(). It's no longer mandatory to create a new parser for switching to a different builtins or seftable file.
- Move warning() and types from lslparse to lslcommon.
- Add .copy() to uses of base_keywords, to not rely on it being a frozen set.
- Adjust the test suite.
They were returning TOUCH_INVALID_TEXCOORD for num <= idx <= 15 in detection events which were not touch events. That is incorrect.
Now it correctly returns:
- ZERO_VECTOR when idx < 0 or idx > 15 or the event is known not to be a detection event.
- TOUCH_INVALID_TEXCOORD when idx == 0 and the event is known to be a detection event that is not a touch event.
- Raises ELSLCantCompute otherwise.
We oversought that the optimization that 8d33746 applied was already present, so no need to duplicate it.
A better place for handling '|' was under the code that already did so. No functionality change involved.
CleanNode was too greedy, because children of global declarations (particularly lists) are not marked executable. Make a special case for them and don't recurse, since what matters is whether the declaration itself is executed. Its contents can't be cleaned up.
In Python, NaN*Indet in any order returns the second operand, and NaN/Indet in any order returns the first operand. LSL consistently returns NaN in all cases.
The force type functions ff(), fi(), fs()... should normally trigger ELSLTypeMismatch when the input is not in the expected range of types, rather than ELSLInvalidType, which is reserved for the case where the type is not a valid LSL type.
It can't be done always: flag1 and flag2 must be nonzero powers of two. In that case, we can transform it to:
!~(x|~(flag1|flag2)) = !~(x|constant)
The -2147483648 case has trouble with the sign hack detector and I couldn't trigger it.
Rather than assert that the types are correct, use the force type functions on the parameters:
ff, fk, fs, q2f, v2f, and the new fi, fl.
These functions have also been modified to ensure that the input type supports an implicit typecast to the target type and perform it, or emit ELSLInvalidType otherwise, rather than an assertion failure. fl in particular returns the original list if it isn't changed, or a copy if it is.
A couple bugs were found in testfuncs.py as a result, which have been fixed as well. A test has been added to ensure that the exception that caught these bugs remains in place.
The isxxxx functions are no longer necessary, so they are removed. Same goes for the painful cast handling process in foldconst, which was basically performing this task, and not necessarily well.
This approach is much more robust and should have been used since the beginning, but I didn't figure it out then.
Also simplify and fix the matching expression for #line (gcc inserts numeric flags at the end).
It still has many problems. It's O(n^2). It's calculated at every EParse, and EParse can be triggered and ignored while scanning vectors or globals. UniConvScript doesn't read #line at all, thus failing to report a meaningful input line. But at least it's a start.
ReportError() needed to account for terminal encodings that don't support the characters being printed. It was also reporting an inaccurate column number and its corresponding marker position, because the count was in bytes, not in characters, so that has been fixed.
Now EParse.__init__() calls a new function GetErrLineCol() that calculates the line and column corresponding to an error position.
The algorithm for finding the start of the line has also been changed in both ReportError() and EParse.__init__(); as a result, function fieldpos() has been removed.
The exception's lno and cno fields have been changed to be 1-based, rather than 0-based.
Thanks to @Jomik for the report. Fixes#5.
lslcleanup: Variables renamed, order changed, comments added.
Other changes: remove semicolon at end of sentence, use self.Cast instead of creating a CAST node on the fly.