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