Skip to content

fix(runtime): spec-compliant String.prototype.split with a RegExp separator (test262 tail) - #5027

Merged
proggeramlug merged 1 commit into
mainfrom
language-tail-v3-parity
Jun 11, 2026
Merged

fix(runtime): spec-compliant String.prototype.split with a RegExp separator (test262 tail)#5027
proggeramlug merged 1 commit into
mainfrom
language-tail-v3-parity

Conversation

@proggeramlug

Copy link
Copy Markdown
Contributor

Summary

built-ins/String + built-ins/RegExp test262: +8, zero regressions (verified by diffing the per-test failure set; String+RegExp fails 97 → 89).

Root cause

Perry delegated String.prototype.split(regexp, limit) to the Rust regex crate's Regex::split, which diverges from JS RegExp.prototype[Symbol.split] (21.2.5.11):

  • zero-width matchesregex::split emits the leading/trailing/consecutive empty strings that the spec's e == p skip suppresses. "one-1 two".split(new RegExp) (empty pattern) returned ["","o",…,"o",""] (length 11) instead of the spec's ["o",…,"o"] (length 9, one element per char); and
  • captured groups were never spliced into the result ("a1b".split(/(\d)/) dropped the "1").

Fix

Replaced the standard-engine branch of js_string_split_regex_n with the spec algorithm: a sticky match at each position, the empty-match-at-segment-start (e == p) skip, and capture-group splicing where an unmatched group becomes undefined. limit is honoured per-element. The fancy-regex (lookbehind) fallback is unchanged. Helpers (spec_regex_split, next_char_boundary) live in string/split.rs so regex.rs stays under the 2000-line cap.

Files

  • regex.rs — standard split branch + undefined-aware array build
  • string/split.rsspec_regex_split + next_char_boundary
  • string/mod.rs — re-export

Validation

test262_subset.py --dir built-ins/String built-ins/RegExp vs tc39/test262 @ 4249661, Node v26.3.0: 8 newly-passing (split/call-split-new-reg-exp, the new-reg-exp-and-N family, separator-regexp), 0 newly-broken.

…arator

built-ins/String + built-ins/RegExp test262: +8, zero regressions.

Perry delegated regex split to the Rust `regex` crate's `Regex::split`, which
diverges from JS `RegExp.prototype[Symbol.split]` (21.2.5.11) in two ways:

  * zero-width matches — `regex::split` emits leading/trailing/consecutive empty
    strings that the spec's `e == p` skip suppresses, so
    `"abc".split(/(?:)/)` returned `["","a","b","c",""]` instead of
    `["a","b","c"]`; and
  * captured groups were never spliced into the result.

Replaced the standard-engine branch with the spec algorithm: a sticky match at
each position, the empty-match-at-segment-start skip, and capture-group
splicing (unmatched groups → `undefined`). The helpers live in
`string/split.rs` (keeps `regex.rs` under the 2000-line cap). The
fancy-regex (lookbehind) fallback is unchanged.

Fixes the String.prototype.split/call-split-new-reg-exp + new-reg-exp-and-N +
separator-regexp cluster.
@proggeramlug
proggeramlug merged commit 6f777cb into main Jun 11, 2026
11 of 13 checks passed
@proggeramlug
proggeramlug deleted the language-tail-v3-parity branch June 11, 2026 23:25
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.

1 participant