diff options
author | Andrew Dolgov <[email protected]> | 2022-03-22 12:24:31 +0300 |
---|---|---|
committer | Andrew Dolgov <[email protected]> | 2022-03-22 12:24:31 +0300 |
commit | 1c4f7ab3b838b23afb2ee4dab14acbf75956e952 (patch) | |
tree | 0a19274107d717efe92d2c0376cd3105fead5a11 /vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator | |
parent | 711662948768492e8d05b778a7d80eacaec368d2 (diff) |
* add phpunit as a dev dependency
* add some basic tests for UrlHelper::rewrite_relative()
* fix UrlHelper::rewrite_relative() to work better on non-absolute
relative URL paths
Diffstat (limited to 'vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator')
13 files changed, 618 insertions, 0 deletions
diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php new file mode 100644 index 000000000..6776a5197 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php @@ -0,0 +1,56 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class AttributeEmulator extends TokenEmulator +{ + public function getPhpVersion(): string + { + return Emulative::PHP_8_0; + } + + public function isEmulationNeeded(string $code) : bool + { + return strpos($code, '#[') !== false; + } + + public function emulate(string $code, array $tokens): array + { + // We need to manually iterate and manage a count because we'll change + // the tokens array on the way. + $line = 1; + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + if ($tokens[$i] === '#' && isset($tokens[$i + 1]) && $tokens[$i + 1] === '[') { + array_splice($tokens, $i, 2, [ + [\T_ATTRIBUTE, '#[', $line] + ]); + $c--; + continue; + } + if (\is_array($tokens[$i])) { + $line += substr_count($tokens[$i][1], "\n"); + } + } + + return $tokens; + } + + public function reverseEmulate(string $code, array $tokens): array + { + // TODO + return $tokens; + } + + public function preprocessCode(string $code, array &$patches): string { + $pos = 0; + while (false !== $pos = strpos($code, '#[', $pos)) { + // Replace #[ with %[ + $code[$pos] = '%'; + $patches[] = [$pos, 'replace', '#']; + $pos += 2; + } + return $code; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php new file mode 100644 index 000000000..d91da9214 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php @@ -0,0 +1,47 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class CoaleseEqualTokenEmulator extends TokenEmulator +{ + public function getPhpVersion(): string + { + return Emulative::PHP_7_4; + } + + public function isEmulationNeeded(string $code): bool + { + return strpos($code, '??=') !== false; + } + + public function emulate(string $code, array $tokens): array + { + // We need to manually iterate and manage a count because we'll change + // the tokens array on the way + $line = 1; + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + if (isset($tokens[$i + 1])) { + if ($tokens[$i][0] === T_COALESCE && $tokens[$i + 1] === '=') { + array_splice($tokens, $i, 2, [ + [\T_COALESCE_EQUAL, '??=', $line] + ]); + $c--; + continue; + } + } + if (\is_array($tokens[$i])) { + $line += substr_count($tokens[$i][1], "\n"); + } + } + + return $tokens; + } + + public function reverseEmulate(string $code, array $tokens): array + { + // ??= was not valid code previously, don't bother. + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php new file mode 100644 index 000000000..4ddc0b17e --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php @@ -0,0 +1,31 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class EnumTokenEmulator extends KeywordEmulator +{ + public function getPhpVersion(): string + { + return Emulative::PHP_8_1; + } + + public function getKeywordString(): string + { + return 'enum'; + } + + public function getKeywordToken(): int + { + return \T_ENUM; + } + + protected function isKeywordContext(array $tokens, int $pos): bool + { + return parent::isKeywordContext($tokens, $pos) + && isset($tokens[$pos + 2]) + && $tokens[$pos + 1][0] === \T_WHITESPACE + && $tokens[$pos + 2][0] === \T_STRING; + } +}
\ No newline at end of file diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php new file mode 100644 index 000000000..f5f6805b8 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php @@ -0,0 +1,44 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +class ExplicitOctalEmulator extends TokenEmulator { + public function getPhpVersion(): string { + return Emulative::PHP_8_1; + } + + public function isEmulationNeeded(string $code): bool { + return strpos($code, '0o') !== false || strpos($code, '0O') !== false; + } + + public function emulate(string $code, array $tokens): array { + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + if ($tokens[$i][0] == \T_LNUMBER && $tokens[$i][1] === '0' && + isset($tokens[$i + 1]) && $tokens[$i + 1][0] == \T_STRING && + preg_match('/[oO][0-7]+(?:_[0-7]+)*/', $tokens[$i + 1][1]) + ) { + $tokenKind = $this->resolveIntegerOrFloatToken($tokens[$i + 1][1]); + array_splice($tokens, $i, 2, [ + [$tokenKind, '0' . $tokens[$i + 1][1], $tokens[$i][2]], + ]); + $c--; + } + } + return $tokens; + } + + private function resolveIntegerOrFloatToken(string $str): int + { + $str = substr($str, 1); + $str = str_replace('_', '', $str); + $num = octdec($str); + return is_float($num) ? \T_DNUMBER : \T_LNUMBER; + } + + public function reverseEmulate(string $code, array $tokens): array { + // Explicit octals were not legal code previously, don't bother. + return $tokens; + } +}
\ No newline at end of file diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php new file mode 100644 index 000000000..c15d6271f --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php @@ -0,0 +1,76 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class FlexibleDocStringEmulator extends TokenEmulator +{ + const FLEXIBLE_DOC_STRING_REGEX = <<<'REGEX' +/<<<[ \t]*(['"]?)([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)\1\r?\n +(?:.*\r?\n)*? +(?<indentation>\h*)\2(?![a-zA-Z0-9_\x80-\xff])(?<separator>(?:;?[\r\n])?)/x +REGEX; + + public function getPhpVersion(): string + { + return Emulative::PHP_7_3; + } + + public function isEmulationNeeded(string $code) : bool + { + return strpos($code, '<<<') !== false; + } + + public function emulate(string $code, array $tokens): array + { + // Handled by preprocessing + fixup. + return $tokens; + } + + public function reverseEmulate(string $code, array $tokens): array + { + // Not supported. + return $tokens; + } + + public function preprocessCode(string $code, array &$patches): string { + if (!preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) { + // No heredoc/nowdoc found + return $code; + } + + // Keep track of how much we need to adjust string offsets due to the modifications we + // already made + $posDelta = 0; + foreach ($matches as $match) { + $indentation = $match['indentation'][0]; + $indentationStart = $match['indentation'][1]; + + $separator = $match['separator'][0]; + $separatorStart = $match['separator'][1]; + + if ($indentation === '' && $separator !== '') { + // Ordinary heredoc/nowdoc + continue; + } + + if ($indentation !== '') { + // Remove indentation + $indentationLen = strlen($indentation); + $code = substr_replace($code, '', $indentationStart + $posDelta, $indentationLen); + $patches[] = [$indentationStart + $posDelta, 'add', $indentation]; + $posDelta -= $indentationLen; + } + + if ($separator === '') { + // Insert newline as separator + $code = substr_replace($code, "\n", $separatorStart + $posDelta, 0); + $patches[] = [$separatorStart + $posDelta, 'remove', "\n"]; + $posDelta += 1; + } + } + + return $code; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php new file mode 100644 index 000000000..eb7e49634 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php @@ -0,0 +1,23 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class FnTokenEmulator extends KeywordEmulator +{ + public function getPhpVersion(): string + { + return Emulative::PHP_7_4; + } + + public function getKeywordString(): string + { + return 'fn'; + } + + public function getKeywordToken(): int + { + return \T_FN; + } +}
\ No newline at end of file diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php new file mode 100644 index 000000000..ea261cc17 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php @@ -0,0 +1,62 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +abstract class KeywordEmulator extends TokenEmulator +{ + abstract function getKeywordString(): string; + abstract function getKeywordToken(): int; + + public function isEmulationNeeded(string $code): bool + { + return strpos(strtolower($code), $this->getKeywordString()) !== false; + } + + protected function isKeywordContext(array $tokens, int $pos): bool + { + $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos); + return $previousNonSpaceToken === null || $previousNonSpaceToken[0] !== \T_OBJECT_OPERATOR; + } + + public function emulate(string $code, array $tokens): array + { + $keywordString = $this->getKeywordString(); + foreach ($tokens as $i => $token) { + if ($token[0] === T_STRING && strtolower($token[1]) === $keywordString + && $this->isKeywordContext($tokens, $i)) { + $tokens[$i][0] = $this->getKeywordToken(); + } + } + + return $tokens; + } + + /** + * @param mixed[] $tokens + * @return mixed[]|null + */ + private function getPreviousNonSpaceToken(array $tokens, int $start) + { + for ($i = $start - 1; $i >= 0; --$i) { + if ($tokens[$i][0] === T_WHITESPACE) { + continue; + } + + return $tokens[$i]; + } + + return null; + } + + public function reverseEmulate(string $code, array $tokens): array + { + $keywordToken = $this->getKeywordToken(); + foreach ($tokens as $i => $token) { + if ($token[0] === $keywordToken) { + $tokens[$i][0] = \T_STRING; + } + } + + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php new file mode 100644 index 000000000..902a46dfc --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php @@ -0,0 +1,23 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class MatchTokenEmulator extends KeywordEmulator +{ + public function getPhpVersion(): string + { + return Emulative::PHP_8_0; + } + + public function getKeywordString(): string + { + return 'match'; + } + + public function getKeywordToken(): int + { + return \T_MATCH; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php new file mode 100644 index 000000000..1a29c676e --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php @@ -0,0 +1,67 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class NullsafeTokenEmulator extends TokenEmulator +{ + public function getPhpVersion(): string + { + return Emulative::PHP_8_0; + } + + public function isEmulationNeeded(string $code): bool + { + return strpos($code, '?->') !== false; + } + + public function emulate(string $code, array $tokens): array + { + // We need to manually iterate and manage a count because we'll change + // the tokens array on the way + $line = 1; + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + if ($tokens[$i] === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) { + array_splice($tokens, $i, 2, [ + [\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line] + ]); + $c--; + continue; + } + + // Handle ?-> inside encapsed string. + if ($tokens[$i][0] === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1]) + && $tokens[$i - 1][0] === \T_VARIABLE + && preg_match('/^\?->([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)/', $tokens[$i][1], $matches) + ) { + $replacement = [ + [\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line], + [\T_STRING, $matches[1], $line], + ]; + if (\strlen($matches[0]) !== \strlen($tokens[$i][1])) { + $replacement[] = [ + \T_ENCAPSED_AND_WHITESPACE, + \substr($tokens[$i][1], \strlen($matches[0])), + $line + ]; + } + array_splice($tokens, $i, 1, $replacement); + $c += \count($replacement) - 1; + continue; + } + + if (\is_array($tokens[$i])) { + $line += substr_count($tokens[$i][1], "\n"); + } + } + + return $tokens; + } + + public function reverseEmulate(string $code, array $tokens): array + { + // ?-> was not valid code previously, don't bother. + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php new file mode 100644 index 000000000..cdf793e46 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php @@ -0,0 +1,105 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class NumericLiteralSeparatorEmulator extends TokenEmulator +{ + const BIN = '(?:0b[01]+(?:_[01]+)*)'; + const HEX = '(?:0x[0-9a-f]+(?:_[0-9a-f]+)*)'; + const DEC = '(?:[0-9]+(?:_[0-9]+)*)'; + const SIMPLE_FLOAT = '(?:' . self::DEC . '\.' . self::DEC . '?|\.' . self::DEC . ')'; + const EXP = '(?:e[+-]?' . self::DEC . ')'; + const FLOAT = '(?:' . self::SIMPLE_FLOAT . self::EXP . '?|' . self::DEC . self::EXP . ')'; + const NUMBER = '~' . self::FLOAT . '|' . self::BIN . '|' . self::HEX . '|' . self::DEC . '~iA'; + + public function getPhpVersion(): string + { + return Emulative::PHP_7_4; + } + + public function isEmulationNeeded(string $code) : bool + { + return preg_match('~[0-9]_[0-9]~', $code) + || preg_match('~0x[0-9a-f]+_[0-9a-f]~i', $code); + } + + public function emulate(string $code, array $tokens): array + { + // We need to manually iterate and manage a count because we'll change + // the tokens array on the way + $codeOffset = 0; + for ($i = 0, $c = count($tokens); $i < $c; ++$i) { + $token = $tokens[$i]; + $tokenLen = \strlen(\is_array($token) ? $token[1] : $token); + + if ($token[0] !== T_LNUMBER && $token[0] !== T_DNUMBER) { + $codeOffset += $tokenLen; + continue; + } + + $res = preg_match(self::NUMBER, $code, $matches, 0, $codeOffset); + assert($res, "No number at number token position"); + + $match = $matches[0]; + $matchLen = \strlen($match); + if ($matchLen === $tokenLen) { + // Original token already holds the full number. + $codeOffset += $tokenLen; + continue; + } + + $tokenKind = $this->resolveIntegerOrFloatToken($match); + $newTokens = [[$tokenKind, $match, $token[2]]]; + + $numTokens = 1; + $len = $tokenLen; + while ($matchLen > $len) { + $nextToken = $tokens[$i + $numTokens]; + $nextTokenText = \is_array($nextToken) ? $nextToken[1] : $nextToken; + $nextTokenLen = \strlen($nextTokenText); + + $numTokens++; + if ($matchLen < $len + $nextTokenLen) { + // Split trailing characters into a partial token. + assert(is_array($nextToken), "Partial token should be an array token"); + $partialText = substr($nextTokenText, $matchLen - $len); + $newTokens[] = [$nextToken[0], $partialText, $nextToken[2]]; + break; + } + + $len += $nextTokenLen; + } + + array_splice($tokens, $i, $numTokens, $newTokens); + $c -= $numTokens - \count($newTokens); + $codeOffset += $matchLen; + } + + return $tokens; + } + + private function resolveIntegerOrFloatToken(string $str): int + { + $str = str_replace('_', '', $str); + + if (stripos($str, '0b') === 0) { + $num = bindec($str); + } elseif (stripos($str, '0x') === 0) { + $num = hexdec($str); + } elseif (stripos($str, '0') === 0 && ctype_digit($str)) { + $num = octdec($str); + } else { + $num = +$str; + } + + return is_float($num) ? T_DNUMBER : T_LNUMBER; + } + + public function reverseEmulate(string $code, array $tokens): array + { + // Numeric separators were not legal code previously, don't bother. + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php new file mode 100644 index 000000000..b97f8d112 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php @@ -0,0 +1,23 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +use PhpParser\Lexer\Emulative; + +final class ReadonlyTokenEmulator extends KeywordEmulator +{ + public function getPhpVersion(): string + { + return Emulative::PHP_8_1; + } + + public function getKeywordString(): string + { + return 'readonly'; + } + + public function getKeywordToken(): int + { + return \T_READONLY; + } +}
\ No newline at end of file diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php new file mode 100644 index 000000000..90093f66b --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php @@ -0,0 +1,36 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +/** + * Reverses emulation direction of the inner emulator. + */ +final class ReverseEmulator extends TokenEmulator +{ + /** @var TokenEmulator Inner emulator */ + private $emulator; + + public function __construct(TokenEmulator $emulator) { + $this->emulator = $emulator; + } + + public function getPhpVersion(): string { + return $this->emulator->getPhpVersion(); + } + + public function isEmulationNeeded(string $code): bool { + return $this->emulator->isEmulationNeeded($code); + } + + public function emulate(string $code, array $tokens): array { + return $this->emulator->reverseEmulate($code, $tokens); + } + + public function reverseEmulate(string $code, array $tokens): array { + return $this->emulator->emulate($code, $tokens); + } + + public function preprocessCode(string $code, array &$patches): string { + return $code; + } +}
\ No newline at end of file diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php new file mode 100644 index 000000000..a020bc0ff --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php @@ -0,0 +1,25 @@ +<?php declare(strict_types=1); + +namespace PhpParser\Lexer\TokenEmulator; + +/** @internal */ +abstract class TokenEmulator +{ + abstract public function getPhpVersion(): string; + + abstract public function isEmulationNeeded(string $code): bool; + + /** + * @return array Modified Tokens + */ + abstract public function emulate(string $code, array $tokens): array; + + /** + * @return array Modified Tokens + */ + abstract public function reverseEmulate(string $code, array $tokens): array; + + public function preprocessCode(string $code, array &$patches): string { + return $code; + } +} |