Repository navigation
Conversation
The fast path for unprefixed decimal integers added in 20e626a reports the first invalid underscore and prefers "inner" over "trailing", while pm_strspn_number_kind_underscores (used for prefixed integers, fractions and exponents) overwrote the pointer on every hit, reporting the last one and preferring "trailing". As a result, 1__2__3 and 0d1__2__3 pointed at different relative positions, and 1__2_ and 0d1__2_ even produced different error types. Only write the pointer when it is still unset, so every path follows the rule already documented on the pm_strspn_*_number functions. All callers initialize the pointer to NULL, so reading it is safe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
|
I see that there is that inconsistency, but does it really matter? I'm struggling to see how this could impact anyone. |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Make every number literal path report the same invalid underscore, so the error location and type no longer depend on whether the literal has a base prefix. This PR picks "first invalid underscore, inner wins over trailing"; see the question below.
Why
Two code paths decide where an invalid underscore is reported, and they follow different rules:
lex_numeric(added in 20e626a) records the first invalid underscore. A trailing underscore is only recorded if nothing was found before it, so "inner" wins.pm_strspn_number_kind_underscoresinsrc/char.coverwrites the pointer on every hit. It is used for prefixed integers (0b/0o/0/0d/0x), fractions and exponents. It records the last invalid underscore, and a trailing underscore always wins.So equivalent literals disagree:
1__2__30d1__2__31__2_0d1__2_0b1__0__11.2__3__41e1__2__3The comments in
src/char.cdisagree with each other, too. All of them were added together in 35da3d1 (#1507):pm_strspn_number_kind_underscoressays it reports "the location of the last invalid underscore character", which matches its implementation.pm_strspn_{binary,octal,decimal,hexadecimal}_numbersay "the invalid pointer is set to the index of the first invalid underscore".As far as I can tell, the existing tests never pinned this down. Every fixture has exactly one invalid underscore. The inner/trailing distinction came later, in #2759, and only classifies the pointer that the scan already chose, so "trailing wins" looks like a side effect of the scan order rather than a design choice.
Only the reported location and error type change; whether a literal is accepted or rejected does not.
Question for maintainers
Which rule do you prefer?
pm_strspn_*_numberfunctions. It does not change the current behavior for unprefixed decimals.If "last" was intentional, I'm happy to switch this PR to B. The new fixtures would only need their expected positions updated.
Changes
src/char.c: inpm_strspn_number_kind_underscores, only write*invalidwhen it is stillNULL, both inside the loop and for the trailing underscore. All callers (pm_strspn_*_number_validateinsrc/prism.c) initialize it toNULL. Changed the helper's comment from "last" to "first".test/prism/errors/invalid_number_underscores_13.txt–_22.txt: new fixtures in which each literal has two invalid positions. They cover each base (none,0d,0b,0o,0,0x), fractions and exponents, and pair unprefixed and prefixed decimals to show that both now get the same relative position and type. Existing fixtures are unchanged.🤖 Generated with Claude Code