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
rlichtenwalter added a commit to rlichtenwalter/dir2text that referenced this pull request Oct 30, 2026
This PR contains the following updates:

| Package | Type | Update | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|---|---|
| [DavidAnson/markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) | repository | minor | `v0.23.3` β†’ `v0.24.0` | ![age](https://developer.mend.io/api/mc/badges/age/github-tags/DavidAnson%2fmarkdownlint-cli2/v0.24.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/github-tags/DavidAnson%2fmarkdownlint-cli2/v0.23.3/v0.24.0?slim=true) |
| [ruff](https://docs.astral.sh/ruff) ([source](https://github.com/astral-sh/ruff), [changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)) | dependency-groups | patch | `==0.17.1` β†’ `==0.17.3` | ![age](https://developer.mend.io/api/mc/badges/age/pypi/ruff/0.17.3?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/ruff/0.17.1/0.17.3?slim=true) |

Note: The `pre-commit` manager in Renovate is not supported by the `pre-commit` maintainers or community. Please do not report any problems there, instead [create a Discussion in the Renovate repository](https://github.com/renovatebot/renovate/discussions/new) if you have any questions.

---

### Release Notes

<details>
<summary>DavidAnson/markdownlint-cli2</summary>

### [`v0.24.0`](DavidAnson/markdownlint-cli2@v0.23.3...v0.24.0)

[Compare Source](DavidAnson/markdownlint-cli2@v0.23.3...v0.24.0)

</details>

<details>
<summary>astral-sh/ruff (ruff)</summary>

### [`v0.17.3`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0173)

[Compare Source](astral-sh/ruff@0.17.2...0.17.3)

Released on 2026-10-26.

##### Preview features

- \[`suspicious`] Add `shared-clock-mock` ([#&#8203;29074](astral-sh/ruff#29074))

##### Bug fixes

- \[`pyupgrade`] Avoid incorrect conversions to f-strings (`UP032`) ([#&#8203;25485](astral-sh/ruff#25485))

##### Performance

- Buffer stdout in `ruff format` ([#&#8203;29631](astral-sh/ruff#29631))
- Specialize ASCII identifier lexing ([#&#8203;29503](astral-sh/ruff#29503))
- Speed up identifier and keyword lexing ([#&#8203;29463](astral-sh/ruff#29463))

##### Documentation

- \[`flake8-bandit`] Describe what the rule actually checks for `httpx` (`S113`) ([#&#8203;27936](astral-sh/ruff#27936))

##### Contributors

- [@&#8203;itsvedantkumar](https://github.com/itsvedantkumar)
- [@&#8203;charliermarsh](https://github.com/charliermarsh)
- [@&#8203;anishgirianish](https://github.com/anishgirianish)

### [`v0.17.2`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0172)

[Compare Source](astral-sh/ruff@0.17.1...0.17.2)

Released on 2026-10-22.

##### Preview features

- \[`complexity`] Add `unnecessary-regular-expression-compile` ([#&#8203;25533](astral-sh/ruff#25533))

##### Bug fixes

- Avoid syntax errors for type variables with starred constraints (`UP040`, `UP046`, `UP047`, `RUF053`) ([#&#8203;28362](astral-sh/ruff#28362))
- \[`pydocstyle`] Treat backslash-escaped `*args` and `**kwargs` as documented (`D417`) ([#&#8203;29536](astral-sh/ruff#29536))
- \[`pylint`] Avoid false positive on starred elements (`PLE0643`) ([#&#8203;29483](astral-sh/ruff#29483))
- \[`pylint`] Mark fixes unsafe when deleting comments (`PLR5501`, `PLW0120`) ([#&#8203;29414](astral-sh/ruff#29414))
- \[`pyupgrade`] Mark fix unsafe when deleting comments (`UP035`) ([#&#8203;29413](astral-sh/ruff#29413))

##### Performance

- Avoid intermediate names in lint name resolution ([#&#8203;29506](astral-sh/ruff#29506))
- Prefilter bidirectional Unicode checks by UTF-8 leading bytes ([#&#8203;29561](astral-sh/ruff#29561))
- Share postfix parsing and reduce expression copies ([#&#8203;29480](astral-sh/ruff#29480))

##### Configuration

- \[`pylint`] Add a configurable allowlist for `magic-value-comparison` (`PLR2004`) ([#&#8203;18961](astral-sh/ruff#18961))

##### Documentation

- Clarify documentation and correct stale guidance ([#&#8203;29374](astral-sh/ruff#29374))
- \[`pyupgrade`] Remove mentions of variance related to fix safety (`UP040`, `UP047`) ([#&#8203;29592](astral-sh/ruff#29592))

##### Contributors

- [@&#8203;fixfon](https://github.com/fixfon)
- [@&#8203;MichaReiser](https://github.com/MichaReiser)
- [@&#8203;zaniebot](https://github.com/zaniebot)
- [@&#8203;FrancescoPezzella](https://github.com/FrancescoPezzella)
- [@&#8203;anishgirianish](https://github.com/anishgirianish)
- [@&#8203;rajveer3x](https://github.com/rajveer3x)
- [@&#8203;charliermarsh](https://github.com/charliermarsh)
- [@&#8203;LckyLike](https://github.com/LckyLke)
- [@&#8203;DaniBodor](https://github.com/DaniBodor)

</details>

---

### Configuration

πŸ“… **Schedule**: (in timezone America/Denver)

- Branch creation
  - Between 02:00 AM and 06:59 AM, only on Tuesday (`* 2-6 * * 2`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

β™» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

πŸ‘» **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNDguMyIsInVwZGF0ZWRJblZlciI6IjQ0LjE0OC4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Reviewed-on: https://git.lichtenwalter.site/rlichten/dir2text/pulls/100

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