Skip to content

[POC] Explore reading regex shapes with PHPRegex - #1

Open
yoeunes wants to merge 1 commit into
2.3.xfrom
read-regex-shapes-through-phpregex
Open

yoeunes wants to merge 1 commit into
2.3.xfrom
read-regex-shapes-through-phpregex

Conversation

@yoeunes

@yoeunes yoeunes commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

This is a research branch. It runs PHPStan's regex shape inference on PHPRegex, a PCRE2 pattern parser that runs on PHP 7.4, to see how the library holds up against PHPStan's tests.

What the branch does

  • RegexGroupParser reads the PHPRegex AST, and the type of each group comes from the library's capture shape analysis.
  • IgnoredRegexValidator reads ignoreErrors patterns with the same parser.
  • Patterns are read for the analysed PHP version and the PCRE2 version it bundles. A pcreVersion parameter, or config.platform.lib-pcre in composer.json, sets that version.
  • With bleeding edge, RegularExpressionPatternRule also reports a pattern the running PHP compiles but the analysed PHP does not.
  • The preg_replace_callback() callback is checked against the type its flags give, each preg_replace_callback_array() callback gets the shape of its own pattern, and preg_replace() reads the group references of its replacement.

How it is checked

RegexArrayShapeMatcherEngineTest takes every constant pattern of the preg_* fixtures, matches it with the engine on generated subjects and with every flag combination, and checks that the inferred type accepts what the engine writes. All 327 patterns pass.

The full test suite passes, and make phpstan reports no errors.

poc/ measures the branch and upstream 2.3.x on four pattern sets (the PCRE2 and php-src test suites, patterns from open-source projects, generated edge cases), with a witness for each contradicted pattern and the scripts to replay them: see poc/README.md.

Issues this branch answers

@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch 7 times, most recently from f29e7f3 to affc97a Compare October 23, 2026 08:27
@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch 3 times, most recently from 53cc9c4 to c6aaf88 Compare October 23, 2026 19:43
@yoeunes yoeunes changed the title Read the regex shapes through the PHPRegex parser Replace the Hoa grammar with the PHPRegex parser in the regex shape pipeline Oct 23, 2026
@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch 3 times, most recently from 6aff3b2 to a54e5a6 Compare October 24, 2026 21:29
@yoeunes yoeunes changed the title Replace the Hoa grammar with the PHPRegex parser in the regex shape pipeline [POC] Explore replacing the vendored PCRE grammar with PHPRegex Oct 24, 2026
@yoeunes yoeunes changed the title [POC] Explore replacing the vendored PCRE grammar with PHPRegex [POC] Explore replacing the vendored Hoa regex grammar with PHPRegex Oct 24, 2026
@yoeunes yoeunes changed the title [POC] Explore replacing the vendored Hoa regex grammar with PHPRegex [POC] Explore replacing Hoa regex grammar with PHPRegex Oct 24, 2026
@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch 5 times, most recently from 0036c0a to 6fa8c53 Compare October 26, 2026 08:56
@staabm

staabm commented Oct 26, 2026

Copy link
Copy Markdown

ondrej did something in phpstan#6851

@yoeunes

yoeunes commented Oct 26, 2026 •

Copy link
Copy Markdown
Member Author

ondrej did something in phpstan#6851

Hello @staabm, thanks for the heads-up. Glad to see Hoa gone from PHPStan. I'll probably rebase this branch on the new parser and keep exploring 🙏🏻.

@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch from 6fa8c53 to 3bd8185 Compare October 26, 2026 14:13
@yoeunes yoeunes changed the title [POC] Explore replacing Hoa regex grammar with PHPRegex [POC] Explore reading regex shapes with PHPRegex Oct 26, 2026
@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch from 3bd8185 to 3dd2526 Compare October 26, 2026 15:07
@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch 6 times, most recently from e550d3a to d03c755 Compare October 26, 2026 22:53
The shapes of preg_match(), preg_match_all() and preg_replace_callback()
are read from the AST and the capture shape analysis of PHPRegex, a
PCRE2 pattern parser that runs on PHP 7.4. The generated parser, its
grammar, its build script and the phplrt runtime are removed, and
ignoreErrors patterns are validated with the same parser.

Patterns are read for the analysed PHP version and the PCRE2 version it
bundles; a pcreVersion parameter, or config.platform.lib-pcre in
composer.json, can set that version. With bleeding edge,
RegularExpressionPatternRule also reports a pattern the running PHP
compiles but the analysed PHP does not.

A new test matches every constant pattern of the preg_* fixtures with
the engine, on generated subjects and with every flag combination, and
checks that the inferred type accepts what the engine writes.
@yoeunes
yoeunes force-pushed the read-regex-shapes-through-phpregex branch from d03c755 to d80885a Compare October 27, 2026 04:16
@ondrejmirtes

Copy link
Copy Markdown

The fixes on the PR were actually inspired by test cases in PCRE and PHP.

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.

3 participants