Escape characters a pattern cannot carry as bytes - #58
Merged
Merged
Conversation
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.
Stacked on #55, whose rewrite this relies on. Review that one first.
writeStringserializes one byte per JavaScript code unit:Uint8Arraykeeps the low byte, so every character aboveU+00FFis silently mangled. Unlike the escapes #55 deals with, this hits characters a grammar writes literally. BQN's function pattern upstream:and in
grammars.dattoday:•(U+2022) became",∞(U+221E) became\x1e,π(U+03C0) becameÀ. So BQN's function token matches a double quote followed by word characters, and fights the string-literal pattern for it.33 patterns across 13 languages: agda, apl, applescript, aql, art/arturo, bqn, false, julia, kusto, openqasm/qasm, sas.
Two changes:
sanitizenow spells anything aboveU+007Fas\uXXXX, so a pattern reaches the table as ASCII and every reader gets a code point rather than a byte. An astral character is two code units in JavaScript and so becomes a surrogate pair, which Expand unicode escapes Boost does not read #55 joins back together.writeStringencodes UTF-8 and counts bytes rather than code units. That is a no-op for the table as it stands — with patterns escaped, every string in it is ASCII — but it is the actual bug, and the next non-ASCII title would hit it. (kumir's isKuMir (КуМир); it survives only because the language is on the unsupported list.)UnicodeEscapes.hgains the matching rule: a class member above0x7Fnow has to be lifted out, not just one above0xFF. Boost truncates[¯]to a single byte just as it truncates[∧], and¯is two bytes in UTF-8.Verification
Regenerating and checking the table:
0x7F, down from 33java.util.regex, and the two engines agree on every pattern over the check corpus — the same gate Check every pattern against both regex engines on a pull request #56 addsTokenizing under all 386 listed languages and comparing libprisma against a Java reader of the same table, on a corpus of real
∧ λ ∀ ≤ 😀text: apl, applescript, art, arturo, bqn and julia stop diverging, nothing regresses, and the ASCII corpus stays at 386 of 386.🤖 Generated with Claude Code