Skip to content

Refuse eleven function names the library does not have (#733) - #750

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
fix/refuse-missing-function-names
Aug 5, 2026
Merged

Refuse eleven function names the library does not have (#733)#750
Rafael-SOWNet merged 1 commit into
masterfrom
fix/refuse-missing-function-names

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Collaborator

Closes the remaining defect half of #733. The feature half — actually having these functions — is not this.

What was wrong

A name the grammar does not know, followed by a bracket, is the implicit multiplication that lets a(b + c) mean a * (b + c). For a one-argument call that never fails, so every CAS spelling AngouriMath lacks came back as the product of an undeclared variable with its argument, silently:

"floor(x)".ToEntity()               // floor * x
"floor(x) - 3 = 0".Solve("x")       // { 3 / floor }  — a root of nothing

The same absence was already reported for two arguments, and only reported badly:

"min(x, y)".ToEntity()              // UnhandledParseException: no viable alternative at input '*('

So whether a missing function was invisible or merely cryptic depended on how many arguments the caller happened to pass, and neither told them the function does not exist.

What the fix does

Eleven names — floor, ceil, ceiling, round, trunc, min, max, gcd, lcm, erf, conjugate — are refused by name, exactly as arcsinh already is, with a message that says what happened:

there is no function floor: AngouriMath has no rounding functions. It is refused by name rather than read as the product of a variable named floor with its argument, which is what an unknown name followed by a bracket would otherwise mean

Nothing is being removed — none of these was ever there. This turns a silent wrong answer into a parse error, which is the whole of it.

Refusing every unknown name is not an option, since that rule is what a(b + c) is. So these are refused one at a time and nothing else moves:

written before and after
min + 1, max * 2, floor + floor ordinary variables, unchanged
minimum(x), rounded(x), maxx(y) still the implicit products
a(b + c) still a * (b + c)
sgn, sign, signum, abs, gamma, factorial, exp, log10, log2, arsinh, phi unchanged

re and im are deliberately not refused. They are the sympy spellings for the real and imaginary parts and misparse identically, but two letters is short enough that a caller may reasonably have a variable of that name, and refusing would break their expression to fix nobody's. Pinned by a test so the choice is visible rather than an oversight.

Measured

Grammar regenerated with Sources/Utils/antlr_rerun.bat, so the generated files under Core/Antlr are part of the diff.

Recorded in BREAKING-CHANGES.md — it is a loud break and that file's rule is that a call which used to succeed and now does not gets an entry — and in Docs/Usage/Syntax.md, which is a reading of the grammar.

🤖 Generated with Claude Code

A name the grammar does not know, followed by a bracket, is the implicit
multiplication that lets `a(b + c)` mean `a * (b + c)`. For a one-argument call
that never fails, so every CAS spelling AngouriMath lacks came back as the
product of an undeclared variable with its argument, and nothing said so:

    "floor(x)"                     ->  floor * x
    "floor(x) - 3 = 0".Solve("x")  ->  { 3 / floor }, a root of nothing

`floor`, `ceil`, `ceiling`, `round`, `trunc`, `min`, `max`, `gcd`, `lcm`, `erf`
and `conjugate` are refused by name now, as `arcsinh` already is, with a message
saying what happened and why. None of them is being removed: none was there.

The absence was already reported for two arguments and only reported *badly* --
`min(x, y)` raised `no viable alternative at input '*('` from the parser
generator, so whether a missing function was invisible or merely cryptic
depended on how many arguments the caller happened to pass. Now it is the same
error either way, and it names the function.

Refusing every unknown name is not an option, since that rule is what `a(b + c)`
is, so these are refused one at a time and nothing else moves: each name on its
own is still a variable (`min + 1`, `floor + floor`), and a longer name
beginning the same way is still a product (`minimum(x)`, `rounded(x)`,
`maxx(y)`).

`re` and `im` are deliberately left. They are the sympy spellings for the real
and imaginary parts and misparse identically, but two letters is short enough
that a caller may reasonably have a variable of that name, and refusing would
break their expression to fix nobody's. Pinned by a test so the choice is
visible rather than an oversight.

Grammar regenerated with `Sources/Utils/antlr_rerun.bat`. Recorded in
`BREAKING-CHANGES.md` -- it is a loud break, and the file's own rule is that a
call which used to succeed and now does not gets an entry -- and in
`Docs/Usage/Syntax.md`, which is a reading of the grammar.

Suite 4979 -> 5004 passed / 0 failed, F# 130/130, corpus 112/117 with 0 wrong
and every verdict and answer byte-identical.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Rafael-SOWNet
Rafael-SOWNet merged commit f9759c9 into master Aug 5, 2026
24 checks passed
@Rafael-SOWNet
Rafael-SOWNet deleted the fix/refuse-missing-function-names branch August 5, 2026 22:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant