Skip to content

mruby-regexp: ask the engine's byte questions of a byte-indexed subject too - #7115

Merged
matz merged 1 commit into
mruby:masterfrom
takumin:regexp-byte-indexed-engine-tests
Aug 12, 2026
Merged

mruby-regexp: ask the engine's byte questions of a byte-indexed subject too#7115
matz merged 1 commit into
mruby:masterfrom
takumin:regexp-byte-indexed-engine-tests

Conversation

@takumin

@takumin takumin commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Split out of #7110, which asked for one review of a behaviour change and a
large test rewrite at once. This is the first of four pieces and changes no
behaviour.

The tests that ask what the engine does with a byte standing for no character
ask it through a UTF-8 subject carrying that byte. What each of them pins
belongs to the pattern: which byte a quantifier binds to, whether /i folds a
byte above 127, whether a class holds a byte or the character whose spelling
ends in it, and where a match may start. A byte-indexed subject puts the same
question to the engine, and none of them asked it there.

Why that is a different question to ask

mrb_re_exec() takes a flag for a byte-indexed subject, and the steps it drives
turn on that flag:

  • mrb_re_charlen() and mrb_re_decode_char() advance and decode a byte at a
    time
  • memcmp_ci() folds a byte at a time
  • lookbehind_start() rewinds by bytes
  • the seeding guard skips mrb_re_utf8_interior_p() outright, so every byte is
    a match position

So the answers these tests pin went unasserted on that side.

What this does

Asks each of them there as well, next to the case it answers, leaving the UTF-8
subject each already asks. A byte-indexed subject reports every position in
bytes, which its own indexing agrees with, so #begin states directly what
#pre_match had to state indirectly.

One assertion is new rather than a counterpart: a class that holds the character
µ still does not hold a lone 0xB5 on a byte-indexed subject either, which is
the contrast to the class that holds the byte on the line above it.

Verified

  • rake test on a full-core build (MRB_UTF8_STRING through mruby-encoding):
    2249 tests, all green
  • rake test on the default gembox (no MRB_UTF8_STRING): 2058 tests, all
    green
  • prek run --all-files passes, except that markdownlint could not install
    locally (npm engine mismatch); no Markdown is touched here

Summary by CodeRabbit

  • Tests
    • Added coverage for byte-oriented regular expression matching with ignore-case patterns, quantifiers, character classes, and malformed UTF-8 input.
    • Verified correct match boundaries, extracted values, indexing, and byte offsets when processing invalid or mixed-encoding data.

…ct too

The tests that ask what the engine does with a byte standing for no character
ask it through a UTF-8 subject carrying that byte. What each of them pins
belongs to the pattern: which byte a quantifier binds to, whether `/i` folds a
byte above 127, whether a class holds a byte or the character whose spelling
ends in it, and where a match may start. A byte-indexed subject puts the same
question to the engine, and none of them asked it there.

That is a branch of its own rather than another wording of the same one.
`mrb_re_exec()` takes a flag for a byte-indexed subject and the steps it drives
turn on that flag: `mrb_re_charlen()` and `mrb_re_decode_char()` advance and
decode a byte at a time, `memcmp_ci()` folds a byte at a time,
`lookbehind_start()` rewinds by bytes, and the seeding guard skips
`mrb_re_utf8_interior_p()` outright, so every byte is a match position. What
the answers above are on that side went unasserted.

So ask each of them there as well, next to the case it answers, leaving the
UTF-8 subject each already asks. A byte-indexed subject reports every position
in bytes, which its own indexing agrees with, so `#begin` states directly what
`#pre_match` had to state indirectly.
@takumin
takumin requested a review from matz as a code owner August 12, 2026 11:45
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c4598f0d-266e-4dc7-bf65-3c03ca2cb17f

📥 Commits

Reviewing files that changed from the base of the PR and between 19de6ff and 3b2018b.

📒 Files selected for processing (1)
  • mrbgems/mruby-regexp/test/regexp_utf8.rb

📝 Walkthrough

Walkthrough

The PR adds UTF-8 regexp tests for byte-indexed subjects. The tests cover malformed bytes, ignore-case matching, quantifiers, match positions, MatchData offsets, boundaries, and character classes.

Changes

Byte-oriented regexp behavior

Layer / File(s) Summary
Byte-oriented matching semantics
mrbgems/mruby-regexp/test/regexp_utf8.rb
Tests cover ignore-case matching, quantifiers, optional patterns, dot matching, and standalone continuation bytes.
Byte offsets and match boundaries
mrbgems/mruby-regexp/test/regexp_utf8.rb
Tests verify byte-based positions, MatchData offsets, string indexing, position arguments, and complete-byte boundaries.
Byte-oriented character classes
mrbgems/mruby-regexp/test/regexp_utf8.rb
Tests distinguish raw-byte classes and ranges from Unicode character and escape matching.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • mruby/mruby#7056: Changes multibyte-literal atom compilation exercised by the new quantifier and boundary tests.
  • mruby/mruby#7059: Changes UTF-8 match-boundary handling covered by the new byte-oriented tests.
  • mruby/mruby#7110: Extends byte-indexed UTF-8 regexp tests in the same test file.

Suggested reviewers: matz

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding byte-oriented regexp coverage for byte-indexed subjects.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants