You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A 'provided' inside parentheses followed by a comma throws NullReferenceException from the parser #813
"(1 provided x > 0, 2)".ToEntity()// NullReferenceException
A raw NullReferenceException escapes the parser. Every parse failure is supposed to arrive as something under AngouriMathBaseException — see Docs/Usage/Exceptions.md — so a caller that correctly catches AngouriMathBaseException around user input does not catch this one and the process goes down.
The trigger is narrow and exact: a provided inside parentheses followed by a comma. Without the comma it parses; with the comma but without the provided it is rejected cleanly.
Where it probably comes from
That shape is the piecewise syntax. #326 records the current form as
Piecewise(a provided b, c provided d) without the otherwise case Piecewise(a provided b, c provided d, e) with the otherwise case
and neither of those parses either:
Piecewise(1 provided x > 0, 2 provided x < 0, 3)
-> UnhandledParseException: line 1:26 no viable alternative at input '*(1providedx>0'
Note the * in that message — Piecewise( is being read as the variable Piecewise multiplied by a bracket, which is the "unknown name followed by a bracket" path that #733 was about. So the grammar appears to have a rule for the comma-list-of-provided form but no Piecewise keyword in front of it, and the rule it does have dereferences something it did not build.
Two things worth separating:
The crash is a defect regardless of what the syntax should be. Whatever Syntax for Piecewise? #326 settles on, an input that is not valid must be refused with a typed exception rather than an NRE.
What the syntax should be is Syntax for Piecewise? #326, which is still open and marked Opinions wanted. That the documented current form does not parse is useful information for that discussion.
Fixed in #824, and one claim in the report above needs withdrawing.
The crash is wider than stated. A providedafter the comma crashes too:
(1, 2 provided x > 0) -> NullReferenceException
(1 provided x > 0, 2 provided x < 0) -> NullReferenceException
So the trigger is a provided anywhere in a parenthesised comma list, not specifically one followed by a comma.
The piecewise claim above is wrong. I wrote that neither documented form parses. Both do, and so does the third:
piecewise(1 provided x > 0, 2) -> piecewise(1 provided (x > 0), 2 provided True)
piecewise(1 provided x > 0, 2 provided x < 0) -> parses
piecewise(1 provided x > 0, 2 provided x < 0, 3) -> piecewise(..., 3 provided True)
I tested with Piecewise( — the capitalisation used in #326's prose — and that fails as an unknown name followed by a bracket, which is #733. The lowercase keyword the grammar actually defines works. The inference I drew from it ("the grammar appears to have a rule for the comma-list-of-provided form but no Piecewise keyword in front of it") was therefore backwards: the rule and the keyword both exist. What has no rule is the comma list without a piecewise in front of it — and that is exactly what the crash was hiding.
That also means this issue has nothing useful to contribute to #326 after all, which is worth saying since I claimed it did.
The cause, for the record: ANTLR reports the syntax error to the listener and then recovers, continuing with a rule context whose value was never assigned; the grammar's action for provided runs anyway and dereferences it. The error was recorded the whole time — the parse just died before ParseSilent read it. The fix reads it, guarded on an error having been reported so that a genuine bug of ours still propagates rather than being laundered into a syntax error.
A raw
NullReferenceExceptionescapes the parser. Every parse failure is supposed to arrive as something underAngouriMathBaseException— seeDocs/Usage/Exceptions.md— so a caller that correctly catchesAngouriMathBaseExceptionaround user input does not catch this one and the process goes down.Minimised on
master(21f0d16)1 provided x > 01 provided x > 0✅(1 provided x > 0)1 provided x > 0✅(1, 2)UnhandledParseException✅ (correct rejection)(x, y)UnhandledParseException✅(1 provided x > 0, 2)NullReferenceException❌(a provided b, c)NullReferenceException❌(1 provided x > 0, 2, 3)NullReferenceException❌The trigger is narrow and exact: a
providedinside parentheses followed by a comma. Without the comma it parses; with the comma but without theprovidedit is rejected cleanly.Where it probably comes from
That shape is the piecewise syntax. #326 records the current form as
and neither of those parses either:
Note the
*in that message —Piecewise(is being read as the variablePiecewisemultiplied by a bracket, which is the "unknown name followed by a bracket" path that #733 was about. So the grammar appears to have a rule for the comma-list-of-providedform but noPiecewisekeyword in front of it, and the rule it does have dereferences something it did not build.Two things worth separating:
Fixing 1 does not require deciding 2.