From afb633b676d46db6a0187995a8d1d7514fc2bbdd Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Mon, 14 Nov 2022 08:58:59 +0100 Subject: [PATCH 1/3] Micro-optimize quoted string sub regexes --- src/Lexer/Lexer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Lexer/Lexer.php b/src/Lexer/Lexer.php index dd8c6265..48fba4f3 100644 --- a/src/Lexer/Lexer.php +++ b/src/Lexer/Lexer.php @@ -151,8 +151,8 @@ private function generateRegexp(): string self::TOKEN_FLOAT => '(?:-?[0-9]++\\.[0-9]*+(?:e-?[0-9]++)?)|(?:-?[0-9]*+\\.[0-9]++(?:e-?[0-9]++)?)|(?:-?[0-9]++e-?[0-9]++)', self::TOKEN_INTEGER => '-?(?:(?:0b[0-1]++)|(?:0o[0-7]++)|(?:0x[0-9a-f]++)|(?:[0-9]++))', - self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'', - self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"', + self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\]++)*+\'', + self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\]++)*+"', self::TOKEN_WILDCARD => '\\*', From f884b3cd42e03a99f0fd0d8dd1a2fb2127b62abb Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Mon, 14 Nov 2022 08:59:22 +0100 Subject: [PATCH 2/3] Micro-optimize TokenIterator::joinUntil() --- src/Parser/TokenIterator.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Parser/TokenIterator.php b/src/Parser/TokenIterator.php index 569a9321..3f6e9ea5 100644 --- a/src/Parser/TokenIterator.php +++ b/src/Parser/TokenIterator.php @@ -3,6 +3,7 @@ namespace PHPStan\PhpDocParser\Parser; use PHPStan\PhpDocParser\Lexer\Lexer; +use function array_flip; use function array_pop; use function assert; use function count; @@ -160,8 +161,10 @@ public function getSkippedHorizontalWhiteSpaceIfAny(): string /** @phpstan-impure */ public function joinUntil(int ...$tokenType): string { + $tokenTypeMap = array_flip($tokenType); + $s = ''; - while (!in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, true)) { + while (!isset($tokenTypeMap[$this->tokens[$this->index][Lexer::TYPE_OFFSET]])) { $s .= $this->tokens[$this->index++][Lexer::VALUE_OFFSET]; } return $s; From d0e6a7bb75e5bd0d7f85c3a3dce93739ca4a0993 Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Mon, 14 Nov 2022 09:00:19 +0100 Subject: [PATCH 3/3] Prevent creating heavy exception before parsing const exprs --- src/Parser/TokenIterator.php | 9 +++++++++ src/Parser/TypeParser.php | 21 ++++++++++++--------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/Parser/TokenIterator.php b/src/Parser/TokenIterator.php index 3f6e9ea5..d5e6b43d 100644 --- a/src/Parser/TokenIterator.php +++ b/src/Parser/TokenIterator.php @@ -210,6 +210,15 @@ public function rollback(): void } + /** @internal */ + public function copy(): self + { + $copy = new self($this->tokens, $this->index); + $copy->savePoints = $this->savePoints; + return $copy; + } + + /** * @throws ParserException */ diff --git a/src/Parser/TypeParser.php b/src/Parser/TypeParser.php index 1b07c74e..78124585 100644 --- a/src/Parser/TypeParser.php +++ b/src/Parser/TypeParser.php @@ -139,26 +139,29 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode $tokens->dropSavePoint(); // because of ConstFetchNode } - $exception = new ParserException( - $tokens->currentTokenValue(), - $tokens->currentTokenType(), - $tokens->currentTokenOffset(), - Lexer::TOKEN_IDENTIFIER - ); + $tokensCopy = $tokens->copy(); + $exception = static function () use ($tokensCopy): ParserException { + return new ParserException( + $tokensCopy->currentTokenValue(), + $tokensCopy->currentTokenType(), + $tokensCopy->currentTokenOffset(), + Lexer::TOKEN_IDENTIFIER + ); + }; if ($this->constExprParser === null) { - throw $exception; + throw $exception(); } try { $constExpr = $this->constExprParser->parse($tokens, true); if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) { - throw $exception; + throw $exception(); } return new Ast\Type\ConstTypeNode($constExpr); } catch (LogicException $e) { - throw $exception; + throw $exception(); } }