Skip to content

Commit d085dbe

Browse files
authored
Cache ast-parsing in RegexGroupParser
1 parent 4f93239 commit d085dbe

File tree

1 file changed

+33
-20
lines changed

1 file changed

+33
-20
lines changed

src/Type/Regex/RegexGroupParser.php

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use PHPStan\Type\StringType;
2222
use PHPStan\Type\Type;
2323
use PHPStan\Type\TypeCombinator;
24+
use function array_key_exists;
2425
use function array_values;
2526
use function count;
2627
use function in_array;
@@ -44,6 +45,9 @@ final class RegexGroupParser
4445

4546
private static ?Parser $parser = null;
4647

48+
/** @var array<string, ?TreeNode> */
49+
private static array $parsedAst = [];
50+
4751
public function __construct(
4852
private PhpVersion $phpVersion,
4953
private RegexExpressionHelper $regexExpressionHelper,
@@ -56,30 +60,39 @@ public function parseGroups(string $regex): ?RegexAstWalkResult
5660
/** @throws void */
5761
self::$parser ??= Llk::load(new Read(__DIR__ . '/../../../resources/RegexGrammar.pp'));
5862

59-
try {
60-
Strings::match('', $regex);
61-
} catch (RegexpException) {
62-
// pattern is invalid, so let the RegularExpressionPatternRule report it
63-
return null;
64-
}
65-
66-
$modifiers = $this->regexExpressionHelper->getPatternModifiers($regex) ?? '';
67-
foreach (self::NOT_SUPPORTED_MODIFIERS as $notSupportedModifier) {
68-
if (str_contains($modifiers, $notSupportedModifier)) {
63+
if (array_key_exists($regex, self::$parsedAst)) {
64+
$ast = self::$parsedAst[$regex];
65+
if ($ast === null) {
6966
return null;
7067
}
71-
}
7268

73-
if (str_contains($modifiers, 'x')) {
74-
// in freespacing mode the # character starts a comment and runs until the end of the line
75-
$regex = preg_replace('/(?<!\?)#.*/', '', $regex) ?? '';
76-
}
69+
$modifiers = $this->regexExpressionHelper->getPatternModifiers($regex) ?? '';
70+
} else {
71+
try {
72+
Strings::match('', $regex);
73+
} catch (RegexpException) {
74+
// pattern is invalid, so let the RegularExpressionPatternRule report it
75+
return self::$parsedAst[$regex] = null;
76+
}
7777

78-
$rawRegex = $this->regexExpressionHelper->removeDelimitersAndModifiers($regex);
79-
try {
80-
$ast = self::$parser->parse($rawRegex);
81-
} catch (Exception) {
82-
return null;
78+
$modifiers = $this->regexExpressionHelper->getPatternModifiers($regex) ?? '';
79+
foreach (self::NOT_SUPPORTED_MODIFIERS as $notSupportedModifier) {
80+
if (str_contains($modifiers, $notSupportedModifier)) {
81+
return self::$parsedAst[$regex] = null;
82+
}
83+
}
84+
85+
if (str_contains($modifiers, 'x')) {
86+
// in freespacing mode the # character starts a comment and runs until the end of the line
87+
$regex = preg_replace('/(?<!\?)#.*/', '', $regex) ?? '';
88+
}
89+
90+
$rawRegex = $this->regexExpressionHelper->removeDelimitersAndModifiers($regex);
91+
try {
92+
$ast = self::$parsedAst[$regex] = self::$parser->parse($rawRegex);
93+
} catch (Exception) {
94+
return self::$parsedAst[$regex] = null;
95+
}
8396
}
8497

8598
$this->updateAlternationAstRemoveVerticalBarsAndAddEmptyToken($ast);

0 commit comments

Comments
 (0)