Completed
Push — master ( 8418b3...91ec6e )
by
unknown
13s queued 11s
created

Source/Language/PHP/PHPTokenizerInternal.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * This file is part of PDepend.
4
 *
5
 * PHP Version 5
6
 *
7
 * Copyright (c) 2008-2017 Manuel Pichler <[email protected]>.
8
 * All rights reserved.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 *
14
 *   * Redistributions of source code must retain the above copyright
15
 *     notice, this list of conditions and the following disclaimer.
16
 *
17
 *   * Redistributions in binary form must reproduce the above copyright
18
 *     notice, this list of conditions and the following disclaimer in
19
 *     the documentation and/or other materials provided with the
20
 *     distribution.
21
 *
22
 *   * Neither the name of Manuel Pichler nor the names of his
23
 *     contributors may be used to endorse or promote products derived
24
 *     from this software without specific prior written permission.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37
 * POSSIBILITY OF SUCH DAMAGE.
38
 *
39
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
40
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
41
 */
42
43
namespace PDepend\Source\Language\PHP;
44
45
use PDepend\Source\AST\ASTCompilationUnit;
46
use PDepend\Source\Tokenizer\Token;
47
use PDepend\Source\Tokenizer\Tokenizer;
48
use PDepend\Source\Tokenizer\Tokens;
49
50
/**
51
 * Define PHP 5.4 __TRAIT__ token constant.
52
 */
53
if (!defined('T_TRAIT_C')) {
54
    define('T_TRAIT_C', 42000);
55
}
56
57
/**
58
 * Define PHP 5.4 'trait' token constant.
59
 */
60
if (!defined('T_TRAIT')) {
61
    define('T_TRAIT', 42001);
62
}
63
64
/**
65
 * Define PHP 5.4 'insteadof' token constant.
66
 */
67
if (!defined('T_INSTEADOF')) {
68
    define('T_INSTEADOF', 42002);
69
}
70
71
/**
72
 * Define PHP 5.3 __NAMESPACE__ token constant.
73
 */
74
if (!defined('T_NS_C')) {
75
    define('T_NS_C', 42003);
76
}
77
78
/**
79
 * Define PHP 5.3 'use' token constant
80
 */
81
if (!defined('T_USE')) {
82
    define('T_USE', 42004);
83
}
84
85
/**
86
 * Define PHP 5.3 'namespace' token constant.
87
 */
88
if (!defined('T_NAMESPACE')) {
89
    define('T_NAMESPACE', 42005);
90
}
91
92
/**
93
 * Define PHP 5.6 '...' token constant
94
 */
95
if (!defined('T_ELLIPSIS')) {
96
    define('T_ELLIPSIS', 42006);
97
}
98
99
/**
100
 * Define PHP 5.3's '__DIR__' token constant.
101
 */
102
if (!defined('T_DIR')) {
103
    define('T_DIR', 42006);
104
}
105
106
/**
107
 * Define PHP 5.3's 'T_GOTO' token constant.
108
 */
109
if (!defined('T_GOTO')) {
110
    define('T_GOTO', 42007);
111
}
112
113
/**
114
 * Define PHP 5.4's 'T_CALLABLE' token constant
115
 */
116
if (!defined('T_CALLABLE')) {
117
    define('T_CALLABLE', 42008);
118
}
119
120
/**
121
 * Define PHP 5.5's 'T_YIELD' token constant
122
 */
123
if (!defined('T_YIELD')) {
124
    define('T_YIELD', 42009);
125
}
126
127
/**
128
 * Define PHP 5,5's 'T_FINALLY' token constant
129
 */
130
if (!defined('T_FINALLY')) {
131
    define('T_FINALLY', 42010);
132
}
133
134
/**
135
 * Define character token that was removed in PHP 7
136
 */
137
if (!defined('T_CHARACTER')) {
138
    define('T_CHARACTER', 42011);
139
}
140
141
/**
142
 * Define bad character token that was removed in PHP 7
143
 */
144
if (!defined('T_BAD_CHARACTER')) {
145
    define('T_BAD_CHARACTER', 42012);
146
}
147
148
/**
149
 * Define PHP 7's '<=>' token constant
150
 */
151
if (!defined('T_SPACESHIP')) {
152
    define('T_SPACESHIP', 42013);
153
}
154
155
/**
156
 * Define PHP 7's '??' token constant
157
 */
