You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit d458a5b
Browse filesBrowse the repository at this point in the historyBrowse files
Read regex shapes with PHPRegex instead of the generated parser
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.
Copy file name to clipboardExpand all lines: CLAUDE.md
+7-8Lines changed: 7 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -187,14 +187,13 @@ Collects structural information about a class during AST traversal: properties,
187
187
188
188
### Regex parser (`src/Type/Regex/`)
189
189
190
-
`RegexGroupParser`parses regex patterns to infer `preg_match()` array shapes (via `RegexArrayShapeMatcher`) and `IgnoredRegexValidator` uses it to validate `ignoreErrors` patterns. The parser itself is generated by [phplrt](https://github.com/phplrt/phplrt):
190
+
`RegexGroupParser`reads regex patterns to infer `preg_match()` array shapes (via `RegexArrayShapeMatcher`) and `IgnoredRegexValidator` uses the same reader to validate `ignoreErrors` patterns. Patterns are parsed by [PHPRegex](https://github.com/php-regex/php-regex), from the `php-regex/regex-parser-php74` package (its PHP 7.4 compatible build, so it works after the PHAR is downgraded):
191
191
192
-
-**Grammar**: `build/regex-parser/RegexGrammar.pp3` (phplrt `.pp3` format, derived from Hoa's regex grammar). The reducers in the grammar build a tree of `PHPStan\Type\Regex\Parser\RegexNode` objects (`#capturing`, `#alternation`, `#quantification`, `token`, ...) that `RegexGroupParser` walks.
193
-
-**Generated parser**: `src/Type/Regex/Parser/RegexParser.php`. Never edit it by hand. Change the grammar and regenerate, then commit both files together.
194
-
-**Regenerating**: `make regex-parser`. It installs the phplrt compiler into `build/regex-parser/vendor` (separate `build/regex-parser/composer.json`, needs PHP 8.4+) and runs `build/regex-parser/generate.php`. The script targets PHP 8.1 syntax and post-processes the output so that the PHAR's PHP 7.4 downgrader can handle it (first-class callables become `\Closure::fromCallable()`) and adds `@throws` to `parse()`.
195
-
-**Runtime**: the generated parser only needs the phplrt runtime, which comes from the `ondrejmirtes/phplrt-runtime` fork (a PHP 7.4 compatible downgrade of the `phplrt/*` runtime packages that replaces them). The compiler is a build-time dependency only and is never shipped.
196
-
- Parse failures throw `Phplrt\Contracts\Parser\Exception\ParserExceptionInterface` or `RegexSyntaxException`; callers treat both as "pattern not supported" and infer no shape.
197
-
- After changing the grammar or `RegexGroupParser`, run the regex tests: `tests/PHPStan/Analyser/nsrt/preg_*.php`, `tests/PHPStan/Type/Php/`, `tests/PHPStan/Type/Regex/` and `tests/PHPStan/Rules/Regexp/`.
192
+
-**Reader**: `PHPRegexReader` parses a pattern for the analysed PHP version and the PCRE2 version it bundles (`pcreVersion` parameter, or `config.platform.lib-pcre` in composer.json, see `PcreVersion`). A pattern the analysed engine refuses, or that the library cannot read, gets no shape.
193
+
-**Shapes**: the type of each group comes from the library's capture shape analysis (`CaptureShapeAnalyzer`: participation, values, length, digit and truthiness facts, per-branch arms). `RegexGroupParser` only walks the tree to place each group: its parent group and the alternation branch it belongs to.
194
+
- Library exceptions implement `PHPRegex\Parser\Exception\ExceptionInterface`; callers treat them as "pattern not supported" and infer no shape.
195
+
-`RegexArrayShapeMatcherEngineTest` matches every constant pattern of the `preg_*` fixtures with the engine and checks that the inferred type accepts what the engine writes.
196
+
- After changing `RegexGroupParser` or `RegexArrayShapeMatcher`, run the regex tests: `tests/PHPStan/Analyser/nsrt/preg_*.php`, `tests/PHPStan/Type/Php/`, `tests/PHPStan/Type/Regex/` and `tests/PHPStan/Rules/Regexp/`.
198
197
199
198
## Extension points
200
199
@@ -350,4 +349,4 @@ When adding or editing PHPDoc comments in this codebase, follow these guidelines
-`ondrejmirtes/phplrt-runtime` - PHP 7.4 compatible fork of the phplrt runtime, runs the regex parser generated from `build/regex-parser/RegexGrammar.pp3` (`make regex-parser`)
352
+
-`php-regex/regex-parser-php74` - PHP 7.4 compatible build of the PHPRegex parser, reads regex patterns for `preg_*()` shapes and `ignoreErrors`
0 commit comments