Skip to main content
Drupal API
User account menu
  • Log in

Breadcrumb

  1. Drupal Core 11.1.x
  2. ConstExprParser.php

class ConstExprParser

Hierarchy

  • class \PHPStan\PhpDocParser\Parser\ConstExprParser

Expanded class hierarchy of ConstExprParser

3 files declare their use of ConstExprParser
AbstractPHPStanFactory.php in vendor/phpdocumentor/reflection-docblock/src/DocBlock/Tags/Factory/AbstractPHPStanFactory.php
PhpDocParserHelper.php in vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PhpDocParserHelper.php
TypeResolver.php in vendor/phpdocumentor/type-resolver/src/TypeResolver.php

File

vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php, line 11

Namespace

PHPStan\PhpDocParser\Parser
View source
class ConstExprParser {
    
    /** @var bool */
    private $unescapeStrings;
    
    /** @var bool */
    private $quoteAwareConstExprString;
    
    /** @var bool */
    private $useLinesAttributes;
    
    /** @var bool */
    private $useIndexAttributes;
    
    /** @var bool */
    private $parseDoctrineStrings;
    
    /**
     * @param array{lines?: bool, indexes?: bool} $usedAttributes
     */
    public function __construct(bool $unescapeStrings = false, bool $quoteAwareConstExprString = false, array $usedAttributes = []) {
        $this->unescapeStrings = $unescapeStrings;
        $this->quoteAwareConstExprString = $quoteAwareConstExprString;
        $this->useLinesAttributes = $usedAttributes['lines'] ?? false;
        $this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
        $this->parseDoctrineStrings = false;
    }
    
