Instead of a tree of symbol tables, we keep a running stack of active symbol tables while parsing. The only case in which this causes problems is forward reference resolution for jump labels, which is solved by storing a copy of the stack at the point the jump was found.
Since we need to add variables, we need to know which scope to add them to. Add this information to the {} node, which is what creates a new scope.
An alternative would be to scan for any variable or label declaration within the braces and use that or create a new one if none, which is more expensive and may waste symbol tables.
Example: the optimization of if(i < 2 || i) was suboptimal, because FoldTree was done before FoldCond. In a first stage, the || was removed: if(!!(i < 2 | i)); when folded, the inner ! was optimized first and the result was if(!(1 < i & (!i))), which FoldCond wasn't smart enough to handle.
The new optimization takes over from there, and converts if(!(!a & b)) with b boolean, in any order, to if(a | !b). When applied to the above expression, it gets folded to if(i < 2 | i) as expected, which is optimal.
Also, new function: IsAndBool (see docstring), used on b in the above example.
Add blank lines between functions, between functions and states, between variables and functions or states, between states, and between events.
Or more concisely: add blank lines between events and between all elements at the global level except between variables (that actually describes the algorithm).
Some test cases expected no newlines; fix them.
Rather than using a hardcoded table of list-to-type extraction function, add a 'ListTo' attribute to the function data. No error is raised if more than one function exists to convert to the same type.
This change is of questionable usefulness, but it should soothe those allergic to magic names/numbers. I cringed a bit myself.
While on it, change the syntax error that was raised when the corresponding conversion function did not exist, to a tailor-made error.
After more thought, we believe that transforming llDumpList2String into a sum of strings is a gain even if there is a list constructor containing function calls as first parameter. The rationale is explained in the comment.
In particular, variables and fields. When we implement an analysis of functions contained in subexpressions, we can optimize more expressions, so add that as a TODO.
--prenodef was causing the preprocessor-specific options (like -std=c99 for gcpp or -V199901L for mcpp) to be omitted. That makes no sense; '-p ext' should be used when custom options are desired (also modify the text that mentions it to make that clearer). Only the macros should be omitted.
The comment that warned about side effects with the order of --prenodef with respect to -p no longer applies, so remove it.
Float addition is commutative. Swap the constant to the left side if it's not there. This is a "cheap" version of a bigger change that is planned, to minimize stack usage as much as possible on savepoints.
Float addition is not associative, therefore we don't optimize e.g. 1 + (2 + float).
Integer addition is commutative and associative. If there's a constant, we swap it to the left side. If there's a chained summation of the form const + (const + expression), we apply associativity to turn it into (const + const) + expression and reoptimize.
This doesn't cover all possible cases. Expressions of the form (const + expr) + (const + expr) are not optimized. We need to flatten sums if we want to do the right thing here, but that's not yet implemented.
Get rid of some older code and TODOs that are no longer needed.
The missing bit was to mark labels are SEF when they are not referenced. Label references are now counted at parse time, enabling us to do this.
Also, make FoldStmt clearer when the node is an expression.
(float)"1.1754944e-38" is != 0
(float)"1.1754943e-38" is == 0
Yet, 1.1754944e-38 == 1.1754943e-38.
The fix is to perform the operations as doubles, and convert to F32 *after* comparing the denormal range.
LSO allows this. The compiler does too, but it chokes in RAIL.
This affected a test, which has been adjusted too.
Untyped lazy list elements can no longer be used in isolation in expression lists (including FOR initializator and iterator).
Also rename the terribly named 'self.forbidlabels' to 'self.optenabled' which is more descriptive.