Skip to content

Match only ASCII digits in the lexer number patterns - #195

Merged
bmjcode merged 2 commits into
masterfrom
fix-ascii-digit-regexes
Aug 25, 2026
Merged

Match only ASCII digits in the lexer number patterns#195
bmjcode merged 2 commits into
masterfrom
fix-ascii-digit-regexes

Conversation

@FelippeRoza

Copy link
Copy Markdown
Collaborator

In Python 3 \d matches every Unicode decimal digit, so the lexers read full-width digits as numbers. \tempo 4 = 60 lexes 60 as an IntegerValue and #(display 42) lexes 42 as a Number, though neither is legal LilyPond. Fixes #166.

Replaced with [0-9] in the 12 patterns that match a digit: 3 in scheme.py, 8 in lilypond.py, 1 in html.py.

Six other \d uses are left alone on purpose. They sit inside negated classes or negative lookaheads, where \d correctly excludes every digit. Rewriting [^\W\d_] as [^\W0-9_] would start accepting 4 as an identifier character, which is this bug rather than a fix for it.

tests/test_lex.py is new, so this is the first test for the lexers. Mutation testing covers 10 of the 12 patterns. Scaling and TempoSeparator resist it because both need a valid ASCII number earlier in the expression, so full-width input never reaches them at all.

The html.py line is the loosest fit, HTML numeric character references being a different language. Happy to drop it if you would rather keep this to the LilyPond and Scheme lexers.

In Python 3 \d matches every Unicode decimal digit, so the lexers read
full-width digits as numbers. \tempo 4 = 60 lexed 60 as an IntegerValue and
#(display 42) lexed 42 as a Number, though neither is legal LilyPond.

Replaced \d with [0-9] in the 12 patterns that match a digit, across
ly/lex/scheme.py, ly/lex/lilypond.py and ly/lex/html.py.

Six other \d uses are left as they are. They sit inside negated character
classes or negative lookaheads, where \d correctly excludes every digit.
Rewriting [^\W\d_] as [^\W0-9_] would start accepting 4 as an identifier
character, which is the bug this issue reports rather than a fix for it.

Fixes #166
@bmjcode

bmjcode commented Aug 21, 2026

Copy link
Copy Markdown
Member

In Python 3 \d matches every Unicode decimal digit, so the lexers read full-width digits as numbers. \tempo 4 = 60 lexes 60 as an IntegerValue and #(display 42) lexes 42 as a Number, though neither is legal LilyPond.

This is a good explanation. I'd add a comment in the source files as well so future maintainers will understand why not to change it back. (Something slightly briefer like '\d' matches Unicode digits that are not legal LilyPond is fine.)

Six other \d uses are left alone on purpose. They sit inside negated classes or negative lookaheads, where \d correctly excludes every digit. Rewriting [^\W\d_] as [^\W0-9_] would start accepting 4 as an identifier character, which is this bug rather than a fix for it.

This should also be included as a comment.

Records why \d must not come back, and why the negated classes keep it.
@FelippeRoza

Copy link
Copy Markdown
Collaborator Author

Done in e05d8dd.

The combined note sits above re_identifier in lilypond.py, since that is the negated class it protects:

# digit patterns use [0-9]: \d also matches Unicode digits that are not legal
# LilyPond. \d in a negated class excludes those too, so it stays

scheme.py and html.py get a one-liner each at the pattern itself.

You did not comment on the html.py change, so checking before you review again: keep it, or would you rather this stayed in the LilyPond and Scheme lexers only?

@bmjcode

bmjcode commented Aug 25, 2026

Copy link
Copy Markdown
Member

Looks good to me. @fedelibre and @ksnortum, do you want to double-check anything before we merge?

You did not comment on the html.py change, so checking before you review again: keep it, or would you rather this stayed in the LilyPond and Scheme lexers only?

Let's keep it. I don't see any reason we'd need to handle HTML separately.

@ksnortum

Copy link
Copy Markdown
Contributor

Looks good to me.

@fedelibre fedelibre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@bmjcode

bmjcode commented Aug 25, 2026

Copy link
Copy Markdown
Member

Cool, then let's do this.

@bmjcode
bmjcode merged commit 886ea0d into master Aug 25, 2026
7 checks passed
@FelippeRoza
FelippeRoza deleted the fix-ascii-digit-regexes branch August 27, 2026 14:35
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.

scheme.py: wrong match of ASCII digits

4 participants