    /**
     * @internal
     */
    public function toDoctrine() : self {
        $self = new self($this->unescapeStrings, $this->quoteAwareConstExprString, [
            'lines' => $this->useLinesAttributes,
            'indexes' => $this->useIndexAttributes,
        ]);
        $self->parseDoctrineStrings = true;
        return $self;
    }
    public function parse(TokenIterator $tokens, bool $trimStrings = false) : Ast\ConstExpr\ConstExprNode {
        $startLine = $tokens->currentTokenLine();
        $startIndex = $tokens->currentTokenIndex();
        if ($tokens->isCurrentTokenType(Lexer::TOKEN_FLOAT)) {
            $value = $tokens->currentTokenValue();
            $tokens->next();
            return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprFloatNode(str_replace('_', '', $value)), $startLine, $startIndex);
        }
        if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {
            $value = $tokens->currentTokenValue();
            $tokens->next();
            return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $value)), $startLine, $startIndex);
        }
        if ($this->parseDoctrineStrings && $tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
            $value = $tokens->currentTokenValue();
            $tokens->next();
            return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($value)), $startLine, $startIndex);
        }
        if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
            if ($this->parseDoctrineStrings) {
                if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
                    throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_DOUBLE_QUOTED_STRING, null, $tokens->currentTokenLine());
                }
                $value = $tokens->currentTokenValue();
                $tokens->next();
                return $this->enrichWithAttributes($tokens, $this->parseDoctrineString($value, $tokens), $startLine, $startIndex);
            }
            $value = $tokens->currentTokenValue();
            $type = $tokens->currentTokenType();
            if ($trimStrings) {
                if ($this->unescapeStrings) {
                    $value = StringUnescaper::unescapeString($value);
                }
                else {
                    $value = substr($value, 1, -1);
                }
            }
            $tokens->next();
            if ($this->quoteAwareConstExprString) {
                return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\QuoteAwareConstExprStringNode($value, $type === Lexer::TOKEN_SINGLE_QUOTED_STRING ? Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED : Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED), $startLine, $startIndex);
            }
            return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprStringNode($value), $startLine, $startIndex);
        }
        elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
            $identifier = $tokens->currentTokenValue();
            $tokens->next();
            switch (strtolower($identifier)) {
                case 'true':
                    return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprTrueNode(), $startLine, $startIndex);
                case 'false':
                    return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprFalseNode(), $startLine, $startIndex);
                case 'null':
                    return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprNullNode(), $startLine, $startIndex);
                case 'array':
                    $tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
                    return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex);
            }
            if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
                $classConstantName = '';
                $lastType = null;
                while (true) {
                    if ($lastType !== Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) {
                        $classConstantName .= $tokens->currentTokenValue();
                        $tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
                        $lastType = Lexer::TOKEN_IDENTIFIER;
                        continue;
                    }
                    if ($lastType !== Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {
                        $classConstantName .= '*';
                        $lastType = Lexer::TOKEN_WILDCARD;
                        if ($tokens->getSkippedHorizontalWhiteSpaceIfAny() !== '') {
                            break;
                        }
                        continue;
                    }
                    if ($lastType === null) {
                        // trigger parse error if nothing valid was consumed
                        $tokens->consumeTokenType(Lexer::TOKEN_WILDCARD);
                    }
                    break;
                }
                return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName), $startLine, $startIndex);
            }
            return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstFetchNode('', $identifier), $startLine, $startIndex);
        }
        elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
            return $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET, $startIndex);
        }
        throw new ParserException($tokens->currentTokenValue(), $tokens->currentTokenType(), $tokens->currentTokenOffset(), Lexer::TOKEN_IDENTIFIER, null, $tokens->currentTokenLine());
    }
    private function parseArray(TokenIterator $tokens, int $endToken, int $startIndex) : Ast\ConstExpr\ConstExprArrayNode {
        $items = [];
        $startLine = $tokens->currentTokenLine();
        if (!$tokens->tryConsumeTokenType($endToken)) {
            do {
                $items[] = $this->parseArrayItem($tokens);
            } while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType($endToken));
            $tokens->consumeTokenType($endToken);
        }
        return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprArrayNode($items), $startLine, $startIndex);
    }
    
    /**
     * This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting
     * to the next token.
     */
    public function parseDoctrineString(string $text, TokenIterator $tokens) : Ast\ConstExpr\DoctrineConstExprStringNode {
        // Because of how Lexer works, a valid Doctrine string
        // can consist of a sequence of TOKEN_DOUBLE_QUOTED_STRING and TOKEN_DOCTRINE_ANNOTATION_STRING
        while ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING, Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
            $text .= $tokens->currentTokenValue();
            $tokens->next();
        }
        return new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($text));
    }
    private function parseArrayItem(TokenIterator $tokens) : Ast\ConstExpr\ConstExprArrayItemNode {
        $startLine = $tokens->currentTokenLine();
        $startIndex = $tokens->currentTokenIndex();
        $expr = $this->parse($tokens);
        if ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_ARROW)) {
            $key = $expr;
            $value = $this->parse($tokens);
        }
        else {
            $key = null;
            $value = $expr;
        }
        return $this->enrichWithAttributes($tokens, new Ast\ConstExpr\ConstExprArrayItemNode($key, $value), $startLine, $startIndex);
    }
    
    /**
     * @template T of Ast\ConstExpr\ConstExprNode
     * @param T $node
     * @return T
     */
    private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex) : Ast\ConstExpr\ConstExprNode {
        if ($this->useLinesAttributes) {
            $node->setAttribute(Ast\Attribute::START_LINE, $startLine);
            $node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
        }
        if ($this->useIndexAttributes) {
            $node->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
            $node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
        }
        return $node;
    }

}

Members

Title Sort descending Modifiers Object type Summary
ConstExprParser::$parseDoctrineStrings private property @var bool
ConstExprParser::$quoteAwareConstExprString private property @var bool
ConstExprParser::$unescapeStrings private property @var bool
ConstExprParser::$useIndexAttributes private property @var bool
ConstExprParser::$useLinesAttributes private property @var bool
ConstExprParser::enrichWithAttributes private function * @template T of Ast\ConstExpr\ConstExprNode
*
ConstExprParser::parse public function
ConstExprParser::parseArray private function
ConstExprParser::parseArrayItem private function
ConstExprParser::parseDoctrineString public function * This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting
* to the next token.
ConstExprParser::toDoctrine public function * @internal
ConstExprParser::__construct public function *

API Navigation

  • Drupal Core 11.1.x
  • Topics
  • Classes
  • Functions
  • Constants
  • Globals
  • Files
  • Namespaces
  • Deprecated
  • Services
RSS feed
Powered by Drupal