Skip to content

Specialize ASCII identifier lexing - #29503

Merged
charliermarsh merged 2 commits into
charlie/ruff-ascii-identifiersfrom
charlie/ruff-parser-hillclimb-next
Oct 23, 2026
Merged

charliermarsh merged 2 commits into
charlie/ruff-ascii-identifiersfrom
charlie/ruff-parser-hillclimb-next

Conversation

@charliermarsh

@charliermarsh charliermarsh commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Summary

We give ASCII identifiers a dedicated path, avoiding Unicode bookkeeping and checking string prefixes only when a one- or two-letter name reaches a quote. Both paths share the existing batched ASCII scanner, preserving fast scanning for Unicode names with long ASCII suffixes.

Stacked on #29463 to measure the incremental improvement. CodSpeed reports 6.6–9.8% greater efficiency across all five lexer benchmarks, with no reported regressions. We preserve the existing scanner and add no inlining attributes or unsafe code.

@astral-sh-bot

astral-sh-bot Bot commented Oct 19, 2026

Copy link
Copy Markdown

Memory usage report

Memory usage unchanged ✅

@astral-sh-bot

astral-sh-bot Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

ecosystem-analyzer results

No diagnostic changes detected ✅

Full report with detailed diff (timing results)

@astral-sh-bot

astral-sh-bot Bot commented Oct 19, 2026

Copy link
Copy Markdown

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.

@codspeed

codspeed Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Merging this PR will improve performance by 8.08%

1 warning

⚠️ Base and head ran on different runner types

Some benchmarks with significant performance changes were compared across different runner types, so the changes might not come from the code. Run base and head on the same runner type, or use CodSpeed Macro Runners for more stable results.

Learn more about Macro Runners

Open the report in CodSpeed to investigate

⚡ 5 improved benchmarks
✅ 257 untouched benchmarks
⏩ 14 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
⚡ CPU Simulation lexer[pydantic/types.py] 649.9 µs 594.9 µs +9.24%
⚡ CPU Simulation lexer[numpy/ctypeslib.py] 290 µs 265.9 µs +9.1%
⚡ CPU Simulation lexer[large/dataset.py] 1.4 ms 1.3 ms +8.93%
⚡ CPU Simulation lexer[unicode/pypinyin.py] 98.8 µs 92.3 µs +7.04%
⚡ CPU Simulation lexer[numpy/globals.py] 39.5 µs 37.2 µs +6.11%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing charlie/ruff-parser-hillclimb-next (cc8580c) with charlie/ruff-ascii-identifiers (6818c90)

Open in CodSpeed

Footnotes

  1. 14 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@charliermarsh
charliermarsh force-pushed the charlie/ruff-parser-hillclimb-next branch from dee63d0 to 9d1d502 Compare October 19, 2026 20:35
@charliermarsh
charliermarsh marked this pull request as ready for review October 19, 2026 21:05

@MichaReiser MichaReiser 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.

I don't know why but GitHub does not show me the approve button 😆 but consider this approved

Comment thread crates/ruff_python_parser/src/lexer.rs Outdated
Comment on lines +221 to +222
self.state = State::Other;

identifier
self.lex_unicode_identifier()

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.

Is it an issue that we now assign the state before lexing the identifier?


/// Finishes an identifier after consuming a non-ASCII identifier character.
fn lex_unicode_identifier(&mut self) -> TokenKind {
let ascii_len = ascii_identifier_prefix_len(self.cursor.rest().as_bytes());

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.

Is skipping ascii caracters after a non-ASCII character worth it? Is the assumption here that a non-ASCII character is commonly followed by a long ASCII only sequence. I'm not sure this holds true and is also not something we do for unicode characters in the middle of a word.

Comment thread crates/ruff_python_parser/src/lexer.rs Outdated
Comment on lines +680 to +682
if self.cursor.eat_if(is_xid_continue).is_some() {
return self.lex_unicode_identifier();
}

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.

Could we avoid starting over if there's a non ascii character? Seems a bit wasteful to throw away what we already lexed.

Comment thread crates/ruff_python_parser/src/lexer.rs Outdated
self.current_flags |= TokenFlags::NON_ASCII_IDENTIFIER;
return TokenKind::Identifier;
match bytes.get(ascii_len) {
Some(quote) if ascii_len <= 1 && matches!(quote, b'\'' | b'"') => {

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.

Suggested change
Some(quote) if ascii_len <= 1 && matches!(quote, b'\'' | b'"') => {
Some(b'\'' | b'"') if ascii_len <= 1 => {

@charliermarsh
charliermarsh force-pushed the charlie/ruff-parser-hillclimb-next branch from 7460521 to cc8580c Compare October 23, 2026 17:45
@astral-automations-bot

Copy link
Copy Markdown
Contributor

Memory usage report

Memory usage unchanged ✅


Results for cc8580c · Workflow run

@astral-automations-bot

Copy link
Copy Markdown
Contributor

ecosystem-analyzer results

No diagnostic changes detected ✅

Flaky changes detected. This PR summary excludes flaky changes; see the HTML report for details.

Full report with detailed diff · Timing results


Results for cc8580c · Workflow run

@astral-automations-bot

Copy link
Copy Markdown
Contributor

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.

Formatter (stable)

✅ ecosystem check detected no format changes.

Formatter (preview)

✅ ecosystem check detected no format changes.


Results for cc8580c · Workflow run

@charliermarsh
charliermarsh merged commit e330485 into main Oct 23, 2026
101 of 137 checks passed
@charliermarsh
charliermarsh deleted the charlie/ruff-parser-hillclimb-next branch October 23, 2026 17:58
@ntBre ntBre added performance Potential performance improvement parser Related to the parser labels Oct 23, 2026

This branch was previously deployed

1 inactive deployment
automations — cc8580c0 Deployed Oct 23, 2026 by charliermarsh via security-review / security review #93187
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parser Related to the parser performance Potential performance improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants