2121use PHPStan \Type \StringType ;
2222use PHPStan \Type \Type ;
2323use PHPStan \Type \TypeCombinator ;
24+ use function array_key_exists ;
2425use function array_values ;
2526use function count ;
2627use function in_array ;
@@ -44,7 +45,7 @@ final class RegexGroupParser
4445
4546 private static ?Parser $ parser = null ;
4647
47- /** @var array<string, TreeNode> */
48+ /** @var array<string, ? TreeNode> */
4849 private static array $ parsedAst = [];
4950
5051 public function __construct (
@@ -59,30 +60,39 @@ public function parseGroups(string $regex): ?RegexAstWalkResult
5960 /** @throws void */
6061 self ::$ parser ??= Llk::load (new Read (__DIR__ . '/../../../resources/RegexGrammar.pp ' ));
6162
62- try {
63- Strings::match ('' , $ regex );
64- } catch (RegexpException ) {
65- // pattern is invalid, so let the RegularExpressionPatternRule report it
66- return null ;
67- }
68-
69- $ modifiers = $ this ->regexExpressionHelper ->getPatternModifiers ($ regex ) ?? '' ;
70- foreach (self ::NOT_SUPPORTED_MODIFIERS as $ notSupportedModifier ) {
71- if (str_contains ($ modifiers , $ notSupportedModifier )) {
63+ if (array_key_exists ($ regex , self ::$ parsedAst )) {
64+ $ ast = self ::$ parsedAst [$ regex ];
65+ if ($ ast === null ) {
7266 return null ;
7367 }
74- }
7568
76- if (str_contains ($ modifiers , 'x ' )) {
77- // in freespacing mode the # character starts a comment and runs until the end of the line
78- $ regex = preg_replace ('/(?<!\?)#.*/ ' , '' , $ regex ) ?? '' ;
79- }
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+ }
8077
81- $ rawRegex = $ this ->regexExpressionHelper ->removeDelimitersAndModifiers ($ regex );
82- try {
83- $ ast = self ::$ parsedAst [$ rawRegex ] ??= self ::$ parser ->parse ($ rawRegex );
84- } catch (Exception ) {
85- 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+ }
8696 }
8797
8898 $ this ->updateAlternationAstRemoveVerticalBarsAndAddEmptyToken ($ ast );
0 commit comments