Chris@0
|
1 <?php
|
Chris@0
|
2 /**
|
Chris@0
|
3 * Tokenizes PHP code.
|
Chris@0
|
4 *
|
Chris@0
|
5 * PHP version 5
|
Chris@0
|
6 *
|
Chris@0
|
7 * @category PHP
|
Chris@0
|
8 * @package PHP_CodeSniffer
|
Chris@0
|
9 * @author Greg Sherwood <gsherwood@squiz.net>
|
Chris@0
|
10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@0
|
11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@0
|
12 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
13 */
|
Chris@0
|
14
|
Chris@0
|
15 /**
|
Chris@0
|
16 * Tokenizes PHP code.
|
Chris@0
|
17 *
|
Chris@0
|
18 * @category PHP
|
Chris@0
|
19 * @package PHP_CodeSniffer
|
Chris@0
|
20 * @author Greg Sherwood <gsherwood@squiz.net>
|
Chris@0
|
21 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600)
|
Chris@0
|
22 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
|
Chris@0
|
23 * @version Release: @package_version@
|
Chris@0
|
24 * @link http://pear.php.net/package/PHP_CodeSniffer
|
Chris@0
|
25 */
|
Chris@0
|
26 class PHP_CodeSniffer_Tokenizers_PHP
|
Chris@0
|
27 {
|
Chris@0
|
28
|
Chris@0
|
29 /**
|
Chris@0
|
30 * If TRUE, files that appear to be minified will not be processed.
|
Chris@0
|
31 *
|
Chris@0
|
32 * @var boolean
|
Chris@0
|
33 */
|
Chris@0
|
34 public $skipMinified = false;
|
Chris@0
|
35
|
Chris@0
|
36 /**
|
Chris@0
|
37 * A list of tokens that are allowed to open a scope.
|
Chris@0
|
38 *
|
Chris@0
|
39 * This array also contains information about what kind of token the scope
|
Chris@0
|
40 * opener uses to open and close the scope, if the token strictly requires
|
Chris@0
|
41 * an opener, if the token can share a scope closer, and who it can be shared
|
Chris@0
|
42 * with. An example of a token that shares a scope closer is a CASE scope.
|
Chris@0
|
43 *
|
Chris@0
|
44 * @var array
|
Chris@0
|
45 */
|
Chris@0
|
46 public $scopeOpeners = array(
|
Chris@0
|
47 T_IF => array(
|
Chris@0
|
48 'start' => array(
|
Chris@0
|
49 T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
50 T_COLON => T_COLON,
|
Chris@0
|
51 ),
|
Chris@0
|
52 'end' => array(
|
Chris@0
|
53 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
54 T_ENDIF => T_ENDIF,
|
Chris@0
|
55 T_ELSE => T_ELSE,
|
Chris@0
|
56 T_ELSEIF => T_ELSEIF,
|
Chris@0
|
57 ),
|
Chris@0
|
58 'strict' => false,
|
Chris@0
|
59 'shared' => false,
|
Chris@0
|
60 'with' => array(
|
Chris@0
|
61 T_ELSE => T_ELSE,
|
Chris@0
|
62 T_ELSEIF => T_ELSEIF,
|
Chris@0
|
63 ),
|
Chris@0
|
64 ),
|
Chris@0
|
65 T_TRY => array(
|
Chris@0
|
66 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
67 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
68 'strict' => true,
|
Chris@0
|
69 'shared' => false,
|
Chris@0
|
70 'with' => array(),
|
Chris@0
|
71 ),
|
Chris@0
|
72 T_CATCH => array(
|
Chris@0
|
73 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
74 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
75 'strict' => true,
|
Chris@0
|
76 'shared' => false,
|
Chris@0
|
77 'with' => array(),
|
Chris@0
|
78 ),
|
Chris@0
|
79 T_FINALLY => array(
|
Chris@0
|
80 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
81 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
82 'strict' => true,
|
Chris@0
|
83 'shared' => false,
|
Chris@0
|
84 'with' => array(),
|
Chris@0
|
85 ),
|
Chris@0
|
86 T_ELSE => array(
|
Chris@0
|
87 'start' => array(
|
Chris@0
|
88 T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
89 T_COLON => T_COLON,
|
Chris@0
|
90 ),
|
Chris@0
|
91 'end' => array(
|
Chris@0
|
92 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
93 T_ENDIF => T_ENDIF,
|
Chris@0
|
94 ),
|
Chris@0
|
95 'strict' => false,
|
Chris@0
|
96 'shared' => false,
|
Chris@0
|
97 'with' => array(
|
Chris@0
|
98 T_IF => T_IF,
|
Chris@0
|
99 T_ELSEIF => T_ELSEIF,
|
Chris@0
|
100 ),
|
Chris@0
|
101 ),
|
Chris@0
|
102 T_ELSEIF => array(
|
Chris@0
|
103 'start' => array(
|
Chris@0
|
104 T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
105 T_COLON => T_COLON,
|
Chris@0
|
106 ),
|
Chris@0
|
107 'end' => array(
|
Chris@0
|
108 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
109 T_ENDIF => T_ENDIF,
|
Chris@0
|
110 T_ELSE => T_ELSE,
|
Chris@0
|
111 T_ELSEIF => T_ELSEIF,
|
Chris@0
|
112 ),
|
Chris@0
|
113 'strict' => false,
|
Chris@0
|
114 'shared' => false,
|
Chris@0
|
115 'with' => array(
|
Chris@0
|
116 T_IF => T_IF,
|
Chris@0
|
117 T_ELSE => T_ELSE,
|
Chris@0
|
118 ),
|
Chris@0
|
119 ),
|
Chris@0
|
120 T_FOR => array(
|
Chris@0
|
121 'start' => array(
|
Chris@0
|
122 T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
123 T_COLON => T_COLON,
|
Chris@0
|
124 ),
|
Chris@0
|
125 'end' => array(
|
Chris@0
|
126 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
127 T_ENDFOR => T_ENDFOR,
|
Chris@0
|
128 ),
|
Chris@0
|
129 'strict' => false,
|
Chris@0
|
130 'shared' => false,
|
Chris@0
|
131 'with' => array(),
|
Chris@0
|
132 ),
|
Chris@0
|
133 T_FOREACH => array(
|
Chris@0
|
134 'start' => array(
|
Chris@0
|
135 T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
136 T_COLON => T_COLON,
|
Chris@0
|
137 ),
|
Chris@0
|
138 'end' => array(
|
Chris@0
|
139 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
140 T_ENDFOREACH => T_ENDFOREACH,
|
Chris@0
|
141 ),
|
Chris@0
|
142 'strict' => false,
|
Chris@0
|
143 'shared' => false,
|
Chris@0
|
144 'with' => array(),
|
Chris@0
|
145 ),
|
Chris@0
|
146 T_INTERFACE => array(
|
Chris@0
|
147 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
148 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
149 'strict' => true,
|
Chris@0
|
150 'shared' => false,
|
Chris@0
|
151 'with' => array(),
|
Chris@0
|
152 ),
|
Chris@0
|
153 T_FUNCTION => array(
|
Chris@0
|
154 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
155 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
156 'strict' => true,
|
Chris@0
|
157 'shared' => false,
|
Chris@0
|
158 'with' => array(),
|
Chris@0
|
159 ),
|
Chris@0
|
160 T_CLASS => array(
|
Chris@0
|
161 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
162 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
163 'strict' => true,
|
Chris@0
|
164 'shared' => false,
|
Chris@0
|
165 'with' => array(),
|
Chris@0
|
166 ),
|
Chris@0
|
167 T_TRAIT => array(
|
Chris@0
|
168 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
169 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
170 'strict' => true,
|
Chris@0
|
171 'shared' => false,
|
Chris@0
|
172 'with' => array(),
|
Chris@0
|
173 ),
|
Chris@0
|
174 T_USE => array(
|
Chris@0
|
175 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
176 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
177 'strict' => false,
|
Chris@0
|
178 'shared' => false,
|
Chris@0
|
179 'with' => array(),
|
Chris@0
|
180 ),
|
Chris@0
|
181 T_DECLARE => array(
|
Chris@0
|
182 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
183 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
184 'strict' => false,
|
Chris@0
|
185 'shared' => false,
|
Chris@0
|
186 'with' => array(),
|
Chris@0
|
187 ),
|
Chris@0
|
188 T_NAMESPACE => array(
|
Chris@0
|
189 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
190 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
191 'strict' => false,
|
Chris@0
|
192 'shared' => false,
|
Chris@0
|
193 'with' => array(),
|
Chris@0
|
194 ),
|
Chris@0
|
195 T_WHILE => array(
|
Chris@0
|
196 'start' => array(
|
Chris@0
|
197 T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
198 T_COLON => T_COLON,
|
Chris@0
|
199 ),
|
Chris@0
|
200 'end' => array(
|
Chris@0
|
201 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
202 T_ENDWHILE => T_ENDWHILE,
|
Chris@0
|
203 ),
|
Chris@0
|
204 'strict' => false,
|
Chris@0
|
205 'shared' => false,
|
Chris@0
|
206 'with' => array(),
|
Chris@0
|
207 ),
|
Chris@0
|
208 T_DO => array(
|
Chris@0
|
209 'start' => array(T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET),
|
Chris@0
|
210 'end' => array(T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET),
|
Chris@0
|
211 'strict' => true,
|
Chris@0
|
212 'shared' => false,
|
Chris@0
|
213 'with' => array(),
|
Chris@0
|
214 ),
|
Chris@0
|
215 T_SWITCH => array(
|
Chris@0
|
216 'start' => array(
|
Chris@0
|
217 T_OPEN_CURLY_BRACKET => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
218 T_COLON => T_COLON,
|
Chris@0
|
219 ),
|
Chris@0
|
220 'end' => array(
|
Chris@0
|
221 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
222 T_ENDSWITCH => T_ENDSWITCH,
|
Chris@0
|
223 ),
|
Chris@0
|
224 'strict' => true,
|
Chris@0
|
225 'shared' => false,
|
Chris@0
|
226 'with' => array(),
|
Chris@0
|
227 ),
|
Chris@0
|
228 T_CASE => array(
|
Chris@0
|
229 'start' => array(
|
Chris@0
|
230 T_COLON => T_COLON,
|
Chris@0
|
231 T_SEMICOLON => T_SEMICOLON,
|
Chris@0
|
232 ),
|
Chris@0
|
233 'end' => array(
|
Chris@0
|
234 T_BREAK => T_BREAK,
|
Chris@0
|
235 T_RETURN => T_RETURN,
|
Chris@0
|
236 T_CONTINUE => T_CONTINUE,
|
Chris@0
|
237 T_THROW => T_THROW,
|
Chris@0
|
238 T_EXIT => T_EXIT,
|
Chris@0
|
239 ),
|
Chris@0
|
240 'strict' => true,
|
Chris@0
|
241 'shared' => true,
|
Chris@0
|
242 'with' => array(
|
Chris@0
|
243 T_DEFAULT => T_DEFAULT,
|
Chris@0
|
244 T_CASE => T_CASE,
|
Chris@0
|
245 T_SWITCH => T_SWITCH,
|
Chris@0
|
246 ),
|
Chris@0
|
247 ),
|
Chris@0
|
248 T_DEFAULT => array(
|
Chris@0
|
249 'start' => array(
|
Chris@0
|
250 T_COLON => T_COLON,
|
Chris@0
|
251 T_SEMICOLON => T_SEMICOLON,
|
Chris@0
|
252 ),
|
Chris@0
|
253 'end' => array(
|
Chris@0
|
254 T_BREAK => T_BREAK,
|
Chris@0
|
255 T_RETURN => T_RETURN,
|
Chris@0
|
256 T_CONTINUE => T_CONTINUE,
|
Chris@0
|
257 T_THROW => T_THROW,
|
Chris@0
|
258 T_EXIT => T_EXIT,
|
Chris@0
|
259 ),
|
Chris@0
|
260 'strict' => true,
|
Chris@0
|
261 'shared' => true,
|
Chris@0
|
262 'with' => array(
|
Chris@0
|
263 T_CASE => T_CASE,
|
Chris@0
|
264 T_SWITCH => T_SWITCH,
|
Chris@0
|
265 ),
|
Chris@0
|
266 ),
|
Chris@0
|
267 T_START_HEREDOC => array(
|
Chris@0
|
268 'start' => array(T_START_HEREDOC => T_START_HEREDOC),
|
Chris@0
|
269 'end' => array(T_END_HEREDOC => T_END_HEREDOC),
|
Chris@0
|
270 'strict' => true,
|
Chris@0
|
271 'shared' => false,
|
Chris@0
|
272 'with' => array(),
|
Chris@0
|
273 ),
|
Chris@0
|
274 );
|
Chris@0
|
275
|
Chris@0
|
276 /**
|
Chris@0
|
277 * A list of tokens that end the scope.
|
Chris@0
|
278 *
|
Chris@0
|
279 * This array is just a unique collection of the end tokens
|
Chris@0
|
280 * from the _scopeOpeners array. The data is duplicated here to
|
Chris@0
|
281 * save time during parsing of the file.
|
Chris@0
|
282 *
|
Chris@0
|
283 * @var array
|
Chris@0
|
284 */
|
Chris@0
|
285 public $endScopeTokens = array(
|
Chris@0
|
286 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@0
|
287 T_ENDIF => T_ENDIF,
|
Chris@0
|
288 T_ENDFOR => T_ENDFOR,
|
Chris@0
|
289 T_ENDFOREACH => T_ENDFOREACH,
|
Chris@0
|
290 T_ENDWHILE => T_ENDWHILE,
|
Chris@0
|
291 T_ENDSWITCH => T_ENDSWITCH,
|
Chris@0
|
292 T_BREAK => T_BREAK,
|
Chris@0
|
293 T_END_HEREDOC => T_END_HEREDOC,
|
Chris@0
|
294 );
|
Chris@0
|
295
|
Chris@0
|
296 /**
|
Chris@0
|
297 * A cache of different token types, resolved into arrays.
|
Chris@0
|
298 *
|
Chris@0
|
299 * @var array()
|
Chris@0
|
300 * @see standardiseToken()
|
Chris@0
|
301 */
|
Chris@0
|
302 private static $_resolveTokenCache = array();
|
Chris@0
|
303
|
Chris@0
|
304
|
Chris@0
|
305 /**
|
Chris@0
|
306 * Creates an array of tokens when given some PHP code.
|
Chris@0
|
307 *
|
Chris@0
|
308 * Starts by using token_get_all() but does a lot of extra processing
|
Chris@0
|
309 * to insert information about the context of the token.
|
Chris@0
|
310 *
|
Chris@0
|
311 * @param string $string The string to tokenize.
|
Chris@0
|
312 * @param string $eolChar The EOL character to use for splitting strings.
|
Chris@0
|
313 *
|
Chris@0
|
314 * @return array
|
Chris@0
|
315 */
|
Chris@0
|
316 public function tokenizeString($string, $eolChar='\n')
|
Chris@0
|
317 {
|
Chris@0
|
318 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
319 echo "\t*** START PHP TOKENIZING ***".PHP_EOL;
|
Chris@0
|
320 $isWin = false;
|
Chris@0
|
321 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
Chris@0
|
322 $isWin = true;
|
Chris@0
|
323 }
|
Chris@0
|
324 }
|
Chris@0
|
325
|
Chris@0
|
326 $tokens = @token_get_all($string);
|
Chris@0
|
327 $finalTokens = array();
|
Chris@0
|
328
|
Chris@0
|
329 $newStackPtr = 0;
|
Chris@0
|
330 $numTokens = count($tokens);
|
Chris@0
|
331 $lastNotEmptyToken = 0;
|
Chris@0
|
332
|
Chris@0
|
333 $insideInlineIf = array();
|
Chris@0
|
334 $insideUseGroup = false;
|
Chris@0
|
335
|
Chris@0
|
336 $commentTokenizer = new PHP_CodeSniffer_Tokenizers_Comment();
|
Chris@0
|
337
|
Chris@0
|
338 for ($stackPtr = 0; $stackPtr < $numTokens; $stackPtr++) {
|
Chris@0
|
339 $token = (array) $tokens[$stackPtr];
|
Chris@0
|
340 $tokenIsArray = isset($token[1]);
|
Chris@0
|
341
|
Chris@0
|
342 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
343 if ($tokenIsArray === true) {
|
Chris@0
|
344 $type = token_name($token[0]);
|
Chris@0
|
345 $content = PHP_CodeSniffer::prepareForOutput($token[1]);
|
Chris@0
|
346 } else {
|
Chris@0
|
347 $newToken = self::resolveSimpleToken($token[0]);
|
Chris@0
|
348 $type = $newToken['type'];
|
Chris@0
|
349 $content = PHP_CodeSniffer::prepareForOutput($token[0]);
|
Chris@0
|
350 }
|
Chris@0
|
351
|
Chris@0
|
352 echo "\tProcess token ";
|
Chris@0
|
353 if ($tokenIsArray === true) {
|
Chris@0
|
354 echo "[$stackPtr]";
|
Chris@0
|
355 } else {
|
Chris@0
|
356 echo " $stackPtr ";
|
Chris@0
|
357 }
|
Chris@0
|
358
|
Chris@0
|
359 echo ": $type => $content";
|
Chris@0
|
360 }//end if
|
Chris@0
|
361
|
Chris@0
|
362 if ($newStackPtr > 0 && $finalTokens[($newStackPtr - 1)]['code'] !== T_WHITESPACE) {
|
Chris@0
|
363 $lastNotEmptyToken = ($newStackPtr - 1);
|
Chris@0
|
364 }
|
Chris@0
|
365
|
Chris@0
|
366 /*
|
Chris@0
|
367 If we are using \r\n newline characters, the \r and \n are sometimes
|
Chris@0
|
368 split over two tokens. This normally occurs after comments. We need
|
Chris@0
|
369 to merge these two characters together so that our line endings are
|
Chris@0
|
370 consistent for all lines.
|
Chris@0
|
371 */
|
Chris@0
|
372
|
Chris@0
|
373 if ($tokenIsArray === true && substr($token[1], -1) === "\r") {
|
Chris@0
|
374 if (isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
375 && is_array($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
376 && $tokens[($stackPtr + 1)][1][0] === "\n"
|
Chris@0
|
377 ) {
|
Chris@0
|
378 $token[1] .= "\n";
|
Chris@0
|
379 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
380 if ($isWin === true) {
|
Chris@0
|
381 echo '\n';
|
Chris@0
|
382 } else {
|
Chris@0
|
383 echo "\033[30;1m\\n\033[0m";
|
Chris@0
|
384 }
|
Chris@0
|
385 }
|
Chris@0
|
386
|
Chris@0
|
387 if ($tokens[($stackPtr + 1)][1] === "\n") {
|
Chris@0
|
388 // This token's content has been merged into the previous,
|
Chris@0
|
389 // so we can skip it.
|
Chris@0
|
390 $tokens[($stackPtr + 1)] = '';
|
Chris@0
|
391 } else {
|
Chris@0
|
392 $tokens[($stackPtr + 1)][1] = substr($tokens[($stackPtr + 1)][1], 1);
|
Chris@0
|
393 }
|
Chris@0
|
394 }
|
Chris@0
|
395 }//end if
|
Chris@0
|
396
|
Chris@0
|
397 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
398 echo PHP_EOL;
|
Chris@0
|
399 }
|
Chris@0
|
400
|
Chris@0
|
401 /*
|
Chris@0
|
402 Parse doc blocks into something that can be easily iterated over.
|
Chris@0
|
403 */
|
Chris@0
|
404
|
Chris@0
|
405 if ($tokenIsArray === true && $token[0] === T_DOC_COMMENT) {
|
Chris@0
|
406 $commentTokens = $commentTokenizer->tokenizeString($token[1], $eolChar, $newStackPtr);
|
Chris@0
|
407 foreach ($commentTokens as $commentToken) {
|
Chris@0
|
408 $finalTokens[$newStackPtr] = $commentToken;
|
Chris@0
|
409 $newStackPtr++;
|
Chris@0
|
410 }
|
Chris@0
|
411
|
Chris@0
|
412 continue;
|
Chris@0
|
413 }
|
Chris@0
|
414
|
Chris@0
|
415 /*
|
Chris@0
|
416 If this is a double quoted string, PHP will tokenize the whole
|
Chris@0
|
417 thing which causes problems with the scope map when braces are
|
Chris@0
|
418 within the string. So we need to merge the tokens together to
|
Chris@0
|
419 provide a single string.
|
Chris@0
|
420 */
|
Chris@0
|
421
|
Chris@0
|
422 if ($tokenIsArray === false && ($token[0] === '"' || $token[0] === 'b"')) {
|
Chris@0
|
423 // Binary casts need a special token.
|
Chris@0
|
424 if ($token[0] === 'b"') {
|
Chris@0
|
425 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
426 'code' => T_BINARY_CAST,
|
Chris@0
|
427 'type' => 'T_BINARY_CAST',
|
Chris@0
|
428 'content' => 'b',
|
Chris@0
|
429 );
|
Chris@0
|
430 $newStackPtr++;
|
Chris@0
|
431 }
|
Chris@0
|
432
|
Chris@0
|
433 $tokenContent = '"';
|
Chris@0
|
434 $nestedVars = array();
|
Chris@0
|
435 for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
|
Chris@0
|
436 $subToken = (array) $tokens[$i];
|
Chris@0
|
437 $subTokenIsArray = isset($subToken[1]);
|
Chris@0
|
438
|
Chris@0
|
439 if ($subTokenIsArray === true) {
|
Chris@0
|
440 $tokenContent .= $subToken[1];
|
Chris@0
|
441 if ($subToken[1] === '{'
|
Chris@0
|
442 && $subToken[0] !== T_ENCAPSED_AND_WHITESPACE
|
Chris@0
|
443 ) {
|
Chris@0
|
444 $nestedVars[] = $i;
|
Chris@0
|
445 }
|
Chris@0
|
446 } else {
|
Chris@0
|
447 $tokenContent .= $subToken[0];
|
Chris@0
|
448 if ($subToken[0] === '}') {
|
Chris@0
|
449 array_pop($nestedVars);
|
Chris@0
|
450 }
|
Chris@0
|
451 }
|
Chris@0
|
452
|
Chris@0
|
453 if ($subTokenIsArray === false
|
Chris@0
|
454 && $subToken[0] === '"'
|
Chris@0
|
455 && empty($nestedVars) === true
|
Chris@0
|
456 ) {
|
Chris@0
|
457 // We found the other end of the double quoted string.
|
Chris@0
|
458 break;
|
Chris@0
|
459 }
|
Chris@0
|
460 }//end for
|
Chris@0
|
461
|
Chris@0
|
462 $stackPtr = $i;
|
Chris@0
|
463
|
Chris@0
|
464 // Convert each line within the double quoted string to a
|
Chris@0
|
465 // new token, so it conforms with other multiple line tokens.
|
Chris@0
|
466 $tokenLines = explode($eolChar, $tokenContent);
|
Chris@0
|
467 $numLines = count($tokenLines);
|
Chris@0
|
468 $newToken = array();
|
Chris@0
|
469
|
Chris@0
|
470 for ($j = 0; $j < $numLines; $j++) {
|
Chris@0
|
471 $newToken['content'] = $tokenLines[$j];
|
Chris@0
|
472 if ($j === ($numLines - 1)) {
|
Chris@0
|
473 if ($tokenLines[$j] === '') {
|
Chris@0
|
474 break;
|
Chris@0
|
475 }
|
Chris@0
|
476 } else {
|
Chris@0
|
477 $newToken['content'] .= $eolChar;
|
Chris@0
|
478 }
|
Chris@0
|
479
|
Chris@0
|
480 $newToken['code'] = T_DOUBLE_QUOTED_STRING;
|
Chris@0
|
481 $newToken['type'] = 'T_DOUBLE_QUOTED_STRING';
|
Chris@0
|
482 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
483 $newStackPtr++;
|
Chris@0
|
484 }
|
Chris@0
|
485
|
Chris@0
|
486 // Continue, as we're done with this token.
|
Chris@0
|
487 continue;
|
Chris@0
|
488 }//end if
|
Chris@0
|
489
|
Chris@0
|
490 /*
|
Chris@0
|
491 If this is a heredoc, PHP will tokenize the whole
|
Chris@0
|
492 thing which causes problems when heredocs don't
|
Chris@0
|
493 contain real PHP code, which is almost never.
|
Chris@0
|
494 We want to leave the start and end heredoc tokens
|
Chris@0
|
495 alone though.
|
Chris@0
|
496 */
|
Chris@0
|
497
|
Chris@0
|
498 if ($tokenIsArray === true && $token[0] === T_START_HEREDOC) {
|
Chris@0
|
499 // Add the start heredoc token to the final array.
|
Chris@0
|
500 $finalTokens[$newStackPtr] = self::standardiseToken($token);
|
Chris@0
|
501
|
Chris@0
|
502 // Check if this is actually a nowdoc and use a different token
|
Chris@0
|
503 // to help the sniffs.
|
Chris@0
|
504 $nowdoc = false;
|
Chris@0
|
505 if ($token[1][3] === "'") {
|
Chris@0
|
506 $finalTokens[$newStackPtr]['code'] = T_START_NOWDOC;
|
Chris@0
|
507 $finalTokens[$newStackPtr]['type'] = 'T_START_NOWDOC';
|
Chris@0
|
508 $nowdoc = true;
|
Chris@0
|
509 }
|
Chris@0
|
510
|
Chris@0
|
511 $tokenContent = '';
|
Chris@0
|
512 for ($i = ($stackPtr + 1); $i < $numTokens; $i++) {
|
Chris@0
|
513 $subTokenIsArray = is_array($tokens[$i]);
|
Chris@0
|
514 if ($subTokenIsArray === true
|
Chris@0
|
515 && $tokens[$i][0] === T_END_HEREDOC
|
Chris@0
|
516 ) {
|
Chris@0
|
517 // We found the other end of the heredoc.
|
Chris@0
|
518 break;
|
Chris@0
|
519 }
|
Chris@0
|
520
|
Chris@0
|
521 if ($subTokenIsArray === true) {
|
Chris@0
|
522 $tokenContent .= $tokens[$i][1];
|
Chris@0
|
523 } else {
|
Chris@0
|
524 $tokenContent .= $tokens[$i];
|
Chris@0
|
525 }
|
Chris@0
|
526 }
|
Chris@0
|
527
|
Chris@0
|
528 if ($i === $numTokens) {
|
Chris@0
|
529 // We got to the end of the file and never
|
Chris@0
|
530 // found the closing token, so this probably wasn't
|
Chris@0
|
531 // a heredoc.
|
Chris@0
|
532 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
533 $type = $finalTokens[$newStackPtr]['type'];
|
Chris@0
|
534 echo "\t\t* failed to find the end of the here/nowdoc".PHP_EOL;
|
Chris@0
|
535 echo "\t\t* token $stackPtr changed from $type to T_STRING".PHP_EOL;
|
Chris@0
|
536 }
|
Chris@0
|
537
|
Chris@0
|
538 $finalTokens[$newStackPtr]['code'] = T_STRING;
|
Chris@0
|
539 $finalTokens[$newStackPtr]['type'] = 'T_STRING';
|
Chris@0
|
540 $newStackPtr++;
|
Chris@0
|
541 continue;
|
Chris@0
|
542 }
|
Chris@0
|
543
|
Chris@0
|
544 $stackPtr = $i;
|
Chris@0
|
545 $newStackPtr++;
|
Chris@0
|
546
|
Chris@0
|
547 // Convert each line within the heredoc to a
|
Chris@0
|
548 // new token, so it conforms with other multiple line tokens.
|
Chris@0
|
549 $tokenLines = explode($eolChar, $tokenContent);
|
Chris@0
|
550 $numLines = count($tokenLines);
|
Chris@0
|
551 $newToken = array();
|
Chris@0
|
552
|
Chris@0
|
553 for ($j = 0; $j < $numLines; $j++) {
|
Chris@0
|
554 $newToken['content'] = $tokenLines[$j];
|
Chris@0
|
555 if ($j === ($numLines - 1)) {
|
Chris@0
|
556 if ($tokenLines[$j] === '') {
|
Chris@0
|
557 break;
|
Chris@0
|
558 }
|
Chris@0
|
559 } else {
|
Chris@0
|
560 $newToken['content'] .= $eolChar;
|
Chris@0
|
561 }
|
Chris@0
|
562
|
Chris@0
|
563 if ($nowdoc === true) {
|
Chris@0
|
564 $newToken['code'] = T_NOWDOC;
|
Chris@0
|
565 $newToken['type'] = 'T_NOWDOC';
|
Chris@0
|
566 } else {
|
Chris@0
|
567 $newToken['code'] = T_HEREDOC;
|
Chris@0
|
568 $newToken['type'] = 'T_HEREDOC';
|
Chris@0
|
569 }
|
Chris@0
|
570
|
Chris@0
|
571 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
572 $newStackPtr++;
|
Chris@0
|
573 }//end for
|
Chris@0
|
574
|
Chris@0
|
575 // Add the end heredoc token to the final array.
|
Chris@0
|
576 $finalTokens[$newStackPtr] = self::standardiseToken($tokens[$stackPtr]);
|
Chris@0
|
577
|
Chris@0
|
578 if ($nowdoc === true) {
|
Chris@0
|
579 $finalTokens[$newStackPtr]['code'] = T_END_NOWDOC;
|
Chris@0
|
580 $finalTokens[$newStackPtr]['type'] = 'T_END_NOWDOC';
|
Chris@0
|
581 $nowdoc = true;
|
Chris@0
|
582 }
|
Chris@0
|
583
|
Chris@0
|
584 $newStackPtr++;
|
Chris@0
|
585
|
Chris@0
|
586 // Continue, as we're done with this token.
|
Chris@0
|
587 continue;
|
Chris@0
|
588 }//end if
|
Chris@0
|
589
|
Chris@0
|
590 /*
|
Chris@0
|
591 Before PHP 5.6, the ... operator was tokenized as three
|
Chris@0
|
592 T_STRING_CONCAT tokens in a row. So look for and combine
|
Chris@0
|
593 these tokens in earlier versions.
|
Chris@0
|
594 */
|
Chris@0
|
595
|
Chris@0
|
596 if ($tokenIsArray === false
|
Chris@0
|
597 && $token[0] === '.'
|
Chris@0
|
598 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
599 && isset($tokens[($stackPtr + 2)]) === true
|
Chris@0
|
600 && $tokens[($stackPtr + 1)] === '.'
|
Chris@0
|
601 && $tokens[($stackPtr + 2)] === '.'
|
Chris@0
|
602 ) {
|
Chris@0
|
603 $newToken = array();
|
Chris@0
|
604 $newToken['code'] = T_ELLIPSIS;
|
Chris@0
|
605 $newToken['type'] = 'T_ELLIPSIS';
|
Chris@0
|
606 $newToken['content'] = '...';
|
Chris@0
|
607 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
608
|
Chris@0
|
609 $newStackPtr++;
|
Chris@0
|
610 $stackPtr += 2;
|
Chris@0
|
611 continue;
|
Chris@0
|
612 }
|
Chris@0
|
613
|
Chris@0
|
614 /*
|
Chris@0
|
615 Before PHP 5.6, the ** operator was tokenized as two
|
Chris@0
|
616 T_MULTIPLY tokens in a row. So look for and combine
|
Chris@0
|
617 these tokens in earlier versions.
|
Chris@0
|
618 */
|
Chris@0
|
619
|
Chris@0
|
620 if ($tokenIsArray === false
|
Chris@0
|
621 && $token[0] === '*'
|
Chris@0
|
622 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
623 && $tokens[($stackPtr + 1)] === '*'
|
Chris@0
|
624 ) {
|
Chris@0
|
625 $newToken = array();
|
Chris@0
|
626 $newToken['code'] = T_POW;
|
Chris@0
|
627 $newToken['type'] = 'T_POW';
|
Chris@0
|
628 $newToken['content'] = '**';
|
Chris@0
|
629 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
630
|
Chris@0
|
631 $newStackPtr++;
|
Chris@0
|
632 $stackPtr++;
|
Chris@0
|
633 continue;
|
Chris@0
|
634 }
|
Chris@0
|
635
|
Chris@0
|
636 /*
|
Chris@0
|
637 Before PHP 5.6, the **= operator was tokenized as
|
Chris@0
|
638 T_MULTIPLY followed by T_MUL_EQUAL. So look for and combine
|
Chris@0
|
639 these tokens in earlier versions.
|
Chris@0
|
640 */
|
Chris@0
|
641
|
Chris@0
|
642 if ($tokenIsArray === false
|
Chris@0
|
643 && $token[0] === '*'
|
Chris@0
|
644 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
645 && is_array($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
646 && $tokens[($stackPtr + 1)][1] === '*='
|
Chris@0
|
647 ) {
|
Chris@0
|
648 $newToken = array();
|
Chris@0
|
649 $newToken['code'] = T_POW_EQUAL;
|
Chris@0
|
650 $newToken['type'] = 'T_POW_EQUAL';
|
Chris@0
|
651 $newToken['content'] = '**=';
|
Chris@0
|
652 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
653
|
Chris@0
|
654 $newStackPtr++;
|
Chris@0
|
655 $stackPtr++;
|
Chris@0
|
656 continue;
|
Chris@0
|
657 }
|
Chris@0
|
658
|
Chris@0
|
659 /*
|
Chris@0
|
660 Before PHP 7, the ??= operator was tokenized as
|
Chris@0
|
661 T_INLINE_THEN, T_INLINE_THEN, T_EQUAL.
|
Chris@0
|
662 Between PHP 7.0 and 7.2, the ??= operator was tokenized as
|
Chris@0
|
663 T_COALESCE, T_EQUAL.
|
Chris@0
|
664 So look for and combine these tokens in earlier versions.
|
Chris@0
|
665 */
|
Chris@0
|
666
|
Chris@0
|
667 if (($tokenIsArray === false
|
Chris@0
|
668 && $token[0] === '?'
|
Chris@0
|
669 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
670 && $tokens[($stackPtr + 1)][0] === '?'
|
Chris@0
|
671 && isset($tokens[($stackPtr + 2)]) === true
|
Chris@0
|
672 && $tokens[($stackPtr + 2)][0] === '=')
|
Chris@0
|
673 || ($tokenIsArray === true
|
Chris@0
|
674 && $token[0] === T_COALESCE
|
Chris@0
|
675 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
676 && $tokens[($stackPtr + 1)][0] === '=')
|
Chris@0
|
677 ) {
|
Chris@0
|
678 $newToken = array();
|
Chris@0
|
679 $newToken['code'] = T_COALESCE_EQUAL;
|
Chris@0
|
680 $newToken['type'] = 'T_COALESCE_EQUAL';
|
Chris@0
|
681 $newToken['content'] = '??=';
|
Chris@0
|
682 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
683
|
Chris@0
|
684 $newStackPtr++;
|
Chris@0
|
685 $stackPtr++;
|
Chris@0
|
686
|
Chris@0
|
687 if ($tokenIsArray === false) {
|
Chris@0
|
688 // Pre PHP 7.
|
Chris@0
|
689 $stackPtr++;
|
Chris@0
|
690 }
|
Chris@0
|
691
|
Chris@0
|
692 continue;
|
Chris@0
|
693 }
|
Chris@0
|
694
|
Chris@0
|
695 /*
|
Chris@0
|
696 Before PHP 7, the ?? operator was tokenized as
|
Chris@0
|
697 T_INLINE_THEN followed by T_INLINE_THEN.
|
Chris@0
|
698 So look for and combine these tokens in earlier versions.
|
Chris@0
|
699 */
|
Chris@0
|
700
|
Chris@0
|
701 if ($tokenIsArray === false
|
Chris@0
|
702 && $token[0] === '?'
|
Chris@0
|
703 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
704 && $tokens[($stackPtr + 1)][0] === '?'
|
Chris@0
|
705 ) {
|
Chris@0
|
706 $newToken = array();
|
Chris@0
|
707 $newToken['code'] = T_COALESCE;
|
Chris@0
|
708 $newToken['type'] = 'T_COALESCE';
|
Chris@0
|
709 $newToken['content'] = '??';
|
Chris@0
|
710 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
711
|
Chris@0
|
712 $newStackPtr++;
|
Chris@0
|
713 $stackPtr++;
|
Chris@0
|
714 continue;
|
Chris@0
|
715 }
|
Chris@0
|
716
|
Chris@0
|
717 /*
|
Chris@0
|
718 Convert ? to T_NULLABLE OR T_INLINE_THEN
|
Chris@0
|
719 */
|
Chris@0
|
720
|
Chris@0
|
721 if ($tokenIsArray === false && $token[0] === '?') {
|
Chris@0
|
722 $newToken = array();
|
Chris@0
|
723 $newToken['content'] = '?';
|
Chris@0
|
724
|
Chris@12
|
725 $prevNonEmpty = null;
|
Chris@0
|
726 for ($i = ($stackPtr - 1); $i >= 0; $i--) {
|
Chris@0
|
727 if (is_array($tokens[$i]) === true) {
|
Chris@0
|
728 $tokenType = $tokens[$i][0];
|
Chris@0
|
729 } else {
|
Chris@0
|
730 $tokenType = $tokens[$i];
|
Chris@0
|
731 }
|
Chris@0
|
732
|
Chris@12
|
733 if ($prevNonEmpty === null
|
Chris@12
|
734 && isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokenType]) === false
|
Chris@12
|
735 ) {
|
Chris@12
|
736 // Found the previous non-empty token.
|
Chris@12
|
737 if ($tokenType === ':' || $tokenType === ',') {
|
Chris@12
|
738 $newToken['code'] = T_NULLABLE;
|
Chris@12
|
739 $newToken['type'] = 'T_NULLABLE';
|
Chris@12
|
740 break;
|
Chris@12
|
741 }
|
Chris@12
|
742
|
Chris@12
|
743 $prevNonEmpty = $tokenType;
|
Chris@12
|
744 }
|
Chris@12
|
745
|
Chris@0
|
746 if ($tokenType === T_FUNCTION) {
|
Chris@0
|
747 $newToken['code'] = T_NULLABLE;
|
Chris@0
|
748 $newToken['type'] = 'T_NULLABLE';
|
Chris@0
|
749 break;
|
Chris@12
|
750 } else if (in_array($tokenType, array(T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, '=', '{', ';')) === true) {
|
Chris@0
|
751 $newToken['code'] = T_INLINE_THEN;
|
Chris@0
|
752 $newToken['type'] = 'T_INLINE_THEN';
|
Chris@0
|
753
|
Chris@0
|
754 $insideInlineIf[] = $stackPtr;
|
Chris@0
|
755 break;
|
Chris@0
|
756 }
|
Chris@12
|
757 }//end for
|
Chris@0
|
758
|
Chris@0
|
759 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
760 $newStackPtr++;
|
Chris@0
|
761 continue;
|
Chris@0
|
762 }//end if
|
Chris@0
|
763
|
Chris@0
|
764 /*
|
Chris@0
|
765 Tokens after a double colon may be look like scope openers,
|
Chris@0
|
766 such as when writing code like Foo::NAMESPACE, but they are
|
Chris@0
|
767 only ever variables or strings.
|
Chris@0
|
768 */
|
Chris@0
|
769
|
Chris@0
|
770 if ($stackPtr > 1
|
Chris@0
|
771 && (is_array($tokens[($stackPtr - 1)]) === true
|
Chris@0
|
772 && $tokens[($stackPtr - 1)][0] === T_PAAMAYIM_NEKUDOTAYIM)
|
Chris@0
|
773 && $tokenIsArray === true
|
Chris@0
|
774 && $token[0] !== T_STRING
|
Chris@0
|
775 && $token[0] !== T_VARIABLE
|
Chris@0
|
776 && $token[0] !== T_DOLLAR
|
Chris@0
|
777 && isset(PHP_CodeSniffer_Tokens::$emptyTokens[$token[0]]) === false
|
Chris@0
|
778 ) {
|
Chris@0
|
779 $newToken = array();
|
Chris@0
|
780 $newToken['code'] = T_STRING;
|
Chris@0
|
781 $newToken['type'] = 'T_STRING';
|
Chris@0
|
782 $newToken['content'] = $token[1];
|
Chris@0
|
783 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
784
|
Chris@0
|
785 $newStackPtr++;
|
Chris@0
|
786 continue;
|
Chris@0
|
787 }
|
Chris@0
|
788
|
Chris@0
|
789 /*
|
Chris@0
|
790 The string-like token after a function keyword should always be
|
Chris@0
|
791 tokenized as T_STRING even if it appears to be a different token,
|
Chris@0
|
792 such as when writing code like: function default(): foo
|
Chris@0
|
793 so go forward and change the token type before it is processed.
|
Chris@0
|
794 */
|
Chris@0
|
795
|
Chris@0
|
796 if ($tokenIsArray === true && $token[0] === T_FUNCTION) {
|
Chris@0
|
797 for ($x = ($stackPtr + 1); $x < $numTokens; $x++) {
|
Chris@0
|
798 if (is_array($tokens[$x]) === false
|
Chris@0
|
799 || isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x][0]]) === false
|
Chris@0
|
800 ) {
|
Chris@0
|
801 // Non-empty content.
|
Chris@0
|
802 break;
|
Chris@0
|
803 }
|
Chris@0
|
804 }
|
Chris@0
|
805
|
Chris@0
|
806 if ($x < $numTokens && is_array($tokens[$x]) === true) {
|
Chris@0
|
807 $tokens[$x][0] = T_STRING;
|
Chris@0
|
808 }
|
Chris@0
|
809 }
|
Chris@0
|
810
|
Chris@0
|
811 /*
|
Chris@0
|
812 Before PHP 7, the <=> operator was tokenized as
|
Chris@0
|
813 T_IS_SMALLER_OR_EQUAL followed by T_GREATER_THAN.
|
Chris@0
|
814 So look for and combine these tokens in earlier versions.
|
Chris@0
|
815 */
|
Chris@0
|
816
|
Chris@0
|
817 if ($tokenIsArray === true
|
Chris@0
|
818 && $token[0] === T_IS_SMALLER_OR_EQUAL
|
Chris@0
|
819 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
820 && $tokens[($stackPtr + 1)][0] === '>'
|
Chris@0
|
821 ) {
|
Chris@0
|
822 $newToken = array();
|
Chris@0
|
823 $newToken['code'] = T_SPACESHIP;
|
Chris@0
|
824 $newToken['type'] = 'T_SPACESHIP';
|
Chris@0
|
825 $newToken['content'] = '<=>';
|
Chris@0
|
826 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
827
|
Chris@0
|
828 $newStackPtr++;
|
Chris@0
|
829 $stackPtr++;
|
Chris@0
|
830 continue;
|
Chris@0
|
831 }
|
Chris@0
|
832
|
Chris@0
|
833 /*
|
Chris@0
|
834 Emulate traits in PHP versions less than 5.4.
|
Chris@0
|
835 */
|
Chris@0
|
836
|
Chris@0
|
837 if ($tokenIsArray === true
|
Chris@0
|
838 && $token[0] === T_STRING
|
Chris@0
|
839 && strtolower($token[1]) === 'trait'
|
Chris@0
|
840 && $tokens[($stackPtr - 1)][0] !== T_OBJECT_OPERATOR
|
Chris@0
|
841 && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM
|
Chris@0
|
842 ) {
|
Chris@0
|
843 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
844 'content' => $token[1],
|
Chris@0
|
845 'code' => T_TRAIT,
|
Chris@0
|
846 'type' => 'T_TRAIT',
|
Chris@0
|
847 );
|
Chris@0
|
848
|
Chris@0
|
849 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
850 echo "\t\t* token $stackPtr changed from T_STRING to T_TRAIT".PHP_EOL;
|
Chris@0
|
851 }
|
Chris@0
|
852
|
Chris@0
|
853 $newStackPtr++;
|
Chris@0
|
854 continue;
|
Chris@0
|
855 }
|
Chris@0
|
856
|
Chris@0
|
857 /*
|
Chris@0
|
858 PHP doesn't assign a token to goto labels, so we have to.
|
Chris@0
|
859 These are just string tokens with a single colon after them. Double
|
Chris@0
|
860 colons are already tokenized and so don't interfere with this check.
|
Chris@0
|
861 But we do have to account for CASE statements, that look just like
|
Chris@0
|
862 goto labels.
|
Chris@0
|
863 */
|
Chris@0
|
864
|
Chris@0
|
865 if ($tokenIsArray === true
|
Chris@0
|
866 && $token[0] === T_STRING
|
Chris@0
|
867 && isset($tokens[($stackPtr + 1)]) === true
|
Chris@0
|
868 && $tokens[($stackPtr + 1)] === ':'
|
Chris@0
|
869 && $tokens[($stackPtr - 1)][0] !== T_PAAMAYIM_NEKUDOTAYIM
|
Chris@0
|
870 ) {
|
Chris@0
|
871 $stopTokens = array(
|
Chris@0
|
872 T_CASE => true,
|
Chris@0
|
873 T_SEMICOLON => true,
|
Chris@0
|
874 T_OPEN_CURLY_BRACKET => true,
|
Chris@0
|
875 T_INLINE_THEN => true,
|
Chris@0
|
876 );
|
Chris@0
|
877
|
Chris@0
|
878 for ($x = ($newStackPtr - 1); $x > 0; $x--) {
|
Chris@0
|
879 if (isset($stopTokens[$finalTokens[$x]['code']]) === true) {
|
Chris@0
|
880 break;
|
Chris@0
|
881 }
|
Chris@0
|
882 }
|
Chris@0
|
883
|
Chris@0
|
884 if ($finalTokens[$x]['code'] !== T_CASE
|
Chris@0
|
885 && $finalTokens[$x]['code'] !== T_INLINE_THEN
|
Chris@0
|
886 ) {
|
Chris@0
|
887 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
888 'content' => $token[1].':',
|
Chris@0
|
889 'code' => T_GOTO_LABEL,
|
Chris@0
|
890 'type' => 'T_GOTO_LABEL',
|
Chris@0
|
891 );
|
Chris@0
|
892
|
Chris@0
|
893 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
894 echo "\t\t* token $stackPtr changed from T_STRING to T_GOTO_LABEL".PHP_EOL;
|
Chris@0
|
895 echo "\t\t* skipping T_COLON token ".($stackPtr + 1).PHP_EOL;
|
Chris@0
|
896 }
|
Chris@0
|
897
|
Chris@0
|
898 $newStackPtr++;
|
Chris@0
|
899 $stackPtr++;
|
Chris@0
|
900 continue;
|
Chris@0
|
901 }
|
Chris@0
|
902 }//end if
|
Chris@0
|
903
|
Chris@0
|
904 /*
|
Chris@0
|
905 HHVM 3.5 tokenizes "else[\s]+if" as a T_ELSEIF token while PHP
|
Chris@0
|
906 proper only tokenizes "elseif" as a T_ELSEIF token. So split
|
Chris@0
|
907 up the HHVM token to make it looks like proper PHP.
|
Chris@0
|
908 */
|
Chris@0
|
909
|
Chris@0
|
910 if ($tokenIsArray === true
|
Chris@0
|
911 && $token[0] === T_ELSEIF
|
Chris@0
|
912 && strtolower($token[1]) !== 'elseif'
|
Chris@0
|
913 ) {
|
Chris@0
|
914 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
915 'content' => substr($token[1], 0, 4),
|
Chris@0
|
916 'code' => T_ELSE,
|
Chris@0
|
917 'type' => 'T_ELSE',
|
Chris@0
|
918 );
|
Chris@0
|
919
|
Chris@0
|
920 $newStackPtr++;
|
Chris@0
|
921 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
922 'content' => substr($token[1], 4, -2),
|
Chris@0
|
923 'code' => T_WHITESPACE,
|
Chris@0
|
924 'type' => 'T_WHITESPACE',
|
Chris@0
|
925 );
|
Chris@0
|
926
|
Chris@0
|
927 $newStackPtr++;
|
Chris@0
|
928 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
929 'content' => substr($token[1], -2),
|
Chris@0
|
930 'code' => T_IF,
|
Chris@0
|
931 'type' => 'T_IF',
|
Chris@0
|
932 );
|
Chris@0
|
933
|
Chris@0
|
934 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
935 echo "\t\t* token $stackPtr changed from T_ELSEIF to T_ELSE/T_WHITESPACE/T_IF".PHP_EOL;
|
Chris@0
|
936 }
|
Chris@0
|
937
|
Chris@0
|
938 $newStackPtr++;
|
Chris@0
|
939 continue;
|
Chris@0
|
940 }//end if
|
Chris@0
|
941
|
Chris@0
|
942 /*
|
Chris@0
|
943 HHVM 3.5 and 3.6 tokenizes a hashbang line such as #!/usr/bin/php
|
Chris@0
|
944 as T_HASHANG while PHP proper uses T_INLINE_HTML.
|
Chris@0
|
945 */
|
Chris@0
|
946
|
Chris@0
|
947 if ($tokenIsArray === true && token_name($token[0]) === 'T_HASHBANG') {
|
Chris@0
|
948 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
949 'content' => $token[1],
|
Chris@0
|
950 'code' => T_INLINE_HTML,
|
Chris@0
|
951 'type' => 'T_INLINE_HTML',
|
Chris@0
|
952 );
|
Chris@0
|
953
|
Chris@0
|
954 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
955 echo "\t\t* token $stackPtr changed from T_HASHBANG to T_INLINE_HTML".PHP_EOL;
|
Chris@0
|
956 }
|
Chris@0
|
957
|
Chris@0
|
958 $newStackPtr++;
|
Chris@0
|
959 continue;
|
Chris@0
|
960 }//end if
|
Chris@0
|
961
|
Chris@0
|
962 /*
|
Chris@0
|
963 If this token has newlines in its content, split each line up
|
Chris@0
|
964 and create a new token for each line. We do this so it's easier
|
Chris@0
|
965 to ascertain where errors occur on a line.
|
Chris@0
|
966 Note that $token[1] is the token's content.
|
Chris@0
|
967 */
|
Chris@0
|
968
|
Chris@0
|
969 if ($tokenIsArray === true && strpos($token[1], $eolChar) !== false) {
|
Chris@0
|
970 $tokenLines = explode($eolChar, $token[1]);
|
Chris@0
|
971 $numLines = count($tokenLines);
|
Chris@0
|
972 $newToken = array(
|
Chris@0
|
973 'type' => token_name($token[0]),
|
Chris@0
|
974 'code' => $token[0],
|
Chris@0
|
975 'content' => '',
|
Chris@0
|
976 );
|
Chris@0
|
977
|
Chris@0
|
978 for ($i = 0; $i < $numLines; $i++) {
|
Chris@0
|
979 $newToken['content'] = $tokenLines[$i];
|
Chris@0
|
980 if ($i === ($numLines - 1)) {
|
Chris@0
|
981 if ($tokenLines[$i] === '') {
|
Chris@0
|
982 break;
|
Chris@0
|
983 }
|
Chris@0
|
984 } else {
|
Chris@0
|
985 $newToken['content'] .= $eolChar;
|
Chris@0
|
986 }
|
Chris@0
|
987
|
Chris@0
|
988 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
989 $newStackPtr++;
|
Chris@0
|
990 }
|
Chris@0
|
991 } else {
|
Chris@0
|
992 if ($tokenIsArray === true && $token[0] === T_STRING) {
|
Chris@0
|
993 // Some T_STRING tokens should remain that way
|
Chris@0
|
994 // due to their context.
|
Chris@0
|
995 $context = array(
|
Chris@0
|
996 T_OBJECT_OPERATOR => true,
|
Chris@0
|
997 T_FUNCTION => true,
|
Chris@0
|
998 T_CLASS => true,
|
Chris@0
|
999 T_EXTENDS => true,
|
Chris@0
|
1000 T_IMPLEMENTS => true,
|
Chris@0
|
1001 T_NEW => true,
|
Chris@0
|
1002 T_CONST => true,
|
Chris@0
|
1003 T_NS_SEPARATOR => true,
|
Chris@0
|
1004 T_USE => true,
|
Chris@0
|
1005 T_NAMESPACE => true,
|
Chris@0
|
1006 T_PAAMAYIM_NEKUDOTAYIM => true,
|
Chris@0
|
1007 );
|
Chris@0
|
1008 if (isset($context[$finalTokens[$lastNotEmptyToken]['code']]) === true) {
|
Chris@0
|
1009 // Special case for syntax like: return new self
|
Chris@0
|
1010 // where self should not be a string.
|
Chris@0
|
1011 if ($finalTokens[$lastNotEmptyToken]['code'] === T_NEW
|
Chris@0
|
1012 && strtolower($token[1]) === 'self'
|
Chris@0
|
1013 ) {
|
Chris@0
|
1014 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
1015 'content' => $token[1],
|
Chris@0
|
1016 'code' => T_SELF,
|
Chris@0
|
1017 'type' => 'T_SELF',
|
Chris@0
|
1018 );
|
Chris@0
|
1019 } else {
|
Chris@0
|
1020 $finalTokens[$newStackPtr] = array(
|
Chris@0
|
1021 'content' => $token[1],
|
Chris@0
|
1022 'code' => T_STRING,
|
Chris@0
|
1023 'type' => 'T_STRING',
|
Chris@0
|
1024 );
|
Chris@0
|
1025 }
|
Chris@0
|
1026
|
Chris@0
|
1027 $newStackPtr++;
|
Chris@0
|
1028 continue;
|
Chris@0
|
1029 }//end if
|
Chris@0
|
1030 }//end if
|
Chris@0
|
1031
|
Chris@0
|
1032 $newToken = null;
|
Chris@0
|
1033 if ($tokenIsArray === false) {
|
Chris@0
|
1034 if (isset(self::$_resolveTokenCache[$token[0]]) === true) {
|
Chris@0
|
1035 $newToken = self::$_resolveTokenCache[$token[0]];
|
Chris@0
|
1036 }
|
Chris@0
|
1037 } else {
|
Chris@0
|
1038 $cacheKey = null;
|
Chris@0
|
1039 if ($token[0] === T_STRING) {
|
Chris@0
|
1040 $cacheKey = strtolower($token[1]);
|
Chris@0
|
1041 } else if ($token[0] !== T_CURLY_OPEN) {
|
Chris@0
|
1042 $cacheKey = $token[0];
|
Chris@0
|
1043 }
|
Chris@0
|
1044
|
Chris@0
|
1045 if ($cacheKey !== null && isset(self::$_resolveTokenCache[$cacheKey]) === true) {
|
Chris@0
|
1046 $newToken = self::$_resolveTokenCache[$cacheKey];
|
Chris@0
|
1047 $newToken['content'] = $token[1];
|
Chris@0
|
1048 }
|
Chris@0
|
1049 }
|
Chris@0
|
1050
|
Chris@0
|
1051 if ($newToken === null) {
|
Chris@0
|
1052 $newToken = self::standardiseToken($token);
|
Chris@0
|
1053 }
|
Chris@0
|
1054
|
Chris@0
|
1055 // Convert colons that are actually the ELSE component of an
|
Chris@0
|
1056 // inline IF statement.
|
Chris@0
|
1057 if (empty($insideInlineIf) === false && $newToken['code'] === T_COLON) {
|
Chris@0
|
1058 array_pop($insideInlineIf);
|
Chris@0
|
1059 $newToken['code'] = T_INLINE_ELSE;
|
Chris@0
|
1060 $newToken['type'] = 'T_INLINE_ELSE';
|
Chris@0
|
1061 }
|
Chris@0
|
1062
|
Chris@0
|
1063 // This is a special condition for T_ARRAY tokens used for
|
Chris@0
|
1064 // type hinting function arguments as being arrays. We want to keep
|
Chris@0
|
1065 // the parenthesis map clean, so let's tag these tokens as
|
Chris@0
|
1066 // T_ARRAY_HINT.
|
Chris@0
|
1067 if ($newToken['code'] === T_ARRAY) {
|
Chris@0
|
1068 for ($i = $stackPtr; $i < $numTokens; $i++) {
|
Chris@0
|
1069 if ($tokens[$i] === '(') {
|
Chris@0
|
1070 break;
|
Chris@0
|
1071 } else if ($tokens[$i][0] === T_VARIABLE) {
|
Chris@0
|
1072 $newToken['code'] = T_ARRAY_HINT;
|
Chris@0
|
1073 $newToken['type'] = 'T_ARRAY_HINT';
|
Chris@0
|
1074 break;
|
Chris@0
|
1075 }
|
Chris@0
|
1076 }
|
Chris@0
|
1077 }
|
Chris@0
|
1078
|
Chris@0
|
1079 // This is a special case when checking PHP 5.5+ code in PHP < 5.5
|
Chris@0
|
1080 // where "finally" should be T_FINALLY instead of T_STRING.
|
Chris@0
|
1081 if ($newToken['code'] === T_STRING
|
Chris@0
|
1082 && strtolower($newToken['content']) === 'finally'
|
Chris@0
|
1083 ) {
|
Chris@0
|
1084 $newToken['code'] = T_FINALLY;
|
Chris@0
|
1085 $newToken['type'] = 'T_FINALLY';
|
Chris@0
|
1086 }
|
Chris@0
|
1087
|
Chris@0
|
1088 // This is a special case for the PHP 5.5 classname::class syntax
|
Chris@0
|
1089 // where "class" should be T_STRING instead of T_CLASS.
|
Chris@0
|
1090 if (($newToken['code'] === T_CLASS
|
Chris@0
|
1091 || $newToken['code'] === T_FUNCTION)
|
Chris@0
|
1092 && $finalTokens[($newStackPtr - 1)]['code'] === T_DOUBLE_COLON
|
Chris@0
|
1093 ) {
|
Chris@0
|
1094 $newToken['code'] = T_STRING;
|
Chris@0
|
1095 $newToken['type'] = 'T_STRING';
|
Chris@0
|
1096 }
|
Chris@0
|
1097
|
Chris@0
|
1098 // This is a special case for PHP 5.6 use function and use const
|
Chris@0
|
1099 // where "function" and "const" should be T_STRING instead of T_FUNCTION
|
Chris@0
|
1100 // and T_CONST.
|
Chris@0
|
1101 if (($newToken['code'] === T_FUNCTION
|
Chris@0
|
1102 || $newToken['code'] === T_CONST)
|
Chris@0
|
1103 && $finalTokens[$lastNotEmptyToken]['code'] === T_USE
|
Chris@0
|
1104 ) {
|
Chris@0
|
1105 $newToken['code'] = T_STRING;
|
Chris@0
|
1106 $newToken['type'] = 'T_STRING';
|
Chris@0
|
1107 }
|
Chris@0
|
1108
|
Chris@0
|
1109 // This is a special case for use groups in PHP 7+ where leaving
|
Chris@0
|
1110 // the curly braces as their normal tokens would confuse
|
Chris@0
|
1111 // the scope map and sniffs.
|
Chris@0
|
1112 if ($newToken['code'] === T_OPEN_CURLY_BRACKET
|
Chris@0
|
1113 && $finalTokens[$lastNotEmptyToken]['code'] === T_NS_SEPARATOR
|
Chris@0
|
1114 ) {
|
Chris@0
|
1115 $newToken['code'] = T_OPEN_USE_GROUP;
|
Chris@0
|
1116 $newToken['type'] = 'T_OPEN_USE_GROUP';
|
Chris@0
|
1117 $insideUseGroup = true;
|
Chris@0
|
1118 }
|
Chris@0
|
1119
|
Chris@0
|
1120 if ($insideUseGroup === true && $newToken['code'] === T_CLOSE_CURLY_BRACKET) {
|
Chris@0
|
1121 $newToken['code'] = T_CLOSE_USE_GROUP;
|
Chris@0
|
1122 $newToken['type'] = 'T_CLOSE_USE_GROUP';
|
Chris@0
|
1123 $insideUseGroup = false;
|
Chris@0
|
1124 }
|
Chris@0
|
1125
|
Chris@0
|
1126 $finalTokens[$newStackPtr] = $newToken;
|
Chris@0
|
1127 $newStackPtr++;
|
Chris@0
|
1128 }//end if
|
Chris@0
|
1129 }//end for
|
Chris@0
|
1130
|
Chris@0
|
1131 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1132 echo "\t*** END PHP TOKENIZING ***".PHP_EOL;
|
Chris@0
|
1133 }
|
Chris@0
|
1134
|
Chris@0
|
1135 return $finalTokens;
|
Chris@0
|
1136
|
Chris@0
|
1137 }//end tokenizeString()
|
Chris@0
|
1138
|
Chris@0
|
1139
|
Chris@0
|
1140 /**
|
Chris@0
|
1141 * Performs additional processing after main tokenizing.
|
Chris@0
|
1142 *
|
Chris@0
|
1143 * This additional processing checks for CASE statements that are using curly
|
Chris@0
|
1144 * braces for scope openers and closers. It also turns some T_FUNCTION tokens
|
Chris@0
|
1145 * into T_CLOSURE when they are not standard function definitions. It also
|
Chris@0
|
1146 * detects short array syntax and converts those square brackets into new tokens.
|
Chris@0
|
1147 * It also corrects some usage of the static and class keywords. It also
|
Chris@0
|
1148 * assigns tokens to function return types.
|
Chris@0
|
1149 *
|
Chris@0
|
1150 * @param array $tokens The array of tokens to process.
|
Chris@0
|
1151 * @param string $eolChar The EOL character to use for splitting strings.
|
Chris@0
|
1152 *
|
Chris@0
|
1153 * @return void
|
Chris@0
|
1154 */
|
Chris@0
|
1155 public function processAdditional(&$tokens, $eolChar)
|
Chris@0
|
1156 {
|
Chris@0
|
1157 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1158 echo "\t*** START ADDITIONAL PHP PROCESSING ***".PHP_EOL;
|
Chris@0
|
1159 }
|
Chris@0
|
1160
|
Chris@0
|
1161 $numTokens = count($tokens);
|
Chris@0
|
1162 for ($i = ($numTokens - 1); $i >= 0; $i--) {
|
Chris@0
|
1163 // Check for any unset scope conditions due to alternate IF/ENDIF syntax.
|
Chris@0
|
1164 if (isset($tokens[$i]['scope_opener']) === true
|
Chris@0
|
1165 && isset($tokens[$i]['scope_condition']) === false
|
Chris@0
|
1166 ) {
|
Chris@0
|
1167 $tokens[$i]['scope_condition'] = $tokens[$tokens[$i]['scope_opener']]['scope_condition'];
|
Chris@0
|
1168 }
|
Chris@0
|
1169
|
Chris@0
|
1170 if ($tokens[$i]['code'] === T_FUNCTION) {
|
Chris@0
|
1171 /*
|
Chris@0
|
1172 Detect functions that are actually closures and
|
Chris@0
|
1173 assign them a different token.
|
Chris@0
|
1174 */
|
Chris@0
|
1175
|
Chris@0
|
1176 if (isset($tokens[$i]['scope_opener']) === true) {
|
Chris@0
|
1177 for ($x = ($i + 1); $x < $numTokens; $x++) {
|
Chris@0
|
1178 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false
|
Chris@0
|
1179 && $tokens[$x]['code'] !== T_BITWISE_AND
|
Chris@0
|
1180 ) {
|
Chris@0
|
1181 break;
|
Chris@0
|
1182 }
|
Chris@0
|
1183 }
|
Chris@0
|
1184
|
Chris@0
|
1185 if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS) {
|
Chris@0
|
1186 $tokens[$i]['code'] = T_CLOSURE;
|
Chris@0
|
1187 $tokens[$i]['type'] = 'T_CLOSURE';
|
Chris@0
|
1188 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1189 $line = $tokens[$i]['line'];
|
Chris@0
|
1190 echo "\t* token $i on line $line changed from T_FUNCTION to T_CLOSURE".PHP_EOL;
|
Chris@0
|
1191 }
|
Chris@0
|
1192
|
Chris@0
|
1193 for ($x = ($tokens[$i]['scope_opener'] + 1); $x < $tokens[$i]['scope_closer']; $x++) {
|
Chris@0
|
1194 if (isset($tokens[$x]['conditions'][$i]) === false) {
|
Chris@0
|
1195 continue;
|
Chris@0
|
1196 }
|
Chris@0
|
1197
|
Chris@0
|
1198 $tokens[$x]['conditions'][$i] = T_CLOSURE;
|
Chris@0
|
1199 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1200 $type = $tokens[$x]['type'];
|
Chris@0
|
1201 echo "\t\t* cleaned $x ($type) *".PHP_EOL;
|
Chris@0
|
1202 }
|
Chris@0
|
1203 }
|
Chris@0
|
1204 }
|
Chris@0
|
1205
|
Chris@0
|
1206 $tokenAfterReturnTypeHint = $tokens[$i]['scope_opener'];
|
Chris@0
|
1207 } else if (isset($tokens[$i]['parenthesis_closer']) === true) {
|
Chris@0
|
1208 $tokenAfterReturnTypeHint = null;
|
Chris@0
|
1209 for ($x = ($tokens[$i]['parenthesis_closer'] + 1); $x < $numTokens; $x++) {
|
Chris@0
|
1210 if ($tokens[$x]['code'] === T_SEMICOLON) {
|
Chris@0
|
1211 $tokenAfterReturnTypeHint = $x;
|
Chris@0
|
1212 break;
|
Chris@0
|
1213 }
|
Chris@0
|
1214 }
|
Chris@0
|
1215
|
Chris@0
|
1216 if ($tokenAfterReturnTypeHint === null) {
|
Chris@0
|
1217 // Probably a syntax error.
|
Chris@0
|
1218 continue;
|
Chris@0
|
1219 }
|
Chris@0
|
1220 } else {
|
Chris@0
|
1221 // Probably a syntax error.
|
Chris@0
|
1222 continue;
|
Chris@0
|
1223 }//end if
|
Chris@0
|
1224
|
Chris@0
|
1225 /*
|
Chris@0
|
1226 Detect function return values and assign them
|
Chris@0
|
1227 a special token, because PHP doesn't.
|
Chris@0
|
1228 */
|
Chris@0
|
1229
|
Chris@0
|
1230 for ($x = ($tokenAfterReturnTypeHint - 1); $x > $i; $x--) {
|
Chris@0
|
1231 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1232 if (in_array($tokens[$x]['code'], array(T_STRING, T_ARRAY, T_ARRAY_HINT, T_CALLABLE, T_SELF, T_PARENT), true) === true) {
|
Chris@0
|
1233 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1234 $line = $tokens[$x]['line'];
|
Chris@0
|
1235 $type = $tokens[$x]['type'];
|
Chris@0
|
1236 echo "\t* token $x on line $line changed from $type to T_RETURN_TYPE".PHP_EOL;
|
Chris@0
|
1237 }
|
Chris@0
|
1238
|
Chris@0
|
1239 $tokens[$x]['code'] = T_RETURN_TYPE;
|
Chris@0
|
1240 $tokens[$x]['type'] = 'T_RETURN_TYPE';
|
Chris@0
|
1241 }
|
Chris@0
|
1242
|
Chris@0
|
1243 break;
|
Chris@0
|
1244 }
|
Chris@0
|
1245 }
|
Chris@0
|
1246
|
Chris@0
|
1247 continue;
|
Chris@0
|
1248 } else if ($tokens[$i]['code'] === T_CLASS && isset($tokens[$i]['scope_opener']) === true) {
|
Chris@0
|
1249 /*
|
Chris@0
|
1250 Detect anonymous classes and assign them a different token.
|
Chris@0
|
1251 */
|
Chris@0
|
1252
|
Chris@0
|
1253 for ($x = ($i + 1); $x < $numTokens; $x++) {
|
Chris@0
|
1254 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1255 break;
|
Chris@0
|
1256 }
|
Chris@0
|
1257 }
|
Chris@0
|
1258
|
Chris@0
|
1259 if ($tokens[$x]['code'] === T_OPEN_PARENTHESIS
|
Chris@0
|
1260 || $tokens[$x]['code'] === T_OPEN_CURLY_BRACKET
|
Chris@0
|
1261 || $tokens[$x]['code'] === T_EXTENDS
|
Chris@0
|
1262 || $tokens[$x]['code'] === T_IMPLEMENTS
|
Chris@0
|
1263 ) {
|
Chris@0
|
1264 $tokens[$i]['code'] = T_ANON_CLASS;
|
Chris@0
|
1265 $tokens[$i]['type'] = 'T_ANON_CLASS';
|
Chris@0
|
1266 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1267 $line = $tokens[$i]['line'];
|
Chris@0
|
1268 echo "\t* token $i on line $line changed from T_CLASS to T_ANON_CLASS".PHP_EOL;
|
Chris@0
|
1269 }
|
Chris@0
|
1270
|
Chris@0
|
1271 for ($x = ($tokens[$i]['scope_opener'] + 1); $x < $tokens[$i]['scope_closer']; $x++) {
|
Chris@0
|
1272 if (isset($tokens[$x]['conditions'][$i]) === false) {
|
Chris@0
|
1273 continue;
|
Chris@0
|
1274 }
|
Chris@0
|
1275
|
Chris@0
|
1276 $tokens[$x]['conditions'][$i] = T_ANON_CLASS;
|
Chris@0
|
1277 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1278 $type = $tokens[$x]['type'];
|
Chris@0
|
1279 echo "\t\t* cleaned $x ($type) *".PHP_EOL;
|
Chris@0
|
1280 }
|
Chris@0
|
1281 }
|
Chris@0
|
1282 }
|
Chris@0
|
1283
|
Chris@0
|
1284 continue;
|
Chris@0
|
1285 } else if ($tokens[$i]['code'] === T_OPEN_SQUARE_BRACKET) {
|
Chris@0
|
1286 if (isset($tokens[$i]['bracket_closer']) === false) {
|
Chris@0
|
1287 continue;
|
Chris@0
|
1288 }
|
Chris@0
|
1289
|
Chris@0
|
1290 // Unless there is a variable or a bracket before this token,
|
Chris@0
|
1291 // it is the start of an array being defined using the short syntax.
|
Chris@0
|
1292 $isShortArray = false;
|
Chris@0
|
1293 $allowed = array(
|
Chris@12
|
1294 T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET,
|
Chris@12
|
1295 T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET,
|
Chris@12
|
1296 T_CLOSE_PARENTHESIS => T_CLOSE_PARENTHESIS,
|
Chris@12
|
1297 T_VARIABLE => T_VARIABLE,
|
Chris@12
|
1298 T_OBJECT_OPERATOR => T_OBJECT_OPERATOR,
|
Chris@12
|
1299 T_STRING => T_STRING,
|
Chris@12
|
1300 T_CONSTANT_ENCAPSED_STRING => T_CONSTANT_ENCAPSED_STRING,
|
Chris@0
|
1301 );
|
Chris@0
|
1302
|
Chris@0
|
1303 for ($x = ($i - 1); $x > 0; $x--) {
|
Chris@0
|
1304 // If we hit a scope opener, the statement has ended
|
Chris@0
|
1305 // without finding anything, so it's probably an array
|
Chris@0
|
1306 // using PHP 7.1 short list syntax.
|
Chris@0
|
1307 if (isset($tokens[$x]['scope_opener']) === true) {
|
Chris@0
|
1308 $isShortArray = true;
|
Chris@0
|
1309 break;
|
Chris@0
|
1310 }
|
Chris@0
|
1311
|
Chris@0
|
1312 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1313 if (isset($allowed[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1314 $isShortArray = true;
|
Chris@0
|
1315 }
|
Chris@0
|
1316
|
Chris@0
|
1317 break;
|
Chris@0
|
1318 }
|
Chris@12
|
1319 }
|
Chris@0
|
1320
|
Chris@0
|
1321 if ($isShortArray === true) {
|
Chris@0
|
1322 $tokens[$i]['code'] = T_OPEN_SHORT_ARRAY;
|
Chris@0
|
1323 $tokens[$i]['type'] = 'T_OPEN_SHORT_ARRAY';
|
Chris@0
|
1324
|
Chris@0
|
1325 $closer = $tokens[$i]['bracket_closer'];
|
Chris@0
|
1326 $tokens[$closer]['code'] = T_CLOSE_SHORT_ARRAY;
|
Chris@0
|
1327 $tokens[$closer]['type'] = 'T_CLOSE_SHORT_ARRAY';
|
Chris@0
|
1328 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1329 $line = $tokens[$i]['line'];
|
Chris@0
|
1330 echo "\t* token $i on line $line changed from T_OPEN_SQUARE_BRACKET to T_OPEN_SHORT_ARRAY".PHP_EOL;
|
Chris@0
|
1331 $line = $tokens[$closer]['line'];
|
Chris@0
|
1332 echo "\t* token $closer on line $line changed from T_CLOSE_SQUARE_BRACKET to T_CLOSE_SHORT_ARRAY".PHP_EOL;
|
Chris@0
|
1333 }
|
Chris@0
|
1334 }
|
Chris@0
|
1335
|
Chris@0
|
1336 continue;
|
Chris@0
|
1337 } else if ($tokens[$i]['code'] === T_STATIC) {
|
Chris@0
|
1338 for ($x = ($i - 1); $x > 0; $x--) {
|
Chris@0
|
1339 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1340 break;
|
Chris@0
|
1341 }
|
Chris@0
|
1342 }
|
Chris@0
|
1343
|
Chris@0
|
1344 if ($tokens[$x]['code'] === T_INSTANCEOF) {
|
Chris@0
|
1345 $tokens[$i]['code'] = T_STRING;
|
Chris@0
|
1346 $tokens[$i]['type'] = 'T_STRING';
|
Chris@0
|
1347
|
Chris@0
|
1348 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1349 $line = $tokens[$i]['line'];
|
Chris@0
|
1350 echo "\t* token $i on line $line changed from T_STATIC to T_STRING".PHP_EOL;
|
Chris@0
|
1351 }
|
Chris@0
|
1352 }
|
Chris@0
|
1353
|
Chris@0
|
1354 continue;
|
Chris@0
|
1355 } else if ($tokens[$i]['code'] === T_ECHO && $tokens[$i]['content'] === '<?=') {
|
Chris@0
|
1356 // HHVM tokenizes <?= as T_ECHO but it should be T_OPEN_TAG_WITH_ECHO.
|
Chris@0
|
1357 $tokens[$i]['code'] = T_OPEN_TAG_WITH_ECHO;
|
Chris@0
|
1358 $tokens[$i]['type'] = 'T_OPEN_TAG_WITH_ECHO';
|
Chris@0
|
1359
|
Chris@0
|
1360 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1361 $line = $tokens[$i]['line'];
|
Chris@0
|
1362 echo "\t* token $i on line $line changed from T_ECHO to T_OPEN_TAG_WITH_ECHO".PHP_EOL;
|
Chris@0
|
1363 }
|
Chris@0
|
1364 } else if ($tokens[$i]['code'] === T_TRUE
|
Chris@0
|
1365 || $tokens[$i]['code'] === T_FALSE
|
Chris@0
|
1366 || $tokens[$i]['code'] === T_NULL
|
Chris@0
|
1367 ) {
|
Chris@0
|
1368 for ($x = ($i + 1); $i < $numTokens; $x++) {
|
Chris@0
|
1369 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1370 // Non-whitespace content.
|
Chris@0
|
1371 break;
|
Chris@0
|
1372 }
|
Chris@0
|
1373 }
|
Chris@0
|
1374
|
Chris@0
|
1375 $context = array(
|
Chris@0
|
1376 T_OBJECT_OPERATOR => true,
|
Chris@0
|
1377 T_NS_SEPARATOR => true,
|
Chris@0
|
1378 T_PAAMAYIM_NEKUDOTAYIM => true,
|
Chris@0
|
1379 );
|
Chris@0
|
1380 if (isset($context[$tokens[$x]['code']]) === true) {
|
Chris@0
|
1381 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1382 $line = $tokens[$i]['line'];
|
Chris@0
|
1383 $type = $tokens[$i]['type'];
|
Chris@0
|
1384 echo "\t* token $i on line $line changed from $type to T_STRING".PHP_EOL;
|
Chris@0
|
1385 }
|
Chris@0
|
1386
|
Chris@0
|
1387 $tokens[$i]['code'] = T_STRING;
|
Chris@0
|
1388 $tokens[$i]['type'] = 'T_STRING';
|
Chris@0
|
1389 }
|
Chris@0
|
1390 } else if ($tokens[$i]['code'] === T_CONST) {
|
Chris@0
|
1391 // Context sensitive keywords support.
|
Chris@0
|
1392 for ($x = ($i + 1); $i < $numTokens; $x++) {
|
Chris@0
|
1393 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1394 // Non-whitespace content.
|
Chris@0
|
1395 break;
|
Chris@0
|
1396 }
|
Chris@0
|
1397 }
|
Chris@0
|
1398
|
Chris@0
|
1399 if ($tokens[$x]['code'] !== T_STRING) {
|
Chris@0
|
1400 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1401 $line = $tokens[$x]['line'];
|
Chris@0
|
1402 $type = $tokens[$x]['type'];
|
Chris@0
|
1403 echo "\t* token $x on line $line changed from $type to T_STRING".PHP_EOL;
|
Chris@0
|
1404 }
|
Chris@0
|
1405
|
Chris@0
|
1406 $tokens[$x]['code'] = T_STRING;
|
Chris@0
|
1407 $tokens[$x]['type'] = 'T_STRING';
|
Chris@0
|
1408 }
|
Chris@0
|
1409 }//end if
|
Chris@0
|
1410
|
Chris@0
|
1411 if (($tokens[$i]['code'] !== T_CASE
|
Chris@0
|
1412 && $tokens[$i]['code'] !== T_DEFAULT)
|
Chris@0
|
1413 || isset($tokens[$i]['scope_opener']) === false
|
Chris@0
|
1414 ) {
|
Chris@0
|
1415 // Only interested in CASE and DEFAULT statements from here on in.
|
Chris@0
|
1416 continue;
|
Chris@0
|
1417 }
|
Chris@0
|
1418
|
Chris@0
|
1419 $scopeOpener = $tokens[$i]['scope_opener'];
|
Chris@0
|
1420 $scopeCloser = $tokens[$i]['scope_closer'];
|
Chris@0
|
1421
|
Chris@0
|
1422 // If the first char after the opener is a curly brace
|
Chris@0
|
1423 // and that brace has been ignored, it is actually
|
Chris@0
|
1424 // opening this case statement and the opener and closer are
|
Chris@0
|
1425 // probably set incorrectly.
|
Chris@0
|
1426 for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) {
|
Chris@0
|
1427 if (isset(PHP_CodeSniffer_Tokens::$emptyTokens[$tokens[$x]['code']]) === false) {
|
Chris@0
|
1428 // Non-whitespace content.
|
Chris@0
|
1429 break;
|
Chris@0
|
1430 }
|
Chris@0
|
1431 }
|
Chris@0
|
1432
|
Chris@0
|
1433 if ($tokens[$x]['code'] === T_CASE || $tokens[$x]['code'] === T_DEFAULT) {
|
Chris@0
|
1434 // Special case for multiple CASE statements that share the same
|
Chris@0
|
1435 // closer. Because we are going backwards through the file, this next
|
Chris@0
|
1436 // CASE/DEFAULT statement is already fixed, so just use its closer
|
Chris@0
|
1437 // and don't worry about fixing anything.
|
Chris@0
|
1438 $newCloser = $tokens[$x]['scope_closer'];
|
Chris@0
|
1439 $tokens[$i]['scope_closer'] = $newCloser;
|
Chris@0
|
1440 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1441 $oldType = $tokens[$scopeCloser]['type'];
|
Chris@0
|
1442 $newType = $tokens[$newCloser]['type'];
|
Chris@0
|
1443 $line = $tokens[$i]['line'];
|
Chris@0
|
1444 echo "\t* token $i (T_CASE) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
|
Chris@0
|
1445 }
|
Chris@0
|
1446
|
Chris@0
|
1447 continue;
|
Chris@0
|
1448 }
|
Chris@0
|
1449
|
Chris@0
|
1450 if ($tokens[$x]['code'] !== T_OPEN_CURLY_BRACKET
|
Chris@0
|
1451 || isset($tokens[$x]['scope_condition']) === true
|
Chris@0
|
1452 ) {
|
Chris@0
|
1453 // Not a CASE/DEFAULT with a curly brace opener.
|
Chris@0
|
1454 continue;
|
Chris@0
|
1455 }
|
Chris@0
|
1456
|
Chris@0
|
1457 // The closer for this CASE/DEFAULT should be the closing curly brace and
|
Chris@0
|
1458 // not whatever it already is. The opener needs to be the opening curly
|
Chris@0
|
1459 // brace so everything matches up.
|
Chris@0
|
1460 $newCloser = $tokens[$x]['bracket_closer'];
|
Chris@0
|
1461 foreach (array($i, $x, $newCloser) as $index) {
|
Chris@0
|
1462 $tokens[$index]['scope_condition'] = $i;
|
Chris@0
|
1463 $tokens[$index]['scope_opener'] = $x;
|
Chris@0
|
1464 $tokens[$index]['scope_closer'] = $newCloser;
|
Chris@0
|
1465 }
|
Chris@0
|
1466
|
Chris@0
|
1467 unset($tokens[$scopeOpener]['scope_condition']);
|
Chris@0
|
1468 unset($tokens[$scopeOpener]['scope_opener']);
|
Chris@0
|
1469 unset($tokens[$scopeOpener]['scope_closer']);
|
Chris@0
|
1470 unset($tokens[$scopeCloser]['scope_condition']);
|
Chris@0
|
1471 unset($tokens[$scopeCloser]['scope_opener']);
|
Chris@0
|
1472 unset($tokens[$scopeCloser]['scope_closer']);
|
Chris@0
|
1473 unset($tokens[$x]['bracket_opener']);
|
Chris@0
|
1474 unset($tokens[$x]['bracket_closer']);
|
Chris@0
|
1475 unset($tokens[$newCloser]['bracket_opener']);
|
Chris@0
|
1476 unset($tokens[$newCloser]['bracket_closer']);
|
Chris@0
|
1477 $tokens[$scopeCloser]['conditions'][] = $i;
|
Chris@0
|
1478
|
Chris@0
|
1479 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1480 $line = $tokens[$i]['line'];
|
Chris@0
|
1481 $tokenType = $tokens[$i]['type'];
|
Chris@0
|
1482
|
Chris@0
|
1483 $oldType = $tokens[$scopeOpener]['type'];
|
Chris@0
|
1484 $newType = $tokens[$x]['type'];
|
Chris@0
|
1485 echo "\t* token $i ($tokenType) on line $line opener changed from $scopeOpener ($oldType) to $x ($newType)".PHP_EOL;
|
Chris@0
|
1486
|
Chris@0
|
1487 $oldType = $tokens[$scopeCloser]['type'];
|
Chris@0
|
1488 $newType = $tokens[$newCloser]['type'];
|
Chris@0
|
1489 echo "\t* token $i ($tokenType) on line $line closer changed from $scopeCloser ($oldType) to $newCloser ($newType)".PHP_EOL;
|
Chris@0
|
1490 }
|
Chris@0
|
1491
|
Chris@0
|
1492 // Now fix up all the tokens that think they are
|
Chris@0
|
1493 // inside the CASE/DEFAULT statement when they are really outside.
|
Chris@0
|
1494 for ($x = $newCloser; $x < $scopeCloser; $x++) {
|
Chris@0
|
1495 foreach ($tokens[$x]['conditions'] as $num => $oldCond) {
|
Chris@0
|
1496 if ($oldCond === $tokens[$i]['code']) {
|
Chris@0
|
1497 $oldConditions = $tokens[$x]['conditions'];
|
Chris@0
|
1498 unset($tokens[$x]['conditions'][$num]);
|
Chris@0
|
1499
|
Chris@0
|
1500 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1501 $type = $tokens[$x]['type'];
|
Chris@0
|
1502 $oldConds = '';
|
Chris@0
|
1503 foreach ($oldConditions as $condition) {
|
Chris@0
|
1504 $oldConds .= token_name($condition).',';
|
Chris@0
|
1505 }
|
Chris@0
|
1506
|
Chris@0
|
1507 $oldConds = rtrim($oldConds, ',');
|
Chris@0
|
1508
|
Chris@0
|
1509 $newConds = '';
|
Chris@0
|
1510 foreach ($tokens[$x]['conditions'] as $condition) {
|
Chris@0
|
1511 $newConds .= token_name($condition).',';
|
Chris@0
|
1512 }
|
Chris@0
|
1513
|
Chris@0
|
1514 $newConds = rtrim($newConds, ',');
|
Chris@0
|
1515
|
Chris@0
|
1516 echo "\t\t* cleaned $x ($type) *".PHP_EOL;
|
Chris@0
|
1517 echo "\t\t\t=> conditions changed from $oldConds to $newConds".PHP_EOL;
|
Chris@0
|
1518 }
|
Chris@0
|
1519
|
Chris@0
|
1520 break;
|
Chris@0
|
1521 }//end if
|
Chris@0
|
1522 }//end foreach
|
Chris@0
|
1523 }//end for
|
Chris@0
|
1524 }//end for
|
Chris@0
|
1525
|
Chris@0
|
1526 if (PHP_CODESNIFFER_VERBOSITY > 1) {
|
Chris@0
|
1527 echo "\t*** END ADDITIONAL PHP PROCESSING ***".PHP_EOL;
|
Chris@0
|
1528 }
|
Chris@0
|
1529
|
Chris@0
|
1530 }//end processAdditional()
|
Chris@0
|
1531
|
Chris@0
|
1532
|
Chris@0
|
1533 /**
|
Chris@0
|
1534 * Takes a token produced from <code>token_get_all()</code> and produces a
|
Chris@0
|
1535 * more uniform token.
|
Chris@0
|
1536 *
|
Chris@0
|
1537 * @param string|array $token The token to convert.
|
Chris@0
|
1538 *
|
Chris@0
|
1539 * @return array The new token.
|
Chris@0
|
1540 */
|
Chris@0
|
1541 public static function standardiseToken($token)
|
Chris@0
|
1542 {
|
Chris@0
|
1543 if (isset($token[1]) === false) {
|
Chris@0
|
1544 if (isset(self::$_resolveTokenCache[$token[0]]) === true) {
|
Chris@0
|
1545 return self::$_resolveTokenCache[$token[0]];
|
Chris@0
|
1546 }
|
Chris@0
|
1547 } else {
|
Chris@0
|
1548 $cacheKey = null;
|
Chris@0
|
1549 if ($token[0] === T_STRING) {
|
Chris@0
|
1550 $cacheKey = strtolower($token[1]);
|
Chris@0
|
1551 } else if ($token[0] !== T_CURLY_OPEN) {
|
Chris@0
|
1552 $cacheKey = $token[0];
|
Chris@0
|
1553 }
|
Chris@0
|
1554
|
Chris@0
|
1555 if ($cacheKey !== null && isset(self::$_resolveTokenCache[$cacheKey]) === true) {
|
Chris@0
|
1556 $newToken = self::$_resolveTokenCache[$cacheKey];
|
Chris@0
|
1557 $newToken['content'] = $token[1];
|
Chris@0
|
1558 return $newToken;
|
Chris@0
|
1559 }
|
Chris@0
|
1560 }
|
Chris@0
|
1561
|
Chris@0
|
1562 if (isset($token[1]) === false) {
|
Chris@0
|
1563 return self::resolveSimpleToken($token[0]);
|
Chris@0
|
1564 }
|
Chris@0
|
1565
|
Chris@0
|
1566 if ($token[0] === T_STRING) {
|
Chris@0
|
1567 switch ($cacheKey) {
|
Chris@0
|
1568 case 'false':
|
Chris@0
|
1569 $newToken['type'] = 'T_FALSE';
|
Chris@0
|
1570 break;
|
Chris@0
|
1571 case 'true':
|
Chris@0
|
1572 $newToken['type'] = 'T_TRUE';
|
Chris@0
|
1573 break;
|
Chris@0
|
1574 case 'null':
|
Chris@0
|
1575 $newToken['type'] = 'T_NULL';
|
Chris@0
|
1576 break;
|
Chris@0
|
1577 case 'self':
|
Chris@0
|
1578 $newToken['type'] = 'T_SELF';
|
Chris@0
|
1579 break;
|
Chris@0
|
1580 case 'parent':
|
Chris@0
|
1581 $newToken['type'] = 'T_PARENT';
|
Chris@0
|
1582 break;
|
Chris@0
|
1583 default:
|
Chris@0
|
1584 $newToken['type'] = 'T_STRING';
|
Chris@0
|
1585 break;
|
Chris@0
|
1586 }
|
Chris@0
|
1587
|
Chris@0
|
1588 $newToken['code'] = constant($newToken['type']);
|
Chris@0
|
1589
|
Chris@0
|
1590 self::$_resolveTokenCache[$cacheKey] = $newToken;
|
Chris@0
|
1591 } else if ($token[0] === T_CURLY_OPEN) {
|
Chris@0
|
1592 $newToken = array(
|
Chris@0
|
1593 'code' => T_OPEN_CURLY_BRACKET,
|
Chris@0
|
1594 'type' => 'T_OPEN_CURLY_BRACKET',
|
Chris@0
|
1595 );
|
Chris@0
|
1596 } else {
|
Chris@0
|
1597 $newToken = array(
|
Chris@0
|
1598 'code' => $token[0],
|
Chris@0
|
1599 'type' => token_name($token[0]),
|
Chris@0
|
1600 );
|
Chris@0
|
1601
|
Chris@0
|
1602 self::$_resolveTokenCache[$token[0]] = $newToken;
|
Chris@0
|
1603 }//end if
|
Chris@0
|
1604
|
Chris@0
|
1605 $newToken['content'] = $token[1];
|
Chris@0
|
1606 return $newToken;
|
Chris@0
|
1607
|
Chris@0
|
1608 }//end standardiseToken()
|
Chris@0
|
1609
|
Chris@0
|
1610
|
Chris@0
|
1611 /**
|
Chris@0
|
1612 * Converts simple tokens into a format that conforms to complex tokens
|
Chris@0
|
1613 * produced by token_get_all().
|
Chris@0
|
1614 *
|
Chris@0
|
1615 * Simple tokens are tokens that are not in array form when produced from
|
Chris@0
|
1616 * token_get_all().
|
Chris@0
|
1617 *
|
Chris@0
|
1618 * @param string $token The simple token to convert.
|
Chris@0
|
1619 *
|
Chris@0
|
1620 * @return array The new token in array format.
|
Chris@0
|
1621 */
|
Chris@0
|
1622 public static function resolveSimpleToken($token)
|
Chris@0
|
1623 {
|
Chris@0
|
1624 $newToken = array();
|
Chris@0
|
1625
|
Chris@0
|
1626 switch ($token) {
|
Chris@0
|
1627 case '{':
|
Chris@0
|
1628 $newToken['type'] = 'T_OPEN_CURLY_BRACKET';
|
Chris@0
|
1629 break;
|
Chris@0
|
1630 case '}':
|
Chris@0
|
1631 $newToken['type'] = 'T_CLOSE_CURLY_BRACKET';
|
Chris@0
|
1632 break;
|
Chris@0
|
1633 case '[':
|
Chris@0
|
1634 $newToken['type'] = 'T_OPEN_SQUARE_BRACKET';
|
Chris@0
|
1635 break;
|
Chris@0
|
1636 case ']':
|
Chris@0
|
1637 $newToken['type'] = 'T_CLOSE_SQUARE_BRACKET';
|
Chris@0
|
1638 break;
|
Chris@0
|
1639 case '(':
|
Chris@0
|
1640 $newToken['type'] = 'T_OPEN_PARENTHESIS';
|
Chris@0
|
1641 break;
|
Chris@0
|
1642 case ')':
|
Chris@0
|
1643 $newToken['type'] = 'T_CLOSE_PARENTHESIS';
|
Chris@0
|
1644 break;
|
Chris@0
|
1645 case ':':
|
Chris@0
|
1646 $newToken['type'] = 'T_COLON';
|
Chris@0
|
1647 break;
|
Chris@0
|
1648 case '.':
|
Chris@0
|
1649 $newToken['type'] = 'T_STRING_CONCAT';
|
Chris@0
|
1650 break;
|
Chris@0
|
1651 case ';':
|
Chris@0
|
1652 $newToken['type'] = 'T_SEMICOLON';
|
Chris@0
|
1653 break;
|
Chris@0
|
1654 case '=':
|
Chris@0
|
1655 $newToken['type'] = 'T_EQUAL';
|
Chris@0
|
1656 break;
|
Chris@0
|
1657 case '*':
|
Chris@0
|
1658 $newToken['type'] = 'T_MULTIPLY';
|
Chris@0
|
1659 break;
|
Chris@0
|
1660 case '/':
|
Chris@0
|
1661 $newToken['type'] = 'T_DIVIDE';
|
Chris@0
|
1662 break;
|
Chris@0
|
1663 case '+':
|
Chris@0
|
1664 $newToken['type'] = 'T_PLUS';
|
Chris@0
|
1665 break;
|
Chris@0
|
1666 case '-':
|
Chris@0
|
1667 $newToken['type'] = 'T_MINUS';
|
Chris@0
|
1668 break;
|
Chris@0
|
1669 case '%':
|
Chris@0
|
1670 $newToken['type'] = 'T_MODULUS';
|
Chris@0
|
1671 break;
|
Chris@0
|
1672 case '^':
|
Chris@0
|
1673 $newToken['type'] = 'T_BITWISE_XOR';
|
Chris@0
|
1674 break;
|
Chris@0
|
1675 case '&':
|
Chris@0
|
1676 $newToken['type'] = 'T_BITWISE_AND';
|
Chris@0
|
1677 break;
|
Chris@0
|
1678 case '|':
|
Chris@0
|
1679 $newToken['type'] = 'T_BITWISE_OR';
|
Chris@0
|
1680 break;
|
Chris@0
|
1681 case '<':
|
Chris@0
|
1682 $newToken['type'] = 'T_LESS_THAN';
|
Chris@0
|
1683 break;
|
Chris@0
|
1684 case '>':
|
Chris@0
|
1685 $newToken['type'] = 'T_GREATER_THAN';
|
Chris@0
|
1686 break;
|
Chris@0
|
1687 case '!':
|
Chris@0
|
1688 $newToken['type'] = 'T_BOOLEAN_NOT';
|
Chris@0
|
1689 break;
|
Chris@0
|
1690 case ',':
|
Chris@0
|
1691 $newToken['type'] = 'T_COMMA';
|
Chris@0
|
1692 break;
|
Chris@0
|
1693 case '@':
|
Chris@0
|
1694 $newToken['type'] = 'T_ASPERAND';
|
Chris@0
|
1695 break;
|
Chris@0
|
1696 case '$':
|
Chris@0
|
1697 $newToken['type'] = 'T_DOLLAR';
|
Chris@0
|
1698 break;
|
Chris@0
|
1699 case '`':
|
Chris@0
|
1700 $newToken['type'] = 'T_BACKTICK';
|
Chris@0
|
1701 break;
|
Chris@0
|
1702 default:
|
Chris@0
|
1703 $newToken['type'] = 'T_NONE';
|
Chris@0
|
1704 break;
|
Chris@0
|
1705 }//end switch
|
Chris@0
|
1706
|
Chris@0
|
1707 $newToken['code'] = constant($newToken['type']);
|
Chris@0
|
1708 $newToken['content'] = $token;
|
Chris@0
|
1709
|
Chris@0
|
1710 self::$_resolveTokenCache[$token] = $newToken;
|
Chris@0
|
1711 return $newToken;
|
Chris@0
|
1712
|
Chris@0
|
1713 }//end resolveSimpleToken()
|
Chris@0
|
1714
|
Chris@0
|
1715
|
Chris@0
|
1716 }//end class
|