Chris@13
|
1 <?php declare(strict_types=1);
|
Chris@0
|
2
|
Chris@0
|
3 namespace PhpParser\Lexer;
|
Chris@0
|
4
|
Chris@17
|
5 use PhpParser\ErrorHandler;
|
Chris@0
|
6 use PhpParser\LexerTest;
|
Chris@0
|
7 use PhpParser\Parser\Tokens;
|
Chris@0
|
8
|
Chris@0
|
9 class EmulativeTest extends LexerTest
|
Chris@0
|
10 {
|
Chris@13
|
11 protected function getLexer(array $options = []) {
|
Chris@0
|
12 return new Emulative($options);
|
Chris@0
|
13 }
|
Chris@0
|
14
|
Chris@0
|
15 /**
|
Chris@0
|
16 * @dataProvider provideTestReplaceKeywords
|
Chris@0
|
17 */
|
Chris@0
|
18 public function testReplaceKeywords($keyword, $expectedToken) {
|
Chris@0
|
19 $lexer = $this->getLexer();
|
Chris@0
|
20 $lexer->startLexing('<?php ' . $keyword);
|
Chris@0
|
21
|
Chris@0
|
22 $this->assertSame($expectedToken, $lexer->getNextToken());
|
Chris@0
|
23 $this->assertSame(0, $lexer->getNextToken());
|
Chris@0
|
24 }
|
Chris@0
|
25
|
Chris@0
|
26 /**
|
Chris@0
|
27 * @dataProvider provideTestReplaceKeywords
|
Chris@0
|
28 */
|
Chris@0
|
29 public function testNoReplaceKeywordsAfterObjectOperator($keyword) {
|
Chris@0
|
30 $lexer = $this->getLexer();
|
Chris@0
|
31 $lexer->startLexing('<?php ->' . $keyword);
|
Chris@0
|
32
|
Chris@0
|
33 $this->assertSame(Tokens::T_OBJECT_OPERATOR, $lexer->getNextToken());
|
Chris@0
|
34 $this->assertSame(Tokens::T_STRING, $lexer->getNextToken());
|
Chris@0
|
35 $this->assertSame(0, $lexer->getNextToken());
|
Chris@0
|
36 }
|
Chris@0
|
37
|
Chris@0
|
38 public function provideTestReplaceKeywords() {
|
Chris@13
|
39 return [
|
Chris@0
|
40 // PHP 5.5
|
Chris@13
|
41 ['finally', Tokens::T_FINALLY],
|
Chris@13
|
42 ['yield', Tokens::T_YIELD],
|
Chris@0
|
43
|
Chris@0
|
44 // PHP 5.4
|
Chris@13
|
45 ['callable', Tokens::T_CALLABLE],
|
Chris@13
|
46 ['insteadof', Tokens::T_INSTEADOF],
|
Chris@13
|
47 ['trait', Tokens::T_TRAIT],
|
Chris@13
|
48 ['__TRAIT__', Tokens::T_TRAIT_C],
|
Chris@0
|
49
|
Chris@0
|
50 // PHP 5.3
|
Chris@13
|
51 ['__DIR__', Tokens::T_DIR],
|
Chris@13
|
52 ['goto', Tokens::T_GOTO],
|
Chris@13
|
53 ['namespace', Tokens::T_NAMESPACE],
|
Chris@13
|
54 ['__NAMESPACE__', Tokens::T_NS_C],
|
Chris@13
|
55 ];
|
Chris@0
|
56 }
|
Chris@0
|
57
|
Chris@0
|
58 /**
|
Chris@0
|
59 * @dataProvider provideTestLexNewFeatures
|
Chris@0
|
60 */
|
Chris@0
|
61 public function testLexNewFeatures($code, array $expectedTokens) {
|
Chris@0
|
62 $lexer = $this->getLexer();
|
Chris@0
|
63 $lexer->startLexing('<?php ' . $code);
|
Chris@0
|
64
|
Chris@17
|
65 $tokens = [];
|
Chris@17
|
66 while (0 !== $token = $lexer->getNextToken($text)) {
|
Chris@17
|
67 $tokens[] = [$token, $text];
|
Chris@0
|
68 }
|
Chris@17
|
69 $this->assertSame($expectedTokens, $tokens);
|
Chris@0
|
70 }
|
Chris@0
|
71
|
Chris@0
|
72 /**
|
Chris@0
|
73 * @dataProvider provideTestLexNewFeatures
|
Chris@0
|
74 */
|
Chris@0
|
75 public function testLeaveStuffAloneInStrings($code) {
|
Chris@0
|
76 $stringifiedToken = '"' . addcslashes($code, '"\\') . '"';
|
Chris@0
|
77
|
Chris@0
|
78 $lexer = $this->getLexer();
|
Chris@0
|
79 $lexer->startLexing('<?php ' . $stringifiedToken);
|
Chris@0
|
80
|
Chris@0
|
81 $this->assertSame(Tokens::T_CONSTANT_ENCAPSED_STRING, $lexer->getNextToken($text));
|
Chris@0
|
82 $this->assertSame($stringifiedToken, $text);
|
Chris@0
|
83 $this->assertSame(0, $lexer->getNextToken());
|
Chris@0
|
84 }
|
Chris@0
|
85
|
Chris@17
|
86 /**
|
Chris@17
|
87 * @dataProvider provideTestLexNewFeatures
|
Chris@17
|
88 */
|
Chris@17
|
89 public function testErrorAfterEmulation($code) {
|
Chris@17
|
90 $errorHandler = new ErrorHandler\Collecting;
|
Chris@17
|
91 $lexer = $this->getLexer([]);
|
Chris@17
|
92 $lexer->startLexing('<?php ' . $code . "\0", $errorHandler);
|
Chris@17
|
93
|
Chris@17
|
94 $errors = $errorHandler->getErrors();
|
Chris@17
|
95 $this->assertCount(1, $errors);
|
Chris@17
|
96
|
Chris@17
|
97 $error = $errors[0];
|
Chris@17
|
98 $this->assertSame('Unexpected null byte', $error->getRawMessage());
|
Chris@17
|
99
|
Chris@17
|
100 $attrs = $error->getAttributes();
|
Chris@17
|
101 $expPos = strlen('<?php ' . $code);
|
Chris@17
|
102 $expLine = 1 + substr_count('<?php ' . $code, "\n");
|
Chris@17
|
103 $this->assertSame($expPos, $attrs['startFilePos']);
|
Chris@17
|
104 $this->assertSame($expPos, $attrs['endFilePos']);
|
Chris@17
|
105 $this->assertSame($expLine, $attrs['startLine']);
|
Chris@17
|
106 $this->assertSame($expLine, $attrs['endLine']);
|
Chris@17
|
107 }
|
Chris@17
|
108
|
Chris@0
|
109 public function provideTestLexNewFeatures() {
|
Chris@13
|
110 return [
|
Chris@17
|
111 // PHP 7.4
|
Chris@17
|
112 ['??=', [
|
Chris@17
|
113 [Tokens::T_COALESCE_EQUAL, '??='],
|
Chris@17
|
114 ]],
|
Chris@13
|
115 ['yield from', [
|
Chris@13
|
116 [Tokens::T_YIELD_FROM, 'yield from'],
|
Chris@13
|
117 ]],
|
Chris@13
|
118 ["yield\r\nfrom", [
|
Chris@13
|
119 [Tokens::T_YIELD_FROM, "yield\r\nfrom"],
|
Chris@13
|
120 ]],
|
Chris@13
|
121 ['...', [
|
Chris@13
|
122 [Tokens::T_ELLIPSIS, '...'],
|
Chris@13
|
123 ]],
|
Chris@13
|
124 ['**', [
|
Chris@13
|
125 [Tokens::T_POW, '**'],
|
Chris@13
|
126 ]],
|
Chris@13
|
127 ['**=', [
|
Chris@13
|
128 [Tokens::T_POW_EQUAL, '**='],
|
Chris@13
|
129 ]],
|
Chris@13
|
130 ['??', [
|
Chris@13
|
131 [Tokens::T_COALESCE, '??'],
|
Chris@13
|
132 ]],
|
Chris@13
|
133 ['<=>', [
|
Chris@13
|
134 [Tokens::T_SPACESHIP, '<=>'],
|
Chris@13
|
135 ]],
|
Chris@13
|
136 ['0b1010110', [
|
Chris@13
|
137 [Tokens::T_LNUMBER, '0b1010110'],
|
Chris@13
|
138 ]],
|
Chris@13
|
139 ['0b1011010101001010110101010010101011010101010101101011001110111100', [
|
Chris@13
|
140 [Tokens::T_DNUMBER, '0b1011010101001010110101010010101011010101010101101011001110111100'],
|
Chris@13
|
141 ]],
|
Chris@13
|
142 ['\\', [
|
Chris@13
|
143 [Tokens::T_NS_SEPARATOR, '\\'],
|
Chris@13
|
144 ]],
|
Chris@13
|
145 ["<<<'NOWDOC'\nNOWDOC;\n", [
|
Chris@13
|
146 [Tokens::T_START_HEREDOC, "<<<'NOWDOC'\n"],
|
Chris@13
|
147 [Tokens::T_END_HEREDOC, 'NOWDOC'],
|
Chris@13
|
148 [ord(';'), ';'],
|
Chris@13
|
149 ]],
|
Chris@13
|
150 ["<<<'NOWDOC'\nFoobar\nNOWDOC;\n", [
|
Chris@13
|
151 [Tokens::T_START_HEREDOC, "<<<'NOWDOC'\n"],
|
Chris@13
|
152 [Tokens::T_ENCAPSED_AND_WHITESPACE, "Foobar\n"],
|
Chris@13
|
153 [Tokens::T_END_HEREDOC, 'NOWDOC'],
|
Chris@13
|
154 [ord(';'), ';'],
|
Chris@13
|
155 ]],
|
Chris@17
|
156
|
Chris@17
|
157 // Flexible heredoc/nowdoc
|
Chris@17
|
158 ["<<<LABEL\nLABEL,", [
|
Chris@17
|
159 [Tokens::T_START_HEREDOC, "<<<LABEL\n"],
|
Chris@17
|
160 [Tokens::T_END_HEREDOC, "LABEL"],
|
Chris@17
|
161 [ord(','), ','],
|
Chris@17
|
162 ]],
|
Chris@17
|
163 ["<<<LABEL\n LABEL,", [
|
Chris@17
|
164 [Tokens::T_START_HEREDOC, "<<<LABEL\n"],
|
Chris@17
|
165 [Tokens::T_END_HEREDOC, " LABEL"],
|
Chris@17
|
166 [ord(','), ','],
|
Chris@17
|
167 ]],
|
Chris@17
|
168 ["<<<LABEL\n Foo\n LABEL;", [
|
Chris@17
|
169 [Tokens::T_START_HEREDOC, "<<<LABEL\n"],
|
Chris@17
|
170 [Tokens::T_ENCAPSED_AND_WHITESPACE, " Foo\n"],
|
Chris@17
|
171 [Tokens::T_END_HEREDOC, " LABEL"],
|
Chris@17
|
172 [ord(';'), ';'],
|
Chris@17
|
173 ]],
|
Chris@17
|
174 ["<<<A\n A,<<<A\n A,", [
|
Chris@17
|
175 [Tokens::T_START_HEREDOC, "<<<A\n"],
|
Chris@17
|
176 [Tokens::T_END_HEREDOC, " A"],
|
Chris@17
|
177 [ord(','), ','],
|
Chris@17
|
178 [Tokens::T_START_HEREDOC, "<<<A\n"],
|
Chris@17
|
179 [Tokens::T_END_HEREDOC, " A"],
|
Chris@17
|
180 [ord(','), ','],
|
Chris@17
|
181 ]],
|
Chris@17
|
182 ["<<<LABEL\nLABELNOPE\nLABEL\n", [
|
Chris@17
|
183 [Tokens::T_START_HEREDOC, "<<<LABEL\n"],
|
Chris@17
|
184 [Tokens::T_ENCAPSED_AND_WHITESPACE, "LABELNOPE\n"],
|
Chris@17
|
185 [Tokens::T_END_HEREDOC, "LABEL"],
|
Chris@17
|
186 ]],
|
Chris@17
|
187 // Interpretation changed
|
Chris@17
|
188 ["<<<LABEL\n LABEL\nLABEL\n", [
|
Chris@17
|
189 [Tokens::T_START_HEREDOC, "<<<LABEL\n"],
|
Chris@17
|
190 [Tokens::T_END_HEREDOC, " LABEL"],
|
Chris@17
|
191 [Tokens::T_STRING, "LABEL"],
|
Chris@17
|
192 ]],
|
Chris@13
|
193 ];
|
Chris@0
|
194 }
|
Chris@0
|
195 }
|