158
if (!defined('T_COALESCE')) {
159
    define('T_COALESCE', 42014);
160
}
161
162
/**
163
 * Define PHP 7's '**' token constant
164
 */
165
if (!defined('T_POW')) {
166
    define('T_POW', 42015);
167
}
168
169
/**
170
 * This tokenizer uses the internal {@link token_get_all()} function as token stream
171
 * generator.
172
 *
173
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
174
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
175
 */
176
class PHPTokenizerInternal implements Tokenizer
177
{
178
    /**
179
     * Mapping between php internal tokens and php depend tokens.
180
     *
181
     * @var array<integer, integer>
182
     */
183
    protected static $tokenMap = array(
184
        T_AS                        =>  Tokens::T_AS,
185
        T_DO                        =>  Tokens::T_DO,
186
        T_IF                        =>  Tokens::T_IF,
187
        T_SL                        =>  Tokens::T_SL,
188
        T_SR                        =>  Tokens::T_SR,
189
        T_DEC                       =>  Tokens::T_DEC,
190
        T_FOR                       =>  Tokens::T_FOR,
191
        T_INC                       =>  Tokens::T_INC,
192
        T_NEW                       =>  Tokens::T_NEW,
193
        T_POW                       =>  Tokens::T_POW,
194
        T_TRY                       =>  Tokens::T_TRY,
195
        T_USE                       =>  Tokens::T_USE,
196
        T_VAR                       =>  Tokens::T_VAR,
197
        T_CASE                      =>  Tokens::T_CASE,
198
        T_ECHO                      =>  Tokens::T_ECHO,
199
        T_ELSE                      =>  Tokens::T_ELSE,
200
        T_EVAL                      =>  Tokens::T_EVAL,
201
        T_EXIT                      =>  Tokens::T_EXIT,
202
        T_FILE                      =>  Tokens::T_FILE,
203
        T_GOTO                      =>  Tokens::T_GOTO,
204
        T_LINE                      =>  Tokens::T_LINE,
205
        T_LIST                      =>  Tokens::T_LIST,
206
        T_NS_C                      =>  Tokens::T_NS_C,
207
        T_ARRAY                     =>  Tokens::T_ARRAY,
208
        T_BREAK                     =>  Tokens::T_BREAK,
209
        T_CLASS                     =>  Tokens::T_CLASS,
210
        T_CATCH                     =>  Tokens::T_CATCH,
211
        T_CLONE                     =>  Tokens::T_CLONE,
212
        T_CONST                     =>  Tokens::T_CONST,
213
        T_EMPTY                     =>  Tokens::T_EMPTY,
214
        T_ENDIF                     =>  Tokens::T_ENDIF,
215
        T_FINAL                     =>  Tokens::T_FINAL,
216
        T_ISSET                     =>  Tokens::T_ISSET,
217
        T_PRINT                     =>  Tokens::T_PRINT,
218
        T_THROW                     =>  Tokens::T_THROW,
219
        T_TRAIT                     =>  Tokens::T_TRAIT,
220
        T_UNSET                     =>  Tokens::T_UNSET,
221
        T_WHILE                     =>  Tokens::T_WHILE,
222
        T_ENDFOR                    =>  Tokens::T_ENDFOR,
223
        T_ELSEIF                    =>  Tokens::T_ELSEIF,
224
        T_FUNC_C                    =>  Tokens::T_FUNC_C,
225
        T_GLOBAL                    =>  Tokens::T_GLOBAL,
226
        T_PUBLIC                    =>  Tokens::T_PUBLIC,
227
        T_RETURN                    =>  Tokens::T_RETURN,
228
        T_STATIC                    =>  Tokens::T_STATIC,
229
        T_STRING                    =>  Tokens::T_STRING,
230
        T_SWITCH                    =>  Tokens::T_SWITCH,
231
        T_CLASS_C                   =>  Tokens::T_CLASS_C,
232
        T_COMMENT                   =>  Tokens::T_COMMENT,
233
        T_DECLARE                   =>  Tokens::T_DECLARE,
234
        T_DEFAULT                   =>  Tokens::T_DEFAULT,
235
        T_DNUMBER                   =>  Tokens::T_DNUMBER,
236
        T_EXTENDS                   =>  Tokens::T_EXTENDS,
237
        T_FOREACH                   =>  Tokens::T_FOREACH,
238
        T_INCLUDE                   =>  Tokens::T_INCLUDE,
239
        T_LNUMBER                   =>  Tokens::T_LNUMBER,
240
        T_PRIVATE                   =>  Tokens::T_PRIVATE,
241
        T_REQUIRE                   =>  Tokens::T_REQUIRE,
242
        T_TRAIT_C                   =>  Tokens::T_TRAIT_C,
243
        T_ABSTRACT                  =>  Tokens::T_ABSTRACT,
244
        T_CALLABLE                  =>  Tokens::T_CALLABLE,
245
        T_ENDWHILE                  =>  Tokens::T_ENDWHILE,
246
        T_FUNCTION                  =>  Tokens::T_FUNCTION,
247
        T_INT_CAST                  =>  Tokens::T_INT_CAST,
248
        T_IS_EQUAL                  =>  Tokens::T_IS_EQUAL,
249
        T_OR_EQUAL                  =>  Tokens::T_OR_EQUAL,
250
        T_CONTINUE                  =>  Tokens::T_CONTINUE,
251
        T_METHOD_C                  =>  Tokens::T_METHOD_C,
252
        T_ELLIPSIS                  =>  Tokens::T_ELLIPSIS,
253
        T_OPEN_TAG                  =>  Tokens::T_OPEN_TAG,
254
        T_SL_EQUAL                  =>  Tokens::T_SL_EQUAL,
255
        T_SR_EQUAL                  =>  Tokens::T_SR_EQUAL,
256
        T_VARIABLE                  =>  Tokens::T_VARIABLE,
257
        T_ENDSWITCH                 =>  Tokens::T_ENDSWITCH,
258
        T_DIV_EQUAL                 =>  Tokens::T_DIV_EQUAL,
259
        T_AND_EQUAL                 =>  Tokens::T_AND_EQUAL,
260
        T_MOD_EQUAL                 =>  Tokens::T_MOD_EQUAL,
261
        T_MUL_EQUAL                 =>  Tokens::T_MUL_EQUAL,
262
        T_NAMESPACE                 =>  Tokens::T_NAMESPACE,
263
        T_XOR_EQUAL                 =>  Tokens::T_XOR_EQUAL,
264
        T_INTERFACE                 =>  Tokens::T_INTERFACE,
265
        T_BOOL_CAST                 =>  Tokens::T_BOOL_CAST,
266
        T_CHARACTER                 =>  Tokens::T_CHARACTER,
267
        T_CLOSE_TAG                 =>  Tokens::T_CLOSE_TAG,
268
        T_INSTEADOF                 =>  Tokens::T_INSTEADOF,
269
        T_PROTECTED                 =>  Tokens::T_PROTECTED,
270
        T_SPACESHIP                 =>  Tokens::T_SPACESHIP,
271
        T_CURLY_OPEN                =>  Tokens::T_CURLY_BRACE_OPEN,
272
        T_ENDFOREACH                =>  Tokens::T_ENDFOREACH,
273
        T_ENDDECLARE                =>  Tokens::T_ENDDECLARE,
274
        T_IMPLEMENTS                =>  Tokens::T_IMPLEMENTS,
275
        T_NUM_STRING                =>  Tokens::T_NUM_STRING,
276
        T_PLUS_EQUAL                =>  Tokens::T_PLUS_EQUAL,
277
        T_ARRAY_CAST                =>  Tokens::T_ARRAY_CAST,
278
        T_BOOLEAN_OR                =>  Tokens::T_BOOLEAN_OR,
279
        T_INSTANCEOF                =>  Tokens::T_INSTANCEOF,
280
        T_LOGICAL_OR                =>  Tokens::T_LOGICAL_OR,
281
        T_UNSET_CAST                =>  Tokens::T_UNSET_CAST,
282
        T_DOC_COMMENT               =>  Tokens::T_DOC_COMMENT,
283
        T_END_HEREDOC               =>  Tokens::T_END_HEREDOC,
284
        T_MINUS_EQUAL               =>  Tokens::T_MINUS_EQUAL,
285
        T_BOOLEAN_AND               =>  Tokens::T_BOOLEAN_AND,
286
        T_DOUBLE_CAST               =>  Tokens::T_DOUBLE_CAST,
287
        T_INLINE_HTML               =>  Tokens::T_INLINE_HTML,
288
        T_LOGICAL_AND               =>  Tokens::T_LOGICAL_AND,
289
        T_LOGICAL_XOR               =>  Tokens::T_LOGICAL_XOR,
290
        T_OBJECT_CAST               =>  Tokens::T_OBJECT_CAST,
291
        T_STRING_CAST               =>  Tokens::T_STRING_CAST,
292
        T_DOUBLE_ARROW              =>  Tokens::T_DOUBLE_ARROW,
293
        T_INCLUDE_ONCE              =>  Tokens::T_INCLUDE_ONCE,
294
        T_IS_IDENTICAL              =>  Tokens::T_IS_IDENTICAL,
295
        T_DOUBLE_COLON              =>  Tokens::T_DOUBLE_COLON,
296
        T_CONCAT_EQUAL              =>  Tokens::T_CONCAT_EQUAL,
297
        T_IS_NOT_EQUAL              =>  Tokens::T_IS_NOT_EQUAL,
298
        T_REQUIRE_ONCE              =>  Tokens::T_REQUIRE_ONCE,
299
        T_BAD_CHARACTER             =>  Tokens::T_BAD_CHARACTER,
300
        T_HALT_COMPILER             =>  Tokens::T_HALT_COMPILER,
301
        T_START_HEREDOC             =>  Tokens::T_START_HEREDOC,
302
        T_STRING_VARNAME            =>  Tokens::T_STRING_VARNAME,
303
        T_OBJECT_OPERATOR           =>  Tokens::T_OBJECT_OPERATOR,
304
        T_IS_NOT_IDENTICAL          =>  Tokens::T_IS_NOT_IDENTICAL,
305
        T_OPEN_TAG_WITH_ECHO        =>  Tokens::T_OPEN_TAG_WITH_ECHO,
306
        T_IS_GREATER_OR_EQUAL       =>  Tokens::T_IS_GREATER_OR_EQUAL,
307
        T_IS_SMALLER_OR_EQUAL       =>  Tokens::T_IS_SMALLER_OR_EQUAL,
308
        //T_PAAMAYIM_NEKUDOTAYIM      =>  Tokens::T_DOUBLE_COLON,
309
        T_ENCAPSED_AND_WHITESPACE   =>  Tokens::T_ENCAPSED_AND_WHITESPACE,
310
        T_CONSTANT_ENCAPSED_STRING  =>  Tokens::T_CONSTANT_ENCAPSED_STRING,
311
        T_YIELD                     =>  Tokens::T_YIELD,
312
        T_FINALLY                   =>  Tokens::T_FINALLY,
313
        T_COALESCE                  =>  Tokens::T_COALESCE,
314
        //T_DOLLAR_OPEN_CURLY_BRACES  =>  Tokens::T_CURLY_BRACE_OPEN,
315
    );
316
317
    /**
318
     * Internally used transition token.
319
     */
320
    const T_ELLIPSIS = 23006;
321
322
    /**
323
     * Mapping between php internal text tokens an php depend numeric tokens.
324
     *
325
     * @var array<string, integer>
326
     */
327
    protected static $literalMap = array(
328
        '@'              =>  Tokens::T_AT,
329
        '/'              =>  Tokens::T_DIV,
330
        '%'              =>  Tokens::T_MOD,
331
        '*'              =>  Tokens::T_MUL,
332
        '+'              =>  Tokens::T_PLUS,
333
        ':'              =>  Tokens::T_COLON,
334
        ','              =>  Tokens::T_COMMA,
335
        '='              =>  Tokens::T_EQUAL,
336
        '-'              =>  Tokens::T_MINUS,
337
        '.'              =>  Tokens::T_CONCAT,
338
        '$'              =>  Tokens::T_DOLLAR,
339
        '`'              =>  Tokens::T_BACKTICK,
340
        '\\'             =>  Tokens::T_BACKSLASH,
341
        ';'              =>  Tokens::T_SEMICOLON,
342
        '|'              =>  Tokens::T_BITWISE_OR,
343
        '&'              =>  Tokens::T_BITWISE_AND,
344
        '~'              =>  Tokens::T_BITWISE_NOT,
345
        '^'              =>  Tokens::T_BITWISE_XOR,
346
        '"'              =>  Tokens::T_DOUBLE_QUOTE,
347
        '?'              =>  Tokens::T_QUESTION_MARK,
348
        '!'              =>  Tokens::T_EXCLAMATION_MARK,
349
        '{'              =>  Tokens::T_CURLY_BRACE_OPEN,
350
        '}'              =>  Tokens::T_CURLY_BRACE_CLOSE,
351
        '('              =>  Tokens::T_PARENTHESIS_OPEN,
352
        ')'              =>  Tokens::T_PARENTHESIS_CLOSE,
353
        '<'              =>  Tokens::T_ANGLE_BRACKET_OPEN,
354
        '>'              =>  Tokens::T_ANGLE_BRACKET_CLOSE,
355
        '['              =>  Tokens::T_SQUARED_BRACKET_OPEN,
356
        ']'              =>  Tokens::T_SQUARED_BRACKET_CLOSE,
357
        'use'            =>  Tokens::T_USE,
358
        'goto'           =>  Tokens::T_GOTO,
359
        'null'           =>  Tokens::T_NULL,
360
        'self'           =>  Tokens::T_SELF,
361
        'true'           =>  Tokens::T_TRUE,
362
        'array'          =>  Tokens::T_ARRAY,
363
        'false'          =>  Tokens::T_FALSE,
364
        'trait'          =>  Tokens::T_TRAIT,
365
        'yield'          =>  Tokens::T_YIELD,
366
        'yield from'     =>  Tokens::T_YIELD,
367
        'parent'         =>  Tokens::T_PARENT,
368
        'finally'        =>  Tokens::T_FINALLY,
369
        'callable'       =>  Tokens::T_CALLABLE,
370
        'insteadof'      =>  Tokens::T_INSTEADOF,
371
        'namespace'      =>  Tokens::T_NAMESPACE,
372
        '__dir__'        =>  Tokens::T_DIR,
373
        '__trait__'      =>  Tokens::T_TRAIT_C,
374
        '__namespace__'  =>  Tokens::T_NS_C,
375
    );
376
377
    /**
378
     *
379
     * @var array<mixed, array>
380
     */
381
    protected static $substituteTokens = array(
382
        T_DOLLAR_OPEN_CURLY_BRACES  =>  array('$', '{'),
383
    );
384
385
    /**
386
     * BuilderContext sensitive alternative mappings.
387
     *
388
     * @var array<integer, array>
389
     */
390
    protected static $alternativeMap = array(
391
        Tokens::T_USE => array(
392
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
393
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
394
            Tokens::T_CONST            =>  Tokens::T_STRING,
395
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
396
        ),
397
398
        Tokens::T_GOTO => array(
399
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
400
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
401
            Tokens::T_CONST            =>  Tokens::T_STRING,
402
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
403
        ),
404
405
        Tokens::T_NULL => array(
406
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
407
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
408
            Tokens::T_CONST            =>  Tokens::T_STRING,
409
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
410
        ),
411
412
        Tokens::T_SELF => array(
413
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
414
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
415
            Tokens::T_CONST            =>  Tokens::T_STRING,
416
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
417
        ),
418
419
        Tokens::T_TRUE => array(
420
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
421
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
422
            Tokens::T_NAMESPACE        =>  Tokens::T_STRING,
423
            Tokens::T_CONST            =>  Tokens::T_STRING,
424
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
425
        ),
426
427
        Tokens::T_ARRAY => array(
428
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
429
        ),
430
431
        Tokens::T_FALSE => array(
432
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
433
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
434
            Tokens::T_NAMESPACE        =>  Tokens::T_STRING,
435
            Tokens::T_CONST            =>  Tokens::T_STRING,
436
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
437
        ),
438
439
        Tokens::T_NAMESPACE => array(
440
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
441
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
442
            Tokens::T_CONST            =>  Tokens::T_STRING,
443
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
444
        ),
445
446
        Tokens::T_DIR => array(
447
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
448
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
449
            Tokens::T_CONST            =>  Tokens::T_STRING,
450
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
451
        ),
452
453
        Tokens::T_NS_C => array(
454
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
455
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
456
            Tokens::T_CONST            =>  Tokens::T_STRING,
457
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
458
        ),
459
460
        Tokens::T_PARENT => array(
461
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
462
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
463
            Tokens::T_CONST            =>  Tokens::T_STRING,
464
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
465
        ),
466
467
        Tokens::T_FINALLY => array(
468
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
469
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
470
            Tokens::T_CONST            =>  Tokens::T_STRING,
471
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
472
        ),
473
474
        Tokens::T_CALLABLE => array(
475
            Tokens::T_OBJECT_OPERATOR  => Tokens::T_STRING,
476
            Tokens::T_DOUBLE_COLON     => Tokens::T_STRING,
477
        ),
478
479
        Tokens::T_LIST => array(
480
            Tokens::T_OBJECT_OPERATOR  => Tokens::T_STRING,
481
            Tokens::T_DOUBLE_COLON     => Tokens::T_STRING,
482
        ),
483
484
        Tokens::T_EMPTY => array(
485
            Tokens::T_OBJECT_OPERATOR  => Tokens::T_STRING,
486
            Tokens::T_DOUBLE_COLON     => Tokens::T_STRING,
487
        ),
488
489
        Tokens::T_CLASS => array(
490
            Tokens::T_DOUBLE_COLON     => Tokens::T_CLASS_FQN,
491
        ),
492
    );
493
494
    protected static $reductionMap = array(
495
        Tokens::T_CONCAT => array(
496
            Tokens::T_CONCAT => array(
497
                'type'  => self::T_ELLIPSIS,
498
                'image' => '..',
499
            ),
500
            self::T_ELLIPSIS  =>  array(
501
                'type'  => Tokens::T_ELLIPSIS,
502
                'image' => '...',
503
            )
504
        ),
505
506
        Tokens::T_ANGLE_BRACKET_CLOSE => array(
507
            Tokens::T_IS_SMALLER_OR_EQUAL => array(
508
                'type'  => Tokens::T_SPACESHIP,
509
                'image' => '<=>',
510
            )
511
        ),
512
513
        Tokens::T_QUESTION_MARK => array(
514
            Tokens::T_QUESTION_MARK => array(
515
                'type'  => Tokens::T_COALESCE,
516
                'image' => '??',
517
            )
518
        ),
519
520
        Tokens::T_MUL => array(
521
            Tokens::T_MUL => array(
522
                'type'  => Tokens::T_POW,
523
                'image' => '**',
524
            )
525
        ),
526
    );
527
528
    /**
529
     * The source file instance.
530
     *
531
     * @var \PDepend\Source\AST\ASTCompilationUnit
532
     */
533
    protected $sourceFile = '';
534
535
    /**
536
     * Count of all tokens.
537
     *
538
     * @var integer
539
     */
540
    protected $count = 0;
541
542
    /**
543
     * Internal stream pointer index.
544
     *
545
     * @var integer
546
     */
547
    protected $index = 0;
548
549
    /**
550
     * Prepared token list.
551
     *
552
     * @var Token[]|null
553
     */
554
    protected $tokens = null;
555
556
    /**
557
     * The next free identifier for unknown string tokens.
558
     *
559
     * @var integer
560
     */
561
    private $unknownTokenID = 1000;
562
563
    /**
564
     * Returns the name of the source file.
565
     *
566
     * @return \PDepend\Source\AST\ASTCompilationUnit
567
     */
568
    public function getSourceFile()
569
    {
570
        return $this->sourceFile;
571
    }
572
573
    /**
574
     * Sets a new php source file.
575
     *
576
     * @param string $sourceFile A php source file.
577
     *
578
     * @return void
579
     */
580 28
    public function setSourceFile($sourceFile)
581
    {
582 28
        $this->tokens = null;
583 28
        $this->sourceFile = new ASTCompilationUnit($sourceFile);
584 28
    }
585
586
    /**
587
     * Returns the next token or {@link \PDepend\Source\Tokenizer\Tokenizer::T_EOF} if
588
     * there is no next token.
589
     *
590
     * @return Token|integer
591
     */
592 26 View Code Duplication
    public function next()
593
    {
594 26
        $this->tokenize();
595
596 26
        if ($this->index < $this->count) {
597 26
            return $this->tokens[$this->index++];
598
        }
599 26
        return self::T_EOF;
600
    }
601
602
    /**
603
     * Returns the next token type or {@link \PDepend\Source\Tokenizer\Tokenizer::T_EOF} if
604
     * there is no next token.
605
     *
606
     * @return integer
607
     */
608 View Code Duplication
    public function peek()
609
    {
610
        $this->tokenize();
611
612
        if (isset($this->tokens[$this->index])) {
613
            return $this->tokens[$this->index]->type;
614
        }
615
        return self::T_EOF;
616
    }
617
618
    /**
619
     * Returns the type of next token, after the current token. This method
620
     * ignores all comments between the current and the next token.
621
     *
622
     * @return integer
623
     * @since  0.9.12
624
     */
625
    public function peekNext()
626
    {
627
        $this->tokenize();
628
        
629
        $offset = 0;
630
        do {
631
            $type = $this->tokens[$this->index + ++$offset]->type;
632
        } while ($type == Tokens::T_COMMENT || $type == Tokens::T_DOC_COMMENT);
633
        return $type;
634
    }
635
636
    /**
637
     * Returns the previous token type or {@link \PDepend\Source\Tokenizer\Tokenizer::T_BOF}
638
     * if there is no previous token.
639
     *
640
     * @return integer
641
     */
642 2 View Code Duplication
    public function prev()
643
    {
644 2
        $this->tokenize();
645
646 2
        if ($this->index > 1) {
647
            return $this->tokens[$this->index - 2]->type;
648
        }
649 2
        return self::T_BOF;
650
    }
651
652
    /**
653
     * This method takes an array of tokens returned by <b>token_get_all()</b>
654
     * and substitutes some of the tokens with those required by PDepend's
655
     * parser implementation.
656
     *
657
     * @param array<array> $tokens Unprepared array of php tokens.
658
     *
659
     * @return array<array>
660
     */
661 28
    private function substituteTokens(array $tokens)
662
    {
663 28
        $result = array();
664 28
        foreach ($tokens as $token) {
665 28
            $temp = (array) $token;
666 28
            $temp = $temp[0];
667 28
            if (isset(self::$substituteTokens[$temp])) {
668
                foreach (self::$substituteTokens[$temp] as $token) {
669
                    $result[] = $token;
670
                }
671
            } else {
672 28
                $result[] = $token;
673
            }
674 28
        }
675 28
        return $result;
676
    }
677
678
    /**
679
     * Tokenizes the content of the source file with {@link token_get_all()} and
680
     * filters this token stream.
681
     *
682
     * @return void
683
     */
684 28
    private function tokenize()
685
    {
686 28
        if ($this->tokens !== null) {
687 26
            return;
688
        }
689
690 28
        $this->tokens = array();
691 28
        $this->index  = 0;
692 28
        $this->count  = 0;
693
694
        // Replace short open tags, short open tags will produce invalid results
695
        // in all environments with disabled short open tags.
696 28
        $source = $this->sourceFile->getSource();
697 28
        $source = preg_replace(
698 28
            array('(<\?=)', '(<\?(\s))'),
699 28
            array('<?php echo ', '<?php\1'),
700
            $source
701 28
        );
702
703 28
        if (version_compare(phpversion(), '5.3.0alpha3') < 0) {
704
            $tokens = PHPTokenizerHelperVersion52::tokenize($source);
705
        } else {
706 28
            $tokens = token_get_all($source);
707
        }
708
709 28
        $tokens = $this->substituteTokens($tokens);
710
711
        // Is the current token between an opening and a closing php tag?
712 28
        $inTag = false;
713
714
        // The current line number
715 28
        $startLine = 1;
716
717 28
        $startColumn = 1;
718 28
        $endColumn   = 1;
719
720 28
        $literalMap = self::$literalMap;
721 28
        $tokenMap   = self::$tokenMap;
722
723
        // Previous found type
724 28
        $previousType = null;
725 28
        $previousStartColumn = 0;
726
727 28
        while ($token = current($tokens)) {
728 28
            $type  = null;
729 28
            $image = null;
730
731 28
            if (is_string($token)) {
732 28
                $token = array(null, $token);
733 28
            }
734
735 28
            if ($token[0] === T_OPEN_TAG) {
736 28
                $type  = $tokenMap[$token[0]];
737 28
                $image = $token[1];
738 28
                $inTag = true;
739 28
            } elseif ($token[0] === T_CLOSE_TAG) {
740 12
                $type  = $tokenMap[$token[0]];
741 12
                $image = $token[1];
742 12
                $inTag = false;
743 28
            } elseif ($inTag === false) {
744 6
                $type  = Tokens::T_NO_PHP;
745 6
                $image = $this->consumeNonePhpTokens($tokens);
746 28
            } elseif ($token[0] === T_WHITESPACE) {
747
                // Count newlines in token
748 26
                $lines = substr_count($token[1], "\n");
749 26
                if ($lines === 0) {
750 24
                    $startColumn += strlen($token[1]);
751 24
                } else {
752 20
                    $startColumn = strlen(
753 20
                        substr($token[1], strrpos($token[1], "\n") + 1)
754 20
                    ) + 1;
755
                }
756
757 26
                $startLine += $lines;
758 26
            } else {
759 28
                $value = strtolower($token[1]);
760 28
                if (isset($literalMap[$value])) {
761
                    // Fetch literal type
762 28
                    $type = $literalMap[$value];
763 28
                    $image = $token[1];
764
765
                    // Check for a context sensitive alternative
766 28 View Code Duplication
                    if (isset(self::$alternativeMap[$type][$previousType])) {
767
                        $type = self::$alternativeMap[$type][$previousType];
768
                    }
769
770 28
                    if (isset(self::$reductionMap[$type][$previousType])) {
771
                        $image = self::$reductionMap[$type][$previousType]['image'];
772
                        $type = self::$reductionMap[$type][$previousType]['type'];
773
774
                        $startColumn = $previousStartColumn;
775
776
                        array_pop($this->tokens);
777
                    }
778 28
                } elseif (isset($tokenMap[$token[0]])) {
779 28
                    $type = $tokenMap[$token[0]];
780
                    // Check for a context sensitive alternative
781 28 View Code Duplication
                    if (isset(self::$alternativeMap[$type][$previousType])) {
782
                        $type = self::$alternativeMap[$type][$previousType];
783
                    }
784
785 28
                    $image = $token[1];
786 28
                } else {
787
                    // This should never happen
788
                    // @codeCoverageIgnoreStart
789
                    list($type, $image) = $this->generateUnknownToken($token[1]);
790
                    // @codeCoverageIgnoreEnd
791
                }
792
            }
793
794 28
            if ($type) {
795 28
                $rtrim = rtrim($image);
796 28
                $lines = substr_count($rtrim, "\n");
797 28 View Code Duplication
                if ($lines === 0) {
798 28
                    $endColumn = $startColumn + strlen($rtrim) - 1;
799 28
                } else {
800 16
                    $endColumn = strlen(
801 16
                        substr($rtrim, strrpos($rtrim, "\n") + 1)
802 16
                    );
803
                }
804
805 28
                $endLine = $startLine + $lines;
806
807 28
                $token = new Token($type, $rtrim, $startLine, $endLine, $startColumn, $endColumn);
808
809
                // Store token in internal list
810 28
                $this->tokens[] = $token;
811
812
                // Store previous start column
813 28
                $previousStartColumn = $startColumn;
814
815
                // Count newlines in token
816 28
                $lines = substr_count($image, "\n");
817 28 View Code Duplication
                if ($lines === 0) {
818 28
                    $startColumn += strlen($image);
819 28
                } else {
820 24
                    $startColumn = strlen(
821 24
                        substr($image, strrpos($image, "\n") + 1)
822 24
                    ) + 1;
823
                }
824
825 28
                $startLine += $lines;
826
                
827
                // Store current type
828 28
                if ($type !== Tokens::T_COMMENT && $type !== Tokens::T_DOC_COMMENT) {
829 28
                    $previousType = $type;
830 28
                }
831 28
            }
832
833 28
            next($tokens);
834 28
        }
835
836 28
        $this->count = count($this->tokens);
837 28
    }
838
839
    /**
840
     * This method fetches all tokens until an opening php tag was found and it
841
     * returns the collected content. The returned value will be null if there
842
     * was no none php token.
843
     *
844
     * @param array $tokens Reference to the current token stream.
845
     *
846
     * @return string
847
     */
848 6
    private function consumeNonePhpTokens(array &$tokens)
849
    {
850
        // The collected token content
851 6
        $content = null;
852
853
        // Fetch current token
854 6
        $token = (array) current($tokens);
855
856
        // Skipp all non open tags
857 6
        while ($token[0] !== T_OPEN_TAG_WITH_ECHO &&
858 6
               $token[0] !== T_OPEN_TAG &&
859 6
               $token[0] !== false) {
860 6
            $content .= (isset($token[1]) ? $token[1] : $token[0]);
861
862 6
            $token = (array) next($tokens);
863 6
        }
864
865
        // Set internal pointer one back when there was at least one none php token
866 6
        if ($token[0] !== false) {
867 6
            prev($tokens);
868 6
        }
869
870 6
        return $content;
871
    }
872
873
    /**
874
     * Generates a dummy/temp token for unknown string literals.
875
     *
876
     * @param string $token The unknown string token.
877
     *
878
     * @return array<integer, mixed>
0 ignored issues
show
The doc-type array<integer, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
879
     */
880
    private function generateUnknownToken($token)
881
    {
882
        return array($this->unknownTokenID++, $token);
883
    }
884
}
885