|
10 | 10 | // The replacement value is arbitrary - it just has to be different from other values of token constants. |
11 | 11 | define(__NAMESPACE__ . '\T_COALESCE_EQUAL', defined('T_COALESCE_EQUAL') ? constant('T_COALESCE_EQUAL') : 'T_COALESCE_EQUAL'); |
12 | 12 | define(__NAMESPACE__ . '\T_FN', defined('T_FN') ? constant('T_FN') : 'T_FN'); |
13 | | -// If this predaates PHP 8.0, T_MATCH is unavailable. The replacement value is arbitrary - it just has to be different from other values of token constants. |
| 13 | +// If this predates PHP 8.0, T_MATCH is unavailable. The replacement value is arbitrary - it just has to be different from other values of token constants. |
14 | 14 | define(__NAMESPACE__ . '\T_MATCH', defined('T_MATCH') ? constant('T_MATCH') : 'T_MATCH'); |
| 15 | +define(__NAMESPACE__ . '\T_NULLSAFE_OBJECT_OPERATOR', defined('T_NULLSAFE_OBJECT_OPERATOR') ? constant('T_NULLSAFE_OBJECT_OPERATOR') : 'T_MATCH'); |
15 | 16 |
|
16 | 17 | /** |
17 | 18 | * Tokenizes content using PHP's built-in `token_get_all`, and converts to "lightweight" Token representation. |
@@ -130,6 +131,57 @@ public static function getTokensArrayFromContent( |
130 | 131 | $arr[] = new Token(TokenKind::ScriptSectionStartTag, $fullStart, $start, $pos-$fullStart); |
131 | 132 | $start = $fullStart = $pos; |
132 | 133 | break; |
| 134 | + case \PHP_VERSION_ID >= 80000 ? \T_NAME_QUALIFIED : -1000: |
| 135 | + case \PHP_VERSION_ID >= 80000 ? \T_NAME_FULLY_QUALIFIED : -1001: |
| 136 | + // NOTE: This switch is called on every token of every file being parsed, so this traded performance for readability. |
| 137 | + // |
| 138 | + // PHP's Opcache is able to optimize switches that are exclusively known longs, |
| 139 | + // but not switches that mix strings and longs or have unknown longs. |
| 140 | + // Longs are only known if they're declared within the same *class* or an internal constant (tokenizer). |
| 141 | + // |
| 142 | + // For some reason, the SWITCH_LONG opcode was not generated when the expression was part of a class constant. |
| 143 | + // (seen with php -d opcache.opt_debug_level=0x20000) |
| 144 | + // |
| 145 | + // Use negative values because that's not expected to overlap with token kinds that token_get_all() will return. |
| 146 | + // |
| 147 | + // T_NAME_* was added in php 8.0 to forbid whitespace between parts of names. |
| 148 | + // Here, emulate the tokenization of php 7 by splitting it up into 1 or more tokens. |
| 149 | + foreach (\explode('\\', $token[1]) as $i => $name) { |
| 150 | + if ($i) { |
| 151 | + $arr[] = new Token(TokenKind::BackslashToken, $fullStart, $start, 1 + $start - $fullStart); |
| 152 | + $start++; |
| 153 | + $fullStart = $start; |
| 154 | + } |
| 155 | + if ($name === '') { |
| 156 | + continue; |
| 157 | + } |
| 158 | + // TODO: TokenStringMaps::RESERVED_WORDS[$name] ?? TokenKind::Name for compatibility? |
| 159 | + $len = \strlen($name); |
| 160 | + $arr[] = new Token(TokenKind::Name, $fullStart, $start, $len + $start - $fullStart); |
| 161 | + $start += $len; |
| 162 | + $fullStart = $start; |
| 163 | + } |
| 164 | + break; |
| 165 | + case \PHP_VERSION_ID >= 80000 ? \T_NAME_RELATIVE : -1002: |
| 166 | + // This is a namespace-relative name: namespace\... |
| 167 | + foreach (\explode('\\', $token[1]) as $i => $name) { |
| 168 | + $len = \strlen($name); |
| 169 | + if (!$i) { |
| 170 | + $arr[] = new Token(TokenKind::NamespaceKeyword, $fullStart, $start, $len + $start - $fullStart); |
| 171 | + $start += $len; |
| 172 | + $fullStart = $start; |
| 173 | + continue; |
| 174 | + } |
| 175 | + $arr[] = new Token(TokenKind::BackslashToken, $fullStart, $start, 1); |
| 176 | + $start++; |
| 177 | + |
| 178 | + // TODO: TokenStringMaps::RESERVED_WORDS[$name] ?? TokenKind::Name for compatibility? |
| 179 | + $arr[] = new Token(TokenKind::Name, $start, $start, $len); |
| 180 | + |
| 181 | + $start += $len; |
| 182 | + $fullStart = $start; |
| 183 | + } |
| 184 | + break; |
133 | 185 | case \T_COMMENT: |
134 | 186 | case \T_DOC_COMMENT: |
135 | 187 | if ($treatCommentsAsTrivia) { |
@@ -256,6 +308,7 @@ protected static function tokenGetAll(string $content, $parseContext): array |
256 | 308 | "}" => TokenKind::CloseBraceToken, |
257 | 309 | "." => TokenKind::DotToken, |
258 | 310 | T_OBJECT_OPERATOR => TokenKind::ArrowToken, |
| 311 | + T_NULLSAFE_OBJECT_OPERATOR => TokenKind::QuestionArrowToken, |
259 | 312 | T_INC => TokenKind::PlusPlusToken, |
260 | 313 | T_DEC => TokenKind::MinusMinusToken, |
261 | 314 | T_POW => TokenKind::AsteriskAsteriskToken, |
|
0 commit comments