@@ -6,100 +6,100 @@ |
||
6 | 6 | |
7 | 7 | final class NumericLiteralSeparatorEmulator extends TokenEmulator |
8 | 8 | { |
9 | - const BIN = '(?:0b[01]+(?:_[01]+)*)'; |
|
10 | - const HEX = '(?:0x[0-9a-f]+(?:_[0-9a-f]+)*)'; |
|
11 | - const DEC = '(?:[0-9]+(?:_[0-9]+)*)'; |
|
12 | - const SIMPLE_FLOAT = '(?:' . self::DEC . '\.' . self::DEC . '?|\.' . self::DEC . ')'; |
|
13 | - const EXP = '(?:e[+-]?' . self::DEC . ')'; |
|
14 | - const FLOAT = '(?:' . self::SIMPLE_FLOAT . self::EXP . '?|' . self::DEC . self::EXP . ')'; |
|
15 | - const NUMBER = '~' . self::FLOAT . '|' . self::BIN . '|' . self::HEX . '|' . self::DEC . '~iA'; |
|
16 | - |
|
17 | - public function getPhpVersion(): string |
|
18 | - { |
|
19 | - return Emulative::PHP_7_4; |
|
20 | - } |
|
21 | - |
|
22 | - public function isEmulationNeeded(string $code) : bool |
|
23 | - { |
|
24 | - return preg_match('~[0-9]_[0-9]~', $code) |
|
25 | - || preg_match('~0x[0-9a-f]+_[0-9a-f]~i', $code); |
|
26 | - } |
|
27 | - |
|
28 | - public function emulate(string $code, array $tokens): array |
|
29 | - { |
|
30 | - // We need to manually iterate and manage a count because we'll change |
|
31 | - // the tokens array on the way |
|
32 | - $codeOffset = 0; |
|
33 | - for ($i = 0, $c = count($tokens); $i < $c; ++$i) { |
|
34 | - $token = $tokens[$i]; |
|
35 | - $tokenLen = \strlen(\is_array($token) ? $token[1] : $token); |
|
36 | - |
|
37 | - if ($token[0] !== T_LNUMBER && $token[0] !== T_DNUMBER) { |
|
38 | - $codeOffset += $tokenLen; |
|
39 | - continue; |
|
40 | - } |
|
41 | - |
|
42 | - $res = preg_match(self::NUMBER, $code, $matches, 0, $codeOffset); |
|
43 | - assert($res, "No number at number token position"); |
|
44 | - |
|
45 | - $match = $matches[0]; |
|
46 | - $matchLen = \strlen($match); |
|
47 | - if ($matchLen === $tokenLen) { |
|
48 | - // Original token already holds the full number. |
|
49 | - $codeOffset += $tokenLen; |
|
50 | - continue; |
|
51 | - } |
|
52 | - |
|
53 | - $tokenKind = $this->resolveIntegerOrFloatToken($match); |
|
54 | - $newTokens = [[$tokenKind, $match, $token[2]]]; |
|
55 | - |
|
56 | - $numTokens = 1; |
|
57 | - $len = $tokenLen; |
|
58 | - while ($matchLen > $len) { |
|
59 | - $nextToken = $tokens[$i + $numTokens]; |
|
60 | - $nextTokenText = \is_array($nextToken) ? $nextToken[1] : $nextToken; |
|
61 | - $nextTokenLen = \strlen($nextTokenText); |
|
62 | - |
|
63 | - $numTokens++; |
|
64 | - if ($matchLen < $len + $nextTokenLen) { |
|
65 | - // Split trailing characters into a partial token. |
|
66 | - assert(is_array($nextToken), "Partial token should be an array token"); |
|
67 | - $partialText = substr($nextTokenText, $matchLen - $len); |
|
68 | - $newTokens[] = [$nextToken[0], $partialText, $nextToken[2]]; |
|
69 | - break; |
|
70 | - } |
|
71 | - |
|
72 | - $len += $nextTokenLen; |
|
73 | - } |
|
74 | - |
|
75 | - array_splice($tokens, $i, $numTokens, $newTokens); |
|
76 | - $c -= $numTokens - \count($newTokens); |
|
77 | - $codeOffset += $matchLen; |
|
78 | - } |
|
79 | - |
|
80 | - return $tokens; |
|
81 | - } |
|
82 | - |
|
83 | - private function resolveIntegerOrFloatToken(string $str): int |
|
84 | - { |
|
85 | - $str = str_replace('_', '', $str); |
|
86 | - |
|
87 | - if (stripos($str, '0b') === 0) { |
|
88 | - $num = bindec($str); |
|
89 | - } elseif (stripos($str, '0x') === 0) { |
|
90 | - $num = hexdec($str); |
|
91 | - } elseif (stripos($str, '0') === 0 && ctype_digit($str)) { |
|
92 | - $num = octdec($str); |
|
93 | - } else { |
|
94 | - $num = +$str; |
|
95 | - } |
|
96 | - |
|
97 | - return is_float($num) ? T_DNUMBER : T_LNUMBER; |
|
98 | - } |
|
99 | - |
|
100 | - public function reverseEmulate(string $code, array $tokens): array |
|
101 | - { |
|
102 | - // Numeric separators were not legal code previously, don't bother. |
|
103 | - return $tokens; |
|
104 | - } |
|
9 | + const BIN = '(?:0b[01]+(?:_[01]+)*)'; |
|
10 | + const HEX = '(?:0x[0-9a-f]+(?:_[0-9a-f]+)*)'; |
|
11 | + const DEC = '(?:[0-9]+(?:_[0-9]+)*)'; |
|
12 | + const SIMPLE_FLOAT = '(?:' . self::DEC . '\.' . self::DEC . '?|\.' . self::DEC . ')'; |
|
13 | + const EXP = '(?:e[+-]?' . self::DEC . ')'; |
|
14 | + const FLOAT = '(?:' . self::SIMPLE_FLOAT . self::EXP . '?|' . self::DEC . self::EXP . ')'; |
|
15 | + const NUMBER = '~' . self::FLOAT . '|' . self::BIN . '|' . self::HEX . '|' . self::DEC . '~iA'; |
|
16 | + |
|
17 | + public function getPhpVersion(): string |
|
18 | + { |
|
19 | + return Emulative::PHP_7_4; |
|
20 | + } |
|
21 | + |
|
22 | + public function isEmulationNeeded(string $code) : bool |
|
23 | + { |
|
24 | + return preg_match('~[0-9]_[0-9]~', $code) |
|
25 | + || preg_match('~0x[0-9a-f]+_[0-9a-f]~i', $code); |
|
26 | + } |
|
27 | + |
|
28 | + public function emulate(string $code, array $tokens): array |
|
29 | + { |
|
30 | + // We need to manually iterate and manage a count because we'll change |
|
31 | + // the tokens array on the way |
|
32 | + $codeOffset = 0; |
|
33 | + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { |
|
34 | + $token = $tokens[$i]; |
|
35 | + $tokenLen = \strlen(\is_array($token) ? $token[1] : $token); |
|
36 | + |
|
37 | + if ($token[0] !== T_LNUMBER && $token[0] !== T_DNUMBER) { |
|
38 | + $codeOffset += $tokenLen; |
|
39 | + continue; |
|
40 | + } |
|
41 | + |
|
42 | + $res = preg_match(self::NUMBER, $code, $matches, 0, $codeOffset); |
|
43 | + assert($res, "No number at number token position"); |
|
44 | + |
|
45 | + $match = $matches[0]; |
|
46 | + $matchLen = \strlen($match); |
|
47 | + if ($matchLen === $tokenLen) { |
|
48 | + // Original token already holds the full number. |
|
49 | + $codeOffset += $tokenLen; |
|
50 | + continue; |
|
51 | + } |
|
52 | + |
|
53 | + $tokenKind = $this->resolveIntegerOrFloatToken($match); |
|
54 | + $newTokens = [[$tokenKind, $match, $token[2]]]; |
|
55 | + |
|
56 | + $numTokens = 1; |
|
57 | + $len = $tokenLen; |
|
58 | + while ($matchLen > $len) { |
|
59 | + $nextToken = $tokens[$i + $numTokens]; |
|
60 | + $nextTokenText = \is_array($nextToken) ? $nextToken[1] : $nextToken; |
|
61 | + $nextTokenLen = \strlen($nextTokenText); |
|
62 | + |
|
63 | + $numTokens++; |
|
64 | + if ($matchLen < $len + $nextTokenLen) { |
|
65 | + // Split trailing characters into a partial token. |
|
66 | + assert(is_array($nextToken), "Partial token should be an array token"); |
|
67 | + $partialText = substr($nextTokenText, $matchLen - $len); |
|
68 | + $newTokens[] = [$nextToken[0], $partialText, $nextToken[2]]; |
|
69 | + break; |
|
70 | + } |
|
71 | + |
|
72 | + $len += $nextTokenLen; |
|
73 | + } |
|
74 | + |
|
75 | + array_splice($tokens, $i, $numTokens, $newTokens); |
|
76 | + $c -= $numTokens - \count($newTokens); |
|
77 | + $codeOffset += $matchLen; |
|
78 | + } |
|
79 | + |
|
80 | + return $tokens; |
|
81 | + } |
|
82 | + |
|
83 | + private function resolveIntegerOrFloatToken(string $str): int |
|
84 | + { |
|
85 | + $str = str_replace('_', '', $str); |
|
86 | + |
|
87 | + if (stripos($str, '0b') === 0) { |
|
88 | + $num = bindec($str); |
|
89 | + } elseif (stripos($str, '0x') === 0) { |
|
90 | + $num = hexdec($str); |
|
91 | + } elseif (stripos($str, '0') === 0 && ctype_digit($str)) { |
|
92 | + $num = octdec($str); |
|
93 | + } else { |
|
94 | + $num = +$str; |
|
95 | + } |
|
96 | + |
|
97 | + return is_float($num) ? T_DNUMBER : T_LNUMBER; |
|
98 | + } |
|
99 | + |
|
100 | + public function reverseEmulate(string $code, array $tokens): array |
|
101 | + { |
|
102 | + // Numeric separators were not legal code previously, don't bother. |
|
103 | + return $tokens; |
|
104 | + } |
|
105 | 105 | } |
@@ -9,10 +9,10 @@ |
||
9 | 9 | const BIN = '(?:0b[01]+(?:_[01]+)*)'; |
10 | 10 | const HEX = '(?:0x[0-9a-f]+(?:_[0-9a-f]+)*)'; |
11 | 11 | const DEC = '(?:[0-9]+(?:_[0-9]+)*)'; |
12 | - const SIMPLE_FLOAT = '(?:' . self::DEC . '\.' . self::DEC . '?|\.' . self::DEC . ')'; |
|
13 | - const EXP = '(?:e[+-]?' . self::DEC . ')'; |
|
14 | - const FLOAT = '(?:' . self::SIMPLE_FLOAT . self::EXP . '?|' . self::DEC . self::EXP . ')'; |
|
15 | - const NUMBER = '~' . self::FLOAT . '|' . self::BIN . '|' . self::HEX . '|' . self::DEC . '~iA'; |
|
12 | + const SIMPLE_FLOAT = '(?:'.self::DEC.'\.'.self::DEC.'?|\.'.self::DEC.')'; |
|
13 | + const EXP = '(?:e[+-]?'.self::DEC.')'; |
|
14 | + const FLOAT = '(?:'.self::SIMPLE_FLOAT.self::EXP.'?|'.self::DEC.self::EXP.')'; |
|
15 | + const NUMBER = '~'.self::FLOAT.'|'.self::BIN.'|'.self::HEX.'|'.self::DEC.'~iA'; |
|
16 | 16 | |
17 | 17 | public function getPhpVersion(): string |
18 | 18 | { |
@@ -4,8 +4,7 @@ |
||
4 | 4 | |
5 | 5 | use PhpParser\Lexer\Emulative; |
6 | 6 | |
7 | -final class NumericLiteralSeparatorEmulator extends TokenEmulator |
|
8 | -{ |
|
7 | +final class NumericLiteralSeparatorEmulator extends TokenEmulator { |
|
9 | 8 | const BIN = '(?:0b[01]+(?:_[01]+)*)'; |
10 | 9 | const HEX = '(?:0x[0-9a-f]+(?:_[0-9a-f]+)*)'; |
11 | 10 | const DEC = '(?:[0-9]+(?:_[0-9]+)*)'; |
@@ -6,71 +6,71 @@ |
||
6 | 6 | |
7 | 7 | final class FlexibleDocStringEmulator extends TokenEmulator |
8 | 8 | { |
9 | - const FLEXIBLE_DOC_STRING_REGEX = <<<'REGEX' |
|
9 | + const FLEXIBLE_DOC_STRING_REGEX = <<<'REGEX' |
|
10 | 10 | /<<<[ \t]*(['"]?)([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\1\r?\n |
11 | 11 | (?:.*\r?\n)*? |
12 | 12 | (?<indentation>\h*)\2(?![a-zA-Z0-9_\x80-\xff])(?<separator>(?:;?[\r\n])?)/x |
13 | 13 | REGEX; |
14 | 14 | |
15 | - public function getPhpVersion(): string |
|
16 | - { |
|
17 | - return Emulative::PHP_7_3; |
|
18 | - } |
|
15 | + public function getPhpVersion(): string |
|
16 | + { |
|
17 | + return Emulative::PHP_7_3; |
|
18 | + } |
|
19 | 19 | |
20 | - public function isEmulationNeeded(string $code) : bool |
|
21 | - { |
|
22 | - return strpos($code, '<<<') !== false; |
|
23 | - } |
|
20 | + public function isEmulationNeeded(string $code) : bool |
|
21 | + { |
|
22 | + return strpos($code, '<<<') !== false; |
|
23 | + } |
|
24 | 24 | |
25 | - public function emulate(string $code, array $tokens): array |
|
26 | - { |
|
27 | - // Handled by preprocessing + fixup. |
|
28 | - return $tokens; |
|
29 | - } |
|
25 | + public function emulate(string $code, array $tokens): array |
|
26 | + { |
|
27 | + // Handled by preprocessing + fixup. |
|
28 | + return $tokens; |
|
29 | + } |
|
30 | 30 | |
31 | - public function reverseEmulate(string $code, array $tokens): array |
|
32 | - { |
|
33 | - // Not supported. |
|
34 | - return $tokens; |
|
35 | - } |
|
31 | + public function reverseEmulate(string $code, array $tokens): array |
|
32 | + { |
|
33 | + // Not supported. |
|
34 | + return $tokens; |
|
35 | + } |
|
36 | 36 | |
37 | - public function preprocessCode(string $code, array &$patches): string { |
|
38 | - if (!preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) { |
|
39 | - // No heredoc/nowdoc found |
|
40 | - return $code; |
|
41 | - } |
|
37 | + public function preprocessCode(string $code, array &$patches): string { |
|
38 | + if (!preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) { |
|
39 | + // No heredoc/nowdoc found |
|
40 | + return $code; |
|
41 | + } |
|
42 | 42 | |
43 | - // Keep track of how much we need to adjust string offsets due to the modifications we |
|
44 | - // already made |
|
45 | - $posDelta = 0; |
|
46 | - foreach ($matches as $match) { |
|
47 | - $indentation = $match['indentation'][0]; |
|
48 | - $indentationStart = $match['indentation'][1]; |
|
43 | + // Keep track of how much we need to adjust string offsets due to the modifications we |
|
44 | + // already made |
|
45 | + $posDelta = 0; |
|
46 | + foreach ($matches as $match) { |
|
47 | + $indentation = $match['indentation'][0]; |
|
48 | + $indentationStart = $match['indentation'][1]; |
|
49 | 49 | |
50 | - $separator = $match['separator'][0]; |
|
51 | - $separatorStart = $match['separator'][1]; |
|
50 | + $separator = $match['separator'][0]; |
|
51 | + $separatorStart = $match['separator'][1]; |
|
52 | 52 | |
53 | - if ($indentation === '' && $separator !== '') { |
|
54 | - // Ordinary heredoc/nowdoc |
|
55 | - continue; |
|
56 | - } |
|
53 | + if ($indentation === '' && $separator !== '') { |
|
54 | + // Ordinary heredoc/nowdoc |
|
55 | + continue; |
|
56 | + } |
|
57 | 57 | |
58 | - if ($indentation !== '') { |
|
59 | - // Remove indentation |
|
60 | - $indentationLen = strlen($indentation); |
|
61 | - $code = substr_replace($code, '', $indentationStart + $posDelta, $indentationLen); |
|
62 | - $patches[] = [$indentationStart + $posDelta, 'add', $indentation]; |
|
63 | - $posDelta -= $indentationLen; |
|
64 | - } |
|
58 | + if ($indentation !== '') { |
|
59 | + // Remove indentation |
|
60 | + $indentationLen = strlen($indentation); |
|
61 | + $code = substr_replace($code, '', $indentationStart + $posDelta, $indentationLen); |
|
62 | + $patches[] = [$indentationStart + $posDelta, 'add', $indentation]; |
|
63 | + $posDelta -= $indentationLen; |
|
64 | + } |
|
65 | 65 | |
66 | - if ($separator === '') { |
|
67 | - // Insert newline as separator |
|
68 | - $code = substr_replace($code, "\n", $separatorStart + $posDelta, 0); |
|
69 | - $patches[] = [$separatorStart + $posDelta, 'remove', "\n"]; |
|
70 | - $posDelta += 1; |
|
71 | - } |
|
72 | - } |
|
66 | + if ($separator === '') { |
|
67 | + // Insert newline as separator |
|
68 | + $code = substr_replace($code, "\n", $separatorStart + $posDelta, 0); |
|
69 | + $patches[] = [$separatorStart + $posDelta, 'remove', "\n"]; |
|
70 | + $posDelta += 1; |
|
71 | + } |
|
72 | + } |
|
73 | 73 | |
74 | - return $code; |
|
75 | - } |
|
74 | + return $code; |
|
75 | + } |
|
76 | 76 | } |
@@ -35,7 +35,7 @@ |
||
35 | 35 | } |
36 | 36 | |
37 | 37 | public function preprocessCode(string $code, array &$patches): string { |
38 | - if (!preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) { |
|
38 | + if (!preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) { |
|
39 | 39 | // No heredoc/nowdoc found |
40 | 40 | return $code; |
41 | 41 | } |
@@ -4,8 +4,7 @@ |
||
4 | 4 | |
5 | 5 | use PhpParser\Lexer\Emulative; |
6 | 6 | |
7 | -final class FlexibleDocStringEmulator extends TokenEmulator |
|
8 | -{ |
|
7 | +final class FlexibleDocStringEmulator extends TokenEmulator { |
|
9 | 8 | const FLEXIBLE_DOC_STRING_REGEX = <<<'REGEX' |
10 | 9 | /<<<[ \t]*(['"]?)([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\1\r?\n |
11 | 10 | (?:.*\r?\n)*? |
@@ -4,59 +4,59 @@ |
||
4 | 4 | |
5 | 5 | abstract class KeywordEmulator extends TokenEmulator |
6 | 6 | { |
7 | - abstract function getKeywordString(): string; |
|
8 | - abstract function getKeywordToken(): int; |
|
9 | - |
|
10 | - public function isEmulationNeeded(string $code): bool |
|
11 | - { |
|
12 | - return strpos(strtolower($code), $this->getKeywordString()) !== false; |
|
13 | - } |
|
14 | - |
|
15 | - protected function isKeywordContext(array $tokens, int $pos): bool |
|
16 | - { |
|
17 | - $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos); |
|
18 | - return $previousNonSpaceToken === null || $previousNonSpaceToken[0] !== \T_OBJECT_OPERATOR; |
|
19 | - } |
|
20 | - |
|
21 | - public function emulate(string $code, array $tokens): array |
|
22 | - { |
|
23 | - $keywordString = $this->getKeywordString(); |
|
24 | - foreach ($tokens as $i => $token) { |
|
25 | - if ($token[0] === T_STRING && strtolower($token[1]) === $keywordString |
|
26 | - && $this->isKeywordContext($tokens, $i)) { |
|
27 | - $tokens[$i][0] = $this->getKeywordToken(); |
|
28 | - } |
|
29 | - } |
|
30 | - |
|
31 | - return $tokens; |
|
32 | - } |
|
33 | - |
|
34 | - /** |
|
35 | - * @param mixed[] $tokens |
|
36 | - * @return array|string|null |
|
37 | - */ |
|
38 | - private function getPreviousNonSpaceToken(array $tokens, int $start) |
|
39 | - { |
|
40 | - for ($i = $start - 1; $i >= 0; --$i) { |
|
41 | - if ($tokens[$i][0] === T_WHITESPACE) { |
|
42 | - continue; |
|
43 | - } |
|
44 | - |
|
45 | - return $tokens[$i]; |
|
46 | - } |
|
47 | - |
|
48 | - return null; |
|
49 | - } |
|
50 | - |
|
51 | - public function reverseEmulate(string $code, array $tokens): array |
|
52 | - { |
|
53 | - $keywordToken = $this->getKeywordToken(); |
|
54 | - foreach ($tokens as $i => $token) { |
|
55 | - if ($token[0] === $keywordToken) { |
|
56 | - $tokens[$i][0] = \T_STRING; |
|
57 | - } |
|
58 | - } |
|
59 | - |
|
60 | - return $tokens; |
|
61 | - } |
|
7 | + abstract function getKeywordString(): string; |
|
8 | + abstract function getKeywordToken(): int; |
|
9 | + |
|
10 | + public function isEmulationNeeded(string $code): bool |
|
11 | + { |
|
12 | + return strpos(strtolower($code), $this->getKeywordString()) !== false; |
|
13 | + } |
|
14 | + |
|
15 | + protected function isKeywordContext(array $tokens, int $pos): bool |
|
16 | + { |
|
17 | + $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos); |
|
18 | + return $previousNonSpaceToken === null || $previousNonSpaceToken[0] !== \T_OBJECT_OPERATOR; |
|
19 | + } |
|
20 | + |
|
21 | + public function emulate(string $code, array $tokens): array |
|
22 | + { |
|
23 | + $keywordString = $this->getKeywordString(); |
|
24 | + foreach ($tokens as $i => $token) { |
|
25 | + if ($token[0] === T_STRING && strtolower($token[1]) === $keywordString |
|
26 | + && $this->isKeywordContext($tokens, $i)) { |
|
27 | + $tokens[$i][0] = $this->getKeywordToken(); |
|
28 | + } |
|
29 | + } |
|
30 | + |
|
31 | + return $tokens; |
|
32 | + } |
|
33 | + |
|
34 | + /** |
|
35 | + * @param mixed[] $tokens |
|
36 | + * @return array|string|null |
|
37 | + */ |
|
38 | + private function getPreviousNonSpaceToken(array $tokens, int $start) |
|
39 | + { |
|
40 | + for ($i = $start - 1; $i >= 0; --$i) { |
|
41 | + if ($tokens[$i][0] === T_WHITESPACE) { |
|
42 | + continue; |
|
43 | + } |
|
44 | + |
|
45 | + return $tokens[$i]; |
|
46 | + } |
|
47 | + |
|
48 | + return null; |
|
49 | + } |
|
50 | + |
|
51 | + public function reverseEmulate(string $code, array $tokens): array |
|
52 | + { |
|
53 | + $keywordToken = $this->getKeywordToken(); |
|
54 | + foreach ($tokens as $i => $token) { |
|
55 | + if ($token[0] === $keywordToken) { |
|
56 | + $tokens[$i][0] = \T_STRING; |
|
57 | + } |
|
58 | + } |
|
59 | + |
|
60 | + return $tokens; |
|
61 | + } |
|
62 | 62 | } |
@@ -2,8 +2,7 @@ |
||
2 | 2 | |
3 | 3 | namespace PhpParser\Lexer\TokenEmulator; |
4 | 4 | |
5 | -abstract class KeywordEmulator extends TokenEmulator |
|
6 | -{ |
|
5 | +abstract class KeywordEmulator extends TokenEmulator { |
|
7 | 6 | abstract function getKeywordString(): string; |
8 | 7 | abstract function getKeywordToken(): int; |
9 | 8 |
@@ -6,18 +6,18 @@ |
||
6 | 6 | |
7 | 7 | final class FnTokenEmulator extends KeywordEmulator |
8 | 8 | { |
9 | - public function getPhpVersion(): string |
|
10 | - { |
|
11 | - return Emulative::PHP_7_4; |
|
12 | - } |
|
9 | + public function getPhpVersion(): string |
|
10 | + { |
|
11 | + return Emulative::PHP_7_4; |
|
12 | + } |
|
13 | 13 | |
14 | - public function getKeywordString(): string |
|
15 | - { |
|
16 | - return 'fn'; |
|
17 | - } |
|
14 | + public function getKeywordString(): string |
|
15 | + { |
|
16 | + return 'fn'; |
|
17 | + } |
|
18 | 18 | |
19 | - public function getKeywordToken(): int |
|
20 | - { |
|
21 | - return \T_FN; |
|
22 | - } |
|
19 | + public function getKeywordToken(): int |
|
20 | + { |
|
21 | + return \T_FN; |
|
22 | + } |
|
23 | 23 | } |
24 | 24 | \ No newline at end of file |
@@ -4,8 +4,7 @@ |
||
4 | 4 | |
5 | 5 | use PhpParser\Lexer\Emulative; |
6 | 6 | |
7 | -final class FnTokenEmulator extends KeywordEmulator |
|
8 | -{ |
|
7 | +final class FnTokenEmulator extends KeywordEmulator { |
|
9 | 8 | public function getPhpVersion(): string |
10 | 9 | { |
11 | 10 | return Emulative::PHP_7_4; |
@@ -21,231 +21,231 @@ |
||
21 | 21 | |
22 | 22 | class Emulative extends Lexer |
23 | 23 | { |
24 | - const PHP_7_3 = '7.3dev'; |
|
25 | - const PHP_7_4 = '7.4dev'; |
|
26 | - const PHP_8_0 = '8.0dev'; |
|
27 | - const PHP_8_1 = '8.1dev'; |
|
28 | - const PHP_8_2 = '8.2dev'; |
|
29 | - |
|
30 | - /** @var mixed[] Patches used to reverse changes introduced in the code */ |
|
31 | - private $patches = []; |
|
32 | - |
|
33 | - /** @var TokenEmulator[] */ |
|
34 | - private $emulators = []; |
|
35 | - |
|
36 | - /** @var string */ |
|
37 | - private $targetPhpVersion; |
|
38 | - |
|
39 | - /** |
|
40 | - * @param mixed[] $options Lexer options. In addition to the usual options, |
|
41 | - * accepts a 'phpVersion' string that specifies the |
|
42 | - * version to emulate. Defaults to newest supported. |
|
43 | - */ |
|
44 | - public function __construct(array $options = []) |
|
45 | - { |
|
46 | - $this->targetPhpVersion = $options['phpVersion'] ?? Emulative::PHP_8_2; |
|
47 | - unset($options['phpVersion']); |
|
48 | - |
|
49 | - parent::__construct($options); |
|
50 | - |
|
51 | - $emulators = [ |
|
52 | - new FlexibleDocStringEmulator(), |
|
53 | - new FnTokenEmulator(), |
|
54 | - new MatchTokenEmulator(), |
|
55 | - new CoaleseEqualTokenEmulator(), |
|
56 | - new NumericLiteralSeparatorEmulator(), |
|
57 | - new NullsafeTokenEmulator(), |
|
58 | - new AttributeEmulator(), |
|
59 | - new EnumTokenEmulator(), |
|
60 | - new ReadonlyTokenEmulator(), |
|
61 | - new ExplicitOctalEmulator(), |
|
62 | - new ReadonlyFunctionTokenEmulator(), |
|
63 | - ]; |
|
64 | - |
|
65 | - // Collect emulators that are relevant for the PHP version we're running |
|
66 | - // and the PHP version we're targeting for emulation. |
|
67 | - foreach ($emulators as $emulator) { |
|
68 | - $emulatorPhpVersion = $emulator->getPhpVersion(); |
|
69 | - if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) { |
|
70 | - $this->emulators[] = $emulator; |
|
71 | - } else if ($this->isReverseEmulationNeeded($emulatorPhpVersion)) { |
|
72 | - $this->emulators[] = new ReverseEmulator($emulator); |
|
73 | - } |
|
74 | - } |
|
75 | - } |
|
76 | - |
|
77 | - public function startLexing(string $code, ?ErrorHandler $errorHandler = null) { |
|
78 | - $emulators = array_filter($this->emulators, function($emulator) use($code) { |
|
79 | - return $emulator->isEmulationNeeded($code); |
|
80 | - }); |
|
81 | - |
|
82 | - if (empty($emulators)) { |
|
83 | - // Nothing to emulate, yay |
|
84 | - parent::startLexing($code, $errorHandler); |
|
85 | - return; |
|
86 | - } |
|
87 | - |
|
88 | - $this->patches = []; |
|
89 | - foreach ($emulators as $emulator) { |
|
90 | - $code = $emulator->preprocessCode($code, $this->patches); |
|
91 | - } |
|
92 | - |
|
93 | - $collector = new ErrorHandler\Collecting(); |
|
94 | - parent::startLexing($code, $collector); |
|
95 | - $this->sortPatches(); |
|
96 | - $this->fixupTokens(); |
|
97 | - |
|
98 | - $errors = $collector->getErrors(); |
|
99 | - if (!empty($errors)) { |
|
100 | - $this->fixupErrors($errors); |
|
101 | - foreach ($errors as $error) { |
|
102 | - $errorHandler->handleError($error); |
|
103 | - } |
|
104 | - } |
|
105 | - |
|
106 | - foreach ($emulators as $emulator) { |
|
107 | - $this->tokens = $emulator->emulate($code, $this->tokens); |
|
108 | - } |
|
109 | - } |
|
110 | - |
|
111 | - private function isForwardEmulationNeeded(string $emulatorPhpVersion): bool { |
|
112 | - return version_compare(\PHP_VERSION, $emulatorPhpVersion, '<') |
|
113 | - && version_compare($this->targetPhpVersion, $emulatorPhpVersion, '>='); |
|
114 | - } |
|
115 | - |
|
116 | - private function isReverseEmulationNeeded(string $emulatorPhpVersion): bool { |
|
117 | - return version_compare(\PHP_VERSION, $emulatorPhpVersion, '>=') |
|
118 | - && version_compare($this->targetPhpVersion, $emulatorPhpVersion, '<'); |
|
119 | - } |
|
120 | - |
|
121 | - private function sortPatches() |
|
122 | - { |
|
123 | - // Patches may be contributed by different emulators. |
|
124 | - // Make sure they are sorted by increasing patch position. |
|
125 | - usort($this->patches, function($p1, $p2) { |
|
126 | - return $p1[0] <=> $p2[0]; |
|
127 | - }); |
|
128 | - } |
|
129 | - |
|
130 | - private function fixupTokens() |
|
131 | - { |
|
132 | - if (\count($this->patches) === 0) { |
|
133 | - return; |
|
134 | - } |
|
135 | - |
|
136 | - // Load first patch |
|
137 | - $patchIdx = 0; |
|
138 | - |
|
139 | - list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; |
|
140 | - |
|
141 | - // We use a manual loop over the tokens, because we modify the array on the fly |
|
142 | - $pos = 0; |
|
143 | - for ($i = 0, $c = \count($this->tokens); $i < $c; $i++) { |
|
144 | - $token = $this->tokens[$i]; |
|
145 | - if (\is_string($token)) { |
|
146 | - if ($patchPos === $pos) { |
|
147 | - // Only support replacement for string tokens. |
|
148 | - assert($patchType === 'replace'); |
|
149 | - $this->tokens[$i] = $patchText; |
|
150 | - |
|
151 | - // Fetch the next patch |
|
152 | - $patchIdx++; |
|
153 | - if ($patchIdx >= \count($this->patches)) { |
|
154 | - // No more patches, we're done |
|
155 | - return; |
|
156 | - } |
|
157 | - list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; |
|
158 | - } |
|
159 | - |
|
160 | - $pos += \strlen($token); |
|
161 | - continue; |
|
162 | - } |
|
163 | - |
|
164 | - $len = \strlen($token[1]); |
|
165 | - $posDelta = 0; |
|
166 | - while ($patchPos >= $pos && $patchPos < $pos + $len) { |
|
167 | - $patchTextLen = \strlen($patchText); |
|
168 | - if ($patchType === 'remove') { |
|
169 | - if ($patchPos === $pos && $patchTextLen === $len) { |
|
170 | - // Remove token entirely |
|
171 | - array_splice($this->tokens, $i, 1, []); |
|
172 | - $i--; |
|
173 | - $c--; |
|
174 | - } else { |
|
175 | - // Remove from token string |
|
176 | - $this->tokens[$i][1] = substr_replace( |
|
177 | - $token[1], '', $patchPos - $pos + $posDelta, $patchTextLen |
|
178 | - ); |
|
179 | - $posDelta -= $patchTextLen; |
|
180 | - } |
|
181 | - } elseif ($patchType === 'add') { |
|
182 | - // Insert into the token string |
|
183 | - $this->tokens[$i][1] = substr_replace( |
|
184 | - $token[1], $patchText, $patchPos - $pos + $posDelta, 0 |
|
185 | - ); |
|
186 | - $posDelta += $patchTextLen; |
|
187 | - } else if ($patchType === 'replace') { |
|
188 | - // Replace inside the token string |
|
189 | - $this->tokens[$i][1] = substr_replace( |
|
190 | - $token[1], $patchText, $patchPos - $pos + $posDelta, $patchTextLen |
|
191 | - ); |
|
192 | - } else { |
|
193 | - assert(false); |
|
194 | - } |
|
195 | - |
|
196 | - // Fetch the next patch |
|
197 | - $patchIdx++; |
|
198 | - if ($patchIdx >= \count($this->patches)) { |
|
199 | - // No more patches, we're done |
|
200 | - return; |
|
201 | - } |
|
202 | - |
|
203 | - list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; |
|
204 | - |
|
205 | - // Multiple patches may apply to the same token. Reload the current one to check |
|
206 | - // If the new patch applies |
|
207 | - $token = $this->tokens[$i]; |
|
208 | - } |
|
209 | - |
|
210 | - $pos += $len; |
|
211 | - } |
|
212 | - |
|
213 | - // A patch did not apply |
|
214 | - assert(false); |
|
215 | - } |
|
216 | - |
|
217 | - /** |
|
218 | - * Fixup line and position information in errors. |
|
219 | - * |
|
220 | - * @param Error[] $errors |
|
221 | - */ |
|
222 | - private function fixupErrors(array $errors) { |
|
223 | - foreach ($errors as $error) { |
|
224 | - $attrs = $error->getAttributes(); |
|
225 | - |
|
226 | - $posDelta = 0; |
|
227 | - $lineDelta = 0; |
|
228 | - foreach ($this->patches as $patch) { |
|
229 | - list($patchPos, $patchType, $patchText) = $patch; |
|
230 | - if ($patchPos >= $attrs['startFilePos']) { |
|
231 | - // No longer relevant |
|
232 | - break; |
|
233 | - } |
|
234 | - |
|
235 | - if ($patchType === 'add') { |
|
236 | - $posDelta += strlen($patchText); |
|
237 | - $lineDelta += substr_count($patchText, "\n"); |
|
238 | - } else if ($patchType === 'remove') { |
|
239 | - $posDelta -= strlen($patchText); |
|
240 | - $lineDelta -= substr_count($patchText, "\n"); |
|
241 | - } |
|
242 | - } |
|
243 | - |
|
244 | - $attrs['startFilePos'] += $posDelta; |
|
245 | - $attrs['endFilePos'] += $posDelta; |
|
246 | - $attrs['startLine'] += $lineDelta; |
|
247 | - $attrs['endLine'] += $lineDelta; |
|
248 | - $error->setAttributes($attrs); |
|
249 | - } |
|
250 | - } |
|
24 | + const PHP_7_3 = '7.3dev'; |
|
25 | + const PHP_7_4 = '7.4dev'; |
|
26 | + const PHP_8_0 = '8.0dev'; |
|
27 | + const PHP_8_1 = '8.1dev'; |
|
28 | + const PHP_8_2 = '8.2dev'; |
|
29 | + |
|
30 | + /** @var mixed[] Patches used to reverse changes introduced in the code */ |
|
31 | + private $patches = []; |
|
32 | + |
|
33 | + /** @var TokenEmulator[] */ |
|
34 | + private $emulators = []; |
|
35 | + |
|
36 | + /** @var string */ |
|
37 | + private $targetPhpVersion; |
|
38 | + |
|
39 | + /** |
|
40 | + * @param mixed[] $options Lexer options. In addition to the usual options, |
|
41 | + * accepts a 'phpVersion' string that specifies the |
|
42 | + * version to emulate. Defaults to newest supported. |
|
43 | + */ |
|
44 | + public function __construct(array $options = []) |
|
45 | + { |
|
46 | + $this->targetPhpVersion = $options['phpVersion'] ?? Emulative::PHP_8_2; |
|
47 | + unset($options['phpVersion']); |
|
48 | + |
|
49 | + parent::__construct($options); |
|
50 | + |
|
51 | + $emulators = [ |
|
52 | + new FlexibleDocStringEmulator(), |
|
53 | + new FnTokenEmulator(), |
|
54 | + new MatchTokenEmulator(), |
|
55 | + new CoaleseEqualTokenEmulator(), |
|
56 | + new NumericLiteralSeparatorEmulator(), |
|
57 | + new NullsafeTokenEmulator(), |
|
58 | + new AttributeEmulator(), |
|
59 | + new EnumTokenEmulator(), |
|
60 | + new ReadonlyTokenEmulator(), |
|
61 | + new ExplicitOctalEmulator(), |
|
62 | + new ReadonlyFunctionTokenEmulator(), |
|
63 | + ]; |
|
64 | + |
|
65 | + // Collect emulators that are relevant for the PHP version we're running |
|
66 | + // and the PHP version we're targeting for emulation. |
|
67 | + foreach ($emulators as $emulator) { |
|
68 | + $emulatorPhpVersion = $emulator->getPhpVersion(); |
|
69 | + if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) { |
|
70 | + $this->emulators[] = $emulator; |
|
71 | + } else if ($this->isReverseEmulationNeeded($emulatorPhpVersion)) { |
|
72 | + $this->emulators[] = new ReverseEmulator($emulator); |
|
73 | + } |
|
74 | + } |
|
75 | + } |
|
76 | + |
|
77 | + public function startLexing(string $code, ?ErrorHandler $errorHandler = null) { |
|
78 | + $emulators = array_filter($this->emulators, function($emulator) use($code) { |
|
79 | + return $emulator->isEmulationNeeded($code); |
|
80 | + }); |
|
81 | + |
|
82 | + if (empty($emulators)) { |
|
83 | + // Nothing to emulate, yay |
|
84 | + parent::startLexing($code, $errorHandler); |
|
85 | + return; |
|
86 | + } |
|
87 | + |
|
88 | + $this->patches = []; |
|
89 | + foreach ($emulators as $emulator) { |
|
90 | + $code = $emulator->preprocessCode($code, $this->patches); |
|
91 | + } |
|
92 | + |
|
93 | + $collector = new ErrorHandler\Collecting(); |
|
94 | + parent::startLexing($code, $collector); |
|
95 | + $this->sortPatches(); |
|
96 | + $this->fixupTokens(); |
|
97 | + |
|
98 | + $errors = $collector->getErrors(); |
|
99 | + if (!empty($errors)) { |
|
100 | + $this->fixupErrors($errors); |
|
101 | + foreach ($errors as $error) { |
|
102 | + $errorHandler->handleError($error); |
|
103 | + } |
|
104 | + } |
|
105 | + |
|
106 | + foreach ($emulators as $emulator) { |
|
107 | + $this->tokens = $emulator->emulate($code, $this->tokens); |
|
108 | + } |
|
109 | + } |
|
110 | + |
|
111 | + private function isForwardEmulationNeeded(string $emulatorPhpVersion): bool { |
|
112 | + return version_compare(\PHP_VERSION, $emulatorPhpVersion, '<') |
|
113 | + && version_compare($this->targetPhpVersion, $emulatorPhpVersion, '>='); |
|
114 | + } |
|
115 | + |
|
116 | + private function isReverseEmulationNeeded(string $emulatorPhpVersion): bool { |
|
117 | + return version_compare(\PHP_VERSION, $emulatorPhpVersion, '>=') |
|
118 | + && version_compare($this->targetPhpVersion, $emulatorPhpVersion, '<'); |
|
119 | + } |
|
120 | + |
|
121 | + private function sortPatches() |
|
122 | + { |
|
123 | + // Patches may be contributed by different emulators. |
|
124 | + // Make sure they are sorted by increasing patch position. |
|
125 | + usort($this->patches, function($p1, $p2) { |
|
126 | + return $p1[0] <=> $p2[0]; |
|
127 | + }); |
|
128 | + } |
|
129 | + |
|
130 | + private function fixupTokens() |
|
131 | + { |
|
132 | + if (\count($this->patches) === 0) { |
|
133 | + return; |
|
134 | + } |
|
135 | + |
|
136 | + // Load first patch |
|
137 | + $patchIdx = 0; |
|
138 | + |
|
139 | + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; |
|
140 | + |
|
141 | + // We use a manual loop over the tokens, because we modify the array on the fly |
|
142 | + $pos = 0; |
|
143 | + for ($i = 0, $c = \count($this->tokens); $i < $c; $i++) { |
|
144 | + $token = $this->tokens[$i]; |
|
145 | + if (\is_string($token)) { |
|
146 | + if ($patchPos === $pos) { |
|
147 | + // Only support replacement for string tokens. |
|
148 | + assert($patchType === 'replace'); |
|
149 | + $this->tokens[$i] = $patchText; |
|
150 | + |
|
151 | + // Fetch the next patch |
|
152 | + $patchIdx++; |
|
153 | + if ($patchIdx >= \count($this->patches)) { |
|
154 | + // No more patches, we're done |
|
155 | + return; |
|
156 | + } |
|
157 | + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; |
|
158 | + } |
|
159 | + |
|
160 | + $pos += \strlen($token); |
|
161 | + continue; |
|
162 | + } |
|
163 | + |
|
164 | + $len = \strlen($token[1]); |
|
165 | + $posDelta = 0; |
|
166 | + while ($patchPos >= $pos && $patchPos < $pos + $len) { |
|
167 | + $patchTextLen = \strlen($patchText); |
|
168 | + if ($patchType === 'remove') { |
|
169 | + if ($patchPos === $pos && $patchTextLen === $len) { |
|
170 | + // Remove token entirely |
|
171 | + array_splice($this->tokens, $i, 1, []); |
|
172 | + $i--; |
|
173 | + $c--; |
|
174 | + } else { |
|
175 | + // Remove from token string |
|
176 | + $this->tokens[$i][1] = substr_replace( |
|
177 | + $token[1], '', $patchPos - $pos + $posDelta, $patchTextLen |
|
178 | + ); |
|
179 | + $posDelta -= $patchTextLen; |
|
180 | + } |
|
181 | + } elseif ($patchType === 'add') { |
|
182 | + // Insert into the token string |
|
183 | + $this->tokens[$i][1] = substr_replace( |
|
184 | + $token[1], $patchText, $patchPos - $pos + $posDelta, 0 |
|
185 | + ); |
|
186 | + $posDelta += $patchTextLen; |
|
187 | + } else if ($patchType === 'replace') { |
|
188 | + // Replace inside the token string |
|
189 | + $this->tokens[$i][1] = substr_replace( |
|
190 | + $token[1], $patchText, $patchPos - $pos + $posDelta, $patchTextLen |
|
191 | + ); |
|
192 | + } else { |
|
193 | + assert(false); |
|
194 | + } |
|
195 | + |
|
196 | + // Fetch the next patch |
|
197 | + $patchIdx++; |
|
198 | + if ($patchIdx >= \count($this->patches)) { |
|
199 | + // No more patches, we're done |
|
200 | + return; |
|
201 | + } |
|
202 | + |
|
203 | + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; |
|
204 | + |
|
205 | + // Multiple patches may apply to the same token. Reload the current one to check |
|
206 | + // If the new patch applies |
|
207 | + $token = $this->tokens[$i]; |
|
208 | + } |
|
209 | + |
|
210 | + $pos += $len; |
|
211 | + } |
|
212 | + |
|
213 | + // A patch did not apply |
|
214 | + assert(false); |
|
215 | + } |
|
216 | + |
|
217 | + /** |
|
218 | + * Fixup line and position information in errors. |
|
219 | + * |
|
220 | + * @param Error[] $errors |
|
221 | + */ |
|
222 | + private function fixupErrors(array $errors) { |
|
223 | + foreach ($errors as $error) { |
|
224 | + $attrs = $error->getAttributes(); |
|
225 | + |
|
226 | + $posDelta = 0; |
|
227 | + $lineDelta = 0; |
|
228 | + foreach ($this->patches as $patch) { |
|
229 | + list($patchPos, $patchType, $patchText) = $patch; |
|
230 | + if ($patchPos >= $attrs['startFilePos']) { |
|
231 | + // No longer relevant |
|
232 | + break; |
|
233 | + } |
|
234 | + |
|
235 | + if ($patchType === 'add') { |
|
236 | + $posDelta += strlen($patchText); |
|
237 | + $lineDelta += substr_count($patchText, "\n"); |
|
238 | + } else if ($patchType === 'remove') { |
|
239 | + $posDelta -= strlen($patchText); |
|
240 | + $lineDelta -= substr_count($patchText, "\n"); |
|
241 | + } |
|
242 | + } |
|
243 | + |
|
244 | + $attrs['startFilePos'] += $posDelta; |
|
245 | + $attrs['endFilePos'] += $posDelta; |
|
246 | + $attrs['startLine'] += $lineDelta; |
|
247 | + $attrs['endLine'] += $lineDelta; |
|
248 | + $error->setAttributes($attrs); |
|
249 | + } |
|
250 | + } |
|
251 | 251 | } |
@@ -19,8 +19,7 @@ |
||
19 | 19 | use PhpParser\Lexer\TokenEmulator\ReverseEmulator; |
20 | 20 | use PhpParser\Lexer\TokenEmulator\TokenEmulator; |
21 | 21 | |
22 | -class Emulative extends Lexer |
|
23 | -{ |
|
22 | +class Emulative extends Lexer { |
|
24 | 23 | const PHP_7_3 = '7.3dev'; |
25 | 24 | const PHP_7_4 = '7.4dev'; |
26 | 25 | const PHP_8_0 = '8.0dev'; |
@@ -15,27 +15,27 @@ |
||
15 | 15 | */ |
16 | 16 | final class ParentConnectingVisitor extends NodeVisitorAbstract |
17 | 17 | { |
18 | - /** |
|
19 | - * @var Node[] |
|
20 | - */ |
|
21 | - private $stack = []; |
|
18 | + /** |
|
19 | + * @var Node[] |
|
20 | + */ |
|
21 | + private $stack = []; |
|
22 | 22 | |
23 | - public function beforeTraverse(array $nodes) |
|
24 | - { |
|
25 | - $this->stack = []; |
|
26 | - } |
|
23 | + public function beforeTraverse(array $nodes) |
|
24 | + { |
|
25 | + $this->stack = []; |
|
26 | + } |
|
27 | 27 | |
28 | - public function enterNode(Node $node) |
|
29 | - { |
|
30 | - if (!empty($this->stack)) { |
|
31 | - $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); |
|
32 | - } |
|
28 | + public function enterNode(Node $node) |
|
29 | + { |
|
30 | + if (!empty($this->stack)) { |
|
31 | + $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); |
|
32 | + } |
|
33 | 33 | |
34 | - $this->stack[] = $node; |
|
35 | - } |
|
34 | + $this->stack[] = $node; |
|
35 | + } |
|
36 | 36 | |
37 | - public function leaveNode(Node $node) |
|
38 | - { |
|
39 | - array_pop($this->stack); |
|
40 | - } |
|
37 | + public function leaveNode(Node $node) |
|
38 | + { |
|
39 | + array_pop($this->stack); |
|
40 | + } |
|
41 | 41 | } |
@@ -13,8 +13,7 @@ |
||
13 | 13 | * On the child node, the parent node can be accessed through |
14 | 14 | * <code>$node->getAttribute('parent')</code>. |
15 | 15 | */ |
16 | -final class ParentConnectingVisitor extends NodeVisitorAbstract |
|
17 | -{ |
|
16 | +final class ParentConnectingVisitor extends NodeVisitorAbstract { |
|
18 | 17 | /** |
19 | 18 | * @var Node[] |
20 | 19 | */ |
@@ -16,37 +16,37 @@ |
||
16 | 16 | */ |
17 | 17 | final class NodeConnectingVisitor extends NodeVisitorAbstract |
18 | 18 | { |
19 | - /** |
|
20 | - * @var Node[] |
|
21 | - */ |
|
22 | - private $stack = []; |
|
23 | - |
|
24 | - /** |
|
25 | - * @var ?Node |
|
26 | - */ |
|
27 | - private $previous; |
|
28 | - |
|
29 | - public function beforeTraverse(array $nodes) { |
|
30 | - $this->stack = []; |
|
31 | - $this->previous = null; |
|
32 | - } |
|
33 | - |
|
34 | - public function enterNode(Node $node) { |
|
35 | - if (!empty($this->stack)) { |
|
36 | - $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); |
|
37 | - } |
|
38 | - |
|
39 | - if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) { |
|
40 | - $node->setAttribute('previous', $this->previous); |
|
41 | - $this->previous->setAttribute('next', $node); |
|
42 | - } |
|
43 | - |
|
44 | - $this->stack[] = $node; |
|
45 | - } |
|
46 | - |
|
47 | - public function leaveNode(Node $node) { |
|
48 | - $this->previous = $node; |
|
49 | - |
|
50 | - array_pop($this->stack); |
|
51 | - } |
|
19 | + /** |
|
20 | + * @var Node[] |
|
21 | + */ |
|
22 | + private $stack = []; |
|
23 | + |
|
24 | + /** |
|
25 | + * @var ?Node |
|
26 | + */ |
|
27 | + private $previous; |
|
28 | + |
|
29 | + public function beforeTraverse(array $nodes) { |
|
30 | + $this->stack = []; |
|
31 | + $this->previous = null; |
|
32 | + } |
|
33 | + |
|
34 | + public function enterNode(Node $node) { |
|
35 | + if (!empty($this->stack)) { |
|
36 | + $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); |
|
37 | + } |
|
38 | + |
|
39 | + if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) { |
|
40 | + $node->setAttribute('previous', $this->previous); |
|
41 | + $this->previous->setAttribute('next', $node); |
|
42 | + } |
|
43 | + |
|
44 | + $this->stack[] = $node; |
|
45 | + } |
|
46 | + |
|
47 | + public function leaveNode(Node $node) { |
|
48 | + $this->previous = $node; |
|
49 | + |
|
50 | + array_pop($this->stack); |
|
51 | + } |
|
52 | 52 | } |
@@ -14,8 +14,7 @@ |
||
14 | 14 | * node can be accessed through <code>$node->getAttribute('previous')</code>, |
15 | 15 | * and the next node can be accessed through <code>$node->getAttribute('next')</code>. |
16 | 16 | */ |
17 | -final class NodeConnectingVisitor extends NodeVisitorAbstract |
|
18 | -{ |
|
17 | +final class NodeConnectingVisitor extends NodeVisitorAbstract { |
|
19 | 18 | /** |
20 | 19 | * @var Node[] |
21 | 20 | */ |
@@ -11,38 +11,38 @@ |
||
11 | 11 | */ |
12 | 12 | class FindingVisitor extends NodeVisitorAbstract |
13 | 13 | { |
14 | - /** @var callable Filter callback */ |
|
15 | - protected $filterCallback; |
|
16 | - /** @var Node[] Found nodes */ |
|
17 | - protected $foundNodes; |
|
18 | - |
|
19 | - public function __construct(callable $filterCallback) { |
|
20 | - $this->filterCallback = $filterCallback; |
|
21 | - } |
|
22 | - |
|
23 | - /** |
|
24 | - * Get found nodes satisfying the filter callback. |
|
25 | - * |
|
26 | - * Nodes are returned in pre-order. |
|
27 | - * |
|
28 | - * @return Node[] Found nodes |
|
29 | - */ |
|
30 | - public function getFoundNodes() : array { |
|
31 | - return $this->foundNodes; |
|
32 | - } |
|
33 | - |
|
34 | - public function beforeTraverse(array $nodes) { |
|
35 | - $this->foundNodes = []; |
|
36 | - |
|
37 | - return null; |
|
38 | - } |
|
39 | - |
|
40 | - public function enterNode(Node $node) { |
|
41 | - $filterCallback = $this->filterCallback; |
|
42 | - if ($filterCallback($node)) { |
|
43 | - $this->foundNodes[] = $node; |
|
44 | - } |
|
45 | - |
|
46 | - return null; |
|
47 | - } |
|
14 | + /** @var callable Filter callback */ |
|
15 | + protected $filterCallback; |
|
16 | + /** @var Node[] Found nodes */ |
|
17 | + protected $foundNodes; |
|
18 | + |
|
19 | + public function __construct(callable $filterCallback) { |
|
20 | + $this->filterCallback = $filterCallback; |
|
21 | + } |
|
22 | + |
|
23 | + /** |
|
24 | + * Get found nodes satisfying the filter callback. |
|
25 | + * |
|
26 | + * Nodes are returned in pre-order. |
|
27 | + * |
|
28 | + * @return Node[] Found nodes |
|
29 | + */ |
|
30 | + public function getFoundNodes() : array { |
|
31 | + return $this->foundNodes; |
|
32 | + } |
|
33 | + |
|
34 | + public function beforeTraverse(array $nodes) { |
|
35 | + $this->foundNodes = []; |
|
36 | + |
|
37 | + return null; |
|
38 | + } |
|
39 | + |
|
40 | + public function enterNode(Node $node) { |
|
41 | + $filterCallback = $this->filterCallback; |
|
42 | + if ($filterCallback($node)) { |
|
43 | + $this->foundNodes[] = $node; |
|
44 | + } |
|
45 | + |
|
46 | + return null; |
|
47 | + } |
|
48 | 48 | } |
@@ -9,8 +9,7 @@ |
||
9 | 9 | * This visitor can be used to find and collect all nodes satisfying some criterion determined by |
10 | 10 | * a filter callback. |
11 | 11 | */ |
12 | -class FindingVisitor extends NodeVisitorAbstract |
|
13 | -{ |
|
12 | +class FindingVisitor extends NodeVisitorAbstract { |
|
14 | 13 | /** @var callable Filter callback */ |
15 | 14 | protected $filterCallback; |
16 | 15 | /** @var Node[] Found nodes */ |
@@ -13,248 +13,248 @@ |
||
13 | 13 | |
14 | 14 | class NameResolver extends NodeVisitorAbstract |
15 | 15 | { |
16 | - /** @var NameContext Naming context */ |
|
17 | - protected $nameContext; |
|
16 | + /** @var NameContext Naming context */ |
|
17 | + protected $nameContext; |
|
18 | 18 | |
19 | - /** @var bool Whether to preserve original names */ |
|
20 | - protected $preserveOriginalNames; |
|
19 | + /** @var bool Whether to preserve original names */ |
|
20 | + protected $preserveOriginalNames; |
|
21 | 21 | |
22 | - /** @var bool Whether to replace resolved nodes in place, or to add resolvedNode attributes */ |
|
23 | - protected $replaceNodes; |
|
22 | + /** @var bool Whether to replace resolved nodes in place, or to add resolvedNode attributes */ |
|
23 | + protected $replaceNodes; |
|
24 | 24 | |
25 | - /** |
|
26 | - * Constructs a name resolution visitor. |
|
27 | - * |
|
28 | - * Options: |
|
29 | - * * preserveOriginalNames (default false): An "originalName" attribute will be added to |
|
30 | - * all name nodes that underwent resolution. |
|
31 | - * * replaceNodes (default true): Resolved names are replaced in-place. Otherwise, a |
|
32 | - * resolvedName attribute is added. (Names that cannot be statically resolved receive a |
|
33 | - * namespacedName attribute, as usual.) |
|
34 | - * |
|
35 | - * @param ErrorHandler|null $errorHandler Error handler |
|
36 | - * @param array $options Options |
|
37 | - */ |
|
38 | - public function __construct(?ErrorHandler $errorHandler = null, array $options = []) { |
|
39 | - $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing); |
|
40 | - $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false; |
|
41 | - $this->replaceNodes = $options['replaceNodes'] ?? true; |
|
42 | - } |
|
25 | + /** |
|
26 | + * Constructs a name resolution visitor. |
|
27 | + * |
|
28 | + * Options: |
|
29 | + * * preserveOriginalNames (default false): An "originalName" attribute will be added to |
|
30 | + * all name nodes that underwent resolution. |
|
31 | + * * replaceNodes (default true): Resolved names are replaced in-place. Otherwise, a |
|
32 | + * resolvedName attribute is added. (Names that cannot be statically resolved receive a |
|
33 | + * namespacedName attribute, as usual.) |
|
34 | + * |
|
35 | + * @param ErrorHandler|null $errorHandler Error handler |
|
36 | + * @param array $options Options |
|
37 | + */ |
|
38 | + public function __construct(?ErrorHandler $errorHandler = null, array $options = []) { |
|
39 | + $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing); |
|
40 | + $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false; |
|
41 | + $this->replaceNodes = $options['replaceNodes'] ?? true; |
|
42 | + } |
|
43 | 43 | |
44 | - /** |
|
45 | - * Get name resolution context. |
|
46 | - * |
|
47 | - * @return NameContext |
|
48 | - */ |
|
49 | - public function getNameContext() : NameContext { |
|
50 | - return $this->nameContext; |
|
51 | - } |
|
44 | + /** |
|
45 | + * Get name resolution context. |
|
46 | + * |
|
47 | + * @return NameContext |
|
48 | + */ |
|
49 | + public function getNameContext() : NameContext { |
|
50 | + return $this->nameContext; |
|
51 | + } |
|
52 | 52 | |
53 | - public function beforeTraverse(array $nodes) { |
|
54 | - $this->nameContext->startNamespace(); |
|
55 | - return null; |
|
56 | - } |
|
53 | + public function beforeTraverse(array $nodes) { |
|
54 | + $this->nameContext->startNamespace(); |
|
55 | + return null; |
|
56 | + } |
|
57 | 57 | |
58 | - public function enterNode(Node $node) { |
|
59 | - if ($node instanceof Stmt\Namespace_) { |
|
60 | - $this->nameContext->startNamespace($node->name); |
|
61 | - } elseif ($node instanceof Stmt\Use_) { |
|
62 | - foreach ($node->uses as $use) { |
|
63 | - $this->addAlias($use, $node->type, null); |
|
64 | - } |
|
65 | - } elseif ($node instanceof Stmt\GroupUse) { |
|
66 | - foreach ($node->uses as $use) { |
|
67 | - $this->addAlias($use, $node->type, $node->prefix); |
|
68 | - } |
|
69 | - } elseif ($node instanceof Stmt\Class_) { |
|
70 | - if (null !== $node->extends) { |
|
71 | - $node->extends = $this->resolveClassName($node->extends); |
|
72 | - } |
|
58 | + public function enterNode(Node $node) { |
|
59 | + if ($node instanceof Stmt\Namespace_) { |
|
60 | + $this->nameContext->startNamespace($node->name); |
|
61 | + } elseif ($node instanceof Stmt\Use_) { |
|
62 | + foreach ($node->uses as $use) { |
|
63 | + $this->addAlias($use, $node->type, null); |
|
64 | + } |
|
65 | + } elseif ($node instanceof Stmt\GroupUse) { |
|
66 | + foreach ($node->uses as $use) { |
|
67 | + $this->addAlias($use, $node->type, $node->prefix); |
|
68 | + } |
|
69 | + } elseif ($node instanceof Stmt\Class_) { |
|
70 | + if (null !== $node->extends) { |
|
71 | + $node->extends = $this->resolveClassName($node->extends); |
|
72 | + } |
|
73 | 73 | |
74 | - foreach ($node->implements as &$interface) { |
|
75 | - $interface = $this->resolveClassName($interface); |
|
76 | - } |
|
74 | + foreach ($node->implements as &$interface) { |
|
75 | + $interface = $this->resolveClassName($interface); |
|
76 | + } |
|
77 | 77 | |
78 | - $this->resolveAttrGroups($node); |
|
79 | - if (null !== $node->name) { |
|
80 | - $this->addNamespacedName($node); |
|
81 | - } |
|
82 | - } elseif ($node instanceof Stmt\Interface_) { |
|
83 | - foreach ($node->extends as &$interface) { |
|
84 | - $interface = $this->resolveClassName($interface); |
|
85 | - } |
|
78 | + $this->resolveAttrGroups($node); |
|
79 | + if (null !== $node->name) { |
|
80 | + $this->addNamespacedName($node); |
|
81 | + } |
|
82 | + } elseif ($node instanceof Stmt\Interface_) { |
|
83 | + foreach ($node->extends as &$interface) { |
|
84 | + $interface = $this->resolveClassName($interface); |
|
85 | + } |
|
86 | 86 | |
87 | - $this->resolveAttrGroups($node); |
|
88 | - $this->addNamespacedName($node); |
|
89 | - } elseif ($node instanceof Stmt\Enum_) { |
|
90 | - foreach ($node->implements as &$interface) { |
|
91 | - $interface = $this->resolveClassName($interface); |
|
92 | - } |
|
87 | + $this->resolveAttrGroups($node); |
|
88 | + $this->addNamespacedName($node); |
|
89 | + } elseif ($node instanceof Stmt\Enum_) { |
|
90 | + foreach ($node->implements as &$interface) { |
|
91 | + $interface = $this->resolveClassName($interface); |
|
92 | + } |
|
93 | 93 | |
94 | - $this->resolveAttrGroups($node); |
|
95 | - if (null !== $node->name) { |
|
96 | - $this->addNamespacedName($node); |
|
97 | - } |
|
98 | - } elseif ($node instanceof Stmt\Trait_) { |
|
99 | - $this->resolveAttrGroups($node); |
|
100 | - $this->addNamespacedName($node); |
|
101 | - } elseif ($node instanceof Stmt\Function_) { |
|
102 | - $this->resolveSignature($node); |
|
103 | - $this->resolveAttrGroups($node); |
|
104 | - $this->addNamespacedName($node); |
|
105 | - } elseif ($node instanceof Stmt\ClassMethod |
|
106 | - || $node instanceof Expr\Closure |
|
107 | - || $node instanceof Expr\ArrowFunction |
|
108 | - ) { |
|
109 | - $this->resolveSignature($node); |
|
110 | - $this->resolveAttrGroups($node); |
|
111 | - } elseif ($node instanceof Stmt\Property) { |
|
112 | - if (null !== $node->type) { |
|
113 | - $node->type = $this->resolveType($node->type); |
|
114 | - } |
|
115 | - $this->resolveAttrGroups($node); |
|
116 | - } elseif ($node instanceof Stmt\Const_) { |
|
117 | - foreach ($node->consts as $const) { |
|
118 | - $this->addNamespacedName($const); |
|
119 | - } |
|
120 | - } else if ($node instanceof Stmt\ClassConst) { |
|
121 | - if (null !== $node->type) { |
|
122 | - $node->type = $this->resolveType($node->type); |
|
123 | - } |
|
124 | - $this->resolveAttrGroups($node); |
|
125 | - } else if ($node instanceof Stmt\EnumCase) { |
|
126 | - $this->resolveAttrGroups($node); |
|
127 | - } elseif ($node instanceof Expr\StaticCall |
|
128 | - || $node instanceof Expr\StaticPropertyFetch |
|
129 | - || $node instanceof Expr\ClassConstFetch |
|
130 | - || $node instanceof Expr\New_ |
|
131 | - || $node instanceof Expr\Instanceof_ |
|
132 | - ) { |
|
133 | - if ($node->class instanceof Name) { |
|
134 | - $node->class = $this->resolveClassName($node->class); |
|
135 | - } |
|
136 | - } elseif ($node instanceof Stmt\Catch_) { |
|
137 | - foreach ($node->types as &$type) { |
|
138 | - $type = $this->resolveClassName($type); |
|
139 | - } |
|
140 | - } elseif ($node instanceof Expr\FuncCall) { |
|
141 | - if ($node->name instanceof Name) { |
|
142 | - $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION); |
|
143 | - } |
|
144 | - } elseif ($node instanceof Expr\ConstFetch) { |
|
145 | - $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT); |
|
146 | - } elseif ($node instanceof Stmt\TraitUse) { |
|
147 | - foreach ($node->traits as &$trait) { |
|
148 | - $trait = $this->resolveClassName($trait); |
|
149 | - } |
|
94 | + $this->resolveAttrGroups($node); |
|
95 | + if (null !== $node->name) { |
|
96 | + $this->addNamespacedName($node); |
|
97 | + } |
|
98 | + } elseif ($node instanceof Stmt\Trait_) { |
|
99 | + $this->resolveAttrGroups($node); |
|
100 | + $this->addNamespacedName($node); |
|
101 | + } elseif ($node instanceof Stmt\Function_) { |
|
102 | + $this->resolveSignature($node); |
|
103 | + $this->resolveAttrGroups($node); |
|
104 | + $this->addNamespacedName($node); |
|
105 | + } elseif ($node instanceof Stmt\ClassMethod |
|
106 | + || $node instanceof Expr\Closure |
|
107 | + || $node instanceof Expr\ArrowFunction |
|
108 | + ) { |
|
109 | + $this->resolveSignature($node); |
|
110 | + $this->resolveAttrGroups($node); |
|
111 | + } elseif ($node instanceof Stmt\Property) { |
|
112 | + if (null !== $node->type) { |
|
113 | + $node->type = $this->resolveType($node->type); |
|
114 | + } |
|
115 | + $this->resolveAttrGroups($node); |
|
116 | + } elseif ($node instanceof Stmt\Const_) { |
|
117 | + foreach ($node->consts as $const) { |
|
118 | + $this->addNamespacedName($const); |
|
119 | + } |
|
120 | + } else if ($node instanceof Stmt\ClassConst) { |
|
121 | + if (null !== $node->type) { |
|
122 | + $node->type = $this->resolveType($node->type); |
|
123 | + } |
|
124 | + $this->resolveAttrGroups($node); |
|
125 | + } else if ($node instanceof Stmt\EnumCase) { |
|
126 | + $this->resolveAttrGroups($node); |
|
127 | + } elseif ($node instanceof Expr\StaticCall |
|
128 | + || $node instanceof Expr\StaticPropertyFetch |
|
129 | + || $node instanceof Expr\ClassConstFetch |
|
130 | + || $node instanceof Expr\New_ |
|
131 | + || $node instanceof Expr\Instanceof_ |
|
132 | + ) { |
|
133 | + if ($node->class instanceof Name) { |
|
134 | + $node->class = $this->resolveClassName($node->class); |
|
135 | + } |
|
136 | + } elseif ($node instanceof Stmt\Catch_) { |
|
137 | + foreach ($node->types as &$type) { |
|
138 | + $type = $this->resolveClassName($type); |
|
139 | + } |
|
140 | + } elseif ($node instanceof Expr\FuncCall) { |
|
141 | + if ($node->name instanceof Name) { |
|
142 | + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION); |
|
143 | + } |
|
144 | + } elseif ($node instanceof Expr\ConstFetch) { |
|
145 | + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT); |
|
146 | + } elseif ($node instanceof Stmt\TraitUse) { |
|
147 | + foreach ($node->traits as &$trait) { |
|
148 | + $trait = $this->resolveClassName($trait); |
|
149 | + } |
|
150 | 150 | |
151 | - foreach ($node->adaptations as $adaptation) { |
|
152 | - if (null !== $adaptation->trait) { |
|
153 | - $adaptation->trait = $this->resolveClassName($adaptation->trait); |
|
154 | - } |
|
151 | + foreach ($node->adaptations as $adaptation) { |
|
152 | + if (null !== $adaptation->trait) { |
|
153 | + $adaptation->trait = $this->resolveClassName($adaptation->trait); |
|
154 | + } |
|
155 | 155 | |
156 | - if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { |
|
157 | - foreach ($adaptation->insteadof as &$insteadof) { |
|
158 | - $insteadof = $this->resolveClassName($insteadof); |
|
159 | - } |
|
160 | - } |
|
161 | - } |
|
162 | - } |
|
156 | + if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { |
|
157 | + foreach ($adaptation->insteadof as &$insteadof) { |
|
158 | + $insteadof = $this->resolveClassName($insteadof); |
|
159 | + } |
|
160 | + } |
|
161 | + } |
|
162 | + } |
|
163 | 163 | |
164 | - return null; |
|
165 | - } |
|
164 | + return null; |
|
165 | + } |
|
166 | 166 | |
167 | - private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) { |
|
168 | - // Add prefix for group uses |
|
169 | - $name = $prefix ? Name::concat($prefix, $use->name) : $use->name; |
|
170 | - // Type is determined either by individual element or whole use declaration |
|
171 | - $type |= $use->type; |
|
167 | + private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) { |
|
168 | + // Add prefix for group uses |
|
169 | + $name = $prefix ? Name::concat($prefix, $use->name) : $use->name; |
|
170 | + // Type is determined either by individual element or whole use declaration |
|
171 | + $type |= $use->type; |
|
172 | 172 | |
173 | - $this->nameContext->addAlias( |
|
174 | - $name, (string) $use->getAlias(), $type, $use->getAttributes() |
|
175 | - ); |
|
176 | - } |
|
173 | + $this->nameContext->addAlias( |
|
174 | + $name, (string) $use->getAlias(), $type, $use->getAttributes() |
|
175 | + ); |
|
176 | + } |
|
177 | 177 | |
178 | - /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */ |
|
179 | - private function resolveSignature($node) { |
|
180 | - foreach ($node->params as $param) { |
|
181 | - $param->type = $this->resolveType($param->type); |
|
182 | - $this->resolveAttrGroups($param); |
|
183 | - } |
|
184 | - $node->returnType = $this->resolveType($node->returnType); |
|
185 | - } |
|
178 | + /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */ |
|
179 | + private function resolveSignature($node) { |
|
180 | + foreach ($node->params as $param) { |
|
181 | + $param->type = $this->resolveType($param->type); |
|
182 | + $this->resolveAttrGroups($param); |
|
183 | + } |
|
184 | + $node->returnType = $this->resolveType($node->returnType); |
|
185 | + } |
|
186 | 186 | |
187 | - private function resolveType($node) { |
|
188 | - if ($node instanceof Name) { |
|
189 | - return $this->resolveClassName($node); |
|
190 | - } |
|
191 | - if ($node instanceof Node\NullableType) { |
|
192 | - $node->type = $this->resolveType($node->type); |
|
193 | - return $node; |
|
194 | - } |
|
195 | - if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) { |
|
196 | - foreach ($node->types as &$type) { |
|
197 | - $type = $this->resolveType($type); |
|
198 | - } |
|
199 | - return $node; |
|
200 | - } |
|
201 | - return $node; |
|
202 | - } |
|
187 | + private function resolveType($node) { |
|
188 | + if ($node instanceof Name) { |
|
189 | + return $this->resolveClassName($node); |
|
190 | + } |
|
191 | + if ($node instanceof Node\NullableType) { |
|
192 | + $node->type = $this->resolveType($node->type); |
|
193 | + return $node; |
|
194 | + } |
|
195 | + if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) { |
|
196 | + foreach ($node->types as &$type) { |
|
197 | + $type = $this->resolveType($type); |
|
198 | + } |
|
199 | + return $node; |
|
200 | + } |
|
201 | + return $node; |
|
202 | + } |
|
203 | 203 | |
204 | - /** |
|
205 | - * Resolve name, according to name resolver options. |
|
206 | - * |
|
207 | - * @param Name $name Function or constant name to resolve |
|
208 | - * @param int $type One of Stmt\Use_::TYPE_* |
|
209 | - * |
|
210 | - * @return Name Resolved name, or original name with attribute |
|
211 | - */ |
|
212 | - protected function resolveName(Name $name, int $type) : Name { |
|
213 | - if (!$this->replaceNodes) { |
|
214 | - $resolvedName = $this->nameContext->getResolvedName($name, $type); |
|
215 | - if (null !== $resolvedName) { |
|
216 | - $name->setAttribute('resolvedName', $resolvedName); |
|
217 | - } else { |
|
218 | - $name->setAttribute('namespacedName', FullyQualified::concat( |
|
219 | - $this->nameContext->getNamespace(), $name, $name->getAttributes())); |
|
220 | - } |
|
221 | - return $name; |
|
222 | - } |
|
204 | + /** |
|
205 | + * Resolve name, according to name resolver options. |
|
206 | + * |
|
207 | + * @param Name $name Function or constant name to resolve |
|
208 | + * @param int $type One of Stmt\Use_::TYPE_* |
|
209 | + * |
|
210 | + * @return Name Resolved name, or original name with attribute |
|
211 | + */ |
|
212 | + protected function resolveName(Name $name, int $type) : Name { |
|
213 | + if (!$this->replaceNodes) { |
|
214 | + $resolvedName = $this->nameContext->getResolvedName($name, $type); |
|
215 | + if (null !== $resolvedName) { |
|
216 | + $name->setAttribute('resolvedName', $resolvedName); |
|
217 | + } else { |
|
218 | + $name->setAttribute('namespacedName', FullyQualified::concat( |
|
219 | + $this->nameContext->getNamespace(), $name, $name->getAttributes())); |
|
220 | + } |
|
221 | + return $name; |
|
222 | + } |
|
223 | 223 | |
224 | - if ($this->preserveOriginalNames) { |
|
225 | - // Save the original name |
|
226 | - $originalName = $name; |
|
227 | - $name = clone $originalName; |
|
228 | - $name->setAttribute('originalName', $originalName); |
|
229 | - } |
|
224 | + if ($this->preserveOriginalNames) { |
|
225 | + // Save the original name |
|
226 | + $originalName = $name; |
|
227 | + $name = clone $originalName; |
|
228 | + $name->setAttribute('originalName', $originalName); |
|
229 | + } |
|
230 | 230 | |
231 | - $resolvedName = $this->nameContext->getResolvedName($name, $type); |
|
232 | - if (null !== $resolvedName) { |
|
233 | - return $resolvedName; |
|
234 | - } |
|
231 | + $resolvedName = $this->nameContext->getResolvedName($name, $type); |
|
232 | + if (null !== $resolvedName) { |
|
233 | + return $resolvedName; |
|
234 | + } |
|
235 | 235 | |
236 | - // unqualified names inside a namespace cannot be resolved at compile-time |
|
237 | - // add the namespaced version of the name as an attribute |
|
238 | - $name->setAttribute('namespacedName', FullyQualified::concat( |
|
239 | - $this->nameContext->getNamespace(), $name, $name->getAttributes())); |
|
240 | - return $name; |
|
241 | - } |
|
236 | + // unqualified names inside a namespace cannot be resolved at compile-time |
|
237 | + // add the namespaced version of the name as an attribute |
|
238 | + $name->setAttribute('namespacedName', FullyQualified::concat( |
|
239 | + $this->nameContext->getNamespace(), $name, $name->getAttributes())); |
|
240 | + return $name; |
|
241 | + } |
|
242 | 242 | |
243 | - protected function resolveClassName(Name $name) { |
|
244 | - return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL); |
|
245 | - } |
|
243 | + protected function resolveClassName(Name $name) { |
|
244 | + return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL); |
|
245 | + } |
|
246 | 246 | |
247 | - protected function addNamespacedName(Node $node) { |
|
248 | - $node->namespacedName = Name::concat( |
|
249 | - $this->nameContext->getNamespace(), (string) $node->name); |
|
250 | - } |
|
247 | + protected function addNamespacedName(Node $node) { |
|
248 | + $node->namespacedName = Name::concat( |
|
249 | + $this->nameContext->getNamespace(), (string) $node->name); |
|
250 | + } |
|
251 | 251 | |
252 | - protected function resolveAttrGroups(Node $node) |
|
253 | - { |
|
254 | - foreach ($node->attrGroups as $attrGroup) { |
|
255 | - foreach ($attrGroup->attrs as $attr) { |
|
256 | - $attr->name = $this->resolveClassName($attr->name); |
|
257 | - } |
|
258 | - } |
|
259 | - } |
|
252 | + protected function resolveAttrGroups(Node $node) |
|
253 | + { |
|
254 | + foreach ($node->attrGroups as $attrGroup) { |
|
255 | + foreach ($attrGroup->attrs as $attr) { |
|
256 | + $attr->name = $this->resolveClassName($attr->name); |
|
257 | + } |
|
258 | + } |
|
259 | + } |
|
260 | 260 | } |
@@ -171,7 +171,7 @@ discard block |
||
171 | 171 | $type |= $use->type; |
172 | 172 | |
173 | 173 | $this->nameContext->addAlias( |
174 | - $name, (string) $use->getAlias(), $type, $use->getAttributes() |
|
174 | + $name, (string)$use->getAlias(), $type, $use->getAttributes() |
|
175 | 175 | ); |
176 | 176 | } |
177 | 177 | |
@@ -246,7 +246,7 @@ discard block |
||
246 | 246 | |
247 | 247 | protected function addNamespacedName(Node $node) { |
248 | 248 | $node->namespacedName = Name::concat( |
249 | - $this->nameContext->getNamespace(), (string) $node->name); |
|
249 | + $this->nameContext->getNamespace(), (string)$node->name); |
|
250 | 250 | } |
251 | 251 | |
252 | 252 | protected function resolveAttrGroups(Node $node) |
@@ -11,8 +11,7 @@ |
||
11 | 11 | use PhpParser\Node\Stmt; |
12 | 12 | use PhpParser\NodeVisitorAbstract; |
13 | 13 | |
14 | -class NameResolver extends NodeVisitorAbstract |
|
15 | -{ |
|
14 | +class NameResolver extends NodeVisitorAbstract { |
|
16 | 15 | /** @var NameContext Naming context */ |
17 | 16 | protected $nameContext; |
18 | 17 |