EmulativeTest.php 6.5 KB

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