2021-05-10 00:23:30 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
declare (strict_types=1);
|
2022-06-06 17:12:56 +00:00
|
|
|
namespace PHPStan\PhpDocParser\Parser;
|
2021-05-10 00:23:30 +00:00
|
|
|
|
2022-06-06 17:12:56 +00:00
|
|
|
use PHPStan\PhpDocParser\Ast;
|
|
|
|
use PHPStan\PhpDocParser\Lexer\Lexer;
|
2022-03-28 09:17:08 +00:00
|
|
|
use function strtolower;
|
|
|
|
use function trim;
|
2021-05-10 00:23:30 +00:00
|
|
|
class ConstExprParser
|
|
|
|
{
|
2022-06-06 17:12:56 +00:00
|
|
|
public function parse(\PHPStan\PhpDocParser\Parser\TokenIterator $tokens, bool $trimStrings = \false) : \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode
|
2021-05-10 00:23:30 +00:00
|
|
|
{
|
2022-06-06 17:12:56 +00:00
|
|
|
if ($tokens->isCurrentTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_FLOAT)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$value = $tokens->currentTokenValue();
|
|
|
|
$tokens->next();
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFloatNode($value);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
if ($tokens->isCurrentTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_INTEGER)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$value = $tokens->currentTokenValue();
|
|
|
|
$tokens->next();
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode($value);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
if ($tokens->isCurrentTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$value = $tokens->currentTokenValue();
|
|
|
|
if ($trimStrings) {
|
2022-06-06 17:12:56 +00:00
|
|
|
$value = \trim($tokens->currentTokenValue(), "'");
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
|
|
|
$tokens->next();
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode($value);
|
|
|
|
} elseif ($tokens->isCurrentTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$value = $tokens->currentTokenValue();
|
|
|
|
if ($trimStrings) {
|
2022-06-06 17:12:56 +00:00
|
|
|
$value = \trim($tokens->currentTokenValue(), '"');
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
|
|
|
$tokens->next();
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode($value);
|
|
|
|
} elseif ($tokens->isCurrentTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_IDENTIFIER)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$identifier = $tokens->currentTokenValue();
|
|
|
|
$tokens->next();
|
2022-06-06 17:12:56 +00:00
|
|
|
switch (\strtolower($identifier)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
case 'true':
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprTrueNode();
|
2021-05-10 00:23:30 +00:00
|
|
|
case 'false':
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprFalseNode();
|
2021-05-10 00:23:30 +00:00
|
|
|
case 'null':
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNullNode();
|
2021-05-10 00:23:30 +00:00
|
|
|
case 'array':
|
2022-06-06 17:12:56 +00:00
|
|
|
$tokens->consumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_OPEN_PARENTHESES);
|
|
|
|
return $this->parseArray($tokens, \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_CLOSE_PARENTHESES);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
if ($tokens->tryConsumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_DOUBLE_COLON)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$classConstantName = '';
|
2021-09-12 14:45:32 +00:00
|
|
|
$lastType = null;
|
|
|
|
while (\true) {
|
2022-06-06 17:12:56 +00:00
|
|
|
if ($lastType !== \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_IDENTIFIER) {
|
2021-09-12 14:45:32 +00:00
|
|
|
$classConstantName .= $tokens->currentTokenValue();
|
2022-06-06 17:12:56 +00:00
|
|
|
$tokens->consumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_IDENTIFIER);
|
|
|
|
$lastType = \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_IDENTIFIER;
|
2021-09-12 14:45:32 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
if ($lastType !== \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_WILDCARD)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$classConstantName .= '*';
|
2022-06-06 17:12:56 +00:00
|
|
|
$lastType = \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_WILDCARD;
|
2021-10-12 09:14:35 +00:00
|
|
|
if ($tokens->getSkippedHorizontalWhiteSpaceIfAny() !== '') {
|
|
|
|
break;
|
|
|
|
}
|
2021-09-12 14:45:32 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ($lastType === null) {
|
|
|
|
// trigger parse error if nothing valid was consumed
|
2022-06-06 17:12:56 +00:00
|
|
|
$tokens->consumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_WILDCARD);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2021-09-12 14:45:32 +00:00
|
|
|
break;
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode('', $identifier);
|
|
|
|
} elseif ($tokens->tryConsumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
|
|
|
return $this->parseArray($tokens, \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_CLOSE_SQUARE_BRACKET);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
throw new \PHPStan\PhpDocParser\Parser\ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), \PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_IDENTIFIER);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
private function parseArray(\PHPStan\PhpDocParser\Parser\TokenIterator $tokens, int $endToken) : \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode
|
2021-05-10 00:23:30 +00:00
|
|
|
{
|
|
|
|
$items = [];
|
|
|
|
if (!$tokens->tryConsumeTokenType($endToken)) {
|
|
|
|
do {
|
|
|
|
$items[] = $this->parseArrayItem($tokens);
|
2022-06-06 17:12:56 +00:00
|
|
|
} while ($tokens->tryConsumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType($endToken));
|
2021-05-10 00:23:30 +00:00
|
|
|
$tokens->consumeTokenType($endToken);
|
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode($items);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
private function parseArrayItem(\PHPStan\PhpDocParser\Parser\TokenIterator $tokens) : \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayItemNode
|
2021-05-10 00:23:30 +00:00
|
|
|
{
|
|
|
|
$expr = $this->parse($tokens);
|
2022-06-06 17:12:56 +00:00
|
|
|
if ($tokens->tryConsumeTokenType(\PHPStan\PhpDocParser\Lexer\Lexer::TOKEN_DOUBLE_ARROW)) {
|
2021-05-10 00:23:30 +00:00
|
|
|
$key = $expr;
|
|
|
|
$value = $this->parse($tokens);
|
|
|
|
} else {
|
|
|
|
$key = null;
|
|
|
|
$value = $expr;
|
|
|
|
}
|
2022-06-06 17:12:56 +00:00
|
|
|
return new \PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayItemNode($key, $value);
|
2021-05-10 00:23:30 +00:00
|
|
|
}
|
|
|
|
}
|