ExplicitOctalEmulator.php 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. <?php declare(strict_types=1);
  2. namespace PhpParser\Lexer\TokenEmulator;
  3. use PhpParser\PhpVersion;
  4. use PhpParser\Token;
  5. class ExplicitOctalEmulator extends TokenEmulator {
  6. public function getPhpVersion(): PhpVersion {
  7. return PhpVersion::fromComponents(8, 1);
  8. }
  9. public function isEmulationNeeded(string $code): bool {
  10. return strpos($code, '0o') !== false || strpos($code, '0O') !== false;
  11. }
  12. public function emulate(string $code, array $tokens): array {
  13. for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
  14. $token = $tokens[$i];
  15. if ($token->id == \T_LNUMBER && $token->text === '0' &&
  16. isset($tokens[$i + 1]) && $tokens[$i + 1]->id == \T_STRING &&
  17. preg_match('/[oO][0-7]+(?:_[0-7]+)*/', $tokens[$i + 1]->text)
  18. ) {
  19. $tokenKind = $this->resolveIntegerOrFloatToken($tokens[$i + 1]->text);
  20. array_splice($tokens, $i, 2, [
  21. new Token($tokenKind, '0' . $tokens[$i + 1]->text, $token->line, $token->pos),
  22. ]);
  23. $c--;
  24. }
  25. }
  26. return $tokens;
  27. }
  28. private function resolveIntegerOrFloatToken(string $str): int {
  29. $str = substr($str, 1);
  30. $str = str_replace('_', '', $str);
  31. $num = octdec($str);
  32. return is_float($num) ? \T_DNUMBER : \T_LNUMBER;
  33. }
  34. public function reverseEmulate(string $code, array $tokens): array {
  35. // Explicit octals were not legal code previously, don't bother.
  36. return $tokens;
  37. }
  38